id()===$actor->id,403); $current=User::where('tenant_id',$actor->tenant_id)->findOrFail($actor->id); abort_unless(($c['source_scope']['tenant_id']??null)===$current->tenant_id&&$current->hasFunctions(['finance']) &&!app(OrganizationAccess::class)->maintenanceOnly($current),403); $path=config('sgf_invoice.client_package');$pin=config('sgf_invoice.client_package_sha256'); if(!is_string($path)||is_link($path)||!is_file($path)||!is_string($pin)||!preg_match('/^[a-f0-9]{64}$/D',$pin) ||!hash_equals($pin,hash_file('sha256',$path)))throw new LogicException('Verified client package required.'); if(class_exists(\Tempo\SgcInvoiceClient\InvoiceClient::class,false)){ if(!hash_equals($pin,hash_file('sha256',(new \ReflectionClass(\Tempo\SgcInvoiceClient\InvoiceClient::class))->getFileName())))throw new LogicException('Client version changed; restart separately.'); }else require_once $path; $configurationHash=hash('sha256',json_encode($c,JSON_THROW_ON_ERROR)); return new \Tempo\SgcInvoiceClient\InvoiceClient($c['client_id'],$c['token'],$c['context_version'],$c['source_scope'],$c['target_scope'], function(string $method,string $url,array $headers,?array $body)use($actor,$connection,$configurationHash):array{ // Recheck the originating person's authority immediately before every network operation. $now=config('sgf_invoice.connections',[])[$connection]??null; if(config('sgf_invoice.enabled')!==true||!is_array($now)||!hash_equals($configurationHash,hash('sha256',json_encode($now,JSON_THROW_ON_ERROR))) ||auth()->id()!==$actor->id)return ['status'=>403,'json'=>null]; $current=User::where('tenant_id',$actor->tenant_id)->find($actor->id); if(!$current||!$current->hasFunctions(['finance'])||app(OrganizationAccess::class)->maintenanceOnly($current))return ['status'=>403,'json'=>null]; $http=Http::withHeaders($headers)->acceptJson()->asJson()->withoutRedirecting()->connectTimeout(3)->timeout(15); $response=$method==='GET'?$http->get($url):$http->post($url,$body); return ['status'=>$response->status(),'json'=>$response->json()]; },$c['origin']); } }