Merge pull request #11553 from appwrite/claude/apply-cloud-user-pattern-az7qg

Use injected user document for privilege checks
This commit is contained in:
Damodar Lohani
2026-03-30 10:24:58 +05:45
committed by GitHub
57 changed files with 244 additions and 164 deletions
+8 -2
View File
@@ -28,12 +28,18 @@ use Utopia\Validator\Text;
Http::init()
->groups(['graphql'])
->inject('project')
->inject('user')
->inject('request')
->inject('response')
->inject('authorization')
->action(function (Document $project, Authorization $authorization) {
->action(function (Document $project, User $user, Request $request, Response $response, Authorization $authorization) {
$response->setUser($user);
$request->setUser($user);
if (
array_key_exists('graphql', $project->getAttribute('apis', []))
&& !$project->getAttribute('apis', [])['graphql']
&& !(User::isPrivileged($authorization->getRoles()) || User::isApp($authorization->getRoles()))
&& !($user->isPrivileged($authorization->getRoles()) || $user->isApp($authorization->getRoles()))
) {
throw new AppwriteException(AppwriteException::GENERAL_API_DISABLED);
}
+10 -1
View File
@@ -1270,7 +1270,16 @@ Http::error()
* If not a publishable error, track usage stats. Publishable errors are >= 500 or those explicitly marked as publish=true in errors.php
*/
if (!$publish && $project->getId() !== 'console') {
if (!DBUser::isPrivileged($authorization->getRoles())) {
$errorUser = new DBUser();
try {
$resolvedUser = $utopia->getResource('user');
if ($resolvedUser instanceof DBUser) {
$errorUser = $resolvedUser;
}
} catch (\Throwable) {
// User resource may not be available in error context
}
if (!$errorUser->isPrivileged($authorization->getRoles())) {
$bus->dispatch(new RequestCompleted(
project: $project->getArrayCopy(),
request: $request,
+14 -11
View File
@@ -96,7 +96,7 @@ Http::init()
->inject('team')
->inject('apiKey')
->inject('authorization')
->action(function (Http $utopia, Request $request, Database $dbForPlatform, Database $dbForProject, Audit $queueForAudits, Document $project, Document $user, ?Document $session, array $servers, string $mode, Document $team, ?Key $apiKey, Authorization $authorization) {
->action(function (Http $utopia, Request $request, Database $dbForPlatform, Database $dbForProject, Audit $queueForAudits, Document $project, User $user, ?Document $session, array $servers, string $mode, Document $team, ?Key $apiKey, Authorization $authorization) {
$route = $utopia->getRoute();
/**
@@ -419,7 +419,7 @@ Http::init()
if (
array_key_exists($namespace, $project->getAttribute('services', []))
&& ! $project->getAttribute('services', [])[$namespace]
&& ! (User::isPrivileged($authorization->getRoles()) || User::isApp($authorization->getRoles()))
&& ! ($user->isPrivileged($authorization->getRoles()) || $user->isApp($authorization->getRoles()))
) {
throw new Exception(Exception::GENERAL_SERVICE_DISABLED);
}
@@ -483,7 +483,10 @@ Http::init()
->inject('telemetry')
->inject('platform')
->inject('authorization')
->action(function (Http $utopia, Request $request, Response $response, Document $project, Document $user, Event $queueForEvents, Messaging $queueForMessaging, Audit $queueForAudits, Delete $queueForDeletes, EventDatabase $queueForDatabase, Build $queueForBuilds, Context $usage, Func $queueForFunctions, Mail $queueForMails, Database $dbForProject, callable $timelimit, Document $resourceToken, string $mode, ?Key $apiKey, array $plan, Document $devKey, Telemetry $telemetry, array $platform, Authorization $authorization) {
->action(function (Http $utopia, Request $request, Response $response, Document $project, User $user, Event $queueForEvents, Messaging $queueForMessaging, Audit $queueForAudits, Delete $queueForDeletes, EventDatabase $queueForDatabase, Build $queueForBuilds, Context $usage, Func $queueForFunctions, Mail $queueForMails, Database $dbForProject, callable $timelimit, Document $resourceToken, string $mode, ?Key $apiKey, array $plan, Document $devKey, Telemetry $telemetry, array $platform, Authorization $authorization) {
$response->setUser($user);
$request->setUser($user);
$route = $utopia->getRoute();
$path = $route->getMatchedPath();
@@ -496,7 +499,7 @@ Http::init()
if (
array_key_exists('rest', $project->getAttribute('apis', []))
&& ! $project->getAttribute('apis', [])['rest']
&& ! (User::isPrivileged($authorization->getRoles()) || User::isApp($authorization->getRoles()))
&& ! ($user->isPrivileged($authorization->getRoles()) || $user->isApp($authorization->getRoles()))
) {
throw new AppwriteException(AppwriteException::GENERAL_API_DISABLED);
}
@@ -528,8 +531,8 @@ Http::init()
$closestLimit = null;
$roles = $authorization->getRoles();
$isPrivilegedUser = User::isPrivileged($roles);
$isAppUser = User::isApp($roles);
$isPrivilegedUser = $user->isPrivileged($roles);
$isAppUser = $user->isApp($roles);
foreach ($timeLimitArray as $timeLimit) {
foreach ($request->getParams() as $key => $value) { // Set request params as potential abuse keys
@@ -611,7 +614,7 @@ Http::init()
if ($useCache) {
$route = $utopia->match($request);
$isImageTransformation = $route->getPath() === '/v1/storage/buckets/:bucketId/files/:fileId/preview';
$isDisabled = isset($plan['imageTransformations']) && $plan['imageTransformations'] === -1 && ! User::isPrivileged($authorization->getRoles());
$isDisabled = isset($plan['imageTransformations']) && $plan['imageTransformations'] === -1 && ! $user->isPrivileged($authorization->getRoles());
$key = $request->cacheIdentifier();
$cacheLog = $authorization->skip(fn () => $dbForProject->getDocument('cache', $key));
@@ -630,7 +633,7 @@ Http::init()
$bucket = $authorization->skip(fn () => $dbForProject->getDocument('buckets', $bucketId));
$isToken = ! $resourceToken->isEmpty() && $resourceToken->getAttribute('bucketInternalId') === $bucket->getSequence();
$isPrivilegedUser = User::isPrivileged($authorization->getRoles());
$isPrivilegedUser = $user->isPrivileged($authorization->getRoles());
if ($bucket->isEmpty() || (! $bucket->getAttribute('enabled') && ! $isAppUser && ! $isPrivilegedUser)) {
throw new Exception(Exception::STORAGE_BUCKET_NOT_FOUND);
@@ -663,7 +666,7 @@ Http::init()
throw new Exception(Exception::STORAGE_FILE_NOT_FOUND);
}
// Do not update transformedAt if it's a console user
if (! User::isPrivileged($authorization->getRoles())) {
if (! $user->isPrivileged($authorization->getRoles())) {
$transformedAt = $file->getAttribute('transformedAt', '');
if (DateTime::formatTz(DateTime::addSeconds(new \DateTime(), -APP_PROJECT_ACCESS)) > $transformedAt) {
$file->setAttribute('transformedAt', DateTime::now());
@@ -697,7 +700,7 @@ Http::init()
->groups(['session'])
->inject('user')
->inject('request')
->action(function (Document $user, Request $request) {
->action(function (User $user, Request $request) {
if (\str_contains($request->getURI(), 'oauth2')) {
return;
}
@@ -984,7 +987,7 @@ Http::shutdown()
}
if ($project->getId() !== 'console') {
if (! User::isPrivileged($authorization->getRoles())) {
if (! $user->isPrivileged($authorization->getRoles())) {
$bus->dispatch(new RequestCompleted(
project: $project->getArrayCopy(),
request: $request,
+4 -3
View File
@@ -36,8 +36,9 @@ Http::init()
->inject('request')
->inject('project')
->inject('geodb')
->inject('user')
->inject('authorization')
->action(function (Http $utopia, Request $request, Document $project, Reader $geodb, Authorization $authorization) {
->action(function (Http $utopia, Request $request, Document $project, Reader $geodb, User $user, Authorization $authorization) {
$denylist = System::getEnv('_APP_CONSOLE_COUNTRIES_DENYLIST', '');
if (!empty($denylist && $project->getId() === 'console')) {
$countries = explode(',', $denylist);
@@ -50,8 +51,8 @@ Http::init()
$route = $utopia->match($request);
$isPrivilegedUser = User::isPrivileged($authorization->getRoles());
$isAppUser = User::isApp($authorization->getRoles());
$isPrivilegedUser = $user->isPrivileged($authorization->getRoles());
$isAppUser = $user->isApp($authorization->getRoles());
if ($isAppUser || $isPrivilegedUser) { // Skip limits for app and console devs
return;
+3
View File
@@ -432,8 +432,10 @@ Http::setResource('user', function (string $mode, Document $project, Document $c
$jwtUserId = $payload['userId'] ?? '';
if (! empty($jwtUserId)) {
if ($mode === APP_MODE_ADMIN) {
/** @var User $user */
$user = $dbForPlatform->getDocument('users', $jwtUserId);
} else {
/** @var User $user */
$user = $dbForProject->getDocument('users', $jwtUserId);
}
}
@@ -453,6 +455,7 @@ Http::setResource('user', function (string $mode, Document $project, Document $c
throw new Exception(Exception::USER_API_KEY_AND_SESSION_SET);
}
/** @var User $accountKeyUser */
$accountKeyUser = $dbForPlatform->getAuthorization()->skip(fn () => $dbForPlatform->getDocument('users', $accountKeyUserId));
if (! $accountKeyUser->isEmpty()) {
$key = $accountKeyUser->find(
+6 -6
View File
@@ -518,7 +518,7 @@ $server->onWorkerStart(function (int $workerId) use ($server, $register, $stats,
$project = $consoleDatabase->getAuthorization()->skip(fn () => $consoleDatabase->getDocument('projects', $projectId));
$database = getProjectDB($project);
/** @var Appwrite\Utopia\Database\Documents\User $user */
/** @var User $user */
$user = $database->getDocument('users', $userId);
$roles = $user->getRoles($database->getAuthorization());
@@ -642,10 +642,14 @@ $server->onOpen(function (int $connection, SwooleRequest $request) use ($server,
throw new Exception(Exception::REALTIME_POLICY_VIOLATION, 'Missing or unknown project ID');
}
$timelimit = $app->getResource('timelimit');
$user = $app->getResource('user'); /** @var User $user */
$logUser = $user;
if (
array_key_exists('realtime', $project->getAttribute('apis', []))
&& !$project->getAttribute('apis', [])['realtime']
&& !(User::isPrivileged($authorization->getRoles()) || User::isApp($authorization->getRoles()))
&& !($user->isPrivileged($authorization->getRoles()) || $user->isApp($authorization->getRoles()))
) {
throw new AppwriteException(AppwriteException::GENERAL_API_DISABLED);
}
@@ -656,10 +660,6 @@ $server->onOpen(function (int $connection, SwooleRequest $request) use ($server,
throw new AppwriteException(AppwriteException::GENERAL_ACCESS_FORBIDDEN, 'Project is not accessible in this region. Please make sure you are using the correct endpoint');
}
$timelimit = $app->getResource('timelimit');
$user = $app->getResource('user'); /** @var User $user */
$logUser = $user;
/*
* Abuse Check
*
-6
View File
@@ -114,12 +114,6 @@ parameters:
count: 1
path: app/controllers/mock.php
-
message: '#^Call to an undefined method Utopia\\Database\\Document\:\:getRoles\(\)\.$#'
identifier: method.notFound
count: 1
path: app/controllers/shared/api.php
-
message: '#^Variable \$register might not be defined\.$#'
identifier: variable.undefined
@@ -87,13 +87,14 @@ class Decrement extends Action
->inject('usage')
->inject('plan')
->inject('authorization')
->inject('user')
->callback($this->action(...));
}
public function action(string $databaseId, string $collectionId, string $documentId, string $attribute, int|float $value, int|float|null $min, ?string $transactionId, UtopiaResponse $response, Database $dbForProject, callable $getDatabasesDB, Event $queueForEvents, Context $usage, array $plan, Authorization $authorization): void
public function action(string $databaseId, string $collectionId, string $documentId, string $attribute, int|float $value, int|float|null $min, ?string $transactionId, UtopiaResponse $response, Database $dbForProject, callable $getDatabasesDB, Event $queueForEvents, Context $usage, array $plan, Authorization $authorization, User $user): void
{
$isAPIKey = User::isApp($authorization->getRoles());
$isPrivilegedUser = User::isPrivileged($authorization->getRoles());
$isAPIKey = $user->isApp($authorization->getRoles());
$isPrivilegedUser = $user->isPrivileged($authorization->getRoles());
$database = $authorization->skip(fn () => $dbForProject->getDocument('databases', $databaseId));
if ($database->isEmpty()) {
@@ -87,13 +87,14 @@ class Increment extends Action
->inject('usage')
->inject('plan')
->inject('authorization')
->inject('user')
->callback($this->action(...));
}
public function action(string $databaseId, string $collectionId, string $documentId, string $attribute, int|float $value, int|float|null $max, ?string $transactionId, UtopiaResponse $response, Database $dbForProject, callable $getDatabasesDB, Event $queueForEvents, Context $usage, array $plan, Authorization $authorization): void
public function action(string $databaseId, string $collectionId, string $documentId, string $attribute, int|float $value, int|float|null $max, ?string $transactionId, UtopiaResponse $response, Database $dbForProject, callable $getDatabasesDB, Event $queueForEvents, Context $usage, array $plan, Authorization $authorization, User $user): void
{
$isAPIKey = User::isApp($authorization->getRoles());
$isPrivilegedUser = User::isPrivileged($authorization->getRoles());
$isAPIKey = $user->isApp($authorization->getRoles());
$isPrivilegedUser = $user->isPrivileged($authorization->getRoles());
$database = $authorization->skip(fn () => $dbForProject->getDocument('databases', $databaseId));
if ($database->isEmpty()) {
@@ -139,7 +139,7 @@ class Create extends Action
->inject('eventProcessor')
->callback($this->action(...));
}
public function action(string $databaseId, string $documentId, string $collectionId, string|array $data, ?array $permissions, ?array $documents, ?string $transactionId, UtopiaResponse $response, Database $dbForProject, callable $getDatabasesDB, Document $user, Event $queueForEvents, Context $usage, Event $queueForRealtime, Event $queueForFunctions, Event $queueForWebhooks, array $plan, Authorization $authorization, EventProcessor $eventProcessor): void
public function action(string $databaseId, string $documentId, string $collectionId, string|array $data, ?array $permissions, ?array $documents, ?string $transactionId, UtopiaResponse $response, Database $dbForProject, callable $getDatabasesDB, User $user, Event $queueForEvents, Context $usage, Event $queueForRealtime, Event $queueForFunctions, Event $queueForWebhooks, array $plan, Authorization $authorization, EventProcessor $eventProcessor): void
{
$data = \is_string($data)
? \json_decode($data, true)
@@ -183,8 +183,8 @@ class Create extends Action
$documents = [$data];
}
$isAPIKey = User::isApp($authorization->getRoles());
$isPrivilegedUser = User::isPrivileged($authorization->getRoles());
$isAPIKey = $user->isApp($authorization->getRoles());
$isPrivilegedUser = $user->isPrivileged($authorization->getRoles());
if ($isBulk && !$isAPIKey && !$isPrivilegedUser) {
throw new Exception(Exception::GENERAL_UNAUTHORIZED_SCOPE);
@@ -85,6 +85,7 @@ class Delete extends Action
->inject('transactionState')
->inject('plan')
->inject('authorization')
->inject('user')
->callback($this->action(...));
}
@@ -101,12 +102,13 @@ class Delete extends Action
Context $usage,
TransactionState $transactionState,
array $plan,
Authorization $authorization
Authorization $authorization,
User $user
): void {
$database = $authorization->skip(fn () => $dbForProject->getDocument('databases', $databaseId));
$isAPIKey = User::isApp($authorization->getRoles());
$isPrivilegedUser = User::isPrivileged($authorization->getRoles());
$isAPIKey = $user->isApp($authorization->getRoles());
$isPrivilegedUser = $user->isPrivileged($authorization->getRoles());
if ($database->isEmpty() || (!$database->getAttribute('enabled', false) && !$isAPIKey && !$isPrivilegedUser)) {
throw new Exception(Exception::DATABASE_NOT_FOUND, params: [$databaseId]);
@@ -72,13 +72,14 @@ class Get extends Action
->inject('usage')
->inject('transactionState')
->inject('authorization')
->inject('user')
->callback($this->action(...));
}
public function action(string $databaseId, string $collectionId, string $documentId, array $queries, ?string $transactionId, UtopiaResponse $response, Database $dbForProject, callable $getDatabasesDB, Context $usage, TransactionState $transactionState, Authorization $authorization): void
public function action(string $databaseId, string $collectionId, string $documentId, array $queries, ?string $transactionId, UtopiaResponse $response, Database $dbForProject, callable $getDatabasesDB, Context $usage, TransactionState $transactionState, Authorization $authorization, User $user): void
{
$isAPIKey = User::isApp($authorization->getRoles());
$isPrivilegedUser = User::isPrivileged($authorization->getRoles());
$isAPIKey = $user->isApp($authorization->getRoles());
$isPrivilegedUser = $user->isPrivileged($authorization->getRoles());
$database = $authorization->skip(fn () => $dbForProject->getDocument('databases', $databaseId));
if ($database->isEmpty() || (!$database->getAttribute('enabled', false) && !$isAPIKey && !$isPrivilegedUser)) {
@@ -89,10 +89,11 @@ class Update extends Action
->inject('transactionState')
->inject('plan')
->inject('authorization')
->inject('user')
->callback($this->action(...));
}
public function action(string $databaseId, string $collectionId, string $documentId, string|array $data, ?array $permissions, ?string $transactionId, ?\DateTime $requestTimestamp, UtopiaResponse $response, Database $dbForProject, callable $getDatabasesDB, Event $queueForEvents, Context $usage, TransactionState $transactionState, array $plan, Authorization $authorization): void
public function action(string $databaseId, string $collectionId, string $documentId, string|array $data, ?array $permissions, ?string $transactionId, ?\DateTime $requestTimestamp, UtopiaResponse $response, Database $dbForProject, callable $getDatabasesDB, Event $queueForEvents, Context $usage, TransactionState $transactionState, array $plan, Authorization $authorization, User $user): void
{
$data = (\is_string($data)) ? \json_decode($data, true) : $data; // Cast to JSON array
@@ -102,8 +103,8 @@ class Update extends Action
$database = $authorization->skip(fn () => $dbForProject->getDocument('databases', $databaseId));
$isAPIKey = User::isApp($authorization->getRoles());
$isPrivilegedUser = User::isPrivileged($authorization->getRoles());
$isAPIKey = $user->isApp($authorization->getRoles());
$isPrivilegedUser = $user->isPrivileged($authorization->getRoles());
if ($database->isEmpty() || (!$database->getAttribute('enabled', false) && !$isAPIKey && !$isPrivilegedUser)) {
throw new Exception(Exception::DATABASE_NOT_FOUND, params: [$databaseId]);
@@ -96,7 +96,7 @@ class Upsert extends Action
->callback($this->action(...));
}
public function action(string $databaseId, string $collectionId, string $documentId, string|array $data, ?array $permissions, ?string $transactionId, ?\DateTime $requestTimestamp, UtopiaResponse $response, Document $user, Database $dbForProject, callable $getDatabasesDB, Event $queueForEvents, Context $usage, TransactionState $transactionState, array $plan, Authorization $authorization): void
public function action(string $databaseId, string $collectionId, string $documentId, string|array $data, ?array $permissions, ?string $transactionId, ?\DateTime $requestTimestamp, UtopiaResponse $response, User $user, Database $dbForProject, callable $getDatabasesDB, Event $queueForEvents, Context $usage, TransactionState $transactionState, array $plan, Authorization $authorization): void
{
$data = (\is_string($data)) ? \json_decode($data, true) : $data; // Cast to JSON array
@@ -108,8 +108,8 @@ class Upsert extends Action
throw new Exception($this->getMissingPayloadException());
}
$isAPIKey = User::isApp($authorization->getRoles());
$isPrivilegedUser = User::isPrivileged($authorization->getRoles());
$isAPIKey = $user->isApp($authorization->getRoles());
$isPrivilegedUser = $user->isPrivileged($authorization->getRoles());
$database = $authorization->skip(fn () => $dbForProject->getDocument('databases', $databaseId));
if ($database->isEmpty() || (!$database->getAttribute('enabled', false) && !$isAPIKey && !$isPrivilegedUser)) {
@@ -83,10 +83,10 @@ class XList extends Action
->callback($this->action(...));
}
public function action(string $databaseId, string $collectionId, array $queries, ?string $transactionId, bool $includeTotal, int $ttl, UtopiaResponse $response, Database $dbForProject, Document $user, callable $getDatabasesDB, Context $usage, TransactionState $transactionState, Authorization $authorization): void
public function action(string $databaseId, string $collectionId, array $queries, ?string $transactionId, bool $includeTotal, int $ttl, UtopiaResponse $response, Database $dbForProject, User $user, callable $getDatabasesDB, Context $usage, TransactionState $transactionState, Authorization $authorization): void
{
$isAPIKey = User::isApp($authorization->getRoles());
$isPrivilegedUser = User::isPrivileged($authorization->getRoles());
$isAPIKey = $user->isApp($authorization->getRoles());
$isPrivilegedUser = $user->isPrivileged($authorization->getRoles());
$database = $authorization->skip(fn () => $dbForProject->getDocument('databases', $databaseId));
if ($database->isEmpty() || (!$database->getAttribute('enabled', false) && !$isAPIKey && !$isPrivilegedUser)) {
@@ -65,17 +65,18 @@ class Create extends Action
->inject('transactionState')
->inject('plan')
->inject('authorization')
->inject('user')
->callback($this->action(...));
}
public function action(string $transactionId, array $operations, UtopiaResponse $response, Database $dbForProject, TransactionState $transactionState, array $plan, Authorization $authorization): void
public function action(string $transactionId, array $operations, UtopiaResponse $response, Database $dbForProject, TransactionState $transactionState, array $plan, Authorization $authorization, User $user): void
{
if (empty($operations)) {
throw new Exception(Exception::GENERAL_BAD_REQUEST, 'Operations array cannot be empty');
}
$isAPIKey = User::isApp($authorization->getRoles());
$isPrivilegedUser = User::isPrivileged($authorization->getRoles());
$isAPIKey = $user->isApp($authorization->getRoles());
$isPrivilegedUser = $user->isPrivileged($authorization->getRoles());
// API keys and admins can read any transaction, regular users need permissions
$transaction = ($isAPIKey || $isPrivilegedUser)
@@ -91,7 +91,7 @@ class Update extends Action
* @param UtopiaResponse $response
* @param Database $dbForProject
* @param callable $getDatabasesDB
* @param Document $user
* @param User $user
* @param TransactionState $transactionState
* @param Delete $queueForDeletes
* @param Event $queueForEvents
@@ -109,7 +109,7 @@ class Update extends Action
* @throws Structure
* @throws \Utopia\Http\Exception
*/
public function action(string $transactionId, bool $commit, bool $rollback, Document $project, UtopiaResponse $response, Database $dbForProject, callable $getDatabasesDB, Document $user, TransactionState $transactionState, Delete $queueForDeletes, Event $queueForEvents, Context $usage, Event $queueForRealtime, Event $queueForFunctions, Event $queueForWebhooks, Authorization $authorization, EventProcessor $eventProcessor): void
public function action(string $transactionId, bool $commit, bool $rollback, Document $project, UtopiaResponse $response, Database $dbForProject, callable $getDatabasesDB, User $user, TransactionState $transactionState, Delete $queueForDeletes, Event $queueForEvents, Context $usage, Event $queueForRealtime, Event $queueForFunctions, Event $queueForWebhooks, Authorization $authorization, EventProcessor $eventProcessor): void
{
if (!$commit && !$rollback) {
throw new Exception(Exception::GENERAL_BAD_REQUEST, 'Either commit or rollback must be true');
@@ -118,8 +118,8 @@ class Update extends Action
throw new Exception(Exception::GENERAL_BAD_REQUEST, 'Cannot commit and rollback at the same time');
}
$isAPIKey = User::isApp($authorization->getRoles());
$isPrivilegedUser = User::isPrivileged($authorization->getRoles());
$isAPIKey = $user->isApp($authorization->getRoles());
$isPrivilegedUser = $user->isPrivileged($authorization->getRoles());
$transaction = ($isAPIKey || $isPrivilegedUser)
? $authorization->skip(fn () => $dbForProject->getDocument('transactions', $transactionId))
@@ -68,6 +68,7 @@ class Decrement extends DecrementDocumentAttribute
->inject('usage')
->inject('plan')
->inject('authorization')
->inject('user')
->callback($this->action(...));
}
}
@@ -68,6 +68,7 @@ class Increment extends IncrementDocumentAttribute
->inject('usage')
->inject('plan')
->inject('authorization')
->inject('user')
->callback($this->action(...));
}
}
@@ -71,6 +71,7 @@ class Delete extends DocumentDelete
->inject('transactionState')
->inject('plan')
->inject('authorization')
->inject('user')
->callback($this->action(...));
}
}
@@ -59,6 +59,7 @@ class Get extends DocumentGet
->inject('usage')
->inject('transactionState')
->inject('authorization')
->inject('user')
->callback($this->action(...));
}
}
@@ -70,6 +70,7 @@ class Update extends DocumentUpdate
->inject('transactionState')
->inject('plan')
->inject('authorization')
->inject('user')
->callback($this->action(...));
}
}
@@ -55,6 +55,7 @@ class Create extends OperationsCreate
->inject('transactionState')
->inject('plan')
->inject('authorization')
->inject('user')
->callback($this->action(...));
}
}
@@ -70,6 +70,7 @@ class Decrement extends DecrementDocumentAttribute
->inject('usage')
->inject('plan')
->inject('authorization')
->inject('user')
->callback($this->action(...));
}
}
@@ -70,6 +70,7 @@ class Increment extends IncrementDocumentAttribute
->inject('usage')
->inject('plan')
->inject('authorization')
->inject('user')
->callback($this->action(...));
}
}
@@ -73,6 +73,7 @@ class Delete extends DocumentDelete
->inject('transactionState')
->inject('plan')
->inject('authorization')
->inject('user')
->callback($this->action(...));
}
}
@@ -61,6 +61,7 @@ class Get extends DocumentGet
->inject('usage')
->inject('transactionState')
->inject('authorization')
->inject('user')
->callback($this->action(...));
}
}
@@ -71,6 +71,7 @@ class Update extends DocumentUpdate
->inject('transactionState')
->inject('plan')
->inject('authorization')
->inject('user')
->callback($this->action(...));
}
}
@@ -56,6 +56,7 @@ class Create extends OperationsCreate
->inject('transactionState')
->inject('plan')
->inject('authorization')
->inject('user')
->callback($this->action(...));
}
}
@@ -71,6 +71,7 @@ class Delete extends DocumentDelete
->inject('transactionState')
->inject('plan')
->inject('authorization')
->inject('user')
->callback($this->action(...));
}
}
@@ -59,6 +59,7 @@ class Get extends DocumentGet
->inject('usage')
->inject('transactionState')
->inject('authorization')
->inject('user')
->callback($this->action(...));
}
}
@@ -70,6 +70,7 @@ class Update extends DocumentUpdate
->inject('transactionState')
->inject('plan')
->inject('authorization')
->inject('user')
->callback($this->action(...));
}
}
@@ -55,6 +55,7 @@ class Create extends OperationsCreate
->inject('transactionState')
->inject('plan')
->inject('authorization')
->inject('user')
->callback($this->action(...));
}
}
@@ -119,7 +119,7 @@ class Create extends Base
Document $project,
Database $dbForProject,
Database $dbForPlatform,
Document $user,
User $user,
Event $queueForEvents,
Context $usage,
Func $queueForFunctions,
@@ -171,8 +171,8 @@ class Create extends Base
/* @var Document $function */
$function = $authorization->skip(fn () => $dbForProject->getDocument('functions', $functionId));
$isAPIKey = User::isApp($authorization->getRoles());
$isPrivilegedUser = User::isPrivileged($authorization->getRoles());
$isAPIKey = $user->isApp($authorization->getRoles());
$isPrivilegedUser = $user->isPrivileged($authorization->getRoles());
if ($function->isEmpty() || (!$function->getAttribute('enabled') && !$isAPIKey && !$isPrivilegedUser)) {
throw new Exception(Exception::FUNCTION_NOT_FOUND);
@@ -53,6 +53,7 @@ class Get extends Base
->inject('response')
->inject('dbForProject')
->inject('authorization')
->inject('user')
->callback($this->action(...));
}
@@ -61,12 +62,13 @@ class Get extends Base
string $executionId,
Response $response,
Database $dbForProject,
Authorization $authorization
Authorization $authorization,
User $user
) {
$function = $authorization->skip(fn () => $dbForProject->getDocument('functions', $functionId));
$isAPIKey = User::isApp($authorization->getRoles());
$isPrivilegedUser = User::isPrivileged($authorization->getRoles());
$isAPIKey = $user->isApp($authorization->getRoles());
$isPrivilegedUser = $user->isPrivileged($authorization->getRoles());
if ($function->isEmpty() || (!$function->getAttribute('enabled') && !$isAPIKey && !$isPrivilegedUser)) {
throw new Exception(Exception::FUNCTION_NOT_FOUND);
@@ -62,6 +62,7 @@ class XList extends Base
->inject('response')
->inject('dbForProject')
->inject('authorization')
->inject('user')
->callback($this->action(...));
}
@@ -71,12 +72,13 @@ class XList extends Base
bool $includeTotal,
Response $response,
Database $dbForProject,
Authorization $authorization
Authorization $authorization,
User $user
) {
$function = $authorization->skip(fn () => $dbForProject->getDocument('functions', $functionId));
$isAPIKey = User::isApp($authorization->getRoles());
$isPrivilegedUser = User::isPrivileged($authorization->getRoles());
$isAPIKey = $user->isApp($authorization->getRoles());
$isPrivilegedUser = $user->isPrivileged($authorization->getRoles());
if ($function->isEmpty() || (!$function->getAttribute('enabled') && !$isAPIKey && !$isPrivilegedUser)) {
throw new Exception(Exception::FUNCTION_NOT_FOUND);
@@ -103,7 +103,7 @@ class Create extends Action
Request $request,
Response $response,
Database $dbForProject,
Document $user,
User $user,
Event $queueForEvents,
string $mode,
Device $deviceForFiles,
@@ -112,8 +112,8 @@ class Create extends Action
) {
$bucket = $authorization->skip(fn () => $dbForProject->getDocument('buckets', $bucketId));
$isAPIKey = User::isApp($authorization->getRoles());
$isPrivilegedUser = User::isPrivileged($authorization->getRoles());
$isAPIKey = $user->isApp($authorization->getRoles());
$isPrivilegedUser = $user->isPrivileged($authorization->getRoles());
if ($bucket->isEmpty() || (!$bucket->getAttribute('enabled') && !$isAPIKey && !$isPrivilegedUser)) {
throw new Exception(Exception::STORAGE_BUCKET_NOT_FOUND);
@@ -66,6 +66,7 @@ class Delete extends Action
->inject('deviceForFiles')
->inject('queueForDeletes')
->inject('authorization')
->inject('user')
->callback($this->action(...));
}
@@ -77,12 +78,13 @@ class Delete extends Action
Event $queueForEvents,
Device $deviceForFiles,
DeleteEvent $queueForDeletes,
Authorization $authorization
Authorization $authorization,
User $user
) {
$bucket = $authorization->skip(fn () => $dbForProject->getDocument('buckets', $bucketId));
$isAPIKey = User::isApp($authorization->getRoles());
$isPrivilegedUser = User::isPrivileged($authorization->getRoles());
$isAPIKey = $user->isApp($authorization->getRoles());
$isPrivilegedUser = $user->isPrivileged($authorization->getRoles());
if ($bucket->isEmpty() || (!$bucket->getAttribute('enabled') && !$isAPIKey && !$isPrivilegedUser)) {
throw new Exception(Exception::STORAGE_BUCKET_NOT_FOUND);
@@ -70,6 +70,7 @@ class Get extends Action
->inject('resourceToken')
->inject('deviceForFiles')
->inject('authorization')
->inject('user')
->callback($this->action(...));
}
@@ -84,12 +85,13 @@ class Get extends Action
Document $resourceToken,
Device $deviceForFiles,
Authorization $authorization,
User $user,
) {
/* @type Document $bucket */
$bucket = $authorization->skip(fn () => $dbForProject->getDocument('buckets', $bucketId));
$isAPIKey = User::isApp($authorization->getRoles());
$isPrivilegedUser = User::isPrivileged($authorization->getRoles());
$isAPIKey = $user->isApp($authorization->getRoles());
$isPrivilegedUser = $user->isPrivileged($authorization->getRoles());
if ($bucket->isEmpty() || (!$bucket->getAttribute('enabled') && !$isAPIKey && !$isPrivilegedUser)) {
throw new Exception(Exception::STORAGE_BUCKET_NOT_FOUND);
@@ -51,6 +51,7 @@ class Get extends Action
->inject('response')
->inject('dbForProject')
->inject('authorization')
->inject('user')
->callback($this->action(...));
}
@@ -59,12 +60,13 @@ class Get extends Action
string $fileId,
Response $response,
Database $dbForProject,
Authorization $authorization
Authorization $authorization,
User $user
) {
$bucket = $authorization->skip(fn () => $dbForProject->getDocument('buckets', $bucketId));
$isAPIKey = User::isApp($authorization->getRoles());
$isPrivilegedUser = User::isPrivileged($authorization->getRoles());
$isAPIKey = $user->isApp($authorization->getRoles());
$isPrivilegedUser = $user->isPrivileged($authorization->getRoles());
if ($bucket->isEmpty() || (!$bucket->getAttribute('enabled') && !$isAPIKey && !$isPrivilegedUser)) {
throw new Exception(Exception::STORAGE_BUCKET_NOT_FOUND);
@@ -92,6 +92,7 @@ class Get extends Action
->inject('deviceForLocal')
->inject('project')
->inject('authorization')
->inject('user')
->callback($this->action(...));
}
@@ -117,7 +118,8 @@ class Get extends Action
Device $deviceForFiles,
Device $deviceForLocal,
Document $project,
Authorization $authorization
Authorization $authorization,
User $user
) {
if (!\extension_loaded('imagick')) {
@@ -127,8 +129,8 @@ class Get extends Action
/* @type Document $bucket */
$bucket = $authorization->skip(fn () => $dbForProject->getDocument('buckets', $bucketId));
$isAPIKey = User::isApp($authorization->getRoles());
$isPrivilegedUser = User::isPrivileged($authorization->getRoles());
$isAPIKey = $user->isApp($authorization->getRoles());
$isPrivilegedUser = $user->isPrivileged($authorization->getRoles());
if ($bucket->isEmpty() || (!$bucket->getAttribute('enabled') && !$isAPIKey && !$isPrivilegedUser)) {
throw new Exception(Exception::STORAGE_BUCKET_NOT_FOUND);
@@ -271,7 +273,7 @@ class Get extends Action
$contentType = (\array_key_exists($output, $outputs)) ? $outputs[$output] : $outputs['jpg'];
//Do not update transformedAt if it's a console user
if (!User::isPrivileged($authorization->getRoles())) {
if (!$user->isPrivileged($authorization->getRoles())) {
$transformedAt = $file->getAttribute('transformedAt', '');
if (DateTime::formatTz(DateTime::addSeconds(new \DateTime(), -APP_PROJECT_ACCESS)) > $transformedAt) {
$file->setAttribute('transformedAt', DateTime::now());
@@ -52,6 +52,7 @@ class Get extends Action
->inject('mode')
->inject('deviceForFiles')
->inject('authorization')
->inject('user')
->callback($this->action(...));
}
@@ -66,7 +67,8 @@ class Get extends Action
Document $project,
string $mode,
Device $deviceForFiles,
Authorization $authorization
Authorization $authorization,
User $user
) {
$decoder = new JWT(System::getEnv('_APP_OPENSSL_KEY_V1'), 'HS256', 3600, 0);
@@ -88,8 +90,8 @@ class Get extends Action
$disposition = $decoded['disposition'] ?? 'inline';
$dbForProject = $isInternal ? $dbForPlatform : $dbForProject;
$isAPIKey = User::isApp($authorization->getRoles());
$isPrivilegedUser = User::isPrivileged($authorization->getRoles());
$isAPIKey = $user->isApp($authorization->getRoles());
$isPrivilegedUser = $user->isPrivileged($authorization->getRoles());
$bucket = $authorization->skip(fn () => $dbForProject->getDocument('buckets', $bucketId));
if ($bucket->isEmpty() || (!$bucket->getAttribute('enabled') && !$isAPIKey && !$isPrivilegedUser)) {
@@ -64,6 +64,7 @@ class Update extends Action
->inject('dbForProject')
->inject('queueForEvents')
->inject('authorization')
->inject('user')
->callback($this->action(...));
}
@@ -75,12 +76,13 @@ class Update extends Action
Response $response,
Database $dbForProject,
Event $queueForEvents,
Authorization $authorization
Authorization $authorization,
User $user
) {
$bucket = $authorization->skip(fn () => $dbForProject->getDocument('buckets', $bucketId));
$isAPIKey = User::isApp($authorization->getRoles());
$isPrivilegedUser = User::isPrivileged($authorization->getRoles());
$isAPIKey = $user->isApp($authorization->getRoles());
$isPrivilegedUser = $user->isPrivileged($authorization->getRoles());
if ($bucket->isEmpty() || (!$bucket->getAttribute('enabled') && !$isAPIKey && !$isPrivilegedUser)) {
throw new Exception(Exception::STORAGE_BUCKET_NOT_FOUND);
@@ -108,7 +110,7 @@ class Update extends Action
// Users can only manage their own roles, API keys and Admin users can manage any
$roles = $authorization->getRoles();
if (!User::isApp($roles) && !User::isPrivileged($roles) && !\is_null($permissions)) {
if (!$user->isApp($roles) && !$user->isPrivileged($roles) && !\is_null($permissions)) {
foreach (Database::PERMISSIONS as $type) {
foreach ($permissions as $permission) {
$permission = Permission::parse($permission);
@@ -71,6 +71,7 @@ class Get extends Action
->inject('resourceToken')
->inject('deviceForFiles')
->inject('authorization')
->inject('user')
->callback($this->action(...));
}
@@ -84,13 +85,14 @@ class Get extends Action
string $mode,
Document $resourceToken,
Device $deviceForFiles,
Authorization $authorization
Authorization $authorization,
User $user
) {
/* @type Document $bucket */
$bucket = $authorization->skip(fn () => $dbForProject->getDocument('buckets', $bucketId));
$isAPIKey = User::isApp($authorization->getRoles());
$isPrivilegedUser = User::isPrivileged($authorization->getRoles());
$isAPIKey = $user->isApp($authorization->getRoles());
$isPrivilegedUser = $user->isPrivileged($authorization->getRoles());
if ($bucket->isEmpty() || (!$bucket->getAttribute('enabled') && !$isAPIKey && !$isPrivilegedUser)) {
throw new Exception(Exception::STORAGE_BUCKET_NOT_FOUND);
@@ -63,6 +63,7 @@ class XList extends Action
->inject('dbForProject')
->inject('mode')
->inject('authorization')
->inject('user')
->callback($this->action(...));
}
@@ -74,12 +75,13 @@ class XList extends Action
Response $response,
Database $dbForProject,
string $mode,
Authorization $authorization
Authorization $authorization,
User $user
) {
$bucket = $authorization->skip(fn () => $dbForProject->getDocument('buckets', $bucketId));
$isAPIKey = User::isApp($authorization->getRoles());
$isPrivilegedUser = User::isPrivileged($authorization->getRoles());
$isAPIKey = $user->isApp($authorization->getRoles());
$isPrivilegedUser = $user->isPrivileged($authorization->getRoles());
if ($bucket->isEmpty() || (!$bucket->getAttribute('enabled') && !$isAPIKey && !$isPrivilegedUser)) {
throw new Exception(Exception::STORAGE_BUCKET_NOT_FOUND);
@@ -98,10 +98,10 @@ class Create extends Action
->callback($this->action(...));
}
public function action(string $teamId, string $email, string $userId, string $phone, array $roles, string $url, string $name, Response $response, Document $project, Document $user, Database $dbForProject, Authorization $authorization, Locale $locale, Mail $queueForMails, Messaging $queueForMessaging, Event $queueForEvents, callable $timelimit, Context $usage, array $plan, Password $proofForPassword, Token $proofForToken)
public function action(string $teamId, string $email, string $userId, string $phone, array $roles, string $url, string $name, Response $response, Document $project, User $user, Database $dbForProject, Authorization $authorization, Locale $locale, Mail $queueForMails, Messaging $queueForMessaging, Event $queueForEvents, callable $timelimit, Context $usage, array $plan, Password $proofForPassword, Token $proofForToken)
{
$isAppUser = User::isApp($authorization->getRoles());
$isPrivilegedUser = User::isPrivileged($authorization->getRoles());
$isAppUser = $user->isApp($authorization->getRoles());
$isPrivilegedUser = $user->isPrivileged($authorization->getRoles());
if (empty($url)) {
if (! $isAppUser && ! $isPrivilegedUser) {
@@ -52,10 +52,11 @@ class Get extends Action
->inject('project')
->inject('dbForProject')
->inject('authorization')
->inject('user')
->callback($this->action(...));
}
public function action(string $teamId, string $membershipId, Response $response, Document $project, Database $dbForProject, Authorization $authorization)
public function action(string $teamId, string $membershipId, Response $response, Document $project, Database $dbForProject, Authorization $authorization, User $user)
{
$team = $dbForProject->getDocument('teams', $teamId);
@@ -76,25 +77,25 @@ class Get extends Action
];
$roles = $authorization->getRoles();
$isPrivilegedUser = User::isPrivileged($roles);
$isAppUser = User::isApp($roles);
$isPrivilegedUser = $user->isPrivileged($roles);
$isAppUser = $user->isApp($roles);
$membershipsPrivacy = array_map(function ($privacy) use ($isPrivilegedUser, $isAppUser) {
return $privacy || $isPrivilegedUser || $isAppUser;
}, $membershipsPrivacy);
$user = !empty(array_filter($membershipsPrivacy))
$memberUser = !empty(array_filter($membershipsPrivacy))
? $dbForProject->getDocument('users', $membership->getAttribute('userId'))
: new Document();
if ($membershipsPrivacy['mfa']) {
$mfa = $user->getAttribute('mfa', false);
$mfa = $memberUser->getAttribute('mfa', false);
if ($mfa) {
$totp = TOTP::getAuthenticatorFromUser($user);
$totp = TOTP::getAuthenticatorFromUser($memberUser);
$totpEnabled = $totp && $totp->getAttribute('verified', false);
$emailEnabled = $user->getAttribute('email', false) && $user->getAttribute('emailVerification', false);
$phoneEnabled = $user->getAttribute('phone', false) && $user->getAttribute('phoneVerification', false);
$emailEnabled = $memberUser->getAttribute('email', false) && $memberUser->getAttribute('emailVerification', false);
$phoneEnabled = $memberUser->getAttribute('phone', false) && $memberUser->getAttribute('phoneVerification', false);
if (!$totpEnabled && !$emailEnabled && !$phoneEnabled) {
$mfa = false;
@@ -105,11 +106,11 @@ class Get extends Action
}
if ($membershipsPrivacy['userName']) {
$membership->setAttribute('userName', $user->getAttribute('name'));
$membership->setAttribute('userName', $memberUser->getAttribute('name'));
}
if ($membershipsPrivacy['userEmail']) {
$membership->setAttribute('userEmail', $user->getAttribute('email'));
$membership->setAttribute('userEmail', $memberUser->getAttribute('email'));
}
$membership->setAttribute('teamName', $team->getAttribute('name'));
@@ -66,7 +66,7 @@ class Update extends Action
->callback($this->action(...));
}
public function action(string $teamId, string $membershipId, array $roles, Request $request, Response $response, Document $user, Document $project, Database $dbForProject, Authorization $authorization, Event $queueForEvents)
public function action(string $teamId, string $membershipId, array $roles, Request $request, Response $response, User $user, Document $project, Database $dbForProject, Authorization $authorization, Event $queueForEvents)
{
$team = $dbForProject->getDocument('teams', $teamId);
if ($team->isEmpty()) {
@@ -83,8 +83,8 @@ class Update extends Action
throw new Exception(Exception::USER_NOT_FOUND);
}
$isPrivilegedUser = User::isPrivileged($authorization->getRoles());
$isAppUser = User::isApp($authorization->getRoles());
$isPrivilegedUser = $user->isPrivileged($authorization->getRoles());
$isAppUser = $user->isApp($authorization->getRoles());
$isOwner = $authorization->hasRole('team:' . $team->getId() . '/owner');
if ($project->getId() === 'console') {
@@ -61,10 +61,11 @@ class XList extends Action
->inject('project')
->inject('dbForProject')
->inject('authorization')
->inject('user')
->callback($this->action(...));
}
public function action(string $teamId, array $queries, string $search, bool $includeTotal, Response $response, Document $project, Database $dbForProject, Authorization $authorization)
public function action(string $teamId, array $queries, string $search, bool $includeTotal, Response $response, Document $project, Database $dbForProject, Authorization $authorization, User $user)
{
$team = $dbForProject->getDocument('teams', $teamId);
@@ -129,26 +130,26 @@ class XList extends Action
];
$roles = $authorization->getRoles();
$isPrivilegedUser = User::isPrivileged($roles);
$isAppUser = User::isApp($roles);
$isPrivilegedUser = $user->isPrivileged($roles);
$isAppUser = $user->isApp($roles);
$membershipsPrivacy = array_map(function ($privacy) use ($isPrivilegedUser, $isAppUser) {
return $privacy || $isPrivilegedUser || $isAppUser;
}, $membershipsPrivacy);
$memberships = array_map(function ($membership) use ($dbForProject, $team, $membershipsPrivacy) {
$user = !empty(array_filter($membershipsPrivacy))
$memberUser = !empty(array_filter($membershipsPrivacy))
? $dbForProject->getDocument('users', $membership->getAttribute('userId'))
: new Document();
if ($membershipsPrivacy['mfa']) {
$mfa = $user->getAttribute('mfa', false);
$mfa = $memberUser->getAttribute('mfa', false);
if ($mfa) {
$totp = TOTP::getAuthenticatorFromUser($user);
$totp = TOTP::getAuthenticatorFromUser($memberUser);
$totpEnabled = $totp && $totp->getAttribute('verified', false);
$emailEnabled = $user->getAttribute('email', false) && $user->getAttribute('emailVerification', false);
$phoneEnabled = $user->getAttribute('phone', false) && $user->getAttribute('phoneVerification', false);
$emailEnabled = $memberUser->getAttribute('email', false) && $memberUser->getAttribute('emailVerification', false);
$phoneEnabled = $memberUser->getAttribute('phone', false) && $memberUser->getAttribute('phoneVerification', false);
if (!$totpEnabled && !$emailEnabled && !$phoneEnabled) {
$mfa = false;
@@ -159,11 +160,11 @@ class XList extends Action
}
if ($membershipsPrivacy['userName']) {
$membership->setAttribute('userName', $user->getAttribute('name'));
$membership->setAttribute('userName', $memberUser->getAttribute('name'));
}
if ($membershipsPrivacy['userEmail']) {
$membership->setAttribute('userEmail', $user->getAttribute('email'));
$membership->setAttribute('userEmail', $memberUser->getAttribute('email'));
}
$membership->setAttribute('teamName', $team->getAttribute('name'));
@@ -68,10 +68,10 @@ class Create extends Action
->callback($this->action(...));
}
public function action(string $teamId, string $name, array $roles, Response $response, Document $user, Database $dbForProject, Authorization $authorization, Event $queueForEvents)
public function action(string $teamId, string $name, array $roles, Response $response, User $user, Database $dbForProject, Authorization $authorization, Event $queueForEvents)
{
$isPrivilegedUser = User::isPrivileged($authorization->getRoles());
$isAppUser = User::isApp($authorization->getRoles());
$isPrivilegedUser = $user->isPrivileged($authorization->getRoles());
$isAppUser = $user->isApp($authorization->getRoles());
$teamId = $teamId == 'unique()' ? ID::unique() : $teamId;
@@ -11,12 +11,12 @@ use Utopia\Platform\Action as UtopiaAction;
class Action extends UtopiaAction
{
protected function getFileAndBucket(Database $dbForProject, Authorization $authorization, string $bucketId, string $fileId): array
protected function getFileAndBucket(Database $dbForProject, Authorization $authorization, User $user, string $bucketId, string $fileId): array
{
$bucket = $authorization->skip(fn () => $dbForProject->getDocument('buckets', $bucketId));
$isAPIKey = User::isApp($authorization->getRoles());
$isPrivilegedUser = User::isPrivileged($authorization->getRoles());
$isAPIKey = $user->isApp($authorization->getRoles());
$isPrivilegedUser = $user->isPrivileged($authorization->getRoles());
if ($bucket->isEmpty() || (!$bucket->getAttribute('enabled') && !$isAPIKey && !$isPrivilegedUser)) {
throw new Exception(Exception::STORAGE_BUCKET_NOT_FOUND);
@@ -8,6 +8,7 @@ use Appwrite\SDK\AuthType;
use Appwrite\SDK\ContentType;
use Appwrite\SDK\Method;
use Appwrite\SDK\Response as SDKResponse;
use Appwrite\Utopia\Database\Documents\User;
use Appwrite\Utopia\Response;
use Utopia\Auth\Proofs\Token;
use Utopia\Database\Database;
@@ -64,19 +65,20 @@ class Create extends Action
->param('fileId', '', fn (Database $dbForProject) => new UID($dbForProject->getAdapter()->getMaxUIDLength()), 'File unique ID.', false, ['dbForProject'])
->param('expire', null, new Nullable(new DatetimeValidator(requireDateInFuture: true)), 'Token expiry date', true)
->inject('response')
->inject('user')
->inject('dbForProject')
->inject('queueForEvents')
->inject('authorization')
->callback($this->action(...));
}
public function action(string $bucketId, string $fileId, ?string $expire, Response $response, Database $dbForProject, Event $queueForEvents, Authorization $authorization): void
public function action(string $bucketId, string $fileId, ?string $expire, Response $response, User $user, Database $dbForProject, Event $queueForEvents, Authorization $authorization): void
{
/**
* @var Document $bucket
* @var Document $file
*/
['bucket' => $bucket, 'file' => $file] = $this->getFileAndBucket($dbForProject, $authorization, $bucketId, $fileId);
['bucket' => $bucket, 'file' => $file] = $this->getFileAndBucket($dbForProject, $authorization, $user, $bucketId, $fileId);
$fileSecurity = $bucket->getAttribute('fileSecurity', false);
$bucketPermission = $authorization->isValid(new Input(Database::PERMISSION_UPDATE, $bucket->getUpdate()));
@@ -7,6 +7,7 @@ use Appwrite\SDK\AuthType;
use Appwrite\SDK\ContentType;
use Appwrite\SDK\Method;
use Appwrite\SDK\Response as SDKResponse;
use Appwrite\Utopia\Database\Documents\User;
use Appwrite\Utopia\Database\Validator\Queries\FileTokens;
use Appwrite\Utopia\Response;
use Utopia\Database\Database;
@@ -57,14 +58,15 @@ class XList extends Action
->param('queries', [], new FileTokens(), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' queries are allowed, each ' . APP_LIMIT_ARRAY_ELEMENT_SIZE . ' characters long. You may filter on the following attributes: ' . implode(', ', FileTokens::ALLOWED_ATTRIBUTES), true)
->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('user')
->inject('dbForProject')
->inject('authorization')
->callback($this->action(...));
}
public function action(string $bucketId, string $fileId, array $queries, bool $includeTotal, Response $response, Database $dbForProject, Authorization $authorization)
public function action(string $bucketId, string $fileId, array $queries, bool $includeTotal, Response $response, User $user, Database $dbForProject, Authorization $authorization)
{
['bucket' => $bucket, 'file' => $file] = $this->getFileAndBucket($dbForProject, $authorization, $bucketId, $fileId);
['bucket' => $bucket, 'file' => $file] = $this->getFileAndBucket($dbForProject, $authorization, $user, $bucketId, $fileId);
$queries = Query::parseQueries($queries);
$queries[] = Query::equal('resourceType', [TOKENS_RESOURCE_TYPE_FILES]);
@@ -102,7 +102,7 @@ class User extends Document
*
* @return bool
*/
public static function isPrivileged(array $roles): bool
public function isPrivileged(array $roles): bool
{
if (
in_array(self::ROLE_OWNER, $roles) ||
@@ -122,7 +122,7 @@ class User extends Document
*
* @return bool
*/
public static function isApp(array $roles): bool
public function isApp(array $roles): bool
{
if (in_array(self::ROLE_APPS, $roles)) {
return true;
@@ -175,7 +175,5 @@ class User extends Document
}
return false;
return false;
}
}
+7 -1
View File
@@ -215,7 +215,7 @@ class Request extends UtopiaRequest
$forwardedUserAgent = $this->getHeader('x-forwarded-user-agent');
if (!empty($forwardedUserAgent)) {
$roles = $this->authorization->getRoles();
$isAppUser = User::isApp($roles);
$isAppUser = $this->user?->isApp($roles) ?? false;
if ($isAppUser) {
return $forwardedUserAgent;
@@ -239,9 +239,15 @@ class Request extends UtopiaRequest
}
private ?Authorization $authorization = null;
private ?User $user = null;
public function setAuthorization(Authorization $authorization): void
{
$this->authorization = $authorization;
}
public function setUser(User $user): void
{
$this->user = $user;
}
}
+9 -2
View File
@@ -505,8 +505,9 @@ class Response extends SwooleResponse
if ($rule['sensitive']) {
$roles = $this->authorization->getRoles();
$isPrivilegedUser = DBUser::isPrivileged($roles);
$isAppUser = DBUser::isApp($roles);
$user = $this->user ?? new DBUser();
$isPrivilegedUser = $user->isPrivileged($roles);
$isAppUser = $user->isApp($roles);
if ((!$isPrivilegedUser && !$isAppUser) && !self::$showSensitive) {
$data->setAttribute($key, '');
@@ -674,9 +675,15 @@ class Response extends SwooleResponse
}
private ?Authorization $authorization = null;
private ?DBUser $user = null;
public function setAuthorization(Authorization $authorization): void
{
$this->authorization = $authorization;
}
public function setUser(DBUser $user): void
{
$this->user = $user;
}
}
@@ -171,36 +171,40 @@ class UserTest extends TestCase
public function testIsPrivilegedUser(): void
{
$this->assertEquals(false, User::isPrivileged([]));
$this->assertEquals(false, User::isPrivileged([Role::guests()->toString()]));
$this->assertEquals(false, User::isPrivileged([Role::users()->toString()]));
$this->assertEquals(true, User::isPrivileged([User::ROLE_ADMIN]));
$this->assertEquals(true, User::isPrivileged([User::ROLE_DEVELOPER]));
$this->assertEquals(true, User::isPrivileged([User::ROLE_OWNER]));
$this->assertEquals(false, User::isPrivileged([User::ROLE_APPS]));
$this->assertEquals(false, User::isPrivileged([User::ROLE_SYSTEM]));
$user = new User();
$this->assertEquals(false, User::isPrivileged([User::ROLE_APPS, User::ROLE_APPS]));
$this->assertEquals(false, User::isPrivileged([User::ROLE_APPS, Role::guests()->toString()]));
$this->assertEquals(true, User::isPrivileged([User::ROLE_OWNER, Role::guests()->toString()]));
$this->assertEquals(true, User::isPrivileged([User::ROLE_OWNER, User::ROLE_ADMIN, User::ROLE_DEVELOPER]));
$this->assertEquals(false, $user->isPrivileged([]));
$this->assertEquals(false, $user->isPrivileged([Role::guests()->toString()]));
$this->assertEquals(false, $user->isPrivileged([Role::users()->toString()]));
$this->assertEquals(true, $user->isPrivileged([User::ROLE_ADMIN]));
$this->assertEquals(true, $user->isPrivileged([User::ROLE_DEVELOPER]));
$this->assertEquals(true, $user->isPrivileged([User::ROLE_OWNER]));
$this->assertEquals(false, $user->isPrivileged([User::ROLE_APPS]));
$this->assertEquals(false, $user->isPrivileged([User::ROLE_SYSTEM]));
$this->assertEquals(false, $user->isPrivileged([User::ROLE_APPS, User::ROLE_APPS]));
$this->assertEquals(false, $user->isPrivileged([User::ROLE_APPS, Role::guests()->toString()]));
$this->assertEquals(true, $user->isPrivileged([User::ROLE_OWNER, Role::guests()->toString()]));
$this->assertEquals(true, $user->isPrivileged([User::ROLE_OWNER, User::ROLE_ADMIN, User::ROLE_DEVELOPER]));
}
public function testIsAppUser(): void
{
$this->assertEquals(false, User::isApp([]));
$this->assertEquals(false, User::isApp([Role::guests()->toString()]));
$this->assertEquals(false, User::isApp([Role::users()->toString()]));
$this->assertEquals(false, User::isApp([User::ROLE_ADMIN]));
$this->assertEquals(false, User::isApp([User::ROLE_DEVELOPER]));
$this->assertEquals(false, User::isApp([User::ROLE_OWNER]));
$this->assertEquals(true, User::isApp([User::ROLE_APPS]));
$this->assertEquals(false, User::isApp([User::ROLE_SYSTEM]));
$user = new User();
$this->assertEquals(true, User::isApp([User::ROLE_APPS, User::ROLE_APPS]));
$this->assertEquals(true, User::isApp([User::ROLE_APPS, Role::guests()->toString()]));
$this->assertEquals(false, User::isApp([User::ROLE_OWNER, Role::guests()->toString()]));
$this->assertEquals(false, User::isApp([User::ROLE_OWNER, User::ROLE_ADMIN, User::ROLE_DEVELOPER]));
$this->assertEquals(false, $user->isApp([]));
$this->assertEquals(false, $user->isApp([Role::guests()->toString()]));
$this->assertEquals(false, $user->isApp([Role::users()->toString()]));
$this->assertEquals(false, $user->isApp([User::ROLE_ADMIN]));
$this->assertEquals(false, $user->isApp([User::ROLE_DEVELOPER]));
$this->assertEquals(false, $user->isApp([User::ROLE_OWNER]));
$this->assertEquals(true, $user->isApp([User::ROLE_APPS]));
$this->assertEquals(false, $user->isApp([User::ROLE_SYSTEM]));
$this->assertEquals(true, $user->isApp([User::ROLE_APPS, User::ROLE_APPS]));
$this->assertEquals(true, $user->isApp([User::ROLE_APPS, Role::guests()->toString()]));
$this->assertEquals(false, $user->isApp([User::ROLE_OWNER, Role::guests()->toString()]));
$this->assertEquals(false, $user->isApp([User::ROLE_OWNER, User::ROLE_ADMIN, User::ROLE_DEVELOPER]));
}
public function testGuestRoles(): void