From 570be467752bf6aa38622356d8d54bf348591e81 Mon Sep 17 00:00:00 2001 From: Chirag Aggarwal Date: Sat, 23 May 2026 09:17:44 +0530 Subject: [PATCH] Reuse resource tokens for orchestrator artifacts --- app/init/constants.php | 1 + app/init/resources/request.php | 25 ++++++ composer.lock | 8 +- src/Appwrite/Builds/OrchestratorToken.php | 89 ------------------- .../Deployments/Artifacts/Build/Update.php | 22 ++++- .../Http/Deployments/Artifacts/Source/Get.php | 21 ++++- .../Http/Deployments/Events/Create.php | 8 +- .../Modules/Functions/Workers/Builds.php | 32 ++++++- .../Deployments/Artifacts/Build/Update.php | 22 ++++- .../Http/Deployments/Artifacts/Source/Get.php | 21 ++++- .../Sites/Http/Deployments/Events/Create.php | 8 +- 11 files changed, 146 insertions(+), 111 deletions(-) delete mode 100644 src/Appwrite/Builds/OrchestratorToken.php diff --git a/app/init/constants.php b/app/init/constants.php index 75cb467be6..26b8ca834e 100644 --- a/app/init/constants.php +++ b/app/init/constants.php @@ -485,6 +485,7 @@ const ADVISOR_REPORT_TYPES = [ // Resource types for Tokens const TOKENS_RESOURCE_TYPE_FILES = 'files'; +const TOKENS_RESOURCE_TYPE_DEPLOYMENT_ARTIFACTS = 'deploymentArtifacts'; const TOKENS_RESOURCE_TYPE_SITES = 'sites'; const TOKENS_RESOURCE_TYPE_FUNCTIONS = 'functions'; const TOKENS_RESOURCE_TYPE_DATABASES = 'databases'; diff --git a/app/init/resources/request.php b/app/init/resources/request.php index 85d8db3698..8703ea963d 100644 --- a/app/init/resources/request.php +++ b/app/init/resources/request.php @@ -1243,6 +1243,31 @@ return function (Container $context): void { 'fileInternalId' => $sequences[1], ]); })(), + TOKENS_RESOURCE_TYPE_DEPLOYMENT_ARTIFACTS => (function () use ($token, $dbForProject, $authorization) { + $sequences = explode(':', $token->getAttribute('resourceInternalId')); + $ids = explode(':', $token->getAttribute('resourceId')); + + if (count($sequences) !== 2 || count($ids) !== 4) { + return new Document([]); + } + + $accessedAt = $token->getAttribute('accessedAt', 0); + if (empty($accessedAt) || DatabaseDateTime::formatTz(DatabaseDateTime::addSeconds(new \DateTime(), -APP_RESOURCE_TOKEN_ACCESS)) > $accessedAt) { + $token->setAttribute('accessedAt', DatabaseDateTime::now()); + $authorization->skip(fn () => $dbForProject->updateDocument('resourceTokens', $token->getId(), new Document([ + 'accessedAt' => $token->getAttribute('accessedAt') + ]))); + } + + return new Document([ + 'resourceType' => $ids[0], + 'resourceId' => $ids[1], + 'deploymentId' => $ids[2], + 'purpose' => $ids[3], + 'resourceInternalId' => $sequences[0], + 'deploymentInternalId' => $sequences[1], + ]); + })(), default => throw new Exception(Exception::TOKEN_RESOURCE_TYPE_INVALID), }; diff --git a/composer.lock b/composer.lock index 2c59c6da51..71f47076b2 100644 --- a/composer.lock +++ b/composer.lock @@ -1230,12 +1230,12 @@ "source": { "type": "git", "url": "https://github.com/open-runtimes/orchestrator-client-php.git", - "reference": "5b44ad8f056d180e63368f844d01d167f706b13e" + "reference": "85d933c3d56467b2fbc09eac7813de7c2b1c47b1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/open-runtimes/orchestrator-client-php/zipball/5b44ad8f056d180e63368f844d01d167f706b13e", - "reference": "5b44ad8f056d180e63368f844d01d167f706b13e", + "url": "https://api.github.com/repos/open-runtimes/orchestrator-client-php/zipball/85d933c3d56467b2fbc09eac7813de7c2b1c47b1", + "reference": "85d933c3d56467b2fbc09eac7813de7c2b1c47b1", "shasum": "" }, "require": { @@ -1294,7 +1294,7 @@ "source": "https://github.com/open-runtimes/orchestrator-client-php/tree/add-jobs-sdk", "issues": "https://github.com/open-runtimes/orchestrator-client-php/issues" }, - "time": "2026-05-22T18:46:15+00:00" + "time": "2026-05-23T03:41:55+00:00" }, { "name": "open-telemetry/api", diff --git a/src/Appwrite/Builds/OrchestratorToken.php b/src/Appwrite/Builds/OrchestratorToken.php deleted file mode 100644 index d45c9196df..0000000000 --- a/src/Appwrite/Builds/OrchestratorToken.php +++ /dev/null @@ -1,89 +0,0 @@ - $projectId, - 'resourceId' => $resourceId, - 'deploymentId' => $deploymentId, - 'purpose' => $purpose, - 'expires' => $expires, - ]; - - $encoded = self::base64UrlEncode(\json_encode($payload, JSON_THROW_ON_ERROR)); - $signature = self::sign($encoded); - - return $encoded . '.' . $signature; - } - - public static function verify(string $token, string $projectId, string $resourceId, string $deploymentId, string $purpose): void - { - [$encoded, $signature] = \array_pad(\explode('.', $token, 2), 2, ''); - - if (empty($encoded) || empty($signature) || !\hash_equals(self::sign($encoded), $signature)) { - throw new Exception(Exception::USER_UNAUTHORIZED, 'Invalid build artifact token.'); - } - - $payload = \json_decode(self::base64UrlDecode($encoded), true); - if (!\is_array($payload)) { - throw new Exception(Exception::USER_UNAUTHORIZED, 'Invalid build artifact token.'); - } - - if (($payload['expires'] ?? 0) < \time()) { - throw new Exception(Exception::USER_UNAUTHORIZED, 'Build artifact token expired.'); - } - - if ( - ($payload['projectId'] ?? '') !== $projectId || - ($payload['resourceId'] ?? '') !== $resourceId || - ($payload['deploymentId'] ?? '') !== $deploymentId || - ($payload['purpose'] ?? '') !== $purpose - ) { - throw new Exception(Exception::USER_UNAUTHORIZED, 'Build artifact token mismatch.'); - } - } - - public static function verifySignature(string $body, string $signature): void - { - $expected = 'sha256=' . \hash_hmac('sha256', $body, self::secret()); - - if (empty($signature) || !\hash_equals($expected, $signature)) { - throw new Exception(Exception::USER_UNAUTHORIZED, 'Invalid orchestrator event signature.'); - } - } - - private static function sign(string $payload): string - { - return \hash_hmac('sha256', $payload, self::secret()); - } - - private static function secret(): string - { - $secret = \Utopia\System\System::getEnv('_APP_ORCHESTRATOR_CALLBACK_SECRET', ''); - - if (empty($secret)) { - $secret = \Utopia\System\System::getEnv('_APP_OPENSSL_KEY_V1', ''); - } - - return $secret; - } - - private static function base64UrlEncode(string $value): string - { - return \rtrim(\strtr(\base64_encode($value), '+/', '-_'), '='); - } - - private static function base64UrlDecode(string $value): string - { - $value .= \str_repeat('=', (4 - \strlen($value) % 4) % 4); - - return \base64_decode(\strtr($value, '-_', '+/')) ?: ''; - } -} diff --git a/src/Appwrite/Platform/Modules/Functions/Http/Deployments/Artifacts/Build/Update.php b/src/Appwrite/Platform/Modules/Functions/Http/Deployments/Artifacts/Build/Update.php index 73177b8bd8..c36c5e45c6 100644 --- a/src/Appwrite/Platform/Modules/Functions/Http/Deployments/Artifacts/Build/Update.php +++ b/src/Appwrite/Platform/Modules/Functions/Http/Deployments/Artifacts/Build/Update.php @@ -2,7 +2,6 @@ namespace Appwrite\Platform\Modules\Functions\Http\Deployments\Artifacts\Build; -use Appwrite\Builds\OrchestratorToken; use Appwrite\Event\Publisher\Build as BuildPublisher; use Appwrite\Extend\Exception; use Appwrite\Platform\Modules\Compute\Http\Deployments\Artifacts\Build\ChunkedBuildArtifact; @@ -43,6 +42,7 @@ class Update extends Action ->inject('request') ->inject('dbForProject') ->inject('project') + ->inject('resourceToken') ->inject('deviceForBuilds') ->inject('publisherForBuilds') ->inject('cache') @@ -58,13 +58,13 @@ class Update extends Action Request $request, Database $dbForProject, Document $project, + Document $resourceToken, Device $deviceForBuilds, BuildPublisher $publisherForBuilds, Cache $cache, callable $locks ) { - $token = $token ?: $request->getQuery('token', ''); - OrchestratorToken::verify($token, $project->getId(), $functionId, $deploymentId, 'build'); + $this->verifyArtifactToken($resourceToken, RESOURCE_TYPE_FUNCTIONS, $functionId, $deploymentId, 'build'); $function = $dbForProject->getAuthorization()->skip(fn () => $dbForProject->getDocument('functions', $functionId)); if ($function->isEmpty()) { @@ -90,4 +90,20 @@ class Update extends Action locks: $locks ); } + + private function verifyArtifactToken(Document $resourceToken, string $resourceType, string $resourceId, string $deploymentId, string $purpose): void + { + if ($resourceToken->isEmpty()) { + throw new Exception(Exception::USER_UNAUTHORIZED, 'Invalid build artifact token.'); + } + + if ( + $resourceToken->getAttribute('resourceType') !== $resourceType || + $resourceToken->getAttribute('resourceId') !== $resourceId || + $resourceToken->getAttribute('deploymentId') !== $deploymentId || + $resourceToken->getAttribute('purpose') !== $purpose + ) { + throw new Exception(Exception::USER_UNAUTHORIZED, 'Build artifact token mismatch.'); + } + } } diff --git a/src/Appwrite/Platform/Modules/Functions/Http/Deployments/Artifacts/Source/Get.php b/src/Appwrite/Platform/Modules/Functions/Http/Deployments/Artifacts/Source/Get.php index 6a6df12055..6bab4e7eb0 100644 --- a/src/Appwrite/Platform/Modules/Functions/Http/Deployments/Artifacts/Source/Get.php +++ b/src/Appwrite/Platform/Modules/Functions/Http/Deployments/Artifacts/Source/Get.php @@ -2,7 +2,6 @@ namespace Appwrite\Platform\Modules\Functions\Http\Deployments\Artifacts\Source; -use Appwrite\Builds\OrchestratorToken; use Appwrite\Extend\Exception; use Appwrite\Utopia\Response; use Utopia\Database\Database; @@ -37,6 +36,7 @@ class Get extends Action ->inject('response') ->inject('dbForProject') ->inject('project') + ->inject('resourceToken') ->inject('deviceForFunctions') ->callback($this->action(...)); } @@ -48,9 +48,10 @@ class Get extends Action Response $response, Database $dbForProject, Document $project, + Document $resourceToken, Device $deviceForFunctions ) { - OrchestratorToken::verify($token, $project->getId(), $functionId, $deploymentId, 'source'); + $this->verifyArtifactToken($resourceToken, RESOURCE_TYPE_FUNCTIONS, $functionId, $deploymentId, 'source'); $function = $dbForProject->getAuthorization()->skip(fn () => $dbForProject->getDocument('functions', $functionId)); if ($function->isEmpty()) { @@ -89,4 +90,20 @@ class Get extends Action $response->send($deviceForFunctions->read($path)); } + + private function verifyArtifactToken(Document $resourceToken, string $resourceType, string $resourceId, string $deploymentId, string $purpose): void + { + if ($resourceToken->isEmpty()) { + throw new Exception(Exception::USER_UNAUTHORIZED, 'Invalid build artifact token.'); + } + + if ( + $resourceToken->getAttribute('resourceType') !== $resourceType || + $resourceToken->getAttribute('resourceId') !== $resourceId || + $resourceToken->getAttribute('deploymentId') !== $deploymentId || + $resourceToken->getAttribute('purpose') !== $purpose + ) { + throw new Exception(Exception::USER_UNAUTHORIZED, 'Build artifact token mismatch.'); + } + } } diff --git a/src/Appwrite/Platform/Modules/Functions/Http/Deployments/Events/Create.php b/src/Appwrite/Platform/Modules/Functions/Http/Deployments/Events/Create.php index be3eaf1cc5..0330802120 100644 --- a/src/Appwrite/Platform/Modules/Functions/Http/Deployments/Events/Create.php +++ b/src/Appwrite/Platform/Modules/Functions/Http/Deployments/Events/Create.php @@ -2,17 +2,18 @@ namespace Appwrite\Platform\Modules\Functions\Http\Deployments\Events; -use Appwrite\Builds\OrchestratorToken; use Appwrite\Event\Message\Build as BuildMessage; use Appwrite\Event\Publisher\Build as BuildPublisher; use Appwrite\Extend\Exception; use Appwrite\Utopia\Response; +use OpenRuntimes\Orchestrator\Callback\Signature; use Utopia\Database\Database; use Utopia\Database\Document; use Utopia\Database\Validator\UID; use Utopia\Http\Adapter\Swoole\Request; use Utopia\Platform\Action; use Utopia\Platform\Scope\HTTP; +use Utopia\System\System; class Create extends Action { @@ -52,7 +53,10 @@ class Create extends Action BuildPublisher $publisherForBuilds ) { $body = $request->getRawPayload(); - OrchestratorToken::verifySignature($body, $request->getHeader('x-signature-256', '')); + $secret = System::getEnv('_APP_ORCHESTRATOR_CALLBACK_SECRET', System::getEnv('_APP_OPENSSL_KEY_V1', '')); + if (! Signature::verify($body, $request->getHeader('x-signature-256', ''), $secret)) { + throw new Exception(Exception::USER_UNAUTHORIZED, 'Invalid orchestrator event signature.'); + } $event = \json_decode($body, true); if (!\is_array($event)) { diff --git a/src/Appwrite/Platform/Modules/Functions/Workers/Builds.php b/src/Appwrite/Platform/Modules/Functions/Workers/Builds.php index d602150245..bb5213877a 100644 --- a/src/Appwrite/Platform/Modules/Functions/Workers/Builds.php +++ b/src/Appwrite/Platform/Modules/Functions/Workers/Builds.php @@ -3,7 +3,6 @@ namespace Appwrite\Platform\Modules\Functions\Workers; use Ahc\Jwt\JWT; -use Appwrite\Builds\OrchestratorToken; use Appwrite\Event\Event; use Appwrite\Event\Message\Func as FunctionMessage; use Appwrite\Event\Message\Usage as UsageMessage; @@ -16,6 +15,7 @@ use Appwrite\Extend\Exception as AppwriteException; use Appwrite\Filter\BranchDomain as BranchDomainFilter; use Appwrite\Usage\Context; use Appwrite\Utopia\Response\Model\Deployment; +use Appwrite\Utopia\Response\Model\ResourceToken as ResourceTokenModel; use Appwrite\Vcs\Comment; use Exception; use Executor\Exception\Timeout as ExecutorTimeout; @@ -29,6 +29,7 @@ use OpenRuntimes\Orchestrator\DTO\JobRequest; use OpenRuntimes\Orchestrator\Enum\CallbackEvent; use OpenRuntimes\Orchestrator\Exception\TimeoutException as OrchestratorTimeout; use Swoole\Coroutine as Co; +use Utopia\Auth\Proofs\Token; use Utopia\Cache\Cache; use Utopia\Config\Config; use Utopia\Console; @@ -39,6 +40,7 @@ use Utopia\Database\Exception\Conflict; use Utopia\Database\Exception\Duplicate; use Utopia\Database\Exception\Restricted; use Utopia\Database\Exception\Structure; +use Utopia\Database\Helpers\ID; use Utopia\Database\Query; use Utopia\Detector\Detection\Rendering\SSR; use Utopia\Detector\Detection\Rendering\XStatic; @@ -722,6 +724,7 @@ class Builds extends Action if ($buildsBackend === 'orchestrator') { $this->createOrchestratorBuild( project: $project, + dbForProject: $dbForProject, resource: $resource, deployment: $deployment, runtime: $runtime, @@ -1326,6 +1329,7 @@ class Builds extends Action protected function createOrchestratorBuild( Document $project, + Database $dbForProject, Document $resource, Document $deployment, array $runtime, @@ -1344,8 +1348,9 @@ class Builds extends Action $callbackBase = \rtrim(System::getEnv('_APP_ORCHESTRATOR_APPWRITE_CALLBACK_ENDPOINT', $base), '/'); $resourcePath = $resource->getCollection(); - $sourceToken = OrchestratorToken::create($project->getId(), $resourceId, $deploymentId, 'source', $timeout + 300); - $buildToken = OrchestratorToken::create($project->getId(), $resourceId, $deploymentId, 'build', $timeout + 300); + $callbackSecret = System::getEnv('_APP_ORCHESTRATOR_CALLBACK_SECRET', System::getEnv('_APP_OPENSSL_KEY_V1', '')); + $sourceToken = $this->createDeploymentArtifactToken($dbForProject, $resource, $deployment, 'source', $timeout + 300); + $buildToken = $this->createDeploymentArtifactToken($dbForProject, $resource, $deployment, 'build', $timeout + 300); $projectQuery = 'project=' . \rawurlencode($project->getId()); $appwriteProjectHeader = ['X-Appwrite-Project' => $project->getId()]; @@ -1443,7 +1448,7 @@ class Builds extends Action CallbackEvent::Artifact, CallbackEvent::Exit, ], - key: System::getEnv('_APP_ORCHESTRATOR_CALLBACK_SECRET', System::getEnv('_APP_OPENSSL_KEY_V1', '')), + key: $callbackSecret, headers: $appwriteProjectHeader, ), ), $timeout); @@ -1452,6 +1457,25 @@ class Builds extends Action } } + protected function createDeploymentArtifactToken( + Database $dbForProject, + Document $resource, + Document $deployment, + string $purpose, + int $duration + ): string { + $token = $dbForProject->getAuthorization()->skip(fn () => $dbForProject->createDocument('resourceTokens', new Document([ + '$id' => ID::unique(), + 'secret' => (new Token(128))->generate(), + 'resourceId' => "{$resource->getCollection()}:{$resource->getId()}:{$deployment->getId()}:{$purpose}", + 'resourceInternalId' => "{$resource->getSequence()}:{$deployment->getSequence()}", + 'resourceType' => TOKENS_RESOURCE_TYPE_DEPLOYMENT_ARTIFACTS, + 'expire' => DateTime::formatTz(DateTime::addSeconds(new \DateTime(), $duration)), + ]))); + + return (new ResourceTokenModel())->filter($token)->getAttribute('secret'); + } + protected function applyOrchestratorEvent( Realtime $queueForRealtime, Context $usage, diff --git a/src/Appwrite/Platform/Modules/Sites/Http/Deployments/Artifacts/Build/Update.php b/src/Appwrite/Platform/Modules/Sites/Http/Deployments/Artifacts/Build/Update.php index 272b09814d..ff151ee8aa 100644 --- a/src/Appwrite/Platform/Modules/Sites/Http/Deployments/Artifacts/Build/Update.php +++ b/src/Appwrite/Platform/Modules/Sites/Http/Deployments/Artifacts/Build/Update.php @@ -2,7 +2,6 @@ namespace Appwrite\Platform\Modules\Sites\Http\Deployments\Artifacts\Build; -use Appwrite\Builds\OrchestratorToken; use Appwrite\Event\Publisher\Build as BuildPublisher; use Appwrite\Extend\Exception; use Appwrite\Platform\Modules\Compute\Http\Deployments\Artifacts\Build\ChunkedBuildArtifact; @@ -43,6 +42,7 @@ class Update extends Action ->inject('request') ->inject('dbForProject') ->inject('project') + ->inject('resourceToken') ->inject('deviceForBuilds') ->inject('publisherForBuilds') ->inject('cache') @@ -58,13 +58,13 @@ class Update extends Action Request $request, Database $dbForProject, Document $project, + Document $resourceToken, Device $deviceForBuilds, BuildPublisher $publisherForBuilds, Cache $cache, callable $locks ) { - $token = $token ?: $request->getQuery('token', ''); - OrchestratorToken::verify($token, $project->getId(), $siteId, $deploymentId, 'build'); + $this->verifyArtifactToken($resourceToken, RESOURCE_TYPE_SITES, $siteId, $deploymentId, 'build'); $site = $dbForProject->getAuthorization()->skip(fn () => $dbForProject->getDocument('sites', $siteId)); if ($site->isEmpty()) { @@ -90,4 +90,20 @@ class Update extends Action locks: $locks ); } + + private function verifyArtifactToken(Document $resourceToken, string $resourceType, string $resourceId, string $deploymentId, string $purpose): void + { + if ($resourceToken->isEmpty()) { + throw new Exception(Exception::USER_UNAUTHORIZED, 'Invalid build artifact token.'); + } + + if ( + $resourceToken->getAttribute('resourceType') !== $resourceType || + $resourceToken->getAttribute('resourceId') !== $resourceId || + $resourceToken->getAttribute('deploymentId') !== $deploymentId || + $resourceToken->getAttribute('purpose') !== $purpose + ) { + throw new Exception(Exception::USER_UNAUTHORIZED, 'Build artifact token mismatch.'); + } + } } diff --git a/src/Appwrite/Platform/Modules/Sites/Http/Deployments/Artifacts/Source/Get.php b/src/Appwrite/Platform/Modules/Sites/Http/Deployments/Artifacts/Source/Get.php index 3577e1e27a..a77672e07e 100644 --- a/src/Appwrite/Platform/Modules/Sites/Http/Deployments/Artifacts/Source/Get.php +++ b/src/Appwrite/Platform/Modules/Sites/Http/Deployments/Artifacts/Source/Get.php @@ -2,7 +2,6 @@ namespace Appwrite\Platform\Modules\Sites\Http\Deployments\Artifacts\Source; -use Appwrite\Builds\OrchestratorToken; use Appwrite\Extend\Exception; use Appwrite\Utopia\Response; use Utopia\Database\Database; @@ -37,6 +36,7 @@ class Get extends Action ->inject('response') ->inject('dbForProject') ->inject('project') + ->inject('resourceToken') ->inject('deviceForSites') ->callback($this->action(...)); } @@ -48,9 +48,10 @@ class Get extends Action Response $response, Database $dbForProject, Document $project, + Document $resourceToken, Device $deviceForSites ) { - OrchestratorToken::verify($token, $project->getId(), $siteId, $deploymentId, 'source'); + $this->verifyArtifactToken($resourceToken, RESOURCE_TYPE_SITES, $siteId, $deploymentId, 'source'); $site = $dbForProject->getAuthorization()->skip(fn () => $dbForProject->getDocument('sites', $siteId)); if ($site->isEmpty()) { @@ -89,4 +90,20 @@ class Get extends Action $response->send($deviceForSites->read($path)); } + + private function verifyArtifactToken(Document $resourceToken, string $resourceType, string $resourceId, string $deploymentId, string $purpose): void + { + if ($resourceToken->isEmpty()) { + throw new Exception(Exception::USER_UNAUTHORIZED, 'Invalid build artifact token.'); + } + + if ( + $resourceToken->getAttribute('resourceType') !== $resourceType || + $resourceToken->getAttribute('resourceId') !== $resourceId || + $resourceToken->getAttribute('deploymentId') !== $deploymentId || + $resourceToken->getAttribute('purpose') !== $purpose + ) { + throw new Exception(Exception::USER_UNAUTHORIZED, 'Build artifact token mismatch.'); + } + } } diff --git a/src/Appwrite/Platform/Modules/Sites/Http/Deployments/Events/Create.php b/src/Appwrite/Platform/Modules/Sites/Http/Deployments/Events/Create.php index f4066df0b7..5d8385067a 100644 --- a/src/Appwrite/Platform/Modules/Sites/Http/Deployments/Events/Create.php +++ b/src/Appwrite/Platform/Modules/Sites/Http/Deployments/Events/Create.php @@ -2,17 +2,18 @@ namespace Appwrite\Platform\Modules\Sites\Http\Deployments\Events; -use Appwrite\Builds\OrchestratorToken; use Appwrite\Event\Message\Build as BuildMessage; use Appwrite\Event\Publisher\Build as BuildPublisher; use Appwrite\Extend\Exception; use Appwrite\Utopia\Response; +use OpenRuntimes\Orchestrator\Callback\Signature; use Utopia\Database\Database; use Utopia\Database\Document; use Utopia\Database\Validator\UID; use Utopia\Http\Adapter\Swoole\Request; use Utopia\Platform\Action; use Utopia\Platform\Scope\HTTP; +use Utopia\System\System; class Create extends Action { @@ -52,7 +53,10 @@ class Create extends Action BuildPublisher $publisherForBuilds ) { $body = $request->getRawPayload(); - OrchestratorToken::verifySignature($body, $request->getHeader('x-signature-256', '')); + $secret = System::getEnv('_APP_ORCHESTRATOR_CALLBACK_SECRET', System::getEnv('_APP_OPENSSL_KEY_V1', '')); + if (! Signature::verify($body, $request->getHeader('x-signature-256', ''), $secret)) { + throw new Exception(Exception::USER_UNAUTHORIZED, 'Invalid orchestrator event signature.'); + } $event = \json_decode($body, true); if (!\is_array($event)) {