From 4fcaeaec0ec85a5bea305726277159b150b72102 Mon Sep 17 00:00:00 2001 From: ArnabChatterjee20k Date: Thu, 14 Aug 2025 18:10:00 +0530 Subject: [PATCH 1/2] Add internal file upload support and authorization checks in migrations --- app/controllers/api/migrations.php | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/app/controllers/api/migrations.php b/app/controllers/api/migrations.php index 85751811ba..aa4cb03ae8 100644 --- a/app/controllers/api/migrations.php +++ b/app/controllers/api/migrations.php @@ -35,6 +35,7 @@ use Utopia\Storage\Compression\Compression; use Utopia\Storage\Device; use Utopia\System\System; use Utopia\Validator\ArrayList; +use Utopia\Validator\Boolean; use Utopia\Validator\Integer; use Utopia\Validator\Text; use Utopia\Validator\URL; @@ -328,24 +329,33 @@ App::post('/v1/migrations/csv') ->param('bucketId', '', new UID(), 'Storage bucket unique ID. You can create a new storage bucket using the Storage service [server integration](https://appwrite.io/docs/server/storage#createBucket).') ->param('fileId', '', new UID(), 'File ID.') ->param('resourceId', null, new CompoundUID(), 'Composite ID in the format {databaseId:collectionId}, identifying a collection within a database.') + ->param('internalFile', false, new Boolean(), 'For uploading to internal bucket', true) ->inject('response') ->inject('dbForProject') + ->inject('dbForPlatform') ->inject('project') ->inject('deviceForFiles') ->inject('deviceForImports') ->inject('queueForEvents') ->inject('queueForMigrations') - ->action(function (string $bucketId, string $fileId, string $resourceId, Response $response, Database $dbForProject, Document $project, Device $deviceForFiles, Device $deviceForImports, Event $queueForEvents, Migration $queueForMigrations) { + ->action(function (string $bucketId, string $fileId, string $resourceId, bool $internalFile, Response $response, Database $dbForProject, Database $dbForPlatform, Document $project, Device $deviceForFiles, Device $deviceForImports, Event $queueForEvents, Migration $queueForMigrations) { $isAPIKey = Auth::isAppUser(Authorization::getRoles()); $isPrivilegedUser = Auth::isPrivilegedUser(Authorization::getRoles()); - - $bucket = Authorization::skip(fn () => $dbForProject->getDocument('buckets', $bucketId)); + if ($internalFile && !$isPrivilegedUser) { + throw new Exception(Exception::USER_UNAUTHORIZED); + } + $bucket = Authorization::skip(function () use ($internalFile, $dbForPlatform, $dbForProject, $bucketId) { + if ($internalFile) { + return $dbForPlatform->getDocument('buckets', 'default'); + } + return $dbForProject->getDocument('buckets', $bucketId); + }); if ($bucket->isEmpty() || (!$isAPIKey && !$isPrivilegedUser)) { throw new Exception(Exception::STORAGE_BUCKET_NOT_FOUND); } - $file = Authorization::skip(fn () => $dbForProject->getDocument('bucket_' . $bucket->getSequence(), $fileId)); + $file = Authorization::skip(fn () => $internalFile ? $dbForPlatform->getDocument('bucket_' . $bucket->getSequence(), $fileId) : $dbForProject->getDocument('bucket_' . $bucket->getSequence(), $fileId)); if ($file->isEmpty()) { throw new Exception(Exception::STORAGE_FILE_NOT_FOUND); } From bc7e240626b41d55d165e3009d88ad9336095d03 Mon Sep 17 00:00:00 2001 From: ArnabChatterjee20k <83803257+ArnabChatterjee20k@users.noreply.github.com> Date: Fri, 15 Aug 2025 15:04:16 +0530 Subject: [PATCH 2/2] updated the the description of the internal files Co-authored-by: Jake Barnby --- app/controllers/api/migrations.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/controllers/api/migrations.php b/app/controllers/api/migrations.php index aa4cb03ae8..4a968e63f2 100644 --- a/app/controllers/api/migrations.php +++ b/app/controllers/api/migrations.php @@ -329,7 +329,7 @@ App::post('/v1/migrations/csv') ->param('bucketId', '', new UID(), 'Storage bucket unique ID. You can create a new storage bucket using the Storage service [server integration](https://appwrite.io/docs/server/storage#createBucket).') ->param('fileId', '', new UID(), 'File ID.') ->param('resourceId', null, new CompoundUID(), 'Composite ID in the format {databaseId:collectionId}, identifying a collection within a database.') - ->param('internalFile', false, new Boolean(), 'For uploading to internal bucket', true) + ->param('internalFile', false, new Boolean(), 'Is the file stored in an internal bucket?', true) ->inject('response') ->inject('dbForProject') ->inject('dbForPlatform')