mirror of
https://github.com/appwrite/appwrite.git
synced 2026-05-26 13:51:13 +00:00
Scope console API key to target project via targetProjectId claim
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
<?php
|
||||
|
||||
use Ahc\Jwt\JWT;
|
||||
use Appwrite\Auth\Key;
|
||||
use Appwrite\Auth\Validator\MockNumber;
|
||||
use Appwrite\Event\Delete;
|
||||
use Appwrite\Event\Mail;
|
||||
@@ -1168,7 +1169,12 @@ Http::get('/v1/projects/:projectId/keys')
|
||||
->param('total', true, new Boolean(true), 'When set to false, the total count returned will be 0 and will not be calculated.', true)
|
||||
->inject('response')
|
||||
->inject('dbForPlatform')
|
||||
->action(function (string $projectId, array $queries, bool $includeTotal, Response $response, Database $dbForPlatform) {
|
||||
->inject('apiKey')
|
||||
->action(function (string $projectId, array $queries, bool $includeTotal, Response $response, Database $dbForPlatform, ?Key $apiKey) {
|
||||
|
||||
if ($apiKey !== null && !empty($apiKey->getTargetProjectId()) && $apiKey->getTargetProjectId() !== $projectId) {
|
||||
throw new Exception(Exception::GENERAL_UNAUTHORIZED_SCOPE);
|
||||
}
|
||||
|
||||
$project = $dbForPlatform->getDocument('projects', $projectId);
|
||||
|
||||
@@ -1240,7 +1246,12 @@ Http::get('/v1/projects/:projectId/keys/:keyId')
|
||||
->param('keyId', '', new UID(), 'Key unique ID.')
|
||||
->inject('response')
|
||||
->inject('dbForPlatform')
|
||||
->action(function (string $projectId, string $keyId, Response $response, Database $dbForPlatform) {
|
||||
->inject('apiKey')
|
||||
->action(function (string $projectId, string $keyId, Response $response, Database $dbForPlatform, ?Key $apiKey) {
|
||||
|
||||
if ($apiKey !== null && !empty($apiKey->getTargetProjectId()) && $apiKey->getTargetProjectId() !== $projectId) {
|
||||
throw new Exception(Exception::GENERAL_UNAUTHORIZED_SCOPE);
|
||||
}
|
||||
|
||||
$project = $dbForPlatform->getDocument('projects', $projectId);
|
||||
|
||||
@@ -1507,7 +1518,12 @@ Http::get('/v1/projects/:projectId/platforms')
|
||||
->param('total', true, new Boolean(true), 'When set to false, the total count returned will be 0 and will not be calculated.', true)
|
||||
->inject('response')
|
||||
->inject('dbForPlatform')
|
||||
->action(function (string $projectId, bool $includeTotal, Response $response, Database $dbForPlatform) {
|
||||
->inject('apiKey')
|
||||
->action(function (string $projectId, bool $includeTotal, Response $response, Database $dbForPlatform, ?Key $apiKey) {
|
||||
|
||||
if ($apiKey !== null && !empty($apiKey->getTargetProjectId()) && $apiKey->getTargetProjectId() !== $projectId) {
|
||||
throw new Exception(Exception::GENERAL_UNAUTHORIZED_SCOPE);
|
||||
}
|
||||
|
||||
$project = $dbForPlatform->getDocument('projects', $projectId);
|
||||
|
||||
@@ -1547,7 +1563,12 @@ Http::get('/v1/projects/:projectId/platforms/:platformId')
|
||||
->param('platformId', '', new UID(), 'Platform unique ID.')
|
||||
->inject('response')
|
||||
->inject('dbForPlatform')
|
||||
->action(function (string $projectId, string $platformId, Response $response, Database $dbForPlatform) {
|
||||
->inject('apiKey')
|
||||
->action(function (string $projectId, string $platformId, Response $response, Database $dbForPlatform, ?Key $apiKey) {
|
||||
|
||||
if ($apiKey !== null && !empty($apiKey->getTargetProjectId()) && $apiKey->getTargetProjectId() !== $projectId) {
|
||||
throw new Exception(Exception::GENERAL_UNAUTHORIZED_SCOPE);
|
||||
}
|
||||
|
||||
$project = $dbForPlatform->getDocument('projects', $projectId);
|
||||
|
||||
|
||||
@@ -28,6 +28,7 @@ class Key
|
||||
protected bool $projectCheckDisabled = false,
|
||||
protected bool $previewAuthDisabled = false,
|
||||
protected bool $deploymentStatusIgnored = false,
|
||||
protected string $targetProjectId = '',
|
||||
) {
|
||||
}
|
||||
|
||||
@@ -103,6 +104,11 @@ class Key
|
||||
return $this->projectCheckDisabled;
|
||||
}
|
||||
|
||||
public function getTargetProjectId(): string
|
||||
{
|
||||
return $this->targetProjectId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Decode the given secret key into a Key object, containing the project ID, type, role, scopes, and name.
|
||||
* Can be a stored API key or a dynamic key (JWT).
|
||||
@@ -161,6 +167,7 @@ class Key
|
||||
$projectCheckDisabled = $payload['projectCheckDisabled'] ?? false;
|
||||
$previewAuthDisabled = $payload['previewAuthDisabled'] ?? false;
|
||||
$deploymentStatusIgnored = $payload['deploymentStatusIgnored'] ?? false;
|
||||
$targetProjectId = $payload['targetProjectId'] ?? '';
|
||||
$scopes = \array_merge($payload['scopes'] ?? [], $scopes);
|
||||
|
||||
if (!$projectCheckDisabled && $projectId !== $project->getId()) {
|
||||
@@ -181,7 +188,8 @@ class Key
|
||||
$bannerDisabled,
|
||||
$projectCheckDisabled,
|
||||
$previewAuthDisabled,
|
||||
$deploymentStatusIgnored
|
||||
$deploymentStatusIgnored,
|
||||
$targetProjectId
|
||||
);
|
||||
case API_KEY_STANDARD:
|
||||
$key = $project->find(
|
||||
|
||||
@@ -333,7 +333,7 @@ class Migrations extends Action
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
protected function generateConsoleAPIKey(): string
|
||||
protected function generateConsoleAPIKey(string $targetProjectId): string
|
||||
{
|
||||
$jwt = new JWT(System::getEnv('_APP_OPENSSL_KEY_V1'), 'HS256', 86400, 0);
|
||||
|
||||
@@ -343,6 +343,7 @@ class Migrations extends Action
|
||||
'platforms.read',
|
||||
'keys.read',
|
||||
],
|
||||
'targetProjectId' => $targetProjectId,
|
||||
]);
|
||||
|
||||
return API_KEY_DYNAMIC . '_' . $apiKey;
|
||||
@@ -388,7 +389,7 @@ class Migrations extends Action
|
||||
// Only generate and set consoleApiKey for same-instance migrations
|
||||
// to avoid leaking a locally-signed JWT to untrusted remote servers
|
||||
if ($credentials['endpoint'] === $endpoint) {
|
||||
$credentials['consoleApiKey'] = $this->generateConsoleAPIKey();
|
||||
$credentials['consoleApiKey'] = $this->generateConsoleAPIKey($credentials['projectId']);
|
||||
$credentials['sourceProjectId'] = $credentials['projectId'];
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user