diff --git a/app/controllers/api/account.php b/app/controllers/api/account.php index 64441fee5c..cb71818df3 100644 --- a/app/controllers/api/account.php +++ b/app/controllers/api/account.php @@ -42,6 +42,7 @@ use Utopia\Database\Helpers\Role; use Utopia\Database\Query; use Utopia\Database\Validator\Authorization; use Utopia\Database\Validator\Queries; +use Utopia\Database\Validator\Query\Cursor; use Utopia\Database\Validator\Query\Limit; use Utopia\Database\Validator\Query\Offset; use Utopia\Database\Validator\UID; @@ -4486,6 +4487,12 @@ App::get('/v1/account/identities') $cursor = reset($cursor); if ($cursor) { /** @var Query $cursor */ + + $validator = new Cursor(); + if (!$validator->isValid($cursor)) { + throw new Exception(Exception::GENERAL_QUERY_INVALID, $validator->getDescription()); + } + $identityId = $cursor->getValue(); $cursorDocument = $dbForProject->getDocument('identities', $identityId); diff --git a/app/controllers/api/databases.php b/app/controllers/api/databases.php index 72e3c6d464..473f09cb7c 100644 --- a/app/controllers/api/databases.php +++ b/app/controllers/api/databases.php @@ -40,6 +40,7 @@ use Utopia\Database\Validator\Index as IndexValidator; use Utopia\Database\Validator\Key; use Utopia\Database\Validator\Permissions; use Utopia\Database\Validator\Queries; +use Utopia\Database\Validator\Query\Cursor; use Utopia\Database\Validator\Query\Limit; use Utopia\Database\Validator\Query\Offset; use Utopia\Database\Validator\Structure; @@ -546,6 +547,13 @@ App::get('/v1/databases') }); $cursor = reset($cursor); if ($cursor) { + /** @var Query $cursor */ + + $validator = new Cursor(); + if (!$validator->isValid($cursor)) { + throw new Exception(Exception::GENERAL_QUERY_INVALID, $validator->getDescription()); + } + $databaseId = $cursor->getValue(); $cursorDocument = $dbForProject->getDocument('databases', $databaseId); @@ -878,6 +886,12 @@ App::get('/v1/databases/:databaseId/collections') $cursor = reset($cursor); if ($cursor) { /** @var Query $cursor */ + + $validator = new Cursor(); + if (!$validator->isValid($cursor)) { + throw new Exception(Exception::GENERAL_QUERY_INVALID, $validator->getDescription()); + } + $collectionId = $cursor->getValue(); $cursorDocument = $dbForProject->getDocument('database_' . $database->getInternalId(), $collectionId); @@ -1788,6 +1802,11 @@ App::get('/v1/databases/:databaseId/collections/:collectionId/attributes') $cursor = \reset($cursor); if ($cursor) { + $validator = new Cursor(); + if (!$validator->isValid($cursor)) { + throw new Exception(Exception::GENERAL_QUERY_INVALID, $validator->getDescription()); + } + $attributeId = $cursor->getValue(); $cursorDocument = Authorization::skip(fn () => $dbForProject->find('attributes', [ Query::equal('collectionInternalId', [$collection->getInternalId()]), @@ -2667,6 +2686,11 @@ App::get('/v1/databases/:databaseId/collections/:collectionId/indexes') $cursor = reset($cursor); if ($cursor) { + $validator = new Cursor(); + if (!$validator->isValid($cursor)) { + throw new Exception(Exception::GENERAL_QUERY_INVALID, $validator->getDescription()); + } + $indexId = $cursor->getValue(); $cursorDocument = Authorization::skip(fn () => $dbForProject->find('indexes', [ Query::equal('collectionInternalId', [$collection->getInternalId()]), @@ -3094,6 +3118,12 @@ App::get('/v1/databases/:databaseId/collections/:collectionId/documents') $cursor = \reset($cursor); if ($cursor) { + $validator = new Cursor(); + if (!$validator->isValid($cursor)) { + throw new Exception(Exception::GENERAL_QUERY_INVALID, $validator->getDescription()); + } + + $documentId = $cursor->getValue(); $cursorDocument = Authorization::skip(fn () => $dbForProject->getDocument('database_' . $database->getInternalId() . '_collection_' . $collection->getInternalId(), $documentId)); diff --git a/app/controllers/api/functions.php b/app/controllers/api/functions.php index f1e8d82a9b..c3051ef476 100644 --- a/app/controllers/api/functions.php +++ b/app/controllers/api/functions.php @@ -37,6 +37,7 @@ use Utopia\Database\Helpers\Role; use Utopia\Database\Query; use Utopia\Database\Validator\Authorization; use Utopia\Database\Validator\Datetime as DatetimeValidator; +use Utopia\Database\Validator\Query\Cursor; use Utopia\Database\Validator\Roles; use Utopia\Database\Validator\UID; use Utopia\Storage\Device; @@ -431,6 +432,12 @@ App::get('/v1/functions') $cursor = reset($cursor); if ($cursor) { /** @var Query $cursor */ + + $validator = new Cursor(); + if (!$validator->isValid($cursor)) { + throw new Exception(Exception::GENERAL_QUERY_INVALID, $validator->getDescription()); + } + $functionId = $cursor->getValue(); $cursorDocument = $dbForProject->getDocument('functions', $functionId); @@ -1407,6 +1414,12 @@ App::get('/v1/functions/:functionId/deployments') $cursor = reset($cursor); if ($cursor) { /** @var Query $cursor */ + + $validator = new Cursor(); + if (!$validator->isValid($cursor)) { + throw new Exception(Exception::GENERAL_QUERY_INVALID, $validator->getDescription()); + } + $deploymentId = $cursor->getValue(); $cursorDocument = $dbForProject->getDocument('deployments', $deploymentId); @@ -2153,6 +2166,12 @@ App::get('/v1/functions/:functionId/executions') $cursor = reset($cursor); if ($cursor) { /** @var Query $cursor */ + + $validator = new Cursor(); + if (!$validator->isValid($cursor)) { + throw new Exception(Exception::GENERAL_QUERY_INVALID, $validator->getDescription()); + } + $executionId = $cursor->getValue(); $cursorDocument = $dbForProject->getDocument('executions', $executionId); diff --git a/app/controllers/api/messaging.php b/app/controllers/api/messaging.php index 7da0348a8f..c68ba91297 100644 --- a/app/controllers/api/messaging.php +++ b/app/controllers/api/messaging.php @@ -32,6 +32,7 @@ use Utopia\Database\Query; use Utopia\Database\Validator\Authorization; use Utopia\Database\Validator\Datetime as DatetimeValidator; use Utopia\Database\Validator\Queries; +use Utopia\Database\Validator\Query\Cursor; use Utopia\Database\Validator\Query\Limit; use Utopia\Database\Validator\Query\Offset; use Utopia\Database\Validator\Roles; @@ -866,6 +867,11 @@ App::get('/v1/messaging/providers') $cursor = reset($cursor); if ($cursor) { + $validator = new Cursor(); + if (!$validator->isValid($cursor)) { + throw new Exception(Exception::GENERAL_QUERY_INVALID, $validator->getDescription()); + } + $providerId = $cursor->getValue(); $cursorDocument = Authorization::skip(fn () => $dbForProject->getDocument('providers', $providerId)); @@ -1998,6 +2004,11 @@ App::get('/v1/messaging/topics') $cursor = reset($cursor); if ($cursor) { + $validator = new Cursor(); + if (!$validator->isValid($cursor)) { + throw new Exception(Exception::GENERAL_QUERY_INVALID, $validator->getDescription()); + } + $topicId = $cursor->getValue(); $cursorDocument = Authorization::skip(fn () => $dbForProject->getDocument('topics', $topicId)); @@ -2352,6 +2363,11 @@ App::get('/v1/messaging/topics/:topicId/subscribers') $cursor = reset($cursor); if ($cursor) { + $validator = new Cursor(); + if (!$validator->isValid($cursor)) { + throw new Exception(Exception::GENERAL_QUERY_INVALID, $validator->getDescription()); + } + $subscriberId = $cursor->getValue(); $cursorDocument = Authorization::skip(fn () => $dbForProject->getDocument('subscribers', $subscriberId)); @@ -3048,6 +3064,11 @@ App::get('/v1/messaging/messages') $cursor = reset($cursor); if ($cursor) { + $validator = new Cursor(); + if (!$validator->isValid($cursor)) { + throw new Exception(Exception::GENERAL_QUERY_INVALID, $validator->getDescription()); + } + $messageId = $cursor->getValue(); $cursorDocument = Authorization::skip(fn () => $dbForProject->getDocument('messages', $messageId)); @@ -3202,6 +3223,11 @@ App::get('/v1/messaging/messages/:messageId/targets') $cursor = reset($cursor); if ($cursor) { + $validator = new Cursor(); + if (!$validator->isValid($cursor)) { + throw new Exception(Exception::GENERAL_QUERY_INVALID, $validator->getDescription()); + } + $targetId = $cursor->getValue(); $cursorDocument = $dbForProject->getDocument('targets', $targetId); diff --git a/app/controllers/api/migrations.php b/app/controllers/api/migrations.php index bb89d4a26f..a4880cef86 100644 --- a/app/controllers/api/migrations.php +++ b/app/controllers/api/migrations.php @@ -16,6 +16,7 @@ use Utopia\Database\Document; use Utopia\Database\Exception\Query as QueryException; use Utopia\Database\Helpers\ID; use Utopia\Database\Query; +use Utopia\Database\Validator\Query\Cursor; use Utopia\Database\Validator\UID; use Utopia\Migration\Sources\Appwrite; use Utopia\Migration\Sources\Firebase; @@ -409,6 +410,12 @@ App::get('/v1/migrations') $cursor = reset($cursor); if ($cursor) { /** @var Query $cursor */ + + $validator = new Cursor(); + if (!$validator->isValid($cursor)) { + throw new Exception(Exception::GENERAL_QUERY_INVALID, $validator->getDescription()); + } + $migrationId = $cursor->getValue(); $cursorDocument = $dbForProject->getDocument('migrations', $migrationId); diff --git a/app/controllers/api/projects.php b/app/controllers/api/projects.php index 934793410b..3bfa416bd8 100644 --- a/app/controllers/api/projects.php +++ b/app/controllers/api/projects.php @@ -31,6 +31,7 @@ use Utopia\Database\Helpers\Permission; use Utopia\Database\Helpers\Role; use Utopia\Database\Query; use Utopia\Database\Validator\Datetime as DatetimeValidator; +use Utopia\Database\Validator\Query\Cursor; use Utopia\Database\Validator\UID; use Utopia\Domains\Validator\PublicDomain; use Utopia\DSN\DSN; @@ -279,6 +280,12 @@ App::get('/v1/projects') $cursor = reset($cursor); if ($cursor) { /** @var Query $cursor */ + + $validator = new Cursor(); + if (!$validator->isValid($cursor)) { + throw new Exception(Exception::GENERAL_QUERY_INVALID, $validator->getDescription()); + } + $projectId = $cursor->getValue(); $cursorDocument = $dbForConsole->getDocument('projects', $projectId); diff --git a/app/controllers/api/proxy.php b/app/controllers/api/proxy.php index 84484a7209..984a9fb974 100644 --- a/app/controllers/api/proxy.php +++ b/app/controllers/api/proxy.php @@ -13,6 +13,7 @@ use Utopia\Database\Document; use Utopia\Database\Exception\Query as QueryException; use Utopia\Database\Helpers\ID; use Utopia\Database\Query; +use Utopia\Database\Validator\Query\Cursor; use Utopia\Database\Validator\UID; use Utopia\Domains\Domain; use Utopia\Logger\Log; @@ -185,6 +186,12 @@ App::get('/v1/proxy/rules') $cursor = reset($cursor); if ($cursor) { /** @var Query $cursor */ + + $validator = new Cursor(); + if (!$validator->isValid($cursor)) { + throw new Exception(Exception::GENERAL_QUERY_INVALID, $validator->getDescription()); + } + $ruleId = $cursor->getValue(); $cursorDocument = $dbForConsole->getDocument('rules', $ruleId); diff --git a/app/controllers/api/storage.php b/app/controllers/api/storage.php index 4e30832a67..c3d57e5470 100644 --- a/app/controllers/api/storage.php +++ b/app/controllers/api/storage.php @@ -24,6 +24,7 @@ use Utopia\Database\Helpers\Role; use Utopia\Database\Query; use Utopia\Database\Validator\Authorization; use Utopia\Database\Validator\Permissions; +use Utopia\Database\Validator\Query\Cursor; use Utopia\Database\Validator\UID; use Utopia\Image\Image; use Utopia\Storage\Compression\Algorithms\GZIP; @@ -178,6 +179,12 @@ App::get('/v1/storage/buckets') $cursor = reset($cursor); if ($cursor) { /** @var Query $cursor */ + + $validator = new Cursor(); + if (!$validator->isValid($cursor)) { + throw new Exception(Exception::GENERAL_QUERY_INVALID, $validator->getDescription()); + } + $bucketId = $cursor->getValue(); $cursorDocument = $dbForProject->getDocument('buckets', $bucketId); @@ -744,6 +751,12 @@ App::get('/v1/storage/buckets/:bucketId/files') $cursor = reset($cursor); if ($cursor) { /** @var Query $cursor */ + + $validator = new Cursor(); + if (!$validator->isValid($cursor)) { + throw new Exception(Exception::GENERAL_QUERY_INVALID, $validator->getDescription()); + } + $fileId = $cursor->getValue(); if ($fileSecurity && !$valid) { diff --git a/app/controllers/api/teams.php b/app/controllers/api/teams.php index 146b5d5f81..f9abaeeb44 100644 --- a/app/controllers/api/teams.php +++ b/app/controllers/api/teams.php @@ -34,6 +34,7 @@ use Utopia\Database\Query; use Utopia\Database\Validator\Authorization; use Utopia\Database\Validator\Key; use Utopia\Database\Validator\Queries; +use Utopia\Database\Validator\Query\Cursor; use Utopia\Database\Validator\Query\Limit; use Utopia\Database\Validator\Query\Offset; use Utopia\Database\Validator\UID; @@ -170,6 +171,12 @@ App::get('/v1/teams') $cursor = reset($cursor); if ($cursor) { /** @var Query $cursor */ + + $validator = new Cursor(); + if (!$validator->isValid($cursor)) { + throw new Exception(Exception::GENERAL_QUERY_INVALID, $validator->getDescription()); + } + $teamId = $cursor->getValue(); $cursorDocument = $dbForProject->getDocument('teams', $teamId); @@ -751,6 +758,13 @@ App::get('/v1/teams/:teamId/memberships') $cursor = reset($cursor); if ($cursor) { /** @var Query $cursor */ + + $validator = new Cursor(); + if (!$validator->isValid($cursor)) { + throw new Exception(Exception::GENERAL_QUERY_INVALID, $validator->getDescription()); + } + + $membershipId = $cursor->getValue(); $cursorDocument = $dbForProject->getDocument('memberships', $membershipId); diff --git a/app/controllers/api/users.php b/app/controllers/api/users.php index 571df4fdb2..f0378ed0e3 100644 --- a/app/controllers/api/users.php +++ b/app/controllers/api/users.php @@ -36,6 +36,7 @@ use Utopia\Database\Helpers\Role; use Utopia\Database\Query; use Utopia\Database\Validator\Authorization; use Utopia\Database\Validator\Queries; +use Utopia\Database\Validator\Query\Cursor; use Utopia\Database\Validator\Query\Limit; use Utopia\Database\Validator\Query\Offset; use Utopia\Database\Validator\UID; @@ -576,6 +577,12 @@ App::get('/v1/users') $cursor = reset($cursor); if ($cursor) { /** @var Query $cursor */ + + $validator = new Cursor(); + if (!$validator->isValid($cursor)) { + throw new Exception(Exception::GENERAL_QUERY_INVALID, $validator->getDescription()); + } + $userId = $cursor->getValue(); $cursorDocument = $dbForProject->getDocument('users', $userId); @@ -886,6 +893,11 @@ App::get('/v1/users/:userId/targets') $cursor = reset($cursor); if ($cursor) { + $validator = new Cursor(); + if (!$validator->isValid($cursor)) { + throw new Exception(Exception::GENERAL_QUERY_INVALID, $validator->getDescription()); + } + $targetId = $cursor->getValue(); $cursorDocument = $dbForProject->getDocument('targets', $targetId); @@ -938,6 +950,12 @@ App::get('/v1/users/identities') $cursor = reset($cursor); if ($cursor) { /** @var Query $cursor */ + + $validator = new Cursor(); + if (!$validator->isValid($cursor)) { + throw new Exception(Exception::GENERAL_QUERY_INVALID, $validator->getDescription()); + } + $identityId = $cursor->getValue(); $cursorDocument = $dbForProject->getDocument('identities', $identityId); diff --git a/app/controllers/api/vcs.php b/app/controllers/api/vcs.php index f3381490ec..e79eb67936 100644 --- a/app/controllers/api/vcs.php +++ b/app/controllers/api/vcs.php @@ -20,6 +20,7 @@ use Utopia\Database\Helpers\Permission; use Utopia\Database\Helpers\Role; use Utopia\Database\Query; use Utopia\Database\Validator\Authorization; +use Utopia\Database\Validator\Query\Cursor; use Utopia\Detector\Adapter\Bun; use Utopia\Detector\Adapter\CPP; use Utopia\Detector\Adapter\Dart; @@ -1069,6 +1070,12 @@ App::get('/v1/vcs/installations') $cursor = reset($cursor); if ($cursor) { /** @var Query $cursor */ + + $validator = new Cursor(); + if (!$validator->isValid($cursor)) { + throw new Exception(Exception::GENERAL_QUERY_INVALID, $validator->getDescription()); + } + $installationId = $cursor->getValue(); $cursorDocument = $dbForConsole->getDocument('installations', $installationId); diff --git a/tests/e2e/Services/Databases/DatabasesBase.php b/tests/e2e/Services/Databases/DatabasesBase.php index 6d8622276e..d079cb313c 100644 --- a/tests/e2e/Services/Databases/DatabasesBase.php +++ b/tests/e2e/Services/Databases/DatabasesBase.php @@ -1744,6 +1744,21 @@ trait DatabasesBase $this->assertEquals(400, $documents['headers']['status-code']); + /** + * Test null value for cursor + */ + + $documents = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $data['moviesId'] . '/documents', array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + ], $this->getHeaders()), [ + 'queries' => [ + '{"method":"cursorAfter","values":[null]}', + ], + ]); + + $this->assertEquals(400, $documents['headers']['status-code']); + return []; }