From ec39ff267c834aaf0fb2d2f4f90feff0ae68a72a Mon Sep 17 00:00:00 2001 From: shimon Date: Sun, 7 Aug 2022 17:30:47 +0300 Subject: [PATCH 01/46] api::parseLabel --- app/controllers/api/storage.php | 68 ++++++++++++--------------------- app/controllers/shared/api.php | 23 +++++++++-- 2 files changed, 44 insertions(+), 47 deletions(-) diff --git a/app/controllers/api/storage.php b/app/controllers/api/storage.php index b62aa750db..202599fea9 100644 --- a/app/controllers/api/storage.php +++ b/app/controllers/api/storage.php @@ -45,6 +45,7 @@ App::post('/v1/storage/buckets') ->desc('Create bucket') ->groups(['api', 'storage']) ->label('scope', 'buckets.write') + ->label('audits.resource', 'storage/buckets/{$id}') ->label('event', 'buckets.[bucketId].create') ->label('sdk.auth', [APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'storage') @@ -65,10 +66,9 @@ App::post('/v1/storage/buckets') ->param('antivirus', true, new Boolean(true), 'Is virus scanning enabled? For file size above ' . Storage::human(APP_LIMIT_ANTIVIRUS, 0) . ' AntiVirus scanning is skipped even if it\'s enabled', true) ->inject('response') ->inject('dbForProject') - ->inject('audits') ->inject('usage') ->inject('events') - ->action(function (string $bucketId, string $name, string $permission, ?array $read, ?array $write, bool $enabled, int $maximumFileSize, array $allowedFileExtensions, bool $encryption, bool $antivirus, Response $response, Database $dbForProject, Audit $audits, Stats $usage, Event $events) { + ->action(function (string $bucketId, string $name, string $permission, ?array $read, ?array $write, bool $enabled, int $maximumFileSize, array $allowedFileExtensions, bool $encryption, bool $antivirus, Response $response, Database $dbForProject, Stats $usage, Event $events) { $bucketId = $bucketId === 'unique()' ? $dbForProject->getId() : $bucketId; try { @@ -126,10 +126,7 @@ App::post('/v1/storage/buckets') throw new Exception('Bucket already exists', 409, Exception::STORAGE_BUCKET_ALREADY_EXISTS); } - $audits - ->setResource('storage/buckets/' . $bucket->getId()) - ->setPayload($bucket->getArrayCopy()) - ; + $events ->setParam('bucketId', $bucket->getId()) @@ -213,6 +210,7 @@ App::put('/v1/storage/buckets/:bucketId') ->desc('Update Bucket') ->groups(['api', 'storage']) ->label('scope', 'buckets.write') + ->label('audits.resource', 'storage/buckets/{$id}') ->label('event', 'buckets.[bucketId].update') ->label('sdk.auth', [APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'storage') @@ -233,10 +231,9 @@ App::put('/v1/storage/buckets/:bucketId') ->param('antivirus', true, new Boolean(true), 'Is virus scanning enabled? For file size above ' . Storage::human(APP_LIMIT_ANTIVIRUS, 0) . ' AntiVirus scanning is skipped even if it\'s enabled', true) ->inject('response') ->inject('dbForProject') - ->inject('audits') ->inject('usage') ->inject('events') - ->action(function (string $bucketId, string $name, string $permission, ?array $read, ?array $write, bool $enabled, ?int $maximumFileSize, array $allowedFileExtensions, bool $encryption, bool $antivirus, Response $response, Database $dbForProject, Audit $audits, Stats $usage, Event $events) { + ->action(function (string $bucketId, string $name, string $permission, ?array $read, ?array $write, bool $enabled, ?int $maximumFileSize, array $allowedFileExtensions, bool $encryption, bool $antivirus, Response $response, Database $dbForProject, Stats $usage, Event $events) { $bucket = $dbForProject->getDocument('buckets', $bucketId); if ($bucket->isEmpty()) { @@ -252,20 +249,15 @@ App::put('/v1/storage/buckets/:bucketId') $antivirus ??= $bucket->getAttribute('antivirus', true); $bucket = $dbForProject->updateDocument('buckets', $bucket->getId(), $bucket - ->setAttribute('name', $name) - ->setAttribute('$read', $read) - ->setAttribute('$write', $write) - ->setAttribute('maximumFileSize', $maximumFileSize) - ->setAttribute('allowedFileExtensions', $allowedFileExtensions) - ->setAttribute('enabled', (bool) filter_var($enabled, FILTER_VALIDATE_BOOLEAN)) - ->setAttribute('encryption', (bool) filter_var($encryption, FILTER_VALIDATE_BOOLEAN)) - ->setAttribute('permission', $permission) - ->setAttribute('antivirus', (bool) filter_var($antivirus, FILTER_VALIDATE_BOOLEAN))); - - $audits - ->setResource('storage/buckets/' . $bucket->getId()) - ->setPayload($bucket->getArrayCopy()) - ; + ->setAttribute('name', $name) + ->setAttribute('$read', $read) + ->setAttribute('$write', $write) + ->setAttribute('maximumFileSize', $maximumFileSize) + ->setAttribute('allowedFileExtensions', $allowedFileExtensions) + ->setAttribute('enabled', (bool) filter_var($enabled, FILTER_VALIDATE_BOOLEAN)) + ->setAttribute('encryption', (bool) filter_var($encryption, FILTER_VALIDATE_BOOLEAN)) + ->setAttribute('permission', $permission) + ->setAttribute('antivirus', (bool) filter_var($antivirus, FILTER_VALIDATE_BOOLEAN))); $events ->setParam('bucketId', $bucket->getId()) @@ -280,6 +272,7 @@ App::delete('/v1/storage/buckets/:bucketId') ->desc('Delete Bucket') ->groups(['api', 'storage']) ->label('scope', 'buckets.write') + ->label('audits.resource', 'storage/buckets/{$id}') ->label('event', 'buckets.[bucketId].delete') ->label('sdk.auth', [APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'storage') @@ -314,10 +307,7 @@ App::delete('/v1/storage/buckets/:bucketId') ->setPayload($response->output($bucket, Response::MODEL_BUCKET)) ; - $audits - ->setResource('storage/buckets/' . $bucket->getId()) - ->setPayload($bucket->getArrayCopy()) - ; + $audits->setPayload($bucket->getArrayCopy()); $usage->setParam('storage.buckets.delete', 1); @@ -329,6 +319,7 @@ App::post('/v1/storage/buckets/:bucketId/files') ->desc('Create File') ->groups(['api', 'storage']) ->label('scope', 'files.write') + ->label('audits.resource', 'storage/files/{$id}') ->label('event', 'buckets.[bucketId].files.[fileId].create') ->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_KEY, APP_AUTH_TYPE_JWT]) ->label('sdk.namespace', 'storage') @@ -348,13 +339,12 @@ App::post('/v1/storage/buckets/:bucketId/files') ->inject('response') ->inject('dbForProject') ->inject('user') - ->inject('audits') ->inject('usage') ->inject('events') ->inject('mode') ->inject('deviceFiles') ->inject('deviceLocal') - ->action(function (string $bucketId, string $fileId, mixed $file, ?array $read, ?array $write, Request $request, Response $response, Database $dbForProject, Document $user, Audit $audits, Stats $usage, Event $events, string $mode, Device $deviceFiles, Device $deviceLocal) { + ->action(function (string $bucketId, string $fileId, mixed $file, ?array $read, ?array $write, Request $request, Response $response, Database $dbForProject, Document $user, Stats $usage, Event $events, string $mode, Device $deviceFiles, Device $deviceLocal) { $bucket = Authorization::skip(fn () => $dbForProject->getDocument('buckets', $bucketId)); if ( @@ -440,8 +430,8 @@ App::post('/v1/storage/buckets/:bucketId/files') } /** - * Validators - */ + * Validators + */ // Check if file type is allowed $allowedFileExtensions = $bucket->getAttribute('allowedFileExtensions', []); $fileExt = new FileExt($allowedFileExtensions); @@ -594,10 +584,6 @@ App::post('/v1/storage/buckets/:bucketId/files') throw new Exception('Document already exists', 409, Exception::DOCUMENT_ALREADY_EXISTS); } - $audits - ->setResource('storage/files/' . $file->getId()) - ; - $usage ->setParam('storage', $sizeActual ?? 0) ->setParam('storage.files.create', 1) @@ -919,7 +905,7 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/preview') ->addHeader('Expires', $date) ->addHeader('X-Appwrite-Cache', 'hit') ->send($data) - ; + ; } $source = $deviceFiles->read($path); @@ -1278,6 +1264,7 @@ App::put('/v1/storage/buckets/:bucketId/files/:fileId') ->desc('Update File') ->groups(['api', 'storage']) ->label('scope', 'files.write') + ->label('audits.resource','storage/files/{$id}') ->label('event', 'buckets.[bucketId].files.[fileId].update') ->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_KEY, APP_AUTH_TYPE_JWT]) ->label('sdk.namespace', 'storage') @@ -1293,11 +1280,10 @@ App::put('/v1/storage/buckets/:bucketId/files/:fileId') ->inject('response') ->inject('dbForProject') ->inject('user') - ->inject('audits') ->inject('usage') ->inject('mode') ->inject('events') - ->action(function (string $bucketId, string $fileId, ?array $read, ?array $write, Response $response, Database $dbForProject, Document $user, Audit $audits, Stats $usage, string $mode, Event $events) { + ->action(function (string $bucketId, string $fileId, ?array $read, ?array $write, Response $response, Database $dbForProject, Document $user, Stats $usage, string $mode, Event $events) { $bucket = Authorization::skip(fn () => $dbForProject->getDocument('buckets', $bucketId)); $read = (is_null($read) && !$user->isEmpty()) ? ['user:' . $user->getId()] : $read ?? []; // By default set read permissions for user $write = (is_null($write) && !$user->isEmpty()) ? ['user:' . $user->getId()] : $write ?? []; @@ -1360,8 +1346,6 @@ App::put('/v1/storage/buckets/:bucketId/files/:fileId') ->setContext('bucket', $bucket) ; - $audits->setResource('file/' . $file->getId()); - $usage ->setParam('storage.files.update', 1) ->setParam('bucketId', $bucketId) @@ -1375,6 +1359,7 @@ App::delete('/v1/storage/buckets/:bucketId/files/:fileId') ->desc('Delete File') ->groups(['api', 'storage']) ->label('scope', 'files.write') + ->label('audits.resource','storage/files/{$id}') ->label('event', 'buckets.[bucketId].files.[fileId].delete') ->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_KEY, APP_AUTH_TYPE_JWT]) ->label('sdk.namespace', 'storage') @@ -1387,12 +1372,11 @@ App::delete('/v1/storage/buckets/:bucketId/files/:fileId') ->inject('response') ->inject('dbForProject') ->inject('events') - ->inject('audits') ->inject('usage') ->inject('mode') ->inject('deviceFiles') ->inject('project') - ->action(function (string $bucketId, string $fileId, Response $response, Database $dbForProject, Event $events, Audit $audits, Stats $usage, string $mode, Device $deviceFiles, Document $project) { + ->action(function (string $bucketId, string $fileId, Response $response, Database $dbForProject, Event $events, Stats $usage, string $mode, Device $deviceFiles, Document $project) { $bucket = Authorization::skip(fn () => $dbForProject->getDocument('buckets', $bucketId)); if ( @@ -1448,8 +1432,6 @@ App::delete('/v1/storage/buckets/:bucketId/files/:fileId') throw new Exception('Failed to delete file from device', 500, Exception::GENERAL_SERVER_ERROR); } - $audits->setResource('file/' . $file->getId()); - $usage ->setParam('storage', $file->getAttribute('size', 0) * -1) ->setParam('storage.files.delete', 1) diff --git a/app/controllers/shared/api.php b/app/controllers/shared/api.php index 2d27209562..5d4897fd72 100644 --- a/app/controllers/shared/api.php +++ b/app/controllers/shared/api.php @@ -86,7 +86,7 @@ App::init() if ( (App::getEnv('_APP_OPTIONS_ABUSE', 'enabled') !== 'disabled' // Route is rate-limited - && $abuse->check()) // Abuse is not disabled + && $abuse->check()) // Abuse is not disabled && (!$isAppUser && !$isPrivilegedUser) ) { // User is not an admin or API key throw new Exception('Too many requests', 429, Exception::GENERAL_RATE_LIMIT_EXCEEDED); @@ -232,7 +232,7 @@ App::shutdown() $bucket = $events->getContext('bucket'); $target = Realtime::fromPayload( - // Pass first, most verbose event pattern + // Pass first, most verbose event pattern event: $allEvents[0], payload: $payload, project: $project, @@ -255,7 +255,22 @@ App::shutdown() } } - if (!empty($audits->getResource())) { + + $parseLabel = function ($params, $label) { + preg_match_all('/{(.*?)}/', $label, $matches); + if(array_key_exists($matches[1][0], $params)){ + return \str_replace($matches[0][0], $params[$matches[1][0]], $label); + } + }; + + $route = $utopia->match($request); + + $resource = $route->getLabel('audits.resource',''); + if(!empty($resource)) { + $audits->setParam('resource', $parseLabel( + $response->getPayload(), $resource) + ); + foreach ($events->getParams() as $key => $value) { $audits->setParam($key, $value); } @@ -270,7 +285,7 @@ App::shutdown() $database->trigger(); } - $route = $utopia->match($request); + if ( App::getEnv('_APP_USAGE_STATS', 'enabled') == 'enabled' && $project->getId() From c8196c41d4e6b0193a0ea08249a73d3d5ff5e25c Mon Sep 17 00:00:00 2001 From: shimon Date: Sun, 7 Aug 2022 18:09:37 +0300 Subject: [PATCH 02/46] api::payload --- app/controllers/api/storage.php | 12 ++++++------ app/controllers/shared/api.php | 8 +++++--- 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/app/controllers/api/storage.php b/app/controllers/api/storage.php index 202599fea9..2af973ae16 100644 --- a/app/controllers/api/storage.php +++ b/app/controllers/api/storage.php @@ -45,8 +45,8 @@ App::post('/v1/storage/buckets') ->desc('Create bucket') ->groups(['api', 'storage']) ->label('scope', 'buckets.write') - ->label('audits.resource', 'storage/buckets/{$id}') ->label('event', 'buckets.[bucketId].create') + ->label('audits.resource', 'storage/buckets/{$id}') ->label('sdk.auth', [APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'storage') ->label('sdk.method', 'createBucket') @@ -210,8 +210,8 @@ App::put('/v1/storage/buckets/:bucketId') ->desc('Update Bucket') ->groups(['api', 'storage']) ->label('scope', 'buckets.write') - ->label('audits.resource', 'storage/buckets/{$id}') ->label('event', 'buckets.[bucketId].update') + ->label('audits.resource', 'storage/buckets/{$id}') ->label('sdk.auth', [APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'storage') ->label('sdk.method', 'updateBucket') @@ -272,8 +272,8 @@ App::delete('/v1/storage/buckets/:bucketId') ->desc('Delete Bucket') ->groups(['api', 'storage']) ->label('scope', 'buckets.write') - ->label('audits.resource', 'storage/buckets/{$id}') ->label('event', 'buckets.[bucketId].delete') + ->label('audits.resource', 'storage/buckets/{$id}') ->label('sdk.auth', [APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'storage') ->label('sdk.method', 'deleteBucket') @@ -319,8 +319,8 @@ App::post('/v1/storage/buckets/:bucketId/files') ->desc('Create File') ->groups(['api', 'storage']) ->label('scope', 'files.write') - ->label('audits.resource', 'storage/files/{$id}') ->label('event', 'buckets.[bucketId].files.[fileId].create') + ->label('audits.resource', 'storage/files/{$id}') ->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_KEY, APP_AUTH_TYPE_JWT]) ->label('sdk.namespace', 'storage') ->label('sdk.method', 'createFile') @@ -1264,8 +1264,8 @@ App::put('/v1/storage/buckets/:bucketId/files/:fileId') ->desc('Update File') ->groups(['api', 'storage']) ->label('scope', 'files.write') - ->label('audits.resource','storage/files/{$id}') ->label('event', 'buckets.[bucketId].files.[fileId].update') + ->label('audits.resource', 'storage/files/{$id}') ->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_KEY, APP_AUTH_TYPE_JWT]) ->label('sdk.namespace', 'storage') ->label('sdk.method', 'updateFile') @@ -1359,8 +1359,8 @@ App::delete('/v1/storage/buckets/:bucketId/files/:fileId') ->desc('Delete File') ->groups(['api', 'storage']) ->label('scope', 'files.write') - ->label('audits.resource','storage/files/{$id}') ->label('event', 'buckets.[bucketId].files.[fileId].delete') + ->label('audits.resource', 'storage/files/{$id}') ->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_KEY, APP_AUTH_TYPE_JWT]) ->label('sdk.namespace', 'storage') ->label('sdk.method', 'deleteFile') diff --git a/app/controllers/shared/api.php b/app/controllers/shared/api.php index 5d4897fd72..619b98afd0 100644 --- a/app/controllers/shared/api.php +++ b/app/controllers/shared/api.php @@ -200,9 +200,11 @@ App::shutdown() ->inject('dbForProject') ->action(function (App $utopia, Request $request, Response $response, Document $project, Event $events, Audit $audits, Stats $usage, Delete $deletes, EventDatabase $database, string $mode, Database $dbForProject) { + $responsePayload = $response->getPayload(); + if (!empty($events->getEvent())) { - if (empty($events->getPayload())) { - $events->setPayload($response->getPayload()); + if (empty($events->getPayload())){ + $events->setPayload($responsePayload); } /** * Trigger functions. @@ -268,7 +270,7 @@ App::shutdown() $resource = $route->getLabel('audits.resource',''); if(!empty($resource)) { $audits->setParam('resource', $parseLabel( - $response->getPayload(), $resource) + $responsePayload, $resource) ); foreach ($events->getParams() as $key => $value) { From e9ef94e8afe386842b1e5c3678552810810fe93e Mon Sep 17 00:00:00 2001 From: shimon Date: Sun, 7 Aug 2022 18:49:30 +0300 Subject: [PATCH 03/46] account controller --- app/controllers/api/account.php | 147 +++++++++----------------------- app/controllers/shared/api.php | 15 ++-- 2 files changed, 49 insertions(+), 113 deletions(-) diff --git a/app/controllers/api/account.php b/app/controllers/api/account.php index 6c90441afb..28f23aaad8 100644 --- a/app/controllers/api/account.php +++ b/app/controllers/api/account.php @@ -47,6 +47,7 @@ App::post('/v1/account') ->label('event', 'users.[userId].create') ->label('scope', 'public') ->label('auth.type', 'emailPassword') + ->label('audits.resource', 'user/{$id}') ->label('sdk.auth', []) ->label('sdk.namespace', 'account') ->label('sdk.method', 'create') @@ -63,10 +64,9 @@ App::post('/v1/account') ->inject('response') ->inject('project') ->inject('dbForProject') - ->inject('audits') ->inject('usage') ->inject('events') - ->action(function (string $userId, string $email, string $password, string $name, Request $request, Response $response, Document $project, Database $dbForProject, Audit $audits, Stats $usage, Event $events) { + ->action(function (string $userId, string $email, string $password, string $name, Request $request, Response $response, Document $project, Database $dbForProject, Stats $usage, Event $events) { $email = \strtolower($email); if ('console' === $project->getId()) { @@ -120,11 +120,6 @@ App::post('/v1/account') Authorization::setRole('user:' . $user->getId()); Authorization::setRole('role:' . Auth::USER_ROLE_MEMBER); - $audits - ->setResource('user/' . $user->getId()) - ->setUser($user) - ; - $usage->setParam('users.create', 1); $events->setParam('userId', $user->getId()); @@ -359,6 +354,7 @@ App::get('/v1/account/sessions/oauth2/:provider/redirect') ->label('abuse-limit', 50) ->label('abuse-key', 'ip:{ip}') ->label('docs', false) + ->label('audits.resource', 'user/{$id}') ->param('provider', '', new WhiteList(\array_keys(Config::getParam('providers')), true), 'OAuth2 provider.') ->param('code', '', new Text(2048), 'OAuth2 code.') ->param('state', '', new Text(2048), 'OAuth2 state params.', true) @@ -368,10 +364,9 @@ App::get('/v1/account/sessions/oauth2/:provider/redirect') ->inject('user') ->inject('dbForProject') ->inject('geodb') - ->inject('audits') ->inject('events') ->inject('usage') - ->action(function (string $provider, string $code, string $state, Request $request, Response $response, Document $project, Document $user, Database $dbForProject, Reader $geodb, Audit $audits, Event $events, Stats $usage) use ($oauthDefaultSuccess) { + ->action(function (string $provider, string $code, string $state, Request $request, Response $response, Document $project, Document $user, Database $dbForProject, Reader $geodb, Event $events, Stats $usage) use ($oauthDefaultSuccess) { $protocol = $request->getProtocol(); $callback = $protocol . '://' . $request->getHostname() . '/v1/account/sessions/oauth2/callback/' . $provider . '/' . $project->getId(); @@ -548,11 +543,6 @@ App::get('/v1/account/sessions/oauth2/:provider/redirect') $dbForProject->deleteCachedDocument('users', $user->getId()); - $audits - ->setResource('user/' . $user->getId()) - ->setUser($user) - ; - $usage ->setParam('users.sessions.create', 1) ->setParam('projectId', $project->getId()) @@ -596,6 +586,7 @@ App::post('/v1/account/sessions/magic-url') ->groups(['api', 'account']) ->label('scope', 'public') ->label('auth.type', 'magic-url') + ->label('audits.resource', 'user/{$id}') ->label('sdk.auth', []) ->label('sdk.namespace', 'account') ->label('sdk.method', 'createMagicURLSession') @@ -613,10 +604,9 @@ App::post('/v1/account/sessions/magic-url') ->inject('project') ->inject('dbForProject') ->inject('locale') - ->inject('audits') ->inject('events') ->inject('mails') - ->action(function (string $userId, string $email, string $url, Request $request, Response $response, Document $project, Database $dbForProject, Locale $locale, Audit $audits, Event $events, Mail $mails) { + ->action(function (string $userId, string $email, string $url, Request $request, Response $response, Document $project, Database $dbForProject, Locale $locale, Event $events, Mail $mails) { if (empty(App::getEnv('_APP_SMTP_HOST'))) { throw new Exception('SMTP Disabled', 503, Exception::GENERAL_SMTP_DISABLED); @@ -709,11 +699,6 @@ App::post('/v1/account/sessions/magic-url') // Hide secret for clients $token->setAttribute('secret', ($isPrivilegedUser || $isAppUser) ? $loginSecret : ''); - $audits - ->setResource('user/' . $user->getId()) - ->setUser($user) - ; - $response ->setStatusCode(Response::STATUS_CODE_CREATED) ->dynamic($token, Response::MODEL_TOKEN) @@ -725,6 +710,7 @@ App::put('/v1/account/sessions/magic-url') ->groups(['api', 'account']) ->label('scope', 'public') ->label('event', 'users.[userId].sessions.[sessionId].create') + ->label('audits.resource', 'user/{$id}') ->label('sdk.auth', []) ->label('sdk.namespace', 'account') ->label('sdk.method', 'updateMagicURLSession') @@ -741,9 +727,8 @@ App::put('/v1/account/sessions/magic-url') ->inject('dbForProject') ->inject('locale') ->inject('geodb') - ->inject('audits') ->inject('events') - ->action(function (string $userId, string $secret, Request $request, Response $response, Database $dbForProject, Locale $locale, Reader $geodb, Audit $audits, Event $events) { + ->action(function (string $userId, string $secret, Request $request, Response $response, Database $dbForProject, Locale $locale, Reader $geodb, Event $events) { /** @var Utopia\Database\Document $user */ @@ -805,8 +790,6 @@ App::put('/v1/account/sessions/magic-url') throw new Exception('Failed saving user to DB', 500, Exception::GENERAL_SERVER_ERROR); } - $audits->setResource('user/' . $user->getId()); - $events ->setParam('userId', $user->getId()) ->setParam('sessionId', $session->getId()) @@ -854,11 +837,10 @@ App::post('/v1/account/sessions/phone') ->inject('response') ->inject('project') ->inject('dbForProject') - ->inject('audits') ->inject('events') ->inject('messaging') ->inject('phone') - ->action(function (string $userId, string $number, Request $request, Response $response, Document $project, Database $dbForProject, Audit $audits, Event $events, EventPhone $messaging, Phone $phone) { + ->action(function (string $userId, string $number, Request $request, Response $response, Document $project, Database $dbForProject, Event $events, EventPhone $messaging, Phone $phone) { if (empty(App::getEnv('_APP_PHONE_PROVIDER'))) { throw new Exception('Phone provider not configured', 503, Exception::GENERAL_PHONE_DISABLED); } @@ -941,11 +923,6 @@ App::post('/v1/account/sessions/phone') // Hide secret for clients $token->setAttribute('secret', ($isPrivilegedUser || $isAppUser) ? $secret : ''); - $audits - ->setResource('user/' . $user->getId()) - ->setUser($user) - ; - $response ->setStatusCode(Response::STATUS_CODE_CREATED) ->dynamic($token, Response::MODEL_TOKEN) @@ -973,9 +950,8 @@ App::put('/v1/account/sessions/phone') ->inject('dbForProject') ->inject('locale') ->inject('geodb') - ->inject('audits') ->inject('events') - ->action(function (string $userId, string $secret, Request $request, Response $response, Database $dbForProject, Locale $locale, Reader $geodb, Audit $audits, Event $events) { + ->action(function (string $userId, string $secret, Request $request, Response $response, Database $dbForProject, Locale $locale, Reader $geodb, Event $events) { $user = Authorization::skip(fn() => $dbForProject->getDocument('users', $userId)); @@ -1033,8 +1009,6 @@ App::put('/v1/account/sessions/phone') throw new Exception('Failed saving user to DB', 500, Exception::GENERAL_SERVER_ERROR); } - $audits->setResource('user/' . $user->getId()); - $events ->setParam('userId', $user->getId()) ->setParam('sessionId', $session->getId()) @@ -1084,10 +1058,9 @@ App::post('/v1/account/sessions/anonymous') ->inject('project') ->inject('dbForProject') ->inject('geodb') - ->inject('audits') ->inject('usage') ->inject('events') - ->action(function (Request $request, Response $response, Locale $locale, Document $user, Document $project, Database $dbForProject, Reader $geodb, Audit $audits, Stats $usage, Event $events) { + ->action(function (Request $request, Response $response, Locale $locale, Document $user, Document $project, Database $dbForProject, Reader $geodb, Stats $usage, Event $events) { $protocol = $request->getProtocol(); @@ -1160,8 +1133,6 @@ App::post('/v1/account/sessions/anonymous') $dbForProject->deleteCachedDocument('users', $user->getId()); - $audits->setResource('user/' . $user->getId()); - $usage ->setParam('users.sessions.create', 1) ->setParam('provider', 'anonymous') @@ -1425,6 +1396,7 @@ App::patch('/v1/account/name') ->groups(['api', 'account']) ->label('event', 'users.[userId].update.name') ->label('scope', 'account') + ->label('audits.resource', 'user/{$id}') ->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_JWT]) ->label('sdk.namespace', 'account') ->label('sdk.method', 'updateName') @@ -1436,20 +1408,14 @@ App::patch('/v1/account/name') ->inject('response') ->inject('user') ->inject('dbForProject') - ->inject('audits') ->inject('usage') ->inject('events') - ->action(function (string $name, Response $response, Document $user, Database $dbForProject, Audit $audits, Stats $usage, Event $events) { + ->action(function (string $name, Response $response, Document $user, Database $dbForProject, Stats $usage, Event $events) { $user = $dbForProject->updateDocument('users', $user->getId(), $user ->setAttribute('name', $name) ->setAttribute('search', implode(' ', [$user->getId(), $name, $user->getAttribute('email')]))); - $audits - ->setResource('user/' . $user->getId()) - ->setUser($user) - ; - $usage->setParam('users.update', 1); $events->setParam('userId', $user->getId()); @@ -1473,10 +1439,9 @@ App::patch('/v1/account/password') ->inject('response') ->inject('user') ->inject('dbForProject') - ->inject('audits') ->inject('usage') ->inject('events') - ->action(function (string $password, string $oldPassword, Response $response, Document $user, Database $dbForProject, Audit $audits, Stats $usage, Event $events) { + ->action(function (string $password, string $oldPassword, Response $response, Document $user, Database $dbForProject, Stats $usage, Event $events) { // Check old password only if its an existing user. if ($user->getAttribute('passwordUpdate') !== 0 && !Auth::passwordVerify($oldPassword, $user->getAttribute('password'))) { // Double check user password @@ -1491,11 +1456,6 @@ App::patch('/v1/account/password') ->setAttribute('passwordUpdate', \time()) ); - $audits - ->setResource('user/' . $user->getId()) - ->setUser($user) - ; - $usage->setParam('users.update', 1); $events->setParam('userId', $user->getId()); @@ -1507,6 +1467,7 @@ App::patch('/v1/account/email') ->groups(['api', 'account']) ->label('event', 'users.[userId].update.email') ->label('scope', 'account') + ->label('audits.resource', 'user/{$id}') ->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_JWT]) ->label('sdk.namespace', 'account') ->label('sdk.method', 'updateEmail') @@ -1519,10 +1480,9 @@ App::patch('/v1/account/email') ->inject('response') ->inject('user') ->inject('dbForProject') - ->inject('audits') ->inject('usage') ->inject('events') - ->action(function (string $email, string $password, Response $response, Document $user, Database $dbForProject, Audit $audits, Stats $usage, Event $events) { + ->action(function (string $email, string $password, Response $response, Document $user, Database $dbForProject, Stats $usage, Event $events) { $isAnonymousUser = Auth::isAnonymousUser($user); // Check if request is from an anonymous account for converting @@ -1547,11 +1507,6 @@ App::patch('/v1/account/email') throw new Exception('Email already exists', 409, Exception::USER_EMAIL_ALREADY_EXISTS); } - $audits - ->setResource('user/' . $user->getId()) - ->setUser($user) - ; - $usage->setParam('users.update', 1); $events->setParam('userId', $user->getId()); @@ -1563,6 +1518,7 @@ App::patch('/v1/account/phone') ->groups(['api', 'account']) ->label('event', 'users.[userId].update.phone') ->label('scope', 'account') + ->label('audits.resource', 'user/{$id}') ->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_JWT]) ->label('sdk.namespace', 'account') ->label('sdk.method', 'updatePhone') @@ -1575,10 +1531,9 @@ App::patch('/v1/account/phone') ->inject('response') ->inject('user') ->inject('dbForProject') - ->inject('audits') ->inject('usage') ->inject('events') - ->action(function (string $phone, string $password, Response $response, Document $user, Database $dbForProject, Audit $audits, Stats $usage, Event $events) { + ->action(function (string $phone, string $password, Response $response, Document $user, Database $dbForProject, Stats $usage, Event $events) { $isAnonymousUser = Auth::isAnonymousUser($user); // Check if request is from an anonymous account for converting @@ -1600,11 +1555,6 @@ App::patch('/v1/account/phone') throw new Exception('Phone number already exists', 409, Exception::USER_PHONE_ALREADY_EXISTS); } - $audits - ->setResource('user/' . $user->getId()) - ->setUser($user) - ; - $usage->setParam('users.update', 1); $events->setParam('userId', $user->getId()); @@ -1616,6 +1566,7 @@ App::patch('/v1/account/prefs') ->groups(['api', 'account']) ->label('event', 'users.[userId].update.prefs') ->label('scope', 'account') + ->label('audits.resource', 'user/{$id}') ->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_JWT]) ->label('sdk.namespace', 'account') ->label('sdk.method', 'updatePrefs') @@ -1627,14 +1578,12 @@ App::patch('/v1/account/prefs') ->inject('response') ->inject('user') ->inject('dbForProject') - ->inject('audits') ->inject('usage') ->inject('events') - ->action(function (array $prefs, Response $response, Document $user, Database $dbForProject, Audit $audits, Stats $usage, Event $events) { + ->action(function (array $prefs, Response $response, Document $user, Database $dbForProject, Stats $usage, Event $events) { $user = $dbForProject->updateDocument('users', $user->getId(), $user->setAttribute('prefs', $prefs)); - $audits->setResource('user/' . $user->getId()); $usage->setParam('users.update', 1); $events->setParam('userId', $user->getId()); @@ -1646,6 +1595,7 @@ App::patch('/v1/account/status') ->groups(['api', 'account']) ->label('event', 'users.[userId].update.status') ->label('scope', 'account') + ->label('audits.resource', 'user/{$id}') ->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_JWT]) ->label('sdk.namespace', 'account') ->label('sdk.method', 'updateStatus') @@ -1664,9 +1614,7 @@ App::patch('/v1/account/status') $user = $dbForProject->updateDocument('users', $user->getId(), $user->setAttribute('status', false)); - $audits - ->setResource('user/' . $user->getId()) - ->setPayload($response->output($user, Response::MODEL_USER)); + $audits->setPayload($response->output($user, Response::MODEL_USER)); // TODO is this a mistake? $events ->setParam('userId', $user->getId()) @@ -1686,6 +1634,7 @@ App::delete('/v1/account/sessions/:sessionId') ->groups(['api', 'account']) ->label('scope', 'account') ->label('event', 'users.[userId].sessions.[sessionId].delete') + ->label('audits.resource', 'user/{$id}') ->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_JWT]) ->label('sdk.namespace', 'account') ->label('sdk.method', 'deleteSession') @@ -1699,10 +1648,9 @@ App::delete('/v1/account/sessions/:sessionId') ->inject('user') ->inject('dbForProject') ->inject('locale') - ->inject('audits') ->inject('events') ->inject('usage') - ->action(function (?string $sessionId, Request $request, Response $response, Document $user, Database $dbForProject, Locale $locale, Audit $audits, Event $events, Stats $usage) { + ->action(function (?string $sessionId, Request $request, Response $response, Document $user, Database $dbForProject, Locale $locale, Event $events, Stats $usage) { $protocol = $request->getProtocol(); $sessionId = ($sessionId === 'current') @@ -1717,8 +1665,6 @@ App::delete('/v1/account/sessions/:sessionId') $dbForProject->deleteDocument('sessions', $session->getId()); - $audits->setResource('user/' . $user->getId()); - $session->setAttribute('current', false); if ($session->getAttribute('secret') == Auth::hash(Auth::$secret)) { // If current session delete the cookies too @@ -1763,6 +1709,7 @@ App::patch('/v1/account/sessions/:sessionId') ->groups(['api', 'account']) ->label('scope', 'account') ->label('event', 'users.[userId].sessions.[sessionId].update') + ->label('audits.resource', 'user/{$id}') ->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_JWT]) ->label('sdk.namespace', 'account') ->label('sdk.method', 'updateSession') @@ -1778,10 +1725,9 @@ App::patch('/v1/account/sessions/:sessionId') ->inject('dbForProject') ->inject('project') ->inject('locale') - ->inject('audits') ->inject('events') ->inject('usage') - ->action(function (?string $sessionId, Request $request, Response $response, Document $user, Database $dbForProject, Document $project, Locale $locale, Audit $audits, Event $events, Stats $usage) { + ->action(function (?string $sessionId, Request $request, Response $response, Document $user, Database $dbForProject, Document $project, Locale $locale, Event $events, Stats $usage) { $sessionId = ($sessionId === 'current') ? Auth::sessionVerify($user->getAttribute('sessions'), Auth::$secret) @@ -1825,8 +1771,6 @@ App::patch('/v1/account/sessions/:sessionId') $dbForProject->deleteCachedDocument('users', $user->getId()); - $audits->setResource('user/' . $user->getId()); - $events ->setParam('userId', $user->getId()) ->setParam('sessionId', $session->getId()) @@ -1850,6 +1794,7 @@ App::delete('/v1/account/sessions') ->groups(['api', 'account']) ->label('scope', 'account') ->label('event', 'users.[userId].sessions.[sessionId].delete') + ->label('audits.resource', 'user/{$id}') ->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_JWT]) ->label('sdk.namespace', 'account') ->label('sdk.method', 'deleteSessions') @@ -1862,10 +1807,9 @@ App::delete('/v1/account/sessions') ->inject('user') ->inject('dbForProject') ->inject('locale') - ->inject('audits') ->inject('events') ->inject('usage') - ->action(function (Request $request, Response $response, Document $user, Database $dbForProject, Locale $locale, Audit $audits, Event $events, Stats $usage) { + ->action(function (Request $request, Response $response, Document $user, Database $dbForProject, Locale $locale, Event $events, Stats $usage) { $protocol = $request->getProtocol(); $sessions = $user->getAttribute('sessions', []); @@ -1873,8 +1817,6 @@ App::delete('/v1/account/sessions') foreach ($sessions as $session) {/** @var Document $session */ $dbForProject->deleteDocument('sessions', $session->getId()); - $audits->setResource('user/' . $user->getId()); - if (!Config::getParam('domainVerification')) { $response->addHeader('X-Fallback-Cookies', \json_encode([])); } @@ -1918,6 +1860,7 @@ App::post('/v1/account/recovery') ->groups(['api', 'account']) ->label('scope', 'public') ->label('event', 'users.[userId].recovery.[tokenId].create') + ->label('audits.resource', 'user/{$id}') ->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_JWT]) ->label('sdk.namespace', 'account') ->label('sdk.method', 'createRecovery') @@ -1935,10 +1878,9 @@ App::post('/v1/account/recovery') ->inject('project') ->inject('locale') ->inject('mails') - ->inject('audits') ->inject('events') ->inject('usage') - ->action(function (string $email, string $url, Request $request, Response $response, Database $dbForProject, Document $project, Locale $locale, Mail $mails, Audit $audits, Event $events, Stats $usage) { + ->action(function (string $email, string $url, Request $request, Response $response, Database $dbForProject, Document $project, Locale $locale, Mail $mails, Event $events, Stats $usage) { if (empty(App::getEnv('_APP_SMTP_HOST'))) { throw new Exception('SMTP Disabled', 503, Exception::GENERAL_SMTP_DISABLED); @@ -2010,7 +1952,6 @@ App::post('/v1/account/recovery') // Hide secret for clients $recovery->setAttribute('secret', ($isPrivilegedUser || $isAppUser) ? $secret : ''); - $audits->setResource('user/' . $profile->getId()); $usage->setParam('users.update', 1); $response->setStatusCode(Response::STATUS_CODE_CREATED); @@ -2022,6 +1963,7 @@ App::put('/v1/account/recovery') ->groups(['api', 'account']) ->label('scope', 'public') ->label('event', 'users.[userId].recovery.[tokenId].update') + ->label('audits.resource', 'user/{$id}') ->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_JWT]) ->label('sdk.namespace', 'account') ->label('sdk.method', 'updateRecovery') @@ -2037,10 +1979,9 @@ App::put('/v1/account/recovery') ->param('passwordAgain', '', new Password(), 'Repeat new user password. Must be at least 8 chars.') ->inject('response') ->inject('dbForProject') - ->inject('audits') ->inject('usage') ->inject('events') - ->action(function (string $userId, string $secret, string $password, string $passwordAgain, Response $response, Database $dbForProject, Audit $audits, Stats $usage, Event $events) { + ->action(function (string $userId, string $secret, string $password, string $passwordAgain, Response $response, Database $dbForProject, Stats $usage, Event $events) { if ($password !== $passwordAgain) { throw new Exception('Passwords must match', 400, Exception::USER_PASSWORD_MISMATCH); @@ -2075,8 +2016,6 @@ App::put('/v1/account/recovery') $dbForProject->deleteDocument('tokens', $recovery); $dbForProject->deleteCachedDocument('users', $profile->getId()); - $audits->setResource('user/' . $profile->getId()); - $usage->setParam('users.update', 1); $events @@ -2092,6 +2031,7 @@ App::post('/v1/account/verification') ->groups(['api', 'account']) ->label('scope', 'account') ->label('event', 'users.[userId].verification.[tokenId].create') + ->label('audits.resource', 'user/{$id}') ->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_JWT]) ->label('sdk.namespace', 'account') ->label('sdk.method', 'createVerification') @@ -2108,11 +2048,10 @@ App::post('/v1/account/verification') ->inject('user') ->inject('dbForProject') ->inject('locale') - ->inject('audits') ->inject('events') ->inject('mails') ->inject('usage') - ->action(function (string $url, Request $request, Response $response, Document $project, Document $user, Database $dbForProject, Locale $locale, Audit $audits, Event $events, Mail $mails, Stats $usage) { + ->action(function (string $url, Request $request, Response $response, Document $project, Document $user, Database $dbForProject, Locale $locale, Event $events, Mail $mails, Stats $usage) { if (empty(App::getEnv('_APP_SMTP_HOST'))) { throw new Exception('SMTP Disabled', 503, Exception::GENERAL_SMTP_DISABLED); @@ -2170,7 +2109,6 @@ App::post('/v1/account/verification') // Hide secret for clients $verification->setAttribute('secret', ($isPrivilegedUser || $isAppUser) ? $verificationSecret : ''); - $audits->setResource('user/' . $user->getId()); $usage->setParam('users.update', 1); $response->setStatusCode(Response::STATUS_CODE_CREATED); @@ -2182,6 +2120,7 @@ App::put('/v1/account/verification') ->groups(['api', 'account']) ->label('scope', 'public') ->label('event', 'users.[userId].verification.[tokenId].update') + ->label('audits.resource', 'user/{$id}') ->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_JWT]) ->label('sdk.namespace', 'account') ->label('sdk.method', 'updateVerification') @@ -2196,10 +2135,9 @@ App::put('/v1/account/verification') ->inject('response') ->inject('user') ->inject('dbForProject') - ->inject('audits') ->inject('usage') ->inject('events') - ->action(function (string $userId, string $secret, Response $response, Document $user, Database $dbForProject, Audit $audits, Stats $usage, Event $events) { + ->action(function (string $userId, string $secret, Response $response, Document $user, Database $dbForProject, Stats $usage, Event $events) { $profile = Authorization::skip(fn() => $dbForProject->getDocument('users', $userId)); @@ -2227,8 +2165,6 @@ App::put('/v1/account/verification') $dbForProject->deleteDocument('tokens', $verification); $dbForProject->deleteCachedDocument('users', $profile->getId()); - $audits->setResource('user/' . $user->getId()); - $usage->setParam('users.update', 1); $events @@ -2244,6 +2180,7 @@ App::post('/v1/account/verification/phone') ->groups(['api', 'account']) ->label('scope', 'account') ->label('event', 'users.[userId].verification.[tokenId].create') + ->label('audits.resource', 'user/{$id}') ->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_JWT]) ->label('sdk.namespace', 'account') ->label('sdk.method', 'createPhoneVerification') @@ -2258,11 +2195,10 @@ App::post('/v1/account/verification/phone') ->inject('phone') ->inject('user') ->inject('dbForProject') - ->inject('audits') ->inject('events') ->inject('usage') ->inject('messaging') - ->action(function (Request $request, Response $response, Phone $phone, Document $user, Database $dbForProject, Audit $audits, Event $events, Stats $usage, EventPhone $messaging) { + ->action(function (Request $request, Response $response, Phone $phone, Document $user, Database $dbForProject, Event $events, Stats $usage, EventPhone $messaging) { if (empty(App::getEnv('_APP_PHONE_PROVIDER'))) { throw new Exception('Phone provider not configured', 503, Exception::GENERAL_PHONE_DISABLED); @@ -2318,7 +2254,6 @@ App::post('/v1/account/verification/phone') // Hide secret for clients $verification->setAttribute('secret', ($isPrivilegedUser || $isAppUser) ? $verificationSecret : ''); - $audits->setResource('user/' . $user->getId()); $usage->setParam('users.update', 1); $response->setStatusCode(Response::STATUS_CODE_CREATED); @@ -2330,6 +2265,7 @@ App::put('/v1/account/verification/phone') ->groups(['api', 'account']) ->label('scope', 'public') ->label('event', 'users.[userId].verification.[tokenId].update') + ->label('audits.resource', 'user/{$id}') ->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_JWT]) ->label('sdk.namespace', 'account') ->label('sdk.method', 'updatePhoneVerification') @@ -2344,10 +2280,9 @@ App::put('/v1/account/verification/phone') ->inject('response') ->inject('user') ->inject('dbForProject') - ->inject('audits') ->inject('usage') ->inject('events') - ->action(function (string $userId, string $secret, Response $response, Document $user, Database $dbForProject, Audit $audits, Stats $usage, Event $events) { + ->action(function (string $userId, string $secret, Response $response, Document $user, Database $dbForProject, Stats $usage, Event $events) { $profile = Authorization::skip(fn() => $dbForProject->getDocument('users', $userId)); @@ -2373,8 +2308,6 @@ App::put('/v1/account/verification/phone') $dbForProject->deleteDocument('tokens', $verification); $dbForProject->deleteCachedDocument('users', $profile->getId()); - $audits->setResource('user/' . $user->getId()); - $usage->setParam('users.update', 1); $events diff --git a/app/controllers/shared/api.php b/app/controllers/shared/api.php index 619b98afd0..3b7f565460 100644 --- a/app/controllers/shared/api.php +++ b/app/controllers/shared/api.php @@ -257,7 +257,6 @@ App::shutdown() } } - $parseLabel = function ($params, $label) { preg_match_all('/{(.*?)}/', $label, $matches); if(array_key_exists($matches[1][0], $params)){ @@ -267,15 +266,19 @@ App::shutdown() $route = $utopia->match($request); - $resource = $route->getLabel('audits.resource',''); - if(!empty($resource)) { - $audits->setParam('resource', $parseLabel( - $responsePayload, $resource) - ); + $auditsResource = $route->getLabel('audits.resource',''); + if(!empty($auditsResource)) { + $resource = $parseLabel($responsePayload, $auditsResource); + if(!empty($resource)){ + $audits->setResource($resource); + } + } + if (!empty($audits->getResource())) { foreach ($events->getParams() as $key => $value) { $audits->setParam($key, $value); } + $audits->trigger(); } From a6a9ad8cc0e8484451e4d5c10c829018e6a074cf Mon Sep 17 00:00:00 2001 From: shimon Date: Mon, 8 Aug 2022 11:14:27 +0300 Subject: [PATCH 04/46] databases controller --- app/controllers/api/account.php | 19 +++-- app/controllers/api/databases.php | 133 ++++++++++++------------------ app/controllers/api/storage.php | 16 ++-- app/controllers/shared/api.php | 18 +++- 4 files changed, 92 insertions(+), 94 deletions(-) diff --git a/app/controllers/api/account.php b/app/controllers/api/account.php index 28f23aaad8..0e65a29762 100644 --- a/app/controllers/api/account.php +++ b/app/controllers/api/account.php @@ -822,6 +822,7 @@ App::post('/v1/account/sessions/phone') ->groups(['api', 'account']) ->label('scope', 'public') ->label('auth.type', 'phone') + ->label('audits.resource', 'user/{$id}') ->label('sdk.auth', []) ->label('sdk.namespace', 'account') ->label('sdk.method', 'createPhoneSession') @@ -934,6 +935,7 @@ App::put('/v1/account/sessions/phone') ->groups(['api', 'account']) ->label('scope', 'public') ->label('event', 'users.[userId].sessions.[sessionId].create') + ->label('audits.resource', 'user/{$id}') ->label('sdk.auth', []) ->label('sdk.namespace', 'account') ->label('sdk.method', 'updatePhoneSession') @@ -1042,6 +1044,7 @@ App::post('/v1/account/sessions/anonymous') ->label('event', 'users.[userId].sessions.[sessionId].create') ->label('scope', 'public') ->label('auth.type', 'anonymous') + ->label('audits.resource', 'user/{$id}') ->label('sdk.auth', []) ->label('sdk.namespace', 'account') ->label('sdk.method', 'createAnonymousSession') @@ -1427,6 +1430,7 @@ App::patch('/v1/account/password') ->groups(['api', 'account']) ->label('event', 'users.[userId].update.password') ->label('scope', 'account') + ->label('audits.resource', 'user/{$id}') ->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_JWT]) ->label('sdk.namespace', 'account') ->label('sdk.method', 'updatePassword') @@ -1596,6 +1600,7 @@ App::patch('/v1/account/status') ->label('event', 'users.[userId].update.status') ->label('scope', 'account') ->label('audits.resource', 'user/{$id}') + ->label('audits.payload', '*') ->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_JWT]) ->label('sdk.namespace', 'account') ->label('sdk.method', 'updateStatus') @@ -1614,8 +1619,6 @@ App::patch('/v1/account/status') $user = $dbForProject->updateDocument('users', $user->getId(), $user->setAttribute('status', false)); - $audits->setPayload($response->output($user, Response::MODEL_USER)); // TODO is this a mistake? - $events ->setParam('userId', $user->getId()) ->setPayload($response->output($user, Response::MODEL_USER)); @@ -1634,7 +1637,6 @@ App::delete('/v1/account/sessions/:sessionId') ->groups(['api', 'account']) ->label('scope', 'account') ->label('event', 'users.[userId].sessions.[sessionId].delete') - ->label('audits.resource', 'user/{$id}') ->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_JWT]) ->label('sdk.namespace', 'account') ->label('sdk.method', 'deleteSession') @@ -1648,9 +1650,10 @@ App::delete('/v1/account/sessions/:sessionId') ->inject('user') ->inject('dbForProject') ->inject('locale') + ->inject('audits') ->inject('events') ->inject('usage') - ->action(function (?string $sessionId, Request $request, Response $response, Document $user, Database $dbForProject, Locale $locale, Event $events, Stats $usage) { + ->action(function (?string $sessionId, Request $request, Response $response, Document $user, Database $dbForProject, Locale $locale, Audit $audits, Event $events, Stats $usage) { $protocol = $request->getProtocol(); $sessionId = ($sessionId === 'current') @@ -1665,6 +1668,8 @@ App::delete('/v1/account/sessions/:sessionId') $dbForProject->deleteDocument('sessions', $session->getId()); + $audits->setResource('user/' . $user->getId()); + $session->setAttribute('current', false); if ($session->getAttribute('secret') == Auth::hash(Auth::$secret)) { // If current session delete the cookies too @@ -1794,7 +1799,6 @@ App::delete('/v1/account/sessions') ->groups(['api', 'account']) ->label('scope', 'account') ->label('event', 'users.[userId].sessions.[sessionId].delete') - ->label('audits.resource', 'user/{$id}') ->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_JWT]) ->label('sdk.namespace', 'account') ->label('sdk.method', 'deleteSessions') @@ -1807,9 +1811,10 @@ App::delete('/v1/account/sessions') ->inject('user') ->inject('dbForProject') ->inject('locale') + ->inject('audits') ->inject('events') ->inject('usage') - ->action(function (Request $request, Response $response, Document $user, Database $dbForProject, Locale $locale, Event $events, Stats $usage) { + ->action(function (Request $request, Response $response, Document $user, Database $dbForProject, Locale $locale, Audit $audits, Event $events, Stats $usage) { $protocol = $request->getProtocol(); $sessions = $user->getAttribute('sessions', []); @@ -1817,6 +1822,8 @@ App::delete('/v1/account/sessions') foreach ($sessions as $session) {/** @var Document $session */ $dbForProject->deleteDocument('sessions', $session->getId()); + $audits->setResource('user/' . $user->getId()); + if (!Config::getParam('domainVerification')) { $response->addHeader('X-Fallback-Cookies', \json_encode([])); } diff --git a/app/controllers/api/databases.php b/app/controllers/api/databases.php index a14e57d6be..0c4213d7e5 100644 --- a/app/controllers/api/databases.php +++ b/app/controllers/api/databases.php @@ -50,7 +50,7 @@ use MaxMind\Db\Reader; * @return Document Newly created attribute document * @throws Exception */ -function createAttribute(string $databaseId, string $collectionId, Document $attribute, Response $response, Database $dbForProject, EventDatabase $database, EventAudit $audits, Event $events, Stats $usage): Document +function createAttribute(string $databaseId, string $collectionId, Document $attribute, Response $response, Database $dbForProject, EventDatabase $database, Event $events, Stats $usage): Document { $key = $attribute->getAttribute('key'); $type = $attribute->getAttribute('type', ''); @@ -141,11 +141,6 @@ function createAttribute(string $databaseId, string $collectionId, Document $att ->setParam('attributeId', $attribute->getId()) ; - $audits - ->setResource('database/' . $db->getId() . '/collection/' . $collectionId) - ->setPayload($attribute->getArrayCopy()) - ; - $response->setStatusCode(Response::STATUS_CODE_CREATED); return $attribute; @@ -156,6 +151,8 @@ App::post('/v1/databases') ->groups(['api', 'database']) ->label('event', 'databases.[databaseId].create') ->label('scope', 'databases.write') + ->label('audits.resource', 'database/{$id}') + ->label('audits.payload', '*') ->label('sdk.auth', [APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'databases') ->label('sdk.method', 'create') @@ -167,10 +164,9 @@ App::post('/v1/databases') ->param('name', '', new Text(128), 'Collection name. Max length: 128 chars.') ->inject('response') ->inject('dbForProject') - ->inject('audits') ->inject('usage') ->inject('events') - ->action(function (string $databaseId, string $name, Response $response, Database $dbForProject, EventAudit $audits, Stats $usage, Event $events) { + ->action(function (string $databaseId, string $name, Response $response, Database $dbForProject, Stats $usage, Event $events) { $databaseId = $databaseId == 'unique()' ? $dbForProject->getId() : $databaseId; @@ -218,11 +214,6 @@ App::post('/v1/databases') throw new Exception('Database already exists', 409, Exception::DATABASE_ALREADY_EXISTS); } - $audits - ->setResource('database/' . $databaseId) - ->setPayload($database->getArrayCopy()) - ; - $events->setParam('databaseId', $database->getId()); $usage->setParam('databases.create', 1); @@ -386,6 +377,8 @@ App::put('/v1/databases/:databaseId') ->groups(['api', 'database']) ->label('scope', 'databases.write') ->label('event', 'databases.[databaseId].update') + ->label('audits.resource', 'database/{$id}') + ->label('audits.payload', '*') ->label('sdk.auth', [APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'databases') ->label('sdk.method', 'update') @@ -397,10 +390,9 @@ App::put('/v1/databases/:databaseId') ->param('name', null, new Text(128), 'Collection name. Max length: 128 chars.') ->inject('response') ->inject('dbForProject') - ->inject('audits') ->inject('usage') ->inject('events') - ->action(function (string $databaseId, string $name, Response $response, Database $dbForProject, EventAudit $audits, Stats $usage, Event $events) { + ->action(function (string $databaseId, string $name, Response $response, Database $dbForProject, Stats $usage, Event $events) { $database = $dbForProject->getDocument('databases', $databaseId); @@ -418,11 +410,6 @@ App::put('/v1/databases/:databaseId') throw new Exception('Bad structure. ' . $exception->getMessage(), 400, Exception::DOCUMENT_INVALID_STRUCTURE); } - $audits - ->setResource('database/' . $databaseId) - ->setPayload($database->getArrayCopy()) - ; - $usage->setParam('databases.update', 1); $events->setParam('databaseId', $database->getId()); @@ -487,6 +474,8 @@ App::post('/v1/databases/:databaseId/collections') ->groups(['api', 'database']) ->label('event', 'databases.[databaseId].collections.[collectionId].create') ->label('scope', 'collections.write') + ->label('audits.resource', 'database/{databaseId}/collection/{collectionId}') + ->label('audits.payload', '*') ->label('sdk.auth', [APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'databases') ->label('sdk.method', 'createCollection') @@ -502,10 +491,9 @@ App::post('/v1/databases/:databaseId/collections') ->param('write', null, new Permissions(APP_LIMIT_ARRAY_PARAMS_SIZE), 'An array of strings with write permissions. By default no user is granted with any write permissions. [learn more about permissions](https://appwrite.io/docs/permissions) and get a full list of available permissions.') ->inject('response') ->inject('dbForProject') - ->inject('audits') ->inject('usage') ->inject('events') - ->action(function (string $databaseId, string $collectionId, string $name, ?string $permission, ?array $read, ?array $write, Response $response, Database $dbForProject, EventAudit $audits, Stats $usage, Event $events) { + ->action(function (string $databaseId, string $collectionId, string $name, ?string $permission, ?array $read, ?array $write, Response $response, Database $dbForProject, Stats $usage, Event $events) { $database = Authorization::skip(fn () => $dbForProject->getDocument('databases', $databaseId)); @@ -536,11 +524,6 @@ App::post('/v1/databases/:databaseId/collections') throw new Exception('Collection limit exceeded', 400, Exception::COLLECTION_LIMIT_EXCEEDED); } - $audits - ->setResource('database/' . $databaseId . '/collection/' . $collectionId) - ->setPayload($collection->getArrayCopy()) - ; - $events ->setContext('database', $database) ->setParam('databaseId', $databaseId) @@ -741,6 +724,8 @@ App::put('/v1/databases/:databaseId/collections/:collectionId') ->groups(['api', 'database']) ->label('scope', 'collections.write') ->label('event', 'databases.[databaseId].collections.[collectionId].update') + ->label('audits-resource', 'database/{databaseId}/collection/{$id}') + ->label('audits-payload', '*') ->label('sdk.auth', [APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'databases') ->label('sdk.method', 'updateCollection') @@ -757,10 +742,9 @@ App::put('/v1/databases/:databaseId/collections/:collectionId') ->param('enabled', true, new Boolean(), 'Is collection enabled?', true) ->inject('response') ->inject('dbForProject') - ->inject('audits') ->inject('usage') ->inject('events') - ->action(function (string $databaseId, string $collectionId, string $name, string $permission, ?array $read, ?array $write, bool $enabled, Response $response, Database $dbForProject, EventAudit $audits, Stats $usage, Event $events) { + ->action(function (string $databaseId, string $collectionId, string $name, string $permission, ?array $read, ?array $write, bool $enabled, Response $response, Database $dbForProject, Stats $usage, Event $events) { $database = Authorization::skip(fn () => $dbForProject->getDocument('databases', $databaseId)); @@ -791,11 +775,6 @@ App::put('/v1/databases/:databaseId/collections/:collectionId') throw new Exception('Bad structure. ' . $exception->getMessage(), 400, Exception::DOCUMENT_INVALID_STRUCTURE); } - $audits - ->setResource('database/' . $databaseId . '/collection/' . $collectionId) - ->setPayload($collection->getArrayCopy()) - ; - $usage ->setParam('databaseId', $databaseId) ->setParam('databases.collections.update', 1); @@ -878,6 +857,8 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/attributes/string ->groups(['api', 'database']) ->label('event', 'databases.[databaseId].collections.[collectionId].attributes.[attributeId].create') ->label('scope', 'collections.write') + ->label('audits.resource', 'database/{databaseId}/collection/{collectionId}') + ->label('audits.payload', '*') ->label('sdk.auth', [APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'databases') ->label('sdk.method', 'createStringAttribute') @@ -895,10 +876,9 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/attributes/string ->inject('response') ->inject('dbForProject') ->inject('database') - ->inject('audits') ->inject('usage') ->inject('events') - ->action(function (string $databaseId, string $collectionId, string $key, ?int $size, ?bool $required, ?string $default, bool $array, Response $response, Database $dbForProject, EventDatabase $database, EventAudit $audits, Stats $usage, Event $events) { + ->action(function (string $databaseId, string $collectionId, string $key, ?int $size, ?bool $required, ?string $default, bool $array, Response $response, Database $dbForProject, EventDatabase $database, Stats $usage, Event $events) { // Ensure attribute default is within required size $validator = new Text($size); @@ -913,7 +893,7 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/attributes/string 'required' => $required, 'default' => $default, 'array' => $array, - ]), $response, $dbForProject, $database, $audits, $events, $usage); + ]), $response, $dbForProject, $database, $events, $usage); $response->dynamic($attribute, Response::MODEL_ATTRIBUTE_STRING); }); @@ -924,6 +904,8 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/attributes/email' ->groups(['api', 'database']) ->label('event', 'databases.[databaseId].collections.[collectionId].attributes.[attributeId].create') ->label('scope', 'collections.write') + ->label('audits.resource', 'database/{databaseId}/collection/{collectionId}') + ->label('audits.payload', '*') ->label('sdk.namespace', 'databases') ->label('sdk.auth', [APP_AUTH_TYPE_KEY]) ->label('sdk.method', 'createEmailAttribute') @@ -940,10 +922,9 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/attributes/email' ->inject('response') ->inject('dbForProject') ->inject('database') - ->inject('audits') ->inject('usage') ->inject('events') - ->action(function (string $databaseId, string $collectionId, string $key, ?bool $required, ?string $default, bool $array, Response $response, Database $dbForProject, EventDatabase $database, EventAudit $audits, Stats $usage, Event $events) { + ->action(function (string $databaseId, string $collectionId, string $key, ?bool $required, ?string $default, bool $array, Response $response, Database $dbForProject, EventDatabase $database, Stats $usage, Event $events) { $attribute = createAttribute($databaseId, $collectionId, new Document([ 'key' => $key, @@ -953,7 +934,7 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/attributes/email' 'default' => $default, 'array' => $array, 'format' => APP_DATABASE_ATTRIBUTE_EMAIL, - ]), $response, $dbForProject, $database, $audits, $events, $usage); + ]), $response, $dbForProject, $database, $events, $usage); $response->dynamic($attribute, Response::MODEL_ATTRIBUTE_EMAIL); }); @@ -964,6 +945,8 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/attributes/enum') ->groups(['api', 'database']) ->label('event', 'databases.[databaseId].collections.[collectionId].attributes.[attributeId].create') ->label('scope', 'collections.write') + ->label('audits.resource', 'database/{databaseId}/collection/{collectionId}') + ->label('audits.payload', '*') ->label('sdk.namespace', 'databases') ->label('sdk.auth', [APP_AUTH_TYPE_KEY]) ->label('sdk.method', 'createEnumAttribute') @@ -981,10 +964,9 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/attributes/enum') ->inject('response') ->inject('dbForProject') ->inject('database') - ->inject('audits') ->inject('usage') ->inject('events') - ->action(function (string $databaseId, string $collectionId, string $key, array $elements, ?bool $required, ?string $default, bool $array, Response $response, Database $dbForProject, EventDatabase $database, EventAudit $audits, Stats $usage, Event $events) { + ->action(function (string $databaseId, string $collectionId, string $key, array $elements, ?bool $required, ?string $default, bool $array, Response $response, Database $dbForProject, EventDatabase $database, Stats $usage, Event $events) { // use length of longest string as attribute size $size = 0; @@ -1009,7 +991,7 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/attributes/enum') 'array' => $array, 'format' => APP_DATABASE_ATTRIBUTE_ENUM, 'formatOptions' => ['elements' => $elements], - ]), $response, $dbForProject, $database, $audits, $events, $usage); + ]), $response, $dbForProject, $database, $events, $usage); $response->dynamic($attribute, Response::MODEL_ATTRIBUTE_ENUM); }); @@ -1020,6 +1002,8 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/attributes/ip') ->groups(['api', 'database']) ->label('event', 'databases.[databaseId].collections.[collectionId].attributes.[attributeId].create') ->label('scope', 'collections.write') + ->label('audits.resource', 'database/{databaseId}/collection/{collectionId}') + ->label('audits.payload', '*') ->label('sdk.namespace', 'databases') ->label('sdk.auth', [APP_AUTH_TYPE_KEY]) ->label('sdk.method', 'createIpAttribute') @@ -1036,10 +1020,9 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/attributes/ip') ->inject('response') ->inject('dbForProject') ->inject('database') - ->inject('audits') ->inject('usage') ->inject('events') - ->action(function (string $databaseId, string $collectionId, string $key, ?bool $required, ?string $default, bool $array, Response $response, Database $dbForProject, EventDatabase $database, EventAudit $audits, Stats $usage, Event $events) { + ->action(function (string $databaseId, string $collectionId, string $key, ?bool $required, ?string $default, bool $array, Response $response, Database $dbForProject, EventDatabase $database, Stats $usage, Event $events) { $attribute = createAttribute($databaseId, $collectionId, new Document([ 'key' => $key, @@ -1049,7 +1032,7 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/attributes/ip') 'default' => $default, 'array' => $array, 'format' => APP_DATABASE_ATTRIBUTE_IP, - ]), $response, $dbForProject, $database, $audits, $events, $usage); + ]), $response, $dbForProject, $database, $events, $usage); $response->dynamic($attribute, Response::MODEL_ATTRIBUTE_IP); }); @@ -1060,6 +1043,8 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/attributes/url') ->groups(['api', 'database']) ->label('event', 'databases.[databaseId].collections.[collectionId].attributes.[attributeId].create') ->label('scope', 'collections.write') + ->label('audits.resource', 'database/{databaseId}/collection/{collectionId}') + ->label('audits.payload', '*') ->label('sdk.namespace', 'databases') ->label('sdk.auth', [APP_AUTH_TYPE_KEY]) ->label('sdk.method', 'createUrlAttribute') @@ -1076,10 +1061,9 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/attributes/url') ->inject('response') ->inject('dbForProject') ->inject('database') - ->inject('audits') ->inject('usage') ->inject('events') - ->action(function (string $databaseId, string $collectionId, string $key, ?bool $required, ?string $default, bool $array, Response $response, Database $dbForProject, EventDatabase $database, EventAudit $audits, Stats $usage, Event $events) { + ->action(function (string $databaseId, string $collectionId, string $key, ?bool $required, ?string $default, bool $array, Response $response, Database $dbForProject, EventDatabase $database, Stats $usage, Event $events) { $attribute = createAttribute($databaseId, $collectionId, new Document([ 'key' => $key, @@ -1089,7 +1073,7 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/attributes/url') 'default' => $default, 'array' => $array, 'format' => APP_DATABASE_ATTRIBUTE_URL, - ]), $response, $dbForProject, $database, $audits, $events, $usage); + ]), $response, $dbForProject, $database, $events, $usage); $response->dynamic($attribute, Response::MODEL_ATTRIBUTE_URL); }); @@ -1100,6 +1084,8 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/attributes/intege ->groups(['api', 'database']) ->label('event', 'databases.[databaseId].collections.[collectionId].attributes.[attributeId].create') ->label('scope', 'collections.write') + ->label('audits.resource', 'database/{databaseId}/collection/{collectionId}') + ->label('audits.payload', '*') ->label('sdk.namespace', 'databases') ->label('sdk.auth', [APP_AUTH_TYPE_KEY]) ->label('sdk.method', 'createIntegerAttribute') @@ -1118,10 +1104,9 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/attributes/intege ->inject('response') ->inject('dbForProject') ->inject('database') - ->inject('audits') ->inject('usage') ->inject('events') - ->action(function (string $databaseId, string $collectionId, string $key, ?bool $required, ?int $min, ?int $max, ?int $default, bool $array, Response $response, Database $dbForProject, EventDatabase $database, EventAudit $audits, Stats $usage, Event $events) { + ->action(function (string $databaseId, string $collectionId, string $key, ?bool $required, ?int $min, ?int $max, ?int $default, bool $array, Response $response, Database $dbForProject, EventDatabase $database, Stats $usage, Event $events) { // Ensure attribute default is within range $min = (is_null($min)) ? PHP_INT_MIN : \intval($min); @@ -1151,7 +1136,7 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/attributes/intege 'min' => $min, 'max' => $max, ], - ]), $response, $dbForProject, $database, $audits, $events, $usage); + ]), $response, $dbForProject, $database, $events, $usage); $formatOptions = $attribute->getAttribute('formatOptions', []); @@ -1169,6 +1154,8 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/attributes/float' ->groups(['api', 'database']) ->label('event', 'databases.[databaseId].collections.[collectionId].attributes.[attributeId].create') ->label('scope', 'collections.write') + ->label('audits.resource', 'database/{databaseId}/collection/{collectionId}') + ->label('audits.payload', '*') ->label('sdk.namespace', 'databases') ->label('sdk.auth', [APP_AUTH_TYPE_KEY]) ->label('sdk.method', 'createFloatAttribute') @@ -1187,10 +1174,9 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/attributes/float' ->inject('response') ->inject('dbForProject') ->inject('database') - ->inject('audits') ->inject('events') ->inject('usage') - ->action(function (string $databaseId, string $collectionId, string $key, ?bool $required, ?float $min, ?float $max, ?float $default, bool $array, Response $response, Database $dbForProject, EventDatabase $database, EventAudit $audits, Event $events, Stats $usage) { + ->action(function (string $databaseId, string $collectionId, string $key, ?bool $required, ?float $min, ?float $max, ?float $default, bool $array, Response $response, Database $dbForProject, EventDatabase $database, Event $events, Stats $usage) { // Ensure attribute default is within range $min = (is_null($min)) ? -PHP_FLOAT_MAX : \floatval($min); @@ -1223,7 +1209,7 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/attributes/float' 'min' => $min, 'max' => $max, ], - ]), $response, $dbForProject, $database, $audits, $events, $usage); + ]), $response, $dbForProject, $database, $events, $usage); $formatOptions = $attribute->getAttribute('formatOptions', []); @@ -1241,6 +1227,8 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/attributes/boolea ->groups(['api', 'database']) ->label('event', 'databases.[databaseId].collections.[collectionId].attributes.[attributeId].create') ->label('scope', 'collections.write') + ->label('audits.resource', 'database/{databaseId}/collection/{collectionId}') + ->label('audits.payload', '*') ->label('sdk.namespace', 'databases') ->label('sdk.auth', [APP_AUTH_TYPE_KEY]) ->label('sdk.method', 'createBooleanAttribute') @@ -1257,10 +1245,9 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/attributes/boolea ->inject('response') ->inject('dbForProject') ->inject('database') - ->inject('audits') ->inject('usage') ->inject('events') - ->action(function (string $databaseId, string $collectionId, string $key, ?bool $required, ?bool $default, bool $array, Response $response, Database $dbForProject, EventDatabase $database, EventAudit $audits, Stats $usage, Event $events) { + ->action(function (string $databaseId, string $collectionId, string $key, ?bool $required, ?bool $default, bool $array, Response $response, Database $dbForProject, EventDatabase $database, Stats $usage, Event $events) { $attribute = createAttribute($databaseId, $collectionId, new Document([ 'key' => $key, @@ -1269,7 +1256,7 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/attributes/boolea 'required' => $required, 'default' => $default, 'array' => $array, - ]), $response, $dbForProject, $database, $audits, $events, $usage); + ]), $response, $dbForProject, $database, $events, $usage); $response->dynamic($attribute, Response::MODEL_ATTRIBUTE_BOOLEAN); }); @@ -1487,6 +1474,8 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/indexes') ->groups(['api', 'database']) ->label('event', 'databases.[databaseId].collections.[collectionId].indexes.[indexId].create') ->label('scope', 'collections.write') + ->label('audits.resource', 'database/{databaseId}/collection/{collectionId}') + ->label('audits.payload', '*') ->label('sdk.auth', [APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'databases') ->label('sdk.method', 'createIndex') @@ -1503,10 +1492,9 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/indexes') ->inject('response') ->inject('dbForProject') ->inject('database') - ->inject('audits') ->inject('usage') ->inject('events') - ->action(function (string $databaseId, string $collectionId, string $key, string $type, array $attributes, array $orders, Response $response, Database $dbForProject, EventDatabase $database, EventAudit $audits, Stats $usage, Event $events) { + ->action(function (string $databaseId, string $collectionId, string $key, string $type, array $attributes, array $orders, Response $response, Database $dbForProject, EventDatabase $database, Stats $usage, Event $events) { $db = Authorization::skip(fn () => $dbForProject->getDocument('databases', $databaseId)); @@ -1628,11 +1616,6 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/indexes') ->setContext('database', $db) ; - $audits - ->setResource('database/' . $databaseId . '/collection/' . $collection->getId()) - ->setPayload($index->getArrayCopy()) - ; - $response->setStatusCode(Response::STATUS_CODE_CREATED); $response->dynamic($index, Response::MODEL_INDEX); }); @@ -1811,6 +1794,8 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/documents') ->groups(['api', 'database']) ->label('event', 'databases.[databaseId].collections.[collectionId].documents.[documentId].create') ->label('scope', 'documents.write') + ->label('audits.resource', 'database/{databaseId}/collection/{collectionId}') + ->label('audits.payload', '*') ->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_KEY, APP_AUTH_TYPE_JWT]) ->label('sdk.namespace', 'databases') ->label('sdk.method', 'createDocument') @@ -1827,11 +1812,10 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/documents') ->inject('response') ->inject('dbForProject') ->inject('user') - ->inject('audits') ->inject('usage') ->inject('events') ->inject('mode') - ->action(function (string $databaseId, string $documentId, string $collectionId, string|array $data, ?array $read, ?array $write, Response $response, Database $dbForProject, Document $user, EventAudit $audits, Stats $usage, Event $events, string $mode) { + ->action(function (string $databaseId, string $documentId, string $collectionId, string|array $data, ?array $read, ?array $write, Response $response, Database $dbForProject, Document $user, Stats $usage, Event $events, string $mode) { $database = Authorization::skip(fn () => $dbForProject->getDocument('databases', $databaseId)); @@ -1919,11 +1903,6 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/documents') ->setParam('collectionId', $collectionId) ; - $audits - ->setResource('database/' . $databaseId . '/collection/' . $collectionId . '/document/' . $document->getId()) - ->setPayload($document->getArrayCopy()) - ; - $response->setStatusCode(Response::STATUS_CODE_CREATED); $response->dynamic($document, Response::MODEL_DOCUMENT); }); @@ -2212,6 +2191,8 @@ App::patch('/v1/databases/:databaseId/collections/:collectionId/documents/:docum ->groups(['api', 'database']) ->label('event', 'databases.[databaseId].collections.[collectionId].documents.[documentId].update') ->label('scope', 'documents.write') + ->label('audits.resource', 'database/{databaseId}/collection/{collectionId}/document/{$id}') + ->label('audits.payload', '*') ->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_KEY, APP_AUTH_TYPE_JWT]) ->label('sdk.namespace', 'databases') ->label('sdk.method', 'updateDocument') @@ -2227,11 +2208,10 @@ App::patch('/v1/databases/:databaseId/collections/:collectionId/documents/:docum ->param('write', null, new Permissions(APP_LIMIT_ARRAY_PARAMS_SIZE), 'An array of strings with write permissions. By default inherits the existing write permissions. [learn more about permissions](https://appwrite.io/docs/permissions) and get a full list of available permissions.', true) ->inject('response') ->inject('dbForProject') - ->inject('audits') ->inject('usage') ->inject('events') ->inject('mode') - ->action(function (string $databaseId, string $collectionId, string $documentId, string|array $data, ?array $read, ?array $write, Response $response, Database $dbForProject, EventAudit $audits, Stats $usage, Event $events, string $mode) { + ->action(function (string $databaseId, string $collectionId, string $documentId, string|array $data, ?array $read, ?array $write, Response $response, Database $dbForProject, Stats $usage, Event $events, string $mode) { $database = Authorization::skip(fn () => $dbForProject->getDocument('databases', $databaseId)); @@ -2337,11 +2317,6 @@ App::patch('/v1/databases/:databaseId/collections/:collectionId/documents/:docum ->setParam('collectionId', $collectionId) ; - $audits - ->setResource('database/' . $databaseId . '/collection/' . $collectionId . '/document/' . $document->getId()) - ->setPayload($document->getArrayCopy()) - ; - $response->dynamic($document, Response::MODEL_DOCUMENT); }); diff --git a/app/controllers/api/storage.php b/app/controllers/api/storage.php index 2af973ae16..104d48e24e 100644 --- a/app/controllers/api/storage.php +++ b/app/controllers/api/storage.php @@ -47,6 +47,7 @@ App::post('/v1/storage/buckets') ->label('scope', 'buckets.write') ->label('event', 'buckets.[bucketId].create') ->label('audits.resource', 'storage/buckets/{$id}') + ->label('audits.pauload', '*') ->label('sdk.auth', [APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'storage') ->label('sdk.method', 'createBucket') @@ -126,8 +127,6 @@ App::post('/v1/storage/buckets') throw new Exception('Bucket already exists', 409, Exception::STORAGE_BUCKET_ALREADY_EXISTS); } - - $events ->setParam('bucketId', $bucket->getId()) ; @@ -212,6 +211,7 @@ App::put('/v1/storage/buckets/:bucketId') ->label('scope', 'buckets.write') ->label('event', 'buckets.[bucketId].update') ->label('audits.resource', 'storage/buckets/{$id}') + ->label('audits.payload', '*') ->label('sdk.auth', [APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'storage') ->label('sdk.method', 'updateBucket') @@ -273,7 +273,6 @@ App::delete('/v1/storage/buckets/:bucketId') ->groups(['api', 'storage']) ->label('scope', 'buckets.write') ->label('event', 'buckets.[bucketId].delete') - ->label('audits.resource', 'storage/buckets/{$id}') ->label('sdk.auth', [APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'storage') ->label('sdk.method', 'deleteBucket') @@ -307,7 +306,10 @@ App::delete('/v1/storage/buckets/:bucketId') ->setPayload($response->output($bucket, Response::MODEL_BUCKET)) ; - $audits->setPayload($bucket->getArrayCopy()); + $audits + ->setResource('storage/buckets/' . $bucket->getId()) + ->setPayload($bucket->getArrayCopy()) + ; $usage->setParam('storage.buckets.delete', 1); @@ -1360,7 +1362,6 @@ App::delete('/v1/storage/buckets/:bucketId/files/:fileId') ->groups(['api', 'storage']) ->label('scope', 'files.write') ->label('event', 'buckets.[bucketId].files.[fileId].delete') - ->label('audits.resource', 'storage/files/{$id}') ->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_KEY, APP_AUTH_TYPE_JWT]) ->label('sdk.namespace', 'storage') ->label('sdk.method', 'deleteFile') @@ -1372,11 +1373,12 @@ App::delete('/v1/storage/buckets/:bucketId/files/:fileId') ->inject('response') ->inject('dbForProject') ->inject('events') + ->inject('audits') ->inject('usage') ->inject('mode') ->inject('deviceFiles') ->inject('project') - ->action(function (string $bucketId, string $fileId, Response $response, Database $dbForProject, Event $events, Stats $usage, string $mode, Device $deviceFiles, Document $project) { + ->action(function (string $bucketId, string $fileId, Response $response, Database $dbForProject, Event $events, Audit $audits, Stats $usage, string $mode, Device $deviceFiles, Document $project) { $bucket = Authorization::skip(fn () => $dbForProject->getDocument('buckets', $bucketId)); if ( @@ -1432,6 +1434,8 @@ App::delete('/v1/storage/buckets/:bucketId/files/:fileId') throw new Exception('Failed to delete file from device', 500, Exception::GENERAL_SERVER_ERROR); } + $audits->setResource('file/' . $file->getId()); + $usage ->setParam('storage', $file->getAttribute('size', 0) * -1) ->setParam('storage.files.delete', 1) diff --git a/app/controllers/shared/api.php b/app/controllers/shared/api.php index 3b7f565460..155be447ae 100644 --- a/app/controllers/shared/api.php +++ b/app/controllers/shared/api.php @@ -259,9 +259,13 @@ App::shutdown() $parseLabel = function ($params, $label) { preg_match_all('/{(.*?)}/', $label, $matches); - if(array_key_exists($matches[1][0], $params)){ - return \str_replace($matches[0][0], $params[$matches[1][0]], $label); + foreach ($matches[1] ?? [] as $pos => $match) { + if(array_key_exists($match, $params)){ + $label = \str_replace($matches[0][$pos], $params[$match], $label); + } } + + return $label; }; $route = $utopia->match($request); @@ -269,11 +273,19 @@ App::shutdown() $auditsResource = $route->getLabel('audits.resource',''); if(!empty($auditsResource)) { $resource = $parseLabel($responsePayload, $auditsResource); - if(!empty($resource)){ + if(!empty($resource)) { $audits->setResource($resource); } } + $auditsPayload = $route->getLabel('audits.payload',''); + if(!empty($auditsPayload)) { + if($auditsPayload === '*'){ + $audits->setPayload($responsePayload); + } + } + + if (!empty($audits->getResource())) { foreach ($events->getParams() as $key => $value) { $audits->setParam($key, $value); From 89f164bdd7dea83245a13d0094d04fa6d9231f16 Mon Sep 17 00:00:00 2001 From: shimon Date: Mon, 8 Aug 2022 15:19:41 +0300 Subject: [PATCH 05/46] resource namespace --- app/controllers/api/account.php | 40 ++++++++++++++-------------- app/controllers/api/databases.php | 30 ++++++++++----------- app/controllers/api/storage.php | 10 +++---- app/controllers/shared/api.php | 43 ++++++++++++++++++++++++++----- docker-compose.yml | 1 + 5 files changed, 77 insertions(+), 47 deletions(-) diff --git a/app/controllers/api/account.php b/app/controllers/api/account.php index 0e65a29762..30d90b0c4d 100644 --- a/app/controllers/api/account.php +++ b/app/controllers/api/account.php @@ -47,7 +47,7 @@ App::post('/v1/account') ->label('event', 'users.[userId].create') ->label('scope', 'public') ->label('auth.type', 'emailPassword') - ->label('audits.resource', 'user/{$id}') + ->label('audits.resource', 'user/{payload.$id}') ->label('sdk.auth', []) ->label('sdk.namespace', 'account') ->label('sdk.method', 'create') @@ -354,7 +354,7 @@ App::get('/v1/account/sessions/oauth2/:provider/redirect') ->label('abuse-limit', 50) ->label('abuse-key', 'ip:{ip}') ->label('docs', false) - ->label('audits.resource', 'user/{$id}') + ->label('audits.resource', 'user/{payload.$id}') ->param('provider', '', new WhiteList(\array_keys(Config::getParam('providers')), true), 'OAuth2 provider.') ->param('code', '', new Text(2048), 'OAuth2 code.') ->param('state', '', new Text(2048), 'OAuth2 state params.', true) @@ -586,7 +586,7 @@ App::post('/v1/account/sessions/magic-url') ->groups(['api', 'account']) ->label('scope', 'public') ->label('auth.type', 'magic-url') - ->label('audits.resource', 'user/{$id}') + ->label('audits.resource', 'user/{payload.$id}') ->label('sdk.auth', []) ->label('sdk.namespace', 'account') ->label('sdk.method', 'createMagicURLSession') @@ -710,7 +710,7 @@ App::put('/v1/account/sessions/magic-url') ->groups(['api', 'account']) ->label('scope', 'public') ->label('event', 'users.[userId].sessions.[sessionId].create') - ->label('audits.resource', 'user/{$id}') + ->label('audits.resource', 'user/{payload.$id}') ->label('sdk.auth', []) ->label('sdk.namespace', 'account') ->label('sdk.method', 'updateMagicURLSession') @@ -822,7 +822,7 @@ App::post('/v1/account/sessions/phone') ->groups(['api', 'account']) ->label('scope', 'public') ->label('auth.type', 'phone') - ->label('audits.resource', 'user/{$id}') + ->label('audits.resource', 'user/{payload.$id}') ->label('sdk.auth', []) ->label('sdk.namespace', 'account') ->label('sdk.method', 'createPhoneSession') @@ -935,7 +935,7 @@ App::put('/v1/account/sessions/phone') ->groups(['api', 'account']) ->label('scope', 'public') ->label('event', 'users.[userId].sessions.[sessionId].create') - ->label('audits.resource', 'user/{$id}') + ->label('audits.resource', 'user/{payload.$id}') ->label('sdk.auth', []) ->label('sdk.namespace', 'account') ->label('sdk.method', 'updatePhoneSession') @@ -1044,7 +1044,7 @@ App::post('/v1/account/sessions/anonymous') ->label('event', 'users.[userId].sessions.[sessionId].create') ->label('scope', 'public') ->label('auth.type', 'anonymous') - ->label('audits.resource', 'user/{$id}') + ->label('audits.resource', 'user/{payload.$id}') ->label('sdk.auth', []) ->label('sdk.namespace', 'account') ->label('sdk.method', 'createAnonymousSession') @@ -1399,7 +1399,7 @@ App::patch('/v1/account/name') ->groups(['api', 'account']) ->label('event', 'users.[userId].update.name') ->label('scope', 'account') - ->label('audits.resource', 'user/{$id}') + ->label('audits.resource', 'user/{payload.$id}') ->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_JWT]) ->label('sdk.namespace', 'account') ->label('sdk.method', 'updateName') @@ -1430,7 +1430,7 @@ App::patch('/v1/account/password') ->groups(['api', 'account']) ->label('event', 'users.[userId].update.password') ->label('scope', 'account') - ->label('audits.resource', 'user/{$id}') + ->label('audits.resource', 'user/{payload.$id}') ->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_JWT]) ->label('sdk.namespace', 'account') ->label('sdk.method', 'updatePassword') @@ -1471,7 +1471,7 @@ App::patch('/v1/account/email') ->groups(['api', 'account']) ->label('event', 'users.[userId].update.email') ->label('scope', 'account') - ->label('audits.resource', 'user/{$id}') + ->label('audits.resource', 'user/{payload.$id}') ->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_JWT]) ->label('sdk.namespace', 'account') ->label('sdk.method', 'updateEmail') @@ -1522,7 +1522,7 @@ App::patch('/v1/account/phone') ->groups(['api', 'account']) ->label('event', 'users.[userId].update.phone') ->label('scope', 'account') - ->label('audits.resource', 'user/{$id}') + ->label('audits.resource', 'user/{payload.$id}') ->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_JWT]) ->label('sdk.namespace', 'account') ->label('sdk.method', 'updatePhone') @@ -1570,7 +1570,7 @@ App::patch('/v1/account/prefs') ->groups(['api', 'account']) ->label('event', 'users.[userId].update.prefs') ->label('scope', 'account') - ->label('audits.resource', 'user/{$id}') + ->label('audits.resource', 'user/{payload.$id}') ->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_JWT]) ->label('sdk.namespace', 'account') ->label('sdk.method', 'updatePrefs') @@ -1599,7 +1599,7 @@ App::patch('/v1/account/status') ->groups(['api', 'account']) ->label('event', 'users.[userId].update.status') ->label('scope', 'account') - ->label('audits.resource', 'user/{$id}') + ->label('audits.resource', 'user/{payload.$id}') ->label('audits.payload', '*') ->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_JWT]) ->label('sdk.namespace', 'account') @@ -1714,7 +1714,7 @@ App::patch('/v1/account/sessions/:sessionId') ->groups(['api', 'account']) ->label('scope', 'account') ->label('event', 'users.[userId].sessions.[sessionId].update') - ->label('audits.resource', 'user/{$id}') + ->label('audits.resource', 'user/{payload.$id}') ->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_JWT]) ->label('sdk.namespace', 'account') ->label('sdk.method', 'updateSession') @@ -1867,7 +1867,7 @@ App::post('/v1/account/recovery') ->groups(['api', 'account']) ->label('scope', 'public') ->label('event', 'users.[userId].recovery.[tokenId].create') - ->label('audits.resource', 'user/{$id}') + ->label('audits.resource', 'user/{payload.$id}') ->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_JWT]) ->label('sdk.namespace', 'account') ->label('sdk.method', 'createRecovery') @@ -1970,7 +1970,7 @@ App::put('/v1/account/recovery') ->groups(['api', 'account']) ->label('scope', 'public') ->label('event', 'users.[userId].recovery.[tokenId].update') - ->label('audits.resource', 'user/{$id}') + ->label('audits.resource', 'user/{payload.$id}') ->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_JWT]) ->label('sdk.namespace', 'account') ->label('sdk.method', 'updateRecovery') @@ -2038,7 +2038,7 @@ App::post('/v1/account/verification') ->groups(['api', 'account']) ->label('scope', 'account') ->label('event', 'users.[userId].verification.[tokenId].create') - ->label('audits.resource', 'user/{$id}') + ->label('audits.resource', 'user/{payload.$id}') ->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_JWT]) ->label('sdk.namespace', 'account') ->label('sdk.method', 'createVerification') @@ -2127,7 +2127,7 @@ App::put('/v1/account/verification') ->groups(['api', 'account']) ->label('scope', 'public') ->label('event', 'users.[userId].verification.[tokenId].update') - ->label('audits.resource', 'user/{$id}') + ->label('audits.resource', 'user/{payload.$id}') ->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_JWT]) ->label('sdk.namespace', 'account') ->label('sdk.method', 'updateVerification') @@ -2187,7 +2187,7 @@ App::post('/v1/account/verification/phone') ->groups(['api', 'account']) ->label('scope', 'account') ->label('event', 'users.[userId].verification.[tokenId].create') - ->label('audits.resource', 'user/{$id}') + ->label('audits.resource', 'user/{payload.$id}') ->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_JWT]) ->label('sdk.namespace', 'account') ->label('sdk.method', 'createPhoneVerification') @@ -2272,7 +2272,7 @@ App::put('/v1/account/verification/phone') ->groups(['api', 'account']) ->label('scope', 'public') ->label('event', 'users.[userId].verification.[tokenId].update') - ->label('audits.resource', 'user/{$id}') + ->label('audits.resource', 'user/{payload.$id}') ->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_JWT]) ->label('sdk.namespace', 'account') ->label('sdk.method', 'updatePhoneVerification') diff --git a/app/controllers/api/databases.php b/app/controllers/api/databases.php index 0c4213d7e5..df032a4dbc 100644 --- a/app/controllers/api/databases.php +++ b/app/controllers/api/databases.php @@ -151,7 +151,7 @@ App::post('/v1/databases') ->groups(['api', 'database']) ->label('event', 'databases.[databaseId].create') ->label('scope', 'databases.write') - ->label('audits.resource', 'database/{$id}') + ->label('audits.resource', 'database/{payload.$id}') ->label('audits.payload', '*') ->label('sdk.auth', [APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'databases') @@ -377,7 +377,7 @@ App::put('/v1/databases/:databaseId') ->groups(['api', 'database']) ->label('scope', 'databases.write') ->label('event', 'databases.[databaseId].update') - ->label('audits.resource', 'database/{$id}') + ->label('audits.resource', 'database/{payload.$id}') ->label('audits.payload', '*') ->label('sdk.auth', [APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'databases') @@ -474,7 +474,7 @@ App::post('/v1/databases/:databaseId/collections') ->groups(['api', 'database']) ->label('event', 'databases.[databaseId].collections.[collectionId].create') ->label('scope', 'collections.write') - ->label('audits.resource', 'database/{databaseId}/collection/{collectionId}') + ->label('audits.resource', 'database/{request.databaseId}/collection/{request.collectionId}') ->label('audits.payload', '*') ->label('sdk.auth', [APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'databases') @@ -724,7 +724,7 @@ App::put('/v1/databases/:databaseId/collections/:collectionId') ->groups(['api', 'database']) ->label('scope', 'collections.write') ->label('event', 'databases.[databaseId].collections.[collectionId].update') - ->label('audits-resource', 'database/{databaseId}/collection/{$id}') + ->label('audits.resource', 'database/{request.databaseId}/collection/{request.collectionId}') ->label('audits-payload', '*') ->label('sdk.auth', [APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'databases') @@ -857,7 +857,7 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/attributes/string ->groups(['api', 'database']) ->label('event', 'databases.[databaseId].collections.[collectionId].attributes.[attributeId].create') ->label('scope', 'collections.write') - ->label('audits.resource', 'database/{databaseId}/collection/{collectionId}') + ->label('audits.resource', 'database/{request.databaseId}/collection/{request.collectionId}') ->label('audits.payload', '*') ->label('sdk.auth', [APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'databases') @@ -904,7 +904,7 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/attributes/email' ->groups(['api', 'database']) ->label('event', 'databases.[databaseId].collections.[collectionId].attributes.[attributeId].create') ->label('scope', 'collections.write') - ->label('audits.resource', 'database/{databaseId}/collection/{collectionId}') + ->label('audits.resource', 'database/{request.databaseId}/collection/{request.collectionId}') ->label('audits.payload', '*') ->label('sdk.namespace', 'databases') ->label('sdk.auth', [APP_AUTH_TYPE_KEY]) @@ -945,7 +945,7 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/attributes/enum') ->groups(['api', 'database']) ->label('event', 'databases.[databaseId].collections.[collectionId].attributes.[attributeId].create') ->label('scope', 'collections.write') - ->label('audits.resource', 'database/{databaseId}/collection/{collectionId}') + ->label('audits.resource', 'database/{request.databaseId}/collection/{request.collectionId}') ->label('audits.payload', '*') ->label('sdk.namespace', 'databases') ->label('sdk.auth', [APP_AUTH_TYPE_KEY]) @@ -1002,7 +1002,7 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/attributes/ip') ->groups(['api', 'database']) ->label('event', 'databases.[databaseId].collections.[collectionId].attributes.[attributeId].create') ->label('scope', 'collections.write') - ->label('audits.resource', 'database/{databaseId}/collection/{collectionId}') + ->label('audits.resource', 'database/{request.databaseId}/collection/{request.collectionId}') ->label('audits.payload', '*') ->label('sdk.namespace', 'databases') ->label('sdk.auth', [APP_AUTH_TYPE_KEY]) @@ -1043,7 +1043,7 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/attributes/url') ->groups(['api', 'database']) ->label('event', 'databases.[databaseId].collections.[collectionId].attributes.[attributeId].create') ->label('scope', 'collections.write') - ->label('audits.resource', 'database/{databaseId}/collection/{collectionId}') + ->label('audits.resource', 'database/{request.databaseId}/collection/{request.collectionId}') ->label('audits.payload', '*') ->label('sdk.namespace', 'databases') ->label('sdk.auth', [APP_AUTH_TYPE_KEY]) @@ -1084,7 +1084,7 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/attributes/intege ->groups(['api', 'database']) ->label('event', 'databases.[databaseId].collections.[collectionId].attributes.[attributeId].create') ->label('scope', 'collections.write') - ->label('audits.resource', 'database/{databaseId}/collection/{collectionId}') + ->label('audits.resource', 'database/{request.databaseId}/collection/{request.collectionId}') ->label('audits.payload', '*') ->label('sdk.namespace', 'databases') ->label('sdk.auth', [APP_AUTH_TYPE_KEY]) @@ -1154,7 +1154,7 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/attributes/float' ->groups(['api', 'database']) ->label('event', 'databases.[databaseId].collections.[collectionId].attributes.[attributeId].create') ->label('scope', 'collections.write') - ->label('audits.resource', 'database/{databaseId}/collection/{collectionId}') + ->label('audits.resource', 'database/{request.databaseId}/collection/{request.collectionId}') ->label('audits.payload', '*') ->label('sdk.namespace', 'databases') ->label('sdk.auth', [APP_AUTH_TYPE_KEY]) @@ -1227,7 +1227,7 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/attributes/boolea ->groups(['api', 'database']) ->label('event', 'databases.[databaseId].collections.[collectionId].attributes.[attributeId].create') ->label('scope', 'collections.write') - ->label('audits.resource', 'database/{databaseId}/collection/{collectionId}') + ->label('audits.resource', 'database/{request.databaseId}/collection/{request.collectionId}') ->label('audits.payload', '*') ->label('sdk.namespace', 'databases') ->label('sdk.auth', [APP_AUTH_TYPE_KEY]) @@ -1474,7 +1474,7 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/indexes') ->groups(['api', 'database']) ->label('event', 'databases.[databaseId].collections.[collectionId].indexes.[indexId].create') ->label('scope', 'collections.write') - ->label('audits.resource', 'database/{databaseId}/collection/{collectionId}') + ->label('audits.resource', 'database/{request.databaseId}/collection/{request.collectionId}') ->label('audits.payload', '*') ->label('sdk.auth', [APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'databases') @@ -1794,7 +1794,7 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/documents') ->groups(['api', 'database']) ->label('event', 'databases.[databaseId].collections.[collectionId].documents.[documentId].create') ->label('scope', 'documents.write') - ->label('audits.resource', 'database/{databaseId}/collection/{collectionId}') + ->label('audits.resource', 'database/{request.databaseId}/collection/{request.collectionId}') ->label('audits.payload', '*') ->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_KEY, APP_AUTH_TYPE_JWT]) ->label('sdk.namespace', 'databases') @@ -2191,7 +2191,7 @@ App::patch('/v1/databases/:databaseId/collections/:collectionId/documents/:docum ->groups(['api', 'database']) ->label('event', 'databases.[databaseId].collections.[collectionId].documents.[documentId].update') ->label('scope', 'documents.write') - ->label('audits.resource', 'database/{databaseId}/collection/{collectionId}/document/{$id}') + ->label('audits.resource', 'database/{request.databaseId}/collection/{request.collectionId}/document/{payload.$id}') ->label('audits.payload', '*') ->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_KEY, APP_AUTH_TYPE_JWT]) ->label('sdk.namespace', 'databases') diff --git a/app/controllers/api/storage.php b/app/controllers/api/storage.php index 104d48e24e..abcd97da25 100644 --- a/app/controllers/api/storage.php +++ b/app/controllers/api/storage.php @@ -46,8 +46,8 @@ App::post('/v1/storage/buckets') ->groups(['api', 'storage']) ->label('scope', 'buckets.write') ->label('event', 'buckets.[bucketId].create') - ->label('audits.resource', 'storage/buckets/{$id}') - ->label('audits.pauload', '*') + ->label('audits.resource', 'storage/buckets/{payload.$id}') + ->label('audits.payload', '*') ->label('sdk.auth', [APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'storage') ->label('sdk.method', 'createBucket') @@ -210,7 +210,7 @@ App::put('/v1/storage/buckets/:bucketId') ->groups(['api', 'storage']) ->label('scope', 'buckets.write') ->label('event', 'buckets.[bucketId].update') - ->label('audits.resource', 'storage/buckets/{$id}') + ->label('audits.resource', 'storage/buckets/{payload.$id}') ->label('audits.payload', '*') ->label('sdk.auth', [APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'storage') @@ -322,7 +322,7 @@ App::post('/v1/storage/buckets/:bucketId/files') ->groups(['api', 'storage']) ->label('scope', 'files.write') ->label('event', 'buckets.[bucketId].files.[fileId].create') - ->label('audits.resource', 'storage/files/{$id}') + ->label('audits.resource', 'storage/files/{payload.$id}') ->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_KEY, APP_AUTH_TYPE_JWT]) ->label('sdk.namespace', 'storage') ->label('sdk.method', 'createFile') @@ -1267,7 +1267,7 @@ App::put('/v1/storage/buckets/:bucketId/files/:fileId') ->groups(['api', 'storage']) ->label('scope', 'files.write') ->label('event', 'buckets.[bucketId].files.[fileId].update') - ->label('audits.resource', 'storage/files/{$id}') + ->label('audits.resource', 'storage/files/{payload.$id}') ->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_KEY, APP_AUTH_TYPE_JWT]) ->label('sdk.namespace', 'storage') ->label('sdk.method', 'updateFile') diff --git a/app/controllers/shared/api.php b/app/controllers/shared/api.php index 155be447ae..e63e48095d 100644 --- a/app/controllers/shared/api.php +++ b/app/controllers/shared/api.php @@ -18,6 +18,7 @@ use Utopia\Database\Database; use Utopia\Database\Document; use Utopia\Database\Validator\Authorization; use Utopia\Registry\Registry; +use Utopia\Route; App::init() ->groups(['api']) @@ -257,22 +258,50 @@ App::shutdown() } } - $parseLabel = function ($params, $label) { + $route = $utopia->match($request); + + $getRequestParams = function() use ($route, $request) { + $url = \parse_url($request->getURI(), PHP_URL_PATH); + $regex = '@' . \preg_replace('@:[^/]+@', '([^/]+)', $route->getPath()) . '@'; + \preg_match($regex, $url, $matches); + \array_shift($matches); + $url = $route->getIsAlias() ? $route->getAliasPath() : $route->getPath(); + $keyRegex = '@^' . \preg_replace('@:[^/]+@', ':([^/]+)', $url) . '$@'; + \preg_match($keyRegex, $url, $keys); + \array_shift($keys); + + return \array_combine($keys, $matches) ?? []; + }; + + + $parseLabel = function ($label) use ($responsePayload, $getRequestParams) { preg_match_all('/{(.*?)}/', $label, $matches); - foreach ($matches[1] ?? [] as $pos => $match) { - if(array_key_exists($match, $params)){ - $label = \str_replace($matches[0][$pos], $params[$match], $label); + foreach ($matches[1] ?? [] as $pos => $match) { + $find = $matches[0][$pos]; + list($namespace, $replace) = explode('.', $match); + + switch ($namespace) { + case 'payload': + $params = $responsePayload; + break; + case 'request': + $params = $getRequestParams(); + break; + default: + $responsePayload; + } + + if(array_key_exists($replace, $params)){ + $label = \str_replace($find, $params[$replace], $label); } } return $label; }; - $route = $utopia->match($request); - $auditsResource = $route->getLabel('audits.resource',''); if(!empty($auditsResource)) { - $resource = $parseLabel($responsePayload, $auditsResource); + $resource = $parseLabel($auditsResource); if(!empty($resource)) { $audits->setResource($resource); } diff --git a/docker-compose.yml b/docker-compose.yml index 20d2c5c2f9..8a002e0801 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -103,6 +103,7 @@ services: - ./phpunit.xml:/usr/src/code/phpunit.xml - ./tests:/usr/src/code/tests - ./app:/usr/src/code/app + #- ./vendor:/usr/src/code/vendor #TODO remove when done!! # - ./vendor/utopia/database:/usr/src/code/vendor/utopia/database - ./docs:/usr/src/code/docs - ./public:/usr/src/code/public From 62ef53280147873c1324807e6348e52e89ddc377 Mon Sep 17 00:00:00 2001 From: shimon Date: Mon, 8 Aug 2022 17:32:54 +0300 Subject: [PATCH 06/46] leftovers --- app/controllers/api/account.php | 45 +++++++++++---------- app/controllers/api/databases.php | 66 +++++++++++++------------------ app/controllers/api/storage.php | 24 +++++------ app/controllers/api/teams.php | 43 ++++++-------------- app/controllers/api/users.php | 46 ++++++--------------- app/controllers/shared/api.php | 11 ++---- 6 files changed, 88 insertions(+), 147 deletions(-) diff --git a/app/controllers/api/account.php b/app/controllers/api/account.php index 30d90b0c4d..0e4f40d8d2 100644 --- a/app/controllers/api/account.php +++ b/app/controllers/api/account.php @@ -47,7 +47,7 @@ App::post('/v1/account') ->label('event', 'users.[userId].create') ->label('scope', 'public') ->label('auth.type', 'emailPassword') - ->label('audits.resource', 'user/{payload.$id}') + ->label('audits.resource', 'user/{response.$id}') ->label('sdk.auth', []) ->label('sdk.namespace', 'account') ->label('sdk.method', 'create') @@ -354,7 +354,7 @@ App::get('/v1/account/sessions/oauth2/:provider/redirect') ->label('abuse-limit', 50) ->label('abuse-key', 'ip:{ip}') ->label('docs', false) - ->label('audits.resource', 'user/{payload.$id}') + ->label('audits.resource', 'user/{response.$id}') ->param('provider', '', new WhiteList(\array_keys(Config::getParam('providers')), true), 'OAuth2 provider.') ->param('code', '', new Text(2048), 'OAuth2 code.') ->param('state', '', new Text(2048), 'OAuth2 state params.', true) @@ -586,7 +586,7 @@ App::post('/v1/account/sessions/magic-url') ->groups(['api', 'account']) ->label('scope', 'public') ->label('auth.type', 'magic-url') - ->label('audits.resource', 'user/{payload.$id}') + ->label('audits.resource', 'user/{response.$id}') ->label('sdk.auth', []) ->label('sdk.namespace', 'account') ->label('sdk.method', 'createMagicURLSession') @@ -710,7 +710,7 @@ App::put('/v1/account/sessions/magic-url') ->groups(['api', 'account']) ->label('scope', 'public') ->label('event', 'users.[userId].sessions.[sessionId].create') - ->label('audits.resource', 'user/{payload.$id}') + ->label('audits.resource', 'user/{response.$id}') ->label('sdk.auth', []) ->label('sdk.namespace', 'account') ->label('sdk.method', 'updateMagicURLSession') @@ -822,7 +822,7 @@ App::post('/v1/account/sessions/phone') ->groups(['api', 'account']) ->label('scope', 'public') ->label('auth.type', 'phone') - ->label('audits.resource', 'user/{payload.$id}') + ->label('audits.resource', 'user/{response.$id}') ->label('sdk.auth', []) ->label('sdk.namespace', 'account') ->label('sdk.method', 'createPhoneSession') @@ -935,7 +935,7 @@ App::put('/v1/account/sessions/phone') ->groups(['api', 'account']) ->label('scope', 'public') ->label('event', 'users.[userId].sessions.[sessionId].create') - ->label('audits.resource', 'user/{payload.$id}') + ->label('audits.resource', 'user/{response.$id}') ->label('sdk.auth', []) ->label('sdk.namespace', 'account') ->label('sdk.method', 'updatePhoneSession') @@ -1044,7 +1044,7 @@ App::post('/v1/account/sessions/anonymous') ->label('event', 'users.[userId].sessions.[sessionId].create') ->label('scope', 'public') ->label('auth.type', 'anonymous') - ->label('audits.resource', 'user/{payload.$id}') + ->label('audits.resource', 'user/{response.$id}') ->label('sdk.auth', []) ->label('sdk.namespace', 'account') ->label('sdk.method', 'createAnonymousSession') @@ -1399,7 +1399,7 @@ App::patch('/v1/account/name') ->groups(['api', 'account']) ->label('event', 'users.[userId].update.name') ->label('scope', 'account') - ->label('audits.resource', 'user/{payload.$id}') + ->label('audits.resource', 'user/{response.$id}') ->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_JWT]) ->label('sdk.namespace', 'account') ->label('sdk.method', 'updateName') @@ -1430,7 +1430,7 @@ App::patch('/v1/account/password') ->groups(['api', 'account']) ->label('event', 'users.[userId].update.password') ->label('scope', 'account') - ->label('audits.resource', 'user/{payload.$id}') + ->label('audits.resource', 'user/{response.$id}') ->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_JWT]) ->label('sdk.namespace', 'account') ->label('sdk.method', 'updatePassword') @@ -1471,7 +1471,7 @@ App::patch('/v1/account/email') ->groups(['api', 'account']) ->label('event', 'users.[userId].update.email') ->label('scope', 'account') - ->label('audits.resource', 'user/{payload.$id}') + ->label('audits.resource', 'user/{response.$id}') ->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_JWT]) ->label('sdk.namespace', 'account') ->label('sdk.method', 'updateEmail') @@ -1522,7 +1522,7 @@ App::patch('/v1/account/phone') ->groups(['api', 'account']) ->label('event', 'users.[userId].update.phone') ->label('scope', 'account') - ->label('audits.resource', 'user/{payload.$id}') + ->label('audits.resource', 'user/{response.$id}') ->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_JWT]) ->label('sdk.namespace', 'account') ->label('sdk.method', 'updatePhone') @@ -1570,7 +1570,7 @@ App::patch('/v1/account/prefs') ->groups(['api', 'account']) ->label('event', 'users.[userId].update.prefs') ->label('scope', 'account') - ->label('audits.resource', 'user/{payload.$id}') + ->label('audits.resource', 'user/{response.$id}') ->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_JWT]) ->label('sdk.namespace', 'account') ->label('sdk.method', 'updatePrefs') @@ -1599,8 +1599,8 @@ App::patch('/v1/account/status') ->groups(['api', 'account']) ->label('event', 'users.[userId].update.status') ->label('scope', 'account') - ->label('audits.resource', 'user/{payload.$id}') - ->label('audits.payload', '*') + ->label('audits.resource', 'user/{response.$id}') + ->label('audits.payload', true) ->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_JWT]) ->label('sdk.namespace', 'account') ->label('sdk.method', 'updateStatus') @@ -1612,10 +1612,9 @@ App::patch('/v1/account/status') ->inject('response') ->inject('user') ->inject('dbForProject') - ->inject('audits') ->inject('events') ->inject('usage') - ->action(function (Request $request, Response $response, Document $user, Database $dbForProject, Audit $audits, Event $events, Stats $usage) { + ->action(function (Request $request, Response $response, Document $user, Database $dbForProject, Event $events, Stats $usage) { $user = $dbForProject->updateDocument('users', $user->getId(), $user->setAttribute('status', false)); @@ -1714,7 +1713,7 @@ App::patch('/v1/account/sessions/:sessionId') ->groups(['api', 'account']) ->label('scope', 'account') ->label('event', 'users.[userId].sessions.[sessionId].update') - ->label('audits.resource', 'user/{payload.$id}') + ->label('audits.resource', 'user/{response.$id}') ->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_JWT]) ->label('sdk.namespace', 'account') ->label('sdk.method', 'updateSession') @@ -1867,7 +1866,7 @@ App::post('/v1/account/recovery') ->groups(['api', 'account']) ->label('scope', 'public') ->label('event', 'users.[userId].recovery.[tokenId].create') - ->label('audits.resource', 'user/{payload.$id}') + ->label('audits.resource', 'user/{response.$id}') ->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_JWT]) ->label('sdk.namespace', 'account') ->label('sdk.method', 'createRecovery') @@ -1970,7 +1969,7 @@ App::put('/v1/account/recovery') ->groups(['api', 'account']) ->label('scope', 'public') ->label('event', 'users.[userId].recovery.[tokenId].update') - ->label('audits.resource', 'user/{payload.$id}') + ->label('audits.resource', 'user/{response.$id}') ->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_JWT]) ->label('sdk.namespace', 'account') ->label('sdk.method', 'updateRecovery') @@ -2038,7 +2037,7 @@ App::post('/v1/account/verification') ->groups(['api', 'account']) ->label('scope', 'account') ->label('event', 'users.[userId].verification.[tokenId].create') - ->label('audits.resource', 'user/{payload.$id}') + ->label('audits.resource', 'user/{response.$id}') ->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_JWT]) ->label('sdk.namespace', 'account') ->label('sdk.method', 'createVerification') @@ -2127,7 +2126,7 @@ App::put('/v1/account/verification') ->groups(['api', 'account']) ->label('scope', 'public') ->label('event', 'users.[userId].verification.[tokenId].update') - ->label('audits.resource', 'user/{payload.$id}') + ->label('audits.resource', 'user/{response.$id}') ->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_JWT]) ->label('sdk.namespace', 'account') ->label('sdk.method', 'updateVerification') @@ -2187,7 +2186,7 @@ App::post('/v1/account/verification/phone') ->groups(['api', 'account']) ->label('scope', 'account') ->label('event', 'users.[userId].verification.[tokenId].create') - ->label('audits.resource', 'user/{payload.$id}') + ->label('audits.resource', 'user/{response.$id}') ->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_JWT]) ->label('sdk.namespace', 'account') ->label('sdk.method', 'createPhoneVerification') @@ -2272,7 +2271,7 @@ App::put('/v1/account/verification/phone') ->groups(['api', 'account']) ->label('scope', 'public') ->label('event', 'users.[userId].verification.[tokenId].update') - ->label('audits.resource', 'user/{payload.$id}') + ->label('audits.resource', 'user/{response.$id}') ->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_JWT]) ->label('sdk.namespace', 'account') ->label('sdk.method', 'updatePhoneVerification') diff --git a/app/controllers/api/databases.php b/app/controllers/api/databases.php index df032a4dbc..dff09bc5e1 100644 --- a/app/controllers/api/databases.php +++ b/app/controllers/api/databases.php @@ -151,8 +151,8 @@ App::post('/v1/databases') ->groups(['api', 'database']) ->label('event', 'databases.[databaseId].create') ->label('scope', 'databases.write') - ->label('audits.resource', 'database/{payload.$id}') - ->label('audits.payload', '*') + ->label('audits.resource', 'database/{response.$id}') + ->label('audits.payload', true) ->label('sdk.auth', [APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'databases') ->label('sdk.method', 'create') @@ -377,8 +377,8 @@ App::put('/v1/databases/:databaseId') ->groups(['api', 'database']) ->label('scope', 'databases.write') ->label('event', 'databases.[databaseId].update') - ->label('audits.resource', 'database/{payload.$id}') - ->label('audits.payload', '*') + ->label('audits.resource', 'database/{response.$id}') + ->label('audits.payload', true) ->label('sdk.auth', [APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'databases') ->label('sdk.method', 'update') @@ -421,6 +421,7 @@ App::delete('/v1/databases/:databaseId') ->groups(['api', 'database']) ->label('scope', 'databases.write') ->label('event', 'databases.[databaseId].delete') + ->label('audits.resource', 'database/{request.databaseId}') ->label('sdk.auth', [APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'databases') ->label('sdk.method', 'delete') @@ -458,10 +459,7 @@ App::delete('/v1/databases/:databaseId') ->setPayload($response->output($database, Response::MODEL_DATABASE)) ; - $audits - ->setResource('database/' . $databaseId) - ->setPayload($database->getArrayCopy()) - ; + $audits->setPayload($database->getArrayCopy()); $usage->setParam('databases.delete', 1); @@ -475,7 +473,7 @@ App::post('/v1/databases/:databaseId/collections') ->label('event', 'databases.[databaseId].collections.[collectionId].create') ->label('scope', 'collections.write') ->label('audits.resource', 'database/{request.databaseId}/collection/{request.collectionId}') - ->label('audits.payload', '*') + ->label('audits.payload', true) ->label('sdk.auth', [APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'databases') ->label('sdk.method', 'createCollection') @@ -725,7 +723,7 @@ App::put('/v1/databases/:databaseId/collections/:collectionId') ->label('scope', 'collections.write') ->label('event', 'databases.[databaseId].collections.[collectionId].update') ->label('audits.resource', 'database/{request.databaseId}/collection/{request.collectionId}') - ->label('audits-payload', '*') + ->label('audits-payload', true) ->label('sdk.auth', [APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'databases') ->label('sdk.method', 'updateCollection') @@ -793,6 +791,7 @@ App::delete('/v1/databases/:databaseId/collections/:collectionId') ->groups(['api', 'database']) ->label('scope', 'collections.write') ->label('event', 'databases.[databaseId].collections.[collectionId].delete') + ->label('audits.resource', 'database/{request.databaseId}/collection/{request.collectionId}') ->label('sdk.auth', [APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'databases') ->label('sdk.method', 'deleteCollection') @@ -839,10 +838,7 @@ App::delete('/v1/databases/:databaseId/collections/:collectionId') ->setPayload($response->output($collection, Response::MODEL_COLLECTION)) ; - $audits - ->setResource('database/' . $databaseId . '/collection/' . $collectionId) - ->setPayload($collection->getArrayCopy()) - ; + $audits->setPayload($collection->getArrayCopy()); $usage ->setParam('databaseId', $databaseId) @@ -858,7 +854,7 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/attributes/string ->label('event', 'databases.[databaseId].collections.[collectionId].attributes.[attributeId].create') ->label('scope', 'collections.write') ->label('audits.resource', 'database/{request.databaseId}/collection/{request.collectionId}') - ->label('audits.payload', '*') + ->label('audits.payload', true) ->label('sdk.auth', [APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'databases') ->label('sdk.method', 'createStringAttribute') @@ -905,7 +901,7 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/attributes/email' ->label('event', 'databases.[databaseId].collections.[collectionId].attributes.[attributeId].create') ->label('scope', 'collections.write') ->label('audits.resource', 'database/{request.databaseId}/collection/{request.collectionId}') - ->label('audits.payload', '*') + ->label('audits.payload', true) ->label('sdk.namespace', 'databases') ->label('sdk.auth', [APP_AUTH_TYPE_KEY]) ->label('sdk.method', 'createEmailAttribute') @@ -946,7 +942,7 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/attributes/enum') ->label('event', 'databases.[databaseId].collections.[collectionId].attributes.[attributeId].create') ->label('scope', 'collections.write') ->label('audits.resource', 'database/{request.databaseId}/collection/{request.collectionId}') - ->label('audits.payload', '*') + ->label('audits.payload', true) ->label('sdk.namespace', 'databases') ->label('sdk.auth', [APP_AUTH_TYPE_KEY]) ->label('sdk.method', 'createEnumAttribute') @@ -1003,7 +999,7 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/attributes/ip') ->label('event', 'databases.[databaseId].collections.[collectionId].attributes.[attributeId].create') ->label('scope', 'collections.write') ->label('audits.resource', 'database/{request.databaseId}/collection/{request.collectionId}') - ->label('audits.payload', '*') + ->label('audits.payload', true) ->label('sdk.namespace', 'databases') ->label('sdk.auth', [APP_AUTH_TYPE_KEY]) ->label('sdk.method', 'createIpAttribute') @@ -1044,7 +1040,7 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/attributes/url') ->label('event', 'databases.[databaseId].collections.[collectionId].attributes.[attributeId].create') ->label('scope', 'collections.write') ->label('audits.resource', 'database/{request.databaseId}/collection/{request.collectionId}') - ->label('audits.payload', '*') + ->label('audits.payload', true) ->label('sdk.namespace', 'databases') ->label('sdk.auth', [APP_AUTH_TYPE_KEY]) ->label('sdk.method', 'createUrlAttribute') @@ -1085,7 +1081,7 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/attributes/intege ->label('event', 'databases.[databaseId].collections.[collectionId].attributes.[attributeId].create') ->label('scope', 'collections.write') ->label('audits.resource', 'database/{request.databaseId}/collection/{request.collectionId}') - ->label('audits.payload', '*') + ->label('audits.payload', true) ->label('sdk.namespace', 'databases') ->label('sdk.auth', [APP_AUTH_TYPE_KEY]) ->label('sdk.method', 'createIntegerAttribute') @@ -1155,7 +1151,7 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/attributes/float' ->label('event', 'databases.[databaseId].collections.[collectionId].attributes.[attributeId].create') ->label('scope', 'collections.write') ->label('audits.resource', 'database/{request.databaseId}/collection/{request.collectionId}') - ->label('audits.payload', '*') + ->label('audits.payload', true) ->label('sdk.namespace', 'databases') ->label('sdk.auth', [APP_AUTH_TYPE_KEY]) ->label('sdk.method', 'createFloatAttribute') @@ -1228,7 +1224,7 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/attributes/boolea ->label('event', 'databases.[databaseId].collections.[collectionId].attributes.[attributeId].create') ->label('scope', 'collections.write') ->label('audits.resource', 'database/{request.databaseId}/collection/{request.collectionId}') - ->label('audits.payload', '*') + ->label('audits.payload', true) ->label('sdk.namespace', 'databases') ->label('sdk.auth', [APP_AUTH_TYPE_KEY]) ->label('sdk.method', 'createBooleanAttribute') @@ -1380,6 +1376,7 @@ App::delete('/v1/databases/:databaseId/collections/:collectionId/attributes/:key ->groups(['api', 'database']) ->label('scope', 'collections.write') ->label('event', 'databases.[databaseId].collections.[collectionId].attributes.[attributeId].delete') + ->label('audits.resource', 'database/{request.databaseId}/collection/{request.collectionId}') ->label('sdk.auth', [APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'databases') ->label('sdk.method', 'deleteAttribute') @@ -1460,10 +1457,7 @@ App::delete('/v1/databases/:databaseId/collections/:collectionId/attributes/:key ->setPayload($response->output($attribute, $model)) ; - $audits - ->setResource('database/' . $databaseId . '/collection/' . $collectionId) - ->setPayload($attribute->getArrayCopy()) - ; + $audits->setPayload($attribute->getArrayCopy()); $response->noContent(); }); @@ -1475,7 +1469,7 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/indexes') ->label('event', 'databases.[databaseId].collections.[collectionId].indexes.[indexId].create') ->label('scope', 'collections.write') ->label('audits.resource', 'database/{request.databaseId}/collection/{request.collectionId}') - ->label('audits.payload', '*') + ->label('audits.payload', true) ->label('sdk.auth', [APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'databases') ->label('sdk.method', 'createIndex') @@ -1719,6 +1713,7 @@ App::delete('/v1/databases/:databaseId/collections/:collectionId/indexes/:key') ->groups(['api', 'database']) ->label('scope', 'collections.write') ->label('event', 'databases.[databaseId].collections.[collectionId].indexes.[indexId].delete') + ->label('audits.resource', 'database/{request.databaseId}/collection/{request.collectionId}') ->label('sdk.auth', [APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'databases') ->label('sdk.method', 'deleteIndex') @@ -1780,10 +1775,7 @@ App::delete('/v1/databases/:databaseId/collections/:collectionId/indexes/:key') ->setPayload($response->output($index, Response::MODEL_INDEX)) ; - $audits - ->setResource('database/' . $databaseId . '/collection/' . $collection->getId()) - ->setPayload($index->getArrayCopy()) - ; + $audits->setPayload($index->getArrayCopy()); $response->noContent(); }); @@ -1795,7 +1787,7 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/documents') ->label('event', 'databases.[databaseId].collections.[collectionId].documents.[documentId].create') ->label('scope', 'documents.write') ->label('audits.resource', 'database/{request.databaseId}/collection/{request.collectionId}') - ->label('audits.payload', '*') + ->label('audits.payload', true) ->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_KEY, APP_AUTH_TYPE_JWT]) ->label('sdk.namespace', 'databases') ->label('sdk.method', 'createDocument') @@ -2191,8 +2183,8 @@ App::patch('/v1/databases/:databaseId/collections/:collectionId/documents/:docum ->groups(['api', 'database']) ->label('event', 'databases.[databaseId].collections.[collectionId].documents.[documentId].update') ->label('scope', 'documents.write') - ->label('audits.resource', 'database/{request.databaseId}/collection/{request.collectionId}/document/{payload.$id}') - ->label('audits.payload', '*') + ->label('audits.resource', 'database/{request.databaseId}/collection/{request.collectionId}/document/{response.$id}') + ->label('audits.payload', true) ->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_KEY, APP_AUTH_TYPE_JWT]) ->label('sdk.namespace', 'databases') ->label('sdk.method', 'updateDocument') @@ -2326,6 +2318,7 @@ App::delete('/v1/databases/:databaseId/collections/:collectionId/documents/:docu ->groups(['api', 'database']) ->label('scope', 'documents.write') ->label('event', 'databases.[databaseId].collections.[collectionId].documents.[documentId].delete') + ->label('audits.resource', 'database/{request.databaseId}/collection/{request.collectionId}/document/{request.documentId}') ->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_KEY, APP_AUTH_TYPE_JWT]) ->label('sdk.namespace', 'databases') ->label('sdk.method', 'deleteDocument') @@ -2412,10 +2405,7 @@ App::delete('/v1/databases/:databaseId/collections/:collectionId/documents/:docu ->setPayload($response->output($document, Response::MODEL_DOCUMENT)) ; - $audits - ->setResource('database/' . $databaseId . '/collection/' . $collectionId . '/document/' . $document->getId()) - ->setPayload($document->getArrayCopy()) - ; + $audits->setPayload($document->getArrayCopy()); $response->noContent(); }); diff --git a/app/controllers/api/storage.php b/app/controllers/api/storage.php index abcd97da25..eb58bc0f82 100644 --- a/app/controllers/api/storage.php +++ b/app/controllers/api/storage.php @@ -46,8 +46,8 @@ App::post('/v1/storage/buckets') ->groups(['api', 'storage']) ->label('scope', 'buckets.write') ->label('event', 'buckets.[bucketId].create') - ->label('audits.resource', 'storage/buckets/{payload.$id}') - ->label('audits.payload', '*') + ->label('audits.resource', 'storage/buckets/{response.$id}') + ->label('audits.payload', true) ->label('sdk.auth', [APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'storage') ->label('sdk.method', 'createBucket') @@ -210,8 +210,8 @@ App::put('/v1/storage/buckets/:bucketId') ->groups(['api', 'storage']) ->label('scope', 'buckets.write') ->label('event', 'buckets.[bucketId].update') - ->label('audits.resource', 'storage/buckets/{payload.$id}') - ->label('audits.payload', '*') + ->label('audits.resource', 'storage/buckets/{response.$id}') + ->label('audits.payload', true) ->label('sdk.auth', [APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'storage') ->label('sdk.method', 'updateBucket') @@ -273,6 +273,7 @@ App::delete('/v1/storage/buckets/:bucketId') ->groups(['api', 'storage']) ->label('scope', 'buckets.write') ->label('event', 'buckets.[bucketId].delete') + ->label('audits.resource', 'storage/buckets/{request.bucketId}') ->label('sdk.auth', [APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'storage') ->label('sdk.method', 'deleteBucket') @@ -306,10 +307,7 @@ App::delete('/v1/storage/buckets/:bucketId') ->setPayload($response->output($bucket, Response::MODEL_BUCKET)) ; - $audits - ->setResource('storage/buckets/' . $bucket->getId()) - ->setPayload($bucket->getArrayCopy()) - ; + $audits->setPayload($bucket->getArrayCopy()); $usage->setParam('storage.buckets.delete', 1); @@ -322,7 +320,7 @@ App::post('/v1/storage/buckets/:bucketId/files') ->groups(['api', 'storage']) ->label('scope', 'files.write') ->label('event', 'buckets.[bucketId].files.[fileId].create') - ->label('audits.resource', 'storage/files/{payload.$id}') + ->label('audits.resource', 'storage/files/{response.$id}') ->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_KEY, APP_AUTH_TYPE_JWT]) ->label('sdk.namespace', 'storage') ->label('sdk.method', 'createFile') @@ -1267,7 +1265,7 @@ App::put('/v1/storage/buckets/:bucketId/files/:fileId') ->groups(['api', 'storage']) ->label('scope', 'files.write') ->label('event', 'buckets.[bucketId].files.[fileId].update') - ->label('audits.resource', 'storage/files/{payload.$id}') + ->label('audits.resource', 'storage/files/{response.$id}') ->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_KEY, APP_AUTH_TYPE_JWT]) ->label('sdk.namespace', 'storage') ->label('sdk.method', 'updateFile') @@ -1362,6 +1360,7 @@ App::delete('/v1/storage/buckets/:bucketId/files/:fileId') ->groups(['api', 'storage']) ->label('scope', 'files.write') ->label('event', 'buckets.[bucketId].files.[fileId].delete') + ->label('audits.resource', 'file/{request.fileId}') ->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_KEY, APP_AUTH_TYPE_JWT]) ->label('sdk.namespace', 'storage') ->label('sdk.method', 'deleteFile') @@ -1373,12 +1372,11 @@ App::delete('/v1/storage/buckets/:bucketId/files/:fileId') ->inject('response') ->inject('dbForProject') ->inject('events') - ->inject('audits') ->inject('usage') ->inject('mode') ->inject('deviceFiles') ->inject('project') - ->action(function (string $bucketId, string $fileId, Response $response, Database $dbForProject, Event $events, Audit $audits, Stats $usage, string $mode, Device $deviceFiles, Document $project) { + ->action(function (string $bucketId, string $fileId, Response $response, Database $dbForProject, Event $events, Stats $usage, string $mode, Device $deviceFiles, Document $project) { $bucket = Authorization::skip(fn () => $dbForProject->getDocument('buckets', $bucketId)); if ( @@ -1434,8 +1432,6 @@ App::delete('/v1/storage/buckets/:bucketId/files/:fileId') throw new Exception('Failed to delete file from device', 500, Exception::GENERAL_SERVER_ERROR); } - $audits->setResource('file/' . $file->getId()); - $usage ->setParam('storage', $file->getAttribute('size', 0) * -1) ->setParam('storage.files.delete', 1) diff --git a/app/controllers/api/teams.php b/app/controllers/api/teams.php index 79e1ac3d18..14141b20bc 100644 --- a/app/controllers/api/teams.php +++ b/app/controllers/api/teams.php @@ -36,6 +36,8 @@ App::post('/v1/teams') ->groups(['api', 'teams']) ->label('event', 'teams.[teamId].create') ->label('scope', 'teams.write') + ->label('audits.resource', 'team/{response.$id}') + ->label('audits.payload', true) ->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_KEY, APP_AUTH_TYPE_JWT]) ->label('sdk.namespace', 'teams') ->label('sdk.method', 'create') @@ -50,8 +52,7 @@ App::post('/v1/teams') ->inject('user') ->inject('dbForProject') ->inject('events') - ->inject('audits') - ->action(function (string $teamId, string $name, array $roles, Response $response, Document $user, Database $dbForProject, Event $events, Event $audits) { + ->action(function (string $teamId, string $name, array $roles, Response $response, Document $user, Database $dbForProject, Event $events) { $isPrivilegedUser = Auth::isPrivilegedUser(Authorization::getRoles()); $isAppUser = Auth::isAppUser(Authorization::getRoles()); @@ -94,12 +95,6 @@ App::post('/v1/teams') $events->setParam('userId', $user->getId()); } - $audits - ->setParam('event', 'teams.create') - ->setParam('resource', 'team/' . $teamId) - ->setParam('data', $team->getArrayCopy()) - ; - $response->setStatusCode(Response::STATUS_CODE_CREATED); $response->dynamic($team, Response::MODEL_TEAM); }); @@ -178,6 +173,7 @@ App::put('/v1/teams/:teamId') ->groups(['api', 'teams']) ->label('event', 'teams.[teamId].update') ->label('scope', 'teams.write') + ->label('audits.resource', 'team/{response.$id}') ->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_KEY, APP_AUTH_TYPE_JWT]) ->label('sdk.namespace', 'teams') ->label('sdk.method', 'update') @@ -190,8 +186,7 @@ App::put('/v1/teams/:teamId') ->inject('response') ->inject('dbForProject') ->inject('events') - ->inject('audits') - ->action(function (string $teamId, string $name, Response $response, Database $dbForProject, Event $events, EventAudit $audits) { + ->action(function (string $teamId, string $name, Response $response, Database $dbForProject, Event $events) { $team = $dbForProject->getDocument('teams', $teamId); @@ -204,7 +199,6 @@ App::put('/v1/teams/:teamId') ->setAttribute('search', implode(' ', [$teamId, $name]))); $events->setParam('teamId', $team->getId()); - $audits->setResource('team/' . $team->getId()); $response->dynamic($team, Response::MODEL_TEAM); }); @@ -259,7 +253,6 @@ App::delete('/v1/teams/:teamId') ; $audits - ->setParam('event', 'teams.delete') ->setParam('resource', 'team/' . $teamId) ->setParam('data', $team->getArrayCopy()) ; @@ -273,6 +266,7 @@ App::post('/v1/teams/:teamId/memberships') ->label('event', 'teams.[teamId].memberships.[membershipId].create') ->label('scope', 'teams.write') ->label('auth.type', 'invites') + ->label('audits.resource', 'team/{response.$id}') ->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_KEY, APP_AUTH_TYPE_JWT]) ->label('sdk.namespace', 'teams') ->label('sdk.method', 'createMembership') @@ -291,10 +285,9 @@ App::post('/v1/teams/:teamId/memberships') ->inject('user') ->inject('dbForProject') ->inject('locale') - ->inject('audits') ->inject('mails') ->inject('events') - ->action(function (string $teamId, string $email, array $roles, string $url, string $name, Response $response, Document $project, Document $user, Database $dbForProject, Locale $locale, EventAudit $audits, Mail $mails, Event $events) { + ->action(function (string $teamId, string $email, array $roles, string $url, string $name, Response $response, Document $project, Document $user, Database $dbForProject, Locale $locale, Mail $mails, Event $events) { $isPrivilegedUser = Auth::isPrivilegedUser(Authorization::getRoles()); $isAppUser = Auth::isAppUser(Authorization::getRoles()); @@ -414,10 +407,6 @@ App::post('/v1/teams/:teamId/memberships') ; } - $audits - ->setResource('team/' . $teamId) - ; - $events ->setParam('teamId', $team->getId()) ->setParam('membershipId', $membership->getId()) @@ -556,6 +545,7 @@ App::patch('/v1/teams/:teamId/memberships/:membershipId') ->groups(['api', 'teams']) ->label('event', 'teams.[teamId].memberships.[membershipId].update') ->label('scope', 'teams.write') + ->label('audits.resource', 'team/{response.$id}') ->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_KEY, APP_AUTH_TYPE_JWT]) ->label('sdk.namespace', 'teams') ->label('sdk.method', 'updateMembershipRoles') @@ -570,9 +560,8 @@ App::patch('/v1/teams/:teamId/memberships/:membershipId') ->inject('response') ->inject('user') ->inject('dbForProject') - ->inject('audits') ->inject('events') - ->action(function (string $teamId, string $membershipId, array $roles, Request $request, Response $response, Document $user, Database $dbForProject, EventAudit $audits, Event $events) { + ->action(function (string $teamId, string $membershipId, array $roles, Request $request, Response $response, Document $user, Database $dbForProject, Event $events) { $team = $dbForProject->getDocument('teams', $teamId); if ($team->isEmpty()) { @@ -608,8 +597,6 @@ App::patch('/v1/teams/:teamId/memberships/:membershipId') */ $dbForProject->deleteCachedDocument('users', $profile->getId()); - $audits->setResource('team/' . $teamId); - $events ->setParam('teamId', $team->getId()) ->setParam('membershipId', $membership->getId()); @@ -628,6 +615,7 @@ App::patch('/v1/teams/:teamId/memberships/:membershipId/status') ->groups(['api', 'teams']) ->label('event', 'teams.[teamId].memberships.[membershipId].update.status') ->label('scope', 'public') + ->label('audits.resource', 'team/{response.$id}') ->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_JWT]) ->label('sdk.namespace', 'teams') ->label('sdk.method', 'updateMembershipStatus') @@ -644,9 +632,8 @@ App::patch('/v1/teams/:teamId/memberships/:membershipId/status') ->inject('user') ->inject('dbForProject') ->inject('geodb') - ->inject('audits') ->inject('events') - ->action(function (string $teamId, string $membershipId, string $userId, string $secret, Request $request, Response $response, Document $user, Database $dbForProject, Reader $geodb, EventAudit $audits, Event $events) { + ->action(function (string $teamId, string $membershipId, string $userId, string $secret, Request $request, Response $response, Document $user, Database $dbForProject, Reader $geodb, Event $events) { $protocol = $request->getProtocol(); $membership = $dbForProject->getDocument('memberships', $membershipId); @@ -729,8 +716,6 @@ App::patch('/v1/teams/:teamId/memberships/:membershipId/status') $team = Authorization::skip(fn() => $dbForProject->updateDocument('teams', $team->getId(), $team->setAttribute('total', $team->getAttribute('total', 0) + 1))); - $audits->setResource('team/' . $teamId); - $events ->setParam('teamId', $team->getId()) ->setParam('membershipId', $membership->getId()) @@ -761,6 +746,7 @@ App::delete('/v1/teams/:teamId/memberships/:membershipId') ->groups(['api', 'teams']) ->label('event', 'teams.[teamId].memberships.[membershipId].delete') ->label('scope', 'teams.write') + ->label('audits.resource', 'team/{request.teamId}') ->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_KEY, APP_AUTH_TYPE_JWT]) ->label('sdk.namespace', 'teams') ->label('sdk.method', 'deleteMembership') @@ -771,9 +757,8 @@ App::delete('/v1/teams/:teamId/memberships/:membershipId') ->param('membershipId', '', new UID(), 'Membership ID.') ->inject('response') ->inject('dbForProject') - ->inject('audits') ->inject('events') - ->action(function (string $teamId, string $membershipId, Response $response, Database $dbForProject, EventAudit $audits, Event $events) { + ->action(function (string $teamId, string $membershipId, Response $response, Database $dbForProject, Event $events) { $membership = $dbForProject->getDocument('memberships', $membershipId); @@ -812,8 +797,6 @@ App::delete('/v1/teams/:teamId/memberships/:membershipId') Authorization::skip(fn() => $dbForProject->updateDocument('teams', $team->getId(), $team)); } - $audits->setResource('team/' . $teamId); - $events ->setParam('teamId', $team->getId()) ->setParam('membershipId', $membership->getId()) diff --git a/app/controllers/api/users.php b/app/controllers/api/users.php index 8845db4810..b8bce1932c 100644 --- a/app/controllers/api/users.php +++ b/app/controllers/api/users.php @@ -483,6 +483,7 @@ App::patch('/v1/users/:userId/name') ->groups(['api', 'users']) ->label('event', 'users.[userId].update.name') ->label('scope', 'users.write') + ->label('audits.resource', 'user/{response.$id}') ->label('sdk.auth', [APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'users') ->label('sdk.method', 'updateName') @@ -494,9 +495,8 @@ App::patch('/v1/users/:userId/name') ->param('name', '', new Text(128), 'User name. Max length: 128 chars.') ->inject('response') ->inject('dbForProject') - ->inject('audits') ->inject('events') - ->action(function (string $userId, string $name, Response $response, Database $dbForProject, EventAudit $audits, Event $events) { + ->action(function (string $userId, string $name, Response $response, Database $dbForProject, Event $events) { $user = $dbForProject->getDocument('users', $userId); @@ -511,13 +511,7 @@ App::patch('/v1/users/:userId/name') $user = $dbForProject->updateDocument('users', $user->getId(), $user); - $audits - ->setResource('user/' . $user->getId()) - ; - - $events - ->setParam('userId', $user->getId()) - ; + $events->setParam('userId', $user->getId()); $response->dynamic($user, Response::MODEL_USER); }); @@ -527,6 +521,7 @@ App::patch('/v1/users/:userId/password') ->groups(['api', 'users']) ->label('event', 'users.[userId].update.password') ->label('scope', 'users.write') + ->label('audits.resource', 'user/{response.$id}') ->label('sdk.auth', [APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'users') ->label('sdk.method', 'updatePassword') @@ -538,9 +533,8 @@ App::patch('/v1/users/:userId/password') ->param('password', '', new Password(), 'New user password. Must be at least 8 chars.') ->inject('response') ->inject('dbForProject') - ->inject('audits') ->inject('events') - ->action(function (string $userId, string $password, Response $response, Database $dbForProject, EventAudit $audits, Event $events) { + ->action(function (string $userId, string $password, Response $response, Database $dbForProject, Event $events) { $user = $dbForProject->getDocument('users', $userId); @@ -554,13 +548,7 @@ App::patch('/v1/users/:userId/password') $user = $dbForProject->updateDocument('users', $user->getId(), $user); - $audits - ->setResource('user/' . $user->getId()) - ; - - $events - ->setParam('userId', $user->getId()) - ; + $events->setParam('userId', $user->getId()); $response->dynamic($user, Response::MODEL_USER); }); @@ -570,6 +558,7 @@ App::patch('/v1/users/:userId/email') ->groups(['api', 'users']) ->label('event', 'users.[userId].update.email') ->label('scope', 'users.write') + ->label('audits.resource', 'user/{response.$id}') ->label('sdk.auth', [APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'users') ->label('sdk.method', 'updateEmail') @@ -581,9 +570,8 @@ App::patch('/v1/users/:userId/email') ->param('email', '', new Email(), 'User email.') ->inject('response') ->inject('dbForProject') - ->inject('audits') ->inject('events') - ->action(function (string $userId, string $email, Response $response, Database $dbForProject, EventAudit $audits, Event $events) { + ->action(function (string $userId, string $email, Response $response, Database $dbForProject, Event $events) { $user = $dbForProject->getDocument('users', $userId); @@ -605,11 +593,6 @@ App::patch('/v1/users/:userId/email') throw new Exception('Email already exists', 409, Exception::USER_EMAIL_ALREADY_EXISTS); } - - $audits - ->setResource('user/' . $user->getId()) - ; - $events ->setParam('userId', $user->getId()) ; @@ -622,6 +605,7 @@ App::patch('/v1/users/:userId/phone') ->groups(['api', 'users']) ->label('event', 'users.[userId].update.phone') ->label('scope', 'users.write') + ->label('audits.resource', 'user/{response.$id}') ->label('sdk.auth', [APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'users') ->label('sdk.method', 'updatePhone') @@ -633,9 +617,8 @@ App::patch('/v1/users/:userId/phone') ->param('number', '', new Phone(), 'User phone number.') ->inject('response') ->inject('dbForProject') - ->inject('audits') ->inject('events') - ->action(function (string $userId, string $number, Response $response, Database $dbForProject, EventAudit $audits, Event $events) { + ->action(function (string $userId, string $number, Response $response, Database $dbForProject, Event $events) { $user = $dbForProject->getDocument('users', $userId); @@ -654,14 +637,7 @@ App::patch('/v1/users/:userId/phone') throw new Exception('Email already exists', 409, Exception::USER_EMAIL_ALREADY_EXISTS); } - - $audits - ->setResource('user/' . $user->getId()) - ; - - $events - ->setParam('userId', $user->getId()) - ; + $events->setParam('userId', $user->getId()); $response->dynamic($user, Response::MODEL_USER); }); diff --git a/app/controllers/shared/api.php b/app/controllers/shared/api.php index e63e48095d..8d8c0b29c8 100644 --- a/app/controllers/shared/api.php +++ b/app/controllers/shared/api.php @@ -281,7 +281,7 @@ App::shutdown() list($namespace, $replace) = explode('.', $match); switch ($namespace) { - case 'payload': + case 'response': $params = $responsePayload; break; case 'request': @@ -299,7 +299,7 @@ App::shutdown() return $label; }; - $auditsResource = $route->getLabel('audits.resource',''); + $auditsResource = $route->getLabel('audits.resource',null); if(!empty($auditsResource)) { $resource = $parseLabel($auditsResource); if(!empty($resource)) { @@ -307,14 +307,11 @@ App::shutdown() } } - $auditsPayload = $route->getLabel('audits.payload',''); + $auditsPayload = $route->getLabel('audits.payload',false); if(!empty($auditsPayload)) { - if($auditsPayload === '*'){ - $audits->setPayload($responsePayload); - } + $audits->setPayload($responsePayload); } - if (!empty($audits->getResource())) { foreach ($events->getParams() as $key => $value) { $audits->setParam($key, $value); From 8a79748b6d61b0c7848be360c333a170377cc3d8 Mon Sep 17 00:00:00 2001 From: shimon Date: Mon, 8 Aug 2022 17:48:51 +0300 Subject: [PATCH 07/46] leftovers --- app/controllers/shared/api.php | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/app/controllers/shared/api.php b/app/controllers/shared/api.php index 8d8c0b29c8..f8ab7a46af 100644 --- a/app/controllers/shared/api.php +++ b/app/controllers/shared/api.php @@ -260,7 +260,7 @@ App::shutdown() $route = $utopia->match($request); - $getRequestParams = function() use ($route, $request) { + $getRequestParams = function() use ($route, $request): array { $url = \parse_url($request->getURI(), PHP_URL_PATH); $regex = '@' . \preg_replace('@:[^/]+@', '([^/]+)', $route->getPath()) . '@'; \preg_match($regex, $url, $matches); @@ -274,11 +274,16 @@ App::shutdown() }; - $parseLabel = function ($label) use ($responsePayload, $getRequestParams) { + $parseLabel = function ($label) use ($responsePayload, $getRequestParams) :string { preg_match_all('/{(.*?)}/', $label, $matches); foreach ($matches[1] ?? [] as $pos => $match) { $find = $matches[0][$pos]; - list($namespace, $replace) = explode('.', $match); + $parts = explode('.', $match); + if(count($parts) < 2){ + return ''; + } + $namespace = $parts[0]; + $replace = $parts[1]; switch ($namespace) { case 'response': From 2d7a2bb57f5e346d66f25175692f4861986c06db Mon Sep 17 00:00:00 2001 From: shimon Date: Mon, 8 Aug 2022 18:23:45 +0300 Subject: [PATCH 08/46] leftovers --- app/controllers/api/teams.php | 6 +++--- app/controllers/shared/api.php | 1 + 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/app/controllers/api/teams.php b/app/controllers/api/teams.php index 14141b20bc..0ccba7a69a 100644 --- a/app/controllers/api/teams.php +++ b/app/controllers/api/teams.php @@ -266,7 +266,7 @@ App::post('/v1/teams/:teamId/memberships') ->label('event', 'teams.[teamId].memberships.[membershipId].create') ->label('scope', 'teams.write') ->label('auth.type', 'invites') - ->label('audits.resource', 'team/{response.$id}') + ->label('audits.resource', 'team/{response.teamId}') ->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_KEY, APP_AUTH_TYPE_JWT]) ->label('sdk.namespace', 'teams') ->label('sdk.method', 'createMembership') @@ -545,7 +545,7 @@ App::patch('/v1/teams/:teamId/memberships/:membershipId') ->groups(['api', 'teams']) ->label('event', 'teams.[teamId].memberships.[membershipId].update') ->label('scope', 'teams.write') - ->label('audits.resource', 'team/{response.$id}') + ->label('audits.resource', 'team/{response.teamId}') ->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_KEY, APP_AUTH_TYPE_JWT]) ->label('sdk.namespace', 'teams') ->label('sdk.method', 'updateMembershipRoles') @@ -615,7 +615,7 @@ App::patch('/v1/teams/:teamId/memberships/:membershipId/status') ->groups(['api', 'teams']) ->label('event', 'teams.[teamId].memberships.[membershipId].update.status') ->label('scope', 'public') - ->label('audits.resource', 'team/{response.$id}') + ->label('audits.resource', 'team/{response.teamId}') ->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_JWT]) ->label('sdk.namespace', 'teams') ->label('sdk.method', 'updateMembershipStatus') diff --git a/app/controllers/shared/api.php b/app/controllers/shared/api.php index f8ab7a46af..722b3c0d14 100644 --- a/app/controllers/shared/api.php +++ b/app/controllers/shared/api.php @@ -307,6 +307,7 @@ App::shutdown() $auditsResource = $route->getLabel('audits.resource',null); if(!empty($auditsResource)) { $resource = $parseLabel($auditsResource); + var_dump($resource); if(!empty($resource)) { $audits->setResource($resource); } From 6e0b7cc65071ba007a8e7bb1e590b2befc155d74 Mon Sep 17 00:00:00 2001 From: shimon Date: Mon, 8 Aug 2022 18:44:11 +0300 Subject: [PATCH 09/46] leftovers --- app/controllers/api/databases.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/controllers/api/databases.php b/app/controllers/api/databases.php index dff09bc5e1..ac48b7a72a 100644 --- a/app/controllers/api/databases.php +++ b/app/controllers/api/databases.php @@ -472,7 +472,7 @@ App::post('/v1/databases/:databaseId/collections') ->groups(['api', 'database']) ->label('event', 'databases.[databaseId].collections.[collectionId].create') ->label('scope', 'collections.write') - ->label('audits.resource', 'database/{request.databaseId}/collection/{request.collectionId}') + ->label('audits.resource', 'database/{request.databaseId}/collection/{response.$id}') ->label('audits.payload', true) ->label('sdk.auth', [APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'databases') From 9eb1c3a731dcc23404d06b8c60f7f245e2800ca6 Mon Sep 17 00:00:00 2001 From: shimon Date: Mon, 8 Aug 2022 18:44:45 +0300 Subject: [PATCH 10/46] leftovers --- app/controllers/shared/api.php | 1 - 1 file changed, 1 deletion(-) diff --git a/app/controllers/shared/api.php b/app/controllers/shared/api.php index 722b3c0d14..f8ab7a46af 100644 --- a/app/controllers/shared/api.php +++ b/app/controllers/shared/api.php @@ -307,7 +307,6 @@ App::shutdown() $auditsResource = $route->getLabel('audits.resource',null); if(!empty($auditsResource)) { $resource = $parseLabel($auditsResource); - var_dump($resource); if(!empty($resource)) { $audits->setResource($resource); } From eb9ca5d7e3f9e5cba73ac4e40a608eabf26415d7 Mon Sep 17 00:00:00 2001 From: shimon Date: Tue, 9 Aug 2022 09:49:55 +0300 Subject: [PATCH 11/46] leftovers --- app/controllers/shared/api.php | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/app/controllers/shared/api.php b/app/controllers/shared/api.php index f8ab7a46af..8884484913 100644 --- a/app/controllers/shared/api.php +++ b/app/controllers/shared/api.php @@ -279,9 +279,11 @@ App::shutdown() foreach ($matches[1] ?? [] as $pos => $match) { $find = $matches[0][$pos]; $parts = explode('.', $match); - if(count($parts) < 2){ + + if(count($parts) !== 2){ return ''; } + $namespace = $parts[0]; $replace = $parts[1]; @@ -293,7 +295,7 @@ App::shutdown() $params = $getRequestParams(); break; default: - $responsePayload; + $params = $responsePayload; } if(array_key_exists($replace, $params)){ @@ -307,7 +309,7 @@ App::shutdown() $auditsResource = $route->getLabel('audits.resource',null); if(!empty($auditsResource)) { $resource = $parseLabel($auditsResource); - if(!empty($resource)) { + if(!empty($resource) && $resource !== $auditsResource) { $audits->setResource($resource); } } From d2519c9a5b78a11810820d105cba50ccb885e40c Mon Sep 17 00:00:00 2001 From: shimon Date: Tue, 9 Aug 2022 17:38:54 +0300 Subject: [PATCH 12/46] addressing comments --- app/controllers/api/account.php | 1 - app/controllers/api/databases.php | 14 -------------- app/controllers/api/functions.php | 7 +++++++ app/controllers/api/storage.php | 2 -- app/controllers/api/teams.php | 1 - app/controllers/api/users.php | 1 - app/controllers/shared/api.php | 14 +++++++++----- docker-compose.yml | 1 - 8 files changed, 16 insertions(+), 25 deletions(-) diff --git a/app/controllers/api/account.php b/app/controllers/api/account.php index 0e4f40d8d2..2ce8e30e6e 100644 --- a/app/controllers/api/account.php +++ b/app/controllers/api/account.php @@ -1600,7 +1600,6 @@ App::patch('/v1/account/status') ->label('event', 'users.[userId].update.status') ->label('scope', 'account') ->label('audits.resource', 'user/{response.$id}') - ->label('audits.payload', true) ->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_JWT]) ->label('sdk.namespace', 'account') ->label('sdk.method', 'updateStatus') diff --git a/app/controllers/api/databases.php b/app/controllers/api/databases.php index ac48b7a72a..1d8e10f984 100644 --- a/app/controllers/api/databases.php +++ b/app/controllers/api/databases.php @@ -152,7 +152,6 @@ App::post('/v1/databases') ->label('event', 'databases.[databaseId].create') ->label('scope', 'databases.write') ->label('audits.resource', 'database/{response.$id}') - ->label('audits.payload', true) ->label('sdk.auth', [APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'databases') ->label('sdk.method', 'create') @@ -378,7 +377,6 @@ App::put('/v1/databases/:databaseId') ->label('scope', 'databases.write') ->label('event', 'databases.[databaseId].update') ->label('audits.resource', 'database/{response.$id}') - ->label('audits.payload', true) ->label('sdk.auth', [APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'databases') ->label('sdk.method', 'update') @@ -473,7 +471,6 @@ App::post('/v1/databases/:databaseId/collections') ->label('event', 'databases.[databaseId].collections.[collectionId].create') ->label('scope', 'collections.write') ->label('audits.resource', 'database/{request.databaseId}/collection/{response.$id}') - ->label('audits.payload', true) ->label('sdk.auth', [APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'databases') ->label('sdk.method', 'createCollection') @@ -854,7 +851,6 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/attributes/string ->label('event', 'databases.[databaseId].collections.[collectionId].attributes.[attributeId].create') ->label('scope', 'collections.write') ->label('audits.resource', 'database/{request.databaseId}/collection/{request.collectionId}') - ->label('audits.payload', true) ->label('sdk.auth', [APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'databases') ->label('sdk.method', 'createStringAttribute') @@ -901,7 +897,6 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/attributes/email' ->label('event', 'databases.[databaseId].collections.[collectionId].attributes.[attributeId].create') ->label('scope', 'collections.write') ->label('audits.resource', 'database/{request.databaseId}/collection/{request.collectionId}') - ->label('audits.payload', true) ->label('sdk.namespace', 'databases') ->label('sdk.auth', [APP_AUTH_TYPE_KEY]) ->label('sdk.method', 'createEmailAttribute') @@ -942,7 +937,6 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/attributes/enum') ->label('event', 'databases.[databaseId].collections.[collectionId].attributes.[attributeId].create') ->label('scope', 'collections.write') ->label('audits.resource', 'database/{request.databaseId}/collection/{request.collectionId}') - ->label('audits.payload', true) ->label('sdk.namespace', 'databases') ->label('sdk.auth', [APP_AUTH_TYPE_KEY]) ->label('sdk.method', 'createEnumAttribute') @@ -999,7 +993,6 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/attributes/ip') ->label('event', 'databases.[databaseId].collections.[collectionId].attributes.[attributeId].create') ->label('scope', 'collections.write') ->label('audits.resource', 'database/{request.databaseId}/collection/{request.collectionId}') - ->label('audits.payload', true) ->label('sdk.namespace', 'databases') ->label('sdk.auth', [APP_AUTH_TYPE_KEY]) ->label('sdk.method', 'createIpAttribute') @@ -1040,7 +1033,6 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/attributes/url') ->label('event', 'databases.[databaseId].collections.[collectionId].attributes.[attributeId].create') ->label('scope', 'collections.write') ->label('audits.resource', 'database/{request.databaseId}/collection/{request.collectionId}') - ->label('audits.payload', true) ->label('sdk.namespace', 'databases') ->label('sdk.auth', [APP_AUTH_TYPE_KEY]) ->label('sdk.method', 'createUrlAttribute') @@ -1081,7 +1073,6 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/attributes/intege ->label('event', 'databases.[databaseId].collections.[collectionId].attributes.[attributeId].create') ->label('scope', 'collections.write') ->label('audits.resource', 'database/{request.databaseId}/collection/{request.collectionId}') - ->label('audits.payload', true) ->label('sdk.namespace', 'databases') ->label('sdk.auth', [APP_AUTH_TYPE_KEY]) ->label('sdk.method', 'createIntegerAttribute') @@ -1151,7 +1142,6 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/attributes/float' ->label('event', 'databases.[databaseId].collections.[collectionId].attributes.[attributeId].create') ->label('scope', 'collections.write') ->label('audits.resource', 'database/{request.databaseId}/collection/{request.collectionId}') - ->label('audits.payload', true) ->label('sdk.namespace', 'databases') ->label('sdk.auth', [APP_AUTH_TYPE_KEY]) ->label('sdk.method', 'createFloatAttribute') @@ -1224,7 +1214,6 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/attributes/boolea ->label('event', 'databases.[databaseId].collections.[collectionId].attributes.[attributeId].create') ->label('scope', 'collections.write') ->label('audits.resource', 'database/{request.databaseId}/collection/{request.collectionId}') - ->label('audits.payload', true) ->label('sdk.namespace', 'databases') ->label('sdk.auth', [APP_AUTH_TYPE_KEY]) ->label('sdk.method', 'createBooleanAttribute') @@ -1469,7 +1458,6 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/indexes') ->label('event', 'databases.[databaseId].collections.[collectionId].indexes.[indexId].create') ->label('scope', 'collections.write') ->label('audits.resource', 'database/{request.databaseId}/collection/{request.collectionId}') - ->label('audits.payload', true) ->label('sdk.auth', [APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'databases') ->label('sdk.method', 'createIndex') @@ -1787,7 +1775,6 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/documents') ->label('event', 'databases.[databaseId].collections.[collectionId].documents.[documentId].create') ->label('scope', 'documents.write') ->label('audits.resource', 'database/{request.databaseId}/collection/{request.collectionId}') - ->label('audits.payload', true) ->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_KEY, APP_AUTH_TYPE_JWT]) ->label('sdk.namespace', 'databases') ->label('sdk.method', 'createDocument') @@ -2184,7 +2171,6 @@ App::patch('/v1/databases/:databaseId/collections/:collectionId/documents/:docum ->label('event', 'databases.[databaseId].collections.[collectionId].documents.[documentId].update') ->label('scope', 'documents.write') ->label('audits.resource', 'database/{request.databaseId}/collection/{request.collectionId}/document/{response.$id}') - ->label('audits.payload', true) ->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_KEY, APP_AUTH_TYPE_JWT]) ->label('sdk.namespace', 'databases') ->label('sdk.method', 'updateDocument') diff --git a/app/controllers/api/functions.php b/app/controllers/api/functions.php index 21b827042d..8c67624427 100644 --- a/app/controllers/api/functions.php +++ b/app/controllers/api/functions.php @@ -43,6 +43,7 @@ App::post('/v1/functions') ->desc('Create Function') ->label('scope', 'functions.write') ->label('event', 'functions.[functionId].create') + ->label('audits.resource', 'function/{response.$id}') ->label('sdk.auth', [APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'functions') ->label('sdk.method', 'create') @@ -281,6 +282,7 @@ App::put('/v1/functions/:functionId') ->desc('Update Function') ->label('scope', 'functions.write') ->label('event', 'functions.[functionId].update') + ->label('audits.resource', 'function/{response.$id}') ->label('sdk.auth', [APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'functions') ->label('sdk.method', 'update') @@ -345,6 +347,7 @@ App::patch('/v1/functions/:functionId/deployments/:deploymentId') ->desc('Update Function Deployment') ->label('scope', 'functions.write') ->label('event', 'functions.[functionId].deployments.[deploymentId].update') + ->label('audits.resource', 'function/{request.functionId}/deployment/{request.deploymentId}') ->label('sdk.auth', [APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'functions') ->label('sdk.method', 'updateDeployment') @@ -410,6 +413,7 @@ App::delete('/v1/functions/:functionId') ->desc('Delete Function') ->label('scope', 'functions.write') ->label('event', 'functions.[functionId].delete') + ->label('audits.resource', 'function/{request.functionId}') ->label('sdk.auth', [APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'functions') ->label('sdk.method', 'delete') @@ -447,6 +451,7 @@ App::post('/v1/functions/:functionId/deployments') ->desc('Create Deployment') ->label('scope', 'functions.write') ->label('event', 'functions.[functionId].deployments.[deploymentId].create') + ->label('audits.resource', 'function/{request.functionId}/deployment/{response.$id}') ->label('sdk.auth', [APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'functions') ->label('sdk.method', 'createDeployment') @@ -728,6 +733,7 @@ App::delete('/v1/functions/:functionId/deployments/:deploymentId') ->desc('Delete Deployment') ->label('scope', 'functions.write') ->label('event', 'functions.[functionId].deployments.[deploymentId].delete') + ->label('audits.resource', 'function/{request.functionId}/deployment/{request.deploymentId}') ->label('sdk.auth', [APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'functions') ->label('sdk.method', 'deleteDeployment') @@ -1063,6 +1069,7 @@ App::post('/v1/functions/:functionId/deployments/:deploymentId/builds/:buildId') ->desc('Retry Build') ->label('scope', 'functions.write') ->label('event', 'functions.[functionId].deployments.[deploymentId].update') + ->label('audits.resource', 'function/{request.functionId}/deployment/{request.deploymentId}/build/{request.buildId}') ->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_KEY, APP_AUTH_TYPE_JWT]) ->label('sdk.namespace', 'functions') ->label('sdk.method', 'retryBuild') diff --git a/app/controllers/api/storage.php b/app/controllers/api/storage.php index eb58bc0f82..06cc659261 100644 --- a/app/controllers/api/storage.php +++ b/app/controllers/api/storage.php @@ -47,7 +47,6 @@ App::post('/v1/storage/buckets') ->label('scope', 'buckets.write') ->label('event', 'buckets.[bucketId].create') ->label('audits.resource', 'storage/buckets/{response.$id}') - ->label('audits.payload', true) ->label('sdk.auth', [APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'storage') ->label('sdk.method', 'createBucket') @@ -211,7 +210,6 @@ App::put('/v1/storage/buckets/:bucketId') ->label('scope', 'buckets.write') ->label('event', 'buckets.[bucketId].update') ->label('audits.resource', 'storage/buckets/{response.$id}') - ->label('audits.payload', true) ->label('sdk.auth', [APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'storage') ->label('sdk.method', 'updateBucket') diff --git a/app/controllers/api/teams.php b/app/controllers/api/teams.php index 0ccba7a69a..875c2835bf 100644 --- a/app/controllers/api/teams.php +++ b/app/controllers/api/teams.php @@ -37,7 +37,6 @@ App::post('/v1/teams') ->label('event', 'teams.[teamId].create') ->label('scope', 'teams.write') ->label('audits.resource', 'team/{response.$id}') - ->label('audits.payload', true) ->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_KEY, APP_AUTH_TYPE_JWT]) ->label('sdk.namespace', 'teams') ->label('sdk.method', 'create') diff --git a/app/controllers/api/users.php b/app/controllers/api/users.php index b8bce1932c..c8fafbefe2 100644 --- a/app/controllers/api/users.php +++ b/app/controllers/api/users.php @@ -6,7 +6,6 @@ use Appwrite\Auth\Validator\Phone; use Appwrite\Detector\Detector; use Appwrite\Event\Delete; use Appwrite\Event\Event; -use Appwrite\Event\Audit as EventAudit; use Appwrite\Network\Validator\Email; use Appwrite\Stats\Stats; use Appwrite\Utopia\Database\Validator\CustomId; diff --git a/app/controllers/shared/api.php b/app/controllers/shared/api.php index 8884484913..4c9a49d2d4 100644 --- a/app/controllers/shared/api.php +++ b/app/controllers/shared/api.php @@ -314,12 +314,16 @@ App::shutdown() } } - $auditsPayload = $route->getLabel('audits.payload',false); - if(!empty($auditsPayload)) { - $audits->setPayload($responsePayload); - } - if (!empty($audits->getResource())) { + /** + * audits.payload is switched to default true + * in order to auto audit payload for all endpoints + */ + $auditsPayload = $route->getLabel('audits.payload',true); + if(!empty($auditsPayload)) { + $audits->setPayload($responsePayload); + } + foreach ($events->getParams() as $key => $value) { $audits->setParam($key, $value); } diff --git a/docker-compose.yml b/docker-compose.yml index 8a002e0801..20d2c5c2f9 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -103,7 +103,6 @@ services: - ./phpunit.xml:/usr/src/code/phpunit.xml - ./tests:/usr/src/code/tests - ./app:/usr/src/code/app - #- ./vendor:/usr/src/code/vendor #TODO remove when done!! # - ./vendor/utopia/database:/usr/src/code/vendor/utopia/database - ./docs:/usr/src/code/docs - ./public:/usr/src/code/public From 5a15d29a22057c25a547fbe904a82e512e50b5eb Mon Sep 17 00:00:00 2001 From: shimon Date: Wed, 10 Aug 2022 12:22:55 +0300 Subject: [PATCH 13/46] sync with 0.16.x --- app/controllers/api/databases.php | 38 +++++++++++++++---------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/app/controllers/api/databases.php b/app/controllers/api/databases.php index a79a1551db..a25752f1da 100644 --- a/app/controllers/api/databases.php +++ b/app/controllers/api/databases.php @@ -859,7 +859,7 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/attributes/string ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) ->label('sdk.response.model', Response::MODEL_ATTRIBUTE_STRING) ->param('databaseId', '', new UID(), 'Database ID.') - ->param('collectionId', '', new UID(), 'Collection ID. You can create a new collection using the Database service [server integration](https://appwrite.io/docs/server/databases#databasesCreateCollection).') + ->param('collectionId', '', new UID(), 'Collection ID. You can create a new collection using the Database service [server integration](https://appwrite.io/docs/server/database#createCollection).') ->param('key', '', new Key(), 'Attribute Key.') ->param('size', null, new Range(1, APP_DATABASE_ATTRIBUTE_STRING_MAX_LENGTH, Range::TYPE_INTEGER), 'Attribute size for text attributes, in number of characters.') ->param('required', null, new Boolean(), 'Is attribute required?') @@ -906,7 +906,7 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/attributes/email' ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) ->label('sdk.response.model', Response::MODEL_ATTRIBUTE_EMAIL) ->param('databaseId', '', new UID(), 'Database ID.') - ->param('collectionId', '', new UID(), 'Collection ID. You can create a new collection using the Database service [server integration](https://appwrite.io/docs/server/databases#databasesCreateCollection).') + ->param('collectionId', '', new UID(), 'Collection ID. You can create a new collection using the Database service [server integration](https://appwrite.io/docs/server/database#createCollection).') ->param('key', '', new Key(), 'Attribute Key.') ->param('required', null, new Boolean(), 'Is attribute required?') ->param('default', null, new Email(), 'Default value for attribute when not provided. Cannot be set when attribute is required.', true) @@ -947,7 +947,7 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/attributes/enum') ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) ->label('sdk.response.model', Response::MODEL_ATTRIBUTE_ENUM) ->param('databaseId', '', new UID(), 'Database ID.') - ->param('collectionId', '', new UID(), 'Collection ID. You can create a new collection using the Database service [server integration](https://appwrite.io/docs/server/databases#databasesCreateCollection).') + ->param('collectionId', '', new UID(), 'Collection ID. You can create a new collection using the Database service [server integration](https://appwrite.io/docs/server/database#createCollection).') ->param('key', '', new Key(), 'Attribute Key.') ->param('elements', [], new ArrayList(new Text(APP_LIMIT_ARRAY_ELEMENT_SIZE), APP_LIMIT_ARRAY_PARAMS_SIZE), 'Array of elements in enumerated type. Uses length of longest element to determine size. Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' elements are allowed, each ' . APP_LIMIT_ARRAY_ELEMENT_SIZE . ' characters long.') ->param('required', null, new Boolean(), 'Is attribute required?') @@ -1004,7 +1004,7 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/attributes/ip') ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) ->label('sdk.response.model', Response::MODEL_ATTRIBUTE_IP) ->param('databaseId', '', new UID(), 'Database ID.') - ->param('collectionId', '', new UID(), 'Collection ID. You can create a new collection using the Database service [server integration](https://appwrite.io/docs/server/databases#databasesCreateCollection).') + ->param('collectionId', '', new UID(), 'Collection ID. You can create a new collection using the Database service [server integration](https://appwrite.io/docs/server/database#createCollection).') ->param('key', '', new Key(), 'Attribute Key.') ->param('required', null, new Boolean(), 'Is attribute required?') ->param('default', null, new IP(), 'Default value for attribute when not provided. Cannot be set when attribute is required.', true) @@ -1045,7 +1045,7 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/attributes/url') ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) ->label('sdk.response.model', Response::MODEL_ATTRIBUTE_URL) ->param('databaseId', '', new UID(), 'Database ID.') - ->param('collectionId', '', new UID(), 'Collection ID. You can create a new collection using the Database service [server integration](https://appwrite.io/docs/server/databases#databasesCreateCollection).') + ->param('collectionId', '', new UID(), 'Collection ID. You can create a new collection using the Database service [server integration](https://appwrite.io/docs/server/database#createCollection).') ->param('key', '', new Key(), 'Attribute Key.') ->param('required', null, new Boolean(), 'Is attribute required?') ->param('default', null, new URL(), 'Default value for attribute when not provided. Cannot be set when attribute is required.', true) @@ -1086,7 +1086,7 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/attributes/intege ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) ->label('sdk.response.model', Response::MODEL_ATTRIBUTE_INTEGER) ->param('databaseId', '', new UID(), 'Database ID.') - ->param('collectionId', '', new UID(), 'Collection ID. You can create a new collection using the Database service [server integration](https://appwrite.io/docs/server/databases#databasesCreateCollection).') + ->param('collectionId', '', new UID(), 'Collection ID. You can create a new collection using the Database service [server integration](https://appwrite.io/docs/server/database#createCollection).') ->param('key', '', new Key(), 'Attribute Key.') ->param('required', null, new Boolean(), 'Is attribute required?') ->param('min', null, new Integer(), 'Minimum value to enforce on new documents', true) @@ -1156,7 +1156,7 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/attributes/float' ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) ->label('sdk.response.model', Response::MODEL_ATTRIBUTE_FLOAT) ->param('databaseId', '', new UID(), 'Database ID.') - ->param('collectionId', '', new UID(), 'Collection ID. You can create a new collection using the Database service [server integration](https://appwrite.io/docs/server/databases#databasesCreateCollection).') + ->param('collectionId', '', new UID(), 'Collection ID. You can create a new collection using the Database service [server integration](https://appwrite.io/docs/server/database#createCollection).') ->param('key', '', new Key(), 'Attribute Key.') ->param('required', null, new Boolean(), 'Is attribute required?') ->param('min', null, new FloatValidator(), 'Minimum value to enforce on new documents', true) @@ -1229,7 +1229,7 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/attributes/boolea ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) ->label('sdk.response.model', Response::MODEL_ATTRIBUTE_BOOLEAN) ->param('databaseId', '', new UID(), 'Database ID.') - ->param('collectionId', '', new UID(), 'Collection ID. You can create a new collection using the Database service [server integration](https://appwrite.io/docs/server/databases#databasesCreateCollection).') + ->param('collectionId', '', new UID(), 'Collection ID. You can create a new collection using the Database service [server integration](https://appwrite.io/docs/server/database#createCollection).') ->param('key', '', new Key(), 'Attribute Key.') ->param('required', null, new Boolean(), 'Is attribute required?') ->param('default', null, new Boolean(), 'Default value for attribute when not provided. Cannot be set when attribute is required.', true) @@ -1317,7 +1317,7 @@ App::get('/v1/databases/:databaseId/collections/:collectionId/attributes/:key') Response::MODEL_ATTRIBUTE_IP, Response::MODEL_ATTRIBUTE_STRING,])// needs to be last, since its condition would dominate any other string attribute ->param('databaseId', '', new UID(), 'Database ID.') - ->param('collectionId', '', new UID(), 'Collection ID. You can create a new collection using the Database service [server integration](https://appwrite.io/docs/server/databases#databasesCreateCollection).') + ->param('collectionId', '', new UID(), 'Collection ID. You can create a new collection using the Database service [server integration](https://appwrite.io/docs/server/database#createCollection).') ->param('key', '', new Key(), 'Attribute Key.') ->inject('response') ->inject('dbForProject') @@ -1381,7 +1381,7 @@ App::delete('/v1/databases/:databaseId/collections/:collectionId/attributes/:key ->label('sdk.response.code', Response::STATUS_CODE_NOCONTENT) ->label('sdk.response.model', Response::MODEL_NONE) ->param('databaseId', '', new UID(), 'Database ID.') - ->param('collectionId', '', new UID(), 'Collection ID. You can create a new collection using the Database service [server integration](https://appwrite.io/docs/server/databases#databasesCreateCollection).') + ->param('collectionId', '', new UID(), 'Collection ID. You can create a new collection using the Database service [server integration](https://appwrite.io/docs/server/database#createCollection).') ->param('key', '', new Key(), 'Attribute Key.') ->inject('response') ->inject('dbForProject') @@ -1474,7 +1474,7 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/indexes') ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) ->label('sdk.response.model', Response::MODEL_INDEX) ->param('databaseId', '', new UID(), 'Database ID.') - ->param('collectionId', '', new UID(), 'Collection ID. You can create a new collection using the Database service [server integration](https://appwrite.io/docs/server/databases#databasesCreateCollection).') + ->param('collectionId', '', new UID(), 'Collection ID. You can create a new collection using the Database service [server integration](https://appwrite.io/docs/server/database#createCollection).') ->param('key', null, new Key(), 'Index Key.') ->param('type', null, new WhiteList([Database::INDEX_KEY, Database::INDEX_FULLTEXT, Database::INDEX_UNIQUE, Database::INDEX_SPATIAL, Database::INDEX_ARRAY]), 'Index type.') ->param('attributes', null, new ArrayList(new Key(true), APP_LIMIT_ARRAY_PARAMS_SIZE), 'Array of attributes to index. Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' attributes are allowed, each 32 characters long.') @@ -1623,7 +1623,7 @@ App::get('/v1/databases/:databaseId/collections/:collectionId/indexes') ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) ->label('sdk.response.model', Response::MODEL_INDEX_LIST) ->param('databaseId', '', new UID(), 'Database ID.') - ->param('collectionId', '', new UID(), 'Collection ID. You can create a new collection using the Database service [server integration](https://appwrite.io/docs/server/databases#databasesCreateCollection).') + ->param('collectionId', '', new UID(), 'Collection ID. You can create a new collection using the Database service [server integration](https://appwrite.io/docs/server/database#createCollection).') ->inject('response') ->inject('dbForProject') ->inject('usage') @@ -1665,7 +1665,7 @@ App::get('/v1/databases/:databaseId/collections/:collectionId/indexes/:key') ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) ->label('sdk.response.model', Response::MODEL_INDEX) ->param('databaseId', '', new UID(), 'Database ID.') - ->param('collectionId', '', new UID(), 'Collection ID. You can create a new collection using the Database service [server integration](https://appwrite.io/docs/server/databases#databasesCreateCollection).') + ->param('collectionId', '', new UID(), 'Collection ID. You can create a new collection using the Database service [server integration](https://appwrite.io/docs/server/database#createCollection).') ->param('key', null, new Key(), 'Index Key.') ->inject('response') ->inject('dbForProject') @@ -1717,7 +1717,7 @@ App::delete('/v1/databases/:databaseId/collections/:collectionId/indexes/:key') ->label('sdk.response.code', Response::STATUS_CODE_NOCONTENT) ->label('sdk.response.model', Response::MODEL_NONE) ->param('databaseId', '', new UID(), 'Database ID.') - ->param('collectionId', null, new UID(), 'Collection ID. You can create a new collection using the Database service [server integration](https://appwrite.io/docs/server/databases#databasesCreateCollection).') + ->param('collectionId', null, new UID(), 'Collection ID. You can create a new collection using the Database service [server integration](https://appwrite.io/docs/server/database#createCollection).') ->param('key', '', new Key(), 'Index Key.') ->inject('response') ->inject('dbForProject') @@ -1792,7 +1792,7 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/documents') ->label('sdk.response.model', Response::MODEL_DOCUMENT) ->param('databaseId', '', new UID(), 'Database ID.') ->param('documentId', '', new CustomId(), 'Document ID. Choose your own unique ID or pass the string "unique()" to auto generate it. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.') - ->param('collectionId', null, new UID(), 'Collection ID. You can create a new collection using the Database service [server integration](https://appwrite.io/docs/server/databases#databasesCreateCollection). Make sure to define attributes before creating documents.') + ->param('collectionId', null, new UID(), 'Collection ID. You can create a new collection using the Database service [server integration](https://appwrite.io/docs/server/database#createCollection). Make sure to define attributes before creating documents.') ->param('data', [], new JSON(), 'Document data as JSON object.') ->param('read', null, new Permissions(APP_LIMIT_ARRAY_PARAMS_SIZE), 'An array of strings with read permissions. By default only the current user is granted with read permissions. [learn more about permissions](https://appwrite.io/docs/permissions) and get a full list of available permissions.', true) ->param('write', null, new Permissions(APP_LIMIT_ARRAY_PARAMS_SIZE), 'An array of strings with write permissions. By default only the current user is granted with write permissions. [learn more about permissions](https://appwrite.io/docs/permissions) and get a full list of available permissions.', true) @@ -1907,8 +1907,8 @@ App::get('/v1/databases/:databaseId/collections/:collectionId/documents') ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) ->label('sdk.response.model', Response::MODEL_DOCUMENT_LIST) ->param('databaseId', '', new UID(), 'Database ID.') - ->param('collectionId', '', new UID(), 'Collection ID. You can create a new collection using the Database service [server integration](https://appwrite.io/docs/server/databases#databasesCreateCollection).') - ->param('queries', [], new ArrayList(new Text(APP_LIMIT_ARRAY_ELEMENT_SIZE), APP_LIMIT_ARRAY_PARAMS_SIZE), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/databases#querying-documents). Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' queries are allowed, each ' . APP_LIMIT_ARRAY_ELEMENT_SIZE . ' characters long.', true) + ->param('collectionId', '', new UID(), 'Collection ID. You can create a new collection using the Database service [server integration](https://appwrite.io/docs/server/database#createCollection).') + ->param('queries', [], new ArrayList(new Text(APP_LIMIT_ARRAY_ELEMENT_SIZE), APP_LIMIT_ARRAY_PARAMS_SIZE), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/database#querying-documents). Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' queries are allowed, each ' . APP_LIMIT_ARRAY_ELEMENT_SIZE . ' characters long.', true) ->param('limit', 25, new Range(0, 100), 'Maximum number of documents to return in response. By default will return maximum 25 results. Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' results allowed per request.', true) ->param('offset', 0, new Range(0, APP_LIMIT_COUNT), 'Offset value. The default value is 0. Use this value to manage pagination. [learn more about pagination](https://appwrite.io/docs/pagination)', true) ->param('cursor', '', new UID(), 'ID of the document used as the starting point for the query, excluding the document itself. Should be used for efficient pagination when working with large sets of data. [learn more about pagination](https://appwrite.io/docs/pagination)', true) @@ -2021,7 +2021,7 @@ App::get('/v1/databases/:databaseId/collections/:collectionId/documents/:documen ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) ->label('sdk.response.model', Response::MODEL_DOCUMENT) ->param('databaseId', '', new UID(), 'Database ID.') - ->param('collectionId', null, new UID(), 'Collection ID. You can create a new collection using the Database service [server integration](https://appwrite.io/docs/server/databases#databasesCreateCollection).') + ->param('collectionId', null, new UID(), 'Collection ID. You can create a new collection using the Database service [server integration](https://appwrite.io/docs/server/database#createCollection).') ->param('documentId', null, new UID(), 'Document ID.') ->inject('response') ->inject('dbForProject') @@ -2320,7 +2320,7 @@ App::delete('/v1/databases/:databaseId/collections/:collectionId/documents/:docu ->label('sdk.response.code', Response::STATUS_CODE_NOCONTENT) ->label('sdk.response.model', Response::MODEL_NONE) ->param('databaseId', '', new UID(), 'Database ID.') - ->param('collectionId', null, new UID(), 'Collection ID. You can create a new collection using the Database service [server integration](https://appwrite.io/docs/server/databases#databasesCreateCollection).') + ->param('collectionId', null, new UID(), 'Collection ID. You can create a new collection using the Database service [server integration](https://appwrite.io/docs/server/database#createCollection).') ->param('documentId', null, new UID(), 'Document ID.') ->inject('response') ->inject('dbForProject') From 2d8abac0e3ba802b6343e1eda4d7d6b4a4ef0225 Mon Sep 17 00:00:00 2001 From: shimon Date: Thu, 11 Aug 2022 11:47:18 +0300 Subject: [PATCH 14/46] clean --- app/controllers/shared/api.php | 39 ++++++++++++---------------------- 1 file changed, 14 insertions(+), 25 deletions(-) diff --git a/app/controllers/shared/api.php b/app/controllers/shared/api.php index 4c9a49d2d4..15b7d83e55 100644 --- a/app/controllers/shared/api.php +++ b/app/controllers/shared/api.php @@ -204,7 +204,7 @@ App::shutdown() $responsePayload = $response->getPayload(); if (!empty($events->getEvent())) { - if (empty($events->getPayload())){ + if (empty($events->getPayload())) { $events->setPayload($responsePayload); } /** @@ -229,11 +229,9 @@ App::shutdown() if ($project->getId() !== 'console') { $allEvents = Event::generateEvents($events->getEvent(), $events->getParams()); $payload = new Document($events->getPayload()); - $db = $events->getContext('database'); $collection = $events->getContext('collection'); $bucket = $events->getContext('bucket'); - $target = Realtime::fromPayload( // Pass first, most verbose event pattern event: $allEvents[0], @@ -251,7 +249,6 @@ App::shutdown() channels: $target['channels'], roles: $target['roles'], options: [ - 'permissionsChanged' => $target['permissionsChanged'], 'userId' => $events->getParam('userId') ] ); @@ -260,22 +257,21 @@ App::shutdown() $route = $utopia->match($request); - $getRequestParams = function() use ($route, $request): array { - $url = \parse_url($request->getURI(), PHP_URL_PATH); + $getRequestParams = function() use ($route, $request) { + $url = \parse_url($request->getURI(),PHP_URL_PATH); $regex = '@' . \preg_replace('@:[^/]+@', '([^/]+)', $route->getPath()) . '@'; - \preg_match($regex, $url, $matches); + \preg_match($regex, $url,$matches); \array_shift($matches); $url = $route->getIsAlias() ? $route->getAliasPath() : $route->getPath(); - $keyRegex = '@^' . \preg_replace('@:[^/]+@', ':([^/]+)', $url) . '$@'; - \preg_match($keyRegex, $url, $keys); + $keyRegex = '@^' . \preg_replace('@:[^/]+@',':([^/]+)', $url) . '$@'; + \preg_match($keyRegex, $url,$keys); \array_shift($keys); return \array_combine($keys, $matches) ?? []; }; - - $parseLabel = function ($label) use ($responsePayload, $getRequestParams) :string { - preg_match_all('/{(.*?)}/', $label, $matches); + $parseLabel = function ($label) use ($responsePayload, $getRequestParams) { + preg_match_all('/{(.*?)}/', $label,$matches); foreach ($matches[1] ?? [] as $pos => $match) { $find = $matches[0][$pos]; $parts = explode('.', $match); @@ -287,16 +283,10 @@ App::shutdown() $namespace = $parts[0]; $replace = $parts[1]; - switch ($namespace) { - case 'response': - $params = $responsePayload; - break; - case 'request': - $params = $getRequestParams(); - break; - default: - $params = $responsePayload; - } + $params = match ($namespace) { + 'request' => $getRequestParams(), + default => $responsePayload, + }; if(array_key_exists($replace, $params)){ $label = \str_replace($find, $params[$replace], $label); @@ -319,8 +309,8 @@ App::shutdown() * audits.payload is switched to default true * in order to auto audit payload for all endpoints */ - $auditsPayload = $route->getLabel('audits.payload',true); - if(!empty($auditsPayload)) { + $auditsPayload = $route->getLabel('audits.payload', true); + if (!empty($auditsPayload)) { $audits->setPayload($responsePayload); } @@ -339,7 +329,6 @@ App::shutdown() $database->trigger(); } - if ( App::getEnv('_APP_USAGE_STATS', 'enabled') == 'enabled' && $project->getId() From 6a4fee641d405b5a3e800f293110cf65b492b623 Mon Sep 17 00:00:00 2001 From: shimon Date: Thu, 11 Aug 2022 12:04:05 +0300 Subject: [PATCH 15/46] clean --- app/controllers/shared/api.php | 8 ++++---- composer.lock | 12 ++++++------ 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/app/controllers/shared/api.php b/app/controllers/shared/api.php index 15b7d83e55..42f9866fc2 100644 --- a/app/controllers/shared/api.php +++ b/app/controllers/shared/api.php @@ -277,7 +277,7 @@ App::shutdown() $parts = explode('.', $match); if(count($parts) !== 2){ - return ''; + throw new Exception('Too less or more parts', 400, Exception::GENERAL_ARGUMENT_INVALID); } $namespace = $parts[0]; @@ -296,10 +296,10 @@ App::shutdown() return $label; }; - $auditsResource = $route->getLabel('audits.resource',null); - if(!empty($auditsResource)) { + $auditsResource = $route->getLabel('audits.resource', null); + if (!empty($auditsResource)) { $resource = $parseLabel($auditsResource); - if(!empty($resource) && $resource !== $auditsResource) { + if (!empty($resource) && $resource !== $auditsResource) { $audits->setResource($resource); } } diff --git a/composer.lock b/composer.lock index 93b8455cac..6ae877fd15 100644 --- a/composer.lock +++ b/composer.lock @@ -1894,16 +1894,16 @@ }, { "name": "utopia-php/cache", - "version": "0.6.0", + "version": "0.6.1", "source": { "type": "git", "url": "https://github.com/utopia-php/cache.git", - "reference": "8ea1353a4bbab617e23c865a7c97b60d8074aee3" + "reference": "9889235a6d3da6cbb1f435201529da4d27c30e79" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/utopia-php/cache/zipball/8ea1353a4bbab617e23c865a7c97b60d8074aee3", - "reference": "8ea1353a4bbab617e23c865a7c97b60d8074aee3", + "url": "https://api.github.com/repos/utopia-php/cache/zipball/9889235a6d3da6cbb1f435201529da4d27c30e79", + "reference": "9889235a6d3da6cbb1f435201529da4d27c30e79", "shasum": "" }, "require": { @@ -1941,9 +1941,9 @@ ], "support": { "issues": "https://github.com/utopia-php/cache/issues", - "source": "https://github.com/utopia-php/cache/tree/0.6.0" + "source": "https://github.com/utopia-php/cache/tree/0.6.1" }, - "time": "2022-04-04T12:30:05+00:00" + "time": "2022-08-10T08:12:46+00:00" }, { "name": "utopia-php/cli", From b5f977e46da3837eec19ccec3c5bed88b651841e Mon Sep 17 00:00:00 2001 From: shimon Date: Thu, 11 Aug 2022 16:19:05 +0300 Subject: [PATCH 16/46] adding user to audits labels --- app/controllers/api/account.php | 38 ++++++++++++------- app/controllers/api/teams.php | 16 +++----- app/controllers/api/users.php | 67 ++++++++++----------------------- app/controllers/shared/api.php | 27 ++++++++----- 4 files changed, 67 insertions(+), 81 deletions(-) diff --git a/app/controllers/api/account.php b/app/controllers/api/account.php index 2ce8e30e6e..95f6a41e8d 100644 --- a/app/controllers/api/account.php +++ b/app/controllers/api/account.php @@ -48,6 +48,7 @@ App::post('/v1/account') ->label('scope', 'public') ->label('auth.type', 'emailPassword') ->label('audits.resource', 'user/{response.$id}') + ->label('audits.userId', '{response.$id}') ->label('sdk.auth', []) ->label('sdk.namespace', 'account') ->label('sdk.method', 'create') @@ -354,7 +355,6 @@ App::get('/v1/account/sessions/oauth2/:provider/redirect') ->label('abuse-limit', 50) ->label('abuse-key', 'ip:{ip}') ->label('docs', false) - ->label('audits.resource', 'user/{response.$id}') ->param('provider', '', new WhiteList(\array_keys(Config::getParam('providers')), true), 'OAuth2 provider.') ->param('code', '', new Text(2048), 'OAuth2 code.') ->param('state', '', new Text(2048), 'OAuth2 state params.', true) @@ -364,9 +364,10 @@ App::get('/v1/account/sessions/oauth2/:provider/redirect') ->inject('user') ->inject('dbForProject') ->inject('geodb') + ->inject('audits') ->inject('events') ->inject('usage') - ->action(function (string $provider, string $code, string $state, Request $request, Response $response, Document $project, Document $user, Database $dbForProject, Reader $geodb, Event $events, Stats $usage) use ($oauthDefaultSuccess) { + ->action(function (string $provider, string $code, string $state, Request $request, Response $response, Document $project, Document $user, Database $dbForProject, Reader $geodb, Audit $audits, Event $events, Stats $usage) use ($oauthDefaultSuccess) { $protocol = $request->getProtocol(); $callback = $protocol . '://' . $request->getHostname() . '/v1/account/sessions/oauth2/callback/' . $provider . '/' . $project->getId(); @@ -543,6 +544,8 @@ App::get('/v1/account/sessions/oauth2/:provider/redirect') $dbForProject->deleteCachedDocument('users', $user->getId()); + $audits->setResource('user/' . $user->getId()); + $usage ->setParam('users.sessions.create', 1) ->setParam('projectId', $project->getId()) @@ -586,7 +589,8 @@ App::post('/v1/account/sessions/magic-url') ->groups(['api', 'account']) ->label('scope', 'public') ->label('auth.type', 'magic-url') - ->label('audits.resource', 'user/{response.$id}') + ->label('audits.resource', 'user/{response.userId}') + ->label('audits.userId', '{response.userId}') ->label('sdk.auth', []) ->label('sdk.namespace', 'account') ->label('sdk.method', 'createMagicURLSession') @@ -710,7 +714,7 @@ App::put('/v1/account/sessions/magic-url') ->groups(['api', 'account']) ->label('scope', 'public') ->label('event', 'users.[userId].sessions.[sessionId].create') - ->label('audits.resource', 'user/{response.$id}') + ->label('audits.resource', 'user/{response.userId}') ->label('sdk.auth', []) ->label('sdk.namespace', 'account') ->label('sdk.method', 'updateMagicURLSession') @@ -822,7 +826,8 @@ App::post('/v1/account/sessions/phone') ->groups(['api', 'account']) ->label('scope', 'public') ->label('auth.type', 'phone') - ->label('audits.resource', 'user/{response.$id}') + ->label('audits.resource', 'user/{response.userId}') + ->label('audits.userId', '{response.userId}') ->label('sdk.auth', []) ->label('sdk.namespace', 'account') ->label('sdk.method', 'createPhoneSession') @@ -935,7 +940,7 @@ App::put('/v1/account/sessions/phone') ->groups(['api', 'account']) ->label('scope', 'public') ->label('event', 'users.[userId].sessions.[sessionId].create') - ->label('audits.resource', 'user/{response.$id}') + ->label('audits.resource', 'user/{response.userId}') ->label('sdk.auth', []) ->label('sdk.namespace', 'account') ->label('sdk.method', 'updatePhoneSession') @@ -1044,7 +1049,7 @@ App::post('/v1/account/sessions/anonymous') ->label('event', 'users.[userId].sessions.[sessionId].create') ->label('scope', 'public') ->label('auth.type', 'anonymous') - ->label('audits.resource', 'user/{response.$id}') + ->label('audits.resource', 'user/{response.userId}') ->label('sdk.auth', []) ->label('sdk.namespace', 'account') ->label('sdk.method', 'createAnonymousSession') @@ -1400,6 +1405,7 @@ App::patch('/v1/account/name') ->label('event', 'users.[userId].update.name') ->label('scope', 'account') ->label('audits.resource', 'user/{response.$id}') + ->label('audits.userId', '{response.$id}') ->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_JWT]) ->label('sdk.namespace', 'account') ->label('sdk.method', 'updateName') @@ -1431,6 +1437,7 @@ App::patch('/v1/account/password') ->label('event', 'users.[userId].update.password') ->label('scope', 'account') ->label('audits.resource', 'user/{response.$id}') + ->label('audits.userId', '{response.$id}') ->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_JWT]) ->label('sdk.namespace', 'account') ->label('sdk.method', 'updatePassword') @@ -1472,6 +1479,7 @@ App::patch('/v1/account/email') ->label('event', 'users.[userId].update.email') ->label('scope', 'account') ->label('audits.resource', 'user/{response.$id}') + ->label('audits.userId', '{response.$id}') ->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_JWT]) ->label('sdk.namespace', 'account') ->label('sdk.method', 'updateEmail') @@ -1523,6 +1531,7 @@ App::patch('/v1/account/phone') ->label('event', 'users.[userId].update.phone') ->label('scope', 'account') ->label('audits.resource', 'user/{response.$id}') + ->label('audits.userId', '{response.$id}') ->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_JWT]) ->label('sdk.namespace', 'account') ->label('sdk.method', 'updatePhone') @@ -1712,7 +1721,7 @@ App::patch('/v1/account/sessions/:sessionId') ->groups(['api', 'account']) ->label('scope', 'account') ->label('event', 'users.[userId].sessions.[sessionId].update') - ->label('audits.resource', 'user/{response.$id}') + ->label('audits.resource', 'user/{response.userId}') ->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_JWT]) ->label('sdk.namespace', 'account') ->label('sdk.method', 'updateSession') @@ -1865,7 +1874,8 @@ App::post('/v1/account/recovery') ->groups(['api', 'account']) ->label('scope', 'public') ->label('event', 'users.[userId].recovery.[tokenId].create') - ->label('audits.resource', 'user/{response.$id}') + ->label('audits.resource', 'user/{response.userId}') + ->label('audits.userId', '{response.userId}') ->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_JWT]) ->label('sdk.namespace', 'account') ->label('sdk.method', 'createRecovery') @@ -1968,7 +1978,7 @@ App::put('/v1/account/recovery') ->groups(['api', 'account']) ->label('scope', 'public') ->label('event', 'users.[userId].recovery.[tokenId].update') - ->label('audits.resource', 'user/{response.$id}') + ->label('audits.resource', 'user/{response.userId}') ->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_JWT]) ->label('sdk.namespace', 'account') ->label('sdk.method', 'updateRecovery') @@ -2036,7 +2046,7 @@ App::post('/v1/account/verification') ->groups(['api', 'account']) ->label('scope', 'account') ->label('event', 'users.[userId].verification.[tokenId].create') - ->label('audits.resource', 'user/{response.$id}') + ->label('audits.resource', 'user/{response.userId}') ->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_JWT]) ->label('sdk.namespace', 'account') ->label('sdk.method', 'createVerification') @@ -2125,7 +2135,7 @@ App::put('/v1/account/verification') ->groups(['api', 'account']) ->label('scope', 'public') ->label('event', 'users.[userId].verification.[tokenId].update') - ->label('audits.resource', 'user/{response.$id}') + ->label('audits.resource', 'user/{response.userId}') ->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_JWT]) ->label('sdk.namespace', 'account') ->label('sdk.method', 'updateVerification') @@ -2185,7 +2195,7 @@ App::post('/v1/account/verification/phone') ->groups(['api', 'account']) ->label('scope', 'account') ->label('event', 'users.[userId].verification.[tokenId].create') - ->label('audits.resource', 'user/{response.$id}') + ->label('audits.resource', 'user/{response.userId}') ->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_JWT]) ->label('sdk.namespace', 'account') ->label('sdk.method', 'createPhoneVerification') @@ -2270,7 +2280,7 @@ App::put('/v1/account/verification/phone') ->groups(['api', 'account']) ->label('scope', 'public') ->label('event', 'users.[userId].verification.[tokenId].update') - ->label('audits.resource', 'user/{response.$id}') + ->label('audits.resource', 'user/{response.userId}') ->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_JWT]) ->label('sdk.namespace', 'account') ->label('sdk.method', 'updatePhoneVerification') diff --git a/app/controllers/api/teams.php b/app/controllers/api/teams.php index 875c2835bf..6c58ac2a91 100644 --- a/app/controllers/api/teams.php +++ b/app/controllers/api/teams.php @@ -207,6 +207,7 @@ App::delete('/v1/teams/:teamId') ->groups(['api', 'teams']) ->label('event', 'teams.[teamId].delete') ->label('scope', 'teams.write') + ->label('audits.resource', 'team/{request.teamId}') ->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_KEY, APP_AUTH_TYPE_JWT]) ->label('sdk.namespace', 'teams') ->label('sdk.method', 'delete') @@ -251,10 +252,7 @@ App::delete('/v1/teams/:teamId') ->setPayload($response->output($team, Response::MODEL_TEAM)) ; - $audits - ->setParam('resource', 'team/' . $teamId) - ->setParam('data', $team->getArrayCopy()) - ; + $audits->setParam('data', $team->getArrayCopy()); $response->noContent(); }); @@ -265,7 +263,7 @@ App::post('/v1/teams/:teamId/memberships') ->label('event', 'teams.[teamId].memberships.[membershipId].create') ->label('scope', 'teams.write') ->label('auth.type', 'invites') - ->label('audits.resource', 'team/{response.teamId}') + ->label('audits.resource', 'team/{request.teamId}') ->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_KEY, APP_AUTH_TYPE_JWT]) ->label('sdk.namespace', 'teams') ->label('sdk.method', 'createMembership') @@ -544,7 +542,7 @@ App::patch('/v1/teams/:teamId/memberships/:membershipId') ->groups(['api', 'teams']) ->label('event', 'teams.[teamId].memberships.[membershipId].update') ->label('scope', 'teams.write') - ->label('audits.resource', 'team/{response.teamId}') + ->label('audits.resource', 'team/{request.teamId}') ->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_KEY, APP_AUTH_TYPE_JWT]) ->label('sdk.namespace', 'teams') ->label('sdk.method', 'updateMembershipRoles') @@ -614,7 +612,7 @@ App::patch('/v1/teams/:teamId/memberships/:membershipId/status') ->groups(['api', 'teams']) ->label('event', 'teams.[teamId].memberships.[membershipId].update.status') ->label('scope', 'public') - ->label('audits.resource', 'team/{response.teamId}') + ->label('audits.resource', 'team/{request.teamId}') ->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_JWT]) ->label('sdk.namespace', 'teams') ->label('sdk.method', 'updateMembershipStatus') @@ -676,9 +674,7 @@ App::patch('/v1/teams/:teamId/memberships/:membershipId/status') ->setAttribute('confirm', true) ; - $user - ->setAttribute('emailVerification', true) - ; + $user->setAttribute('emailVerification', true); // Log user in diff --git a/app/controllers/api/users.php b/app/controllers/api/users.php index c8fafbefe2..da95d086d7 100644 --- a/app/controllers/api/users.php +++ b/app/controllers/api/users.php @@ -76,13 +76,9 @@ App::post('/v1/users') throw new Exception('Account already exists', 409, Exception::USER_ALREADY_EXISTS); } - $usage - ->setParam('users.create', 1) - ; + $usage->setParam('users.create', 1); - $events - ->setParam('userId', $user->getId()) - ; + $events->setParam('userId', $user->getId()); $response->setStatusCode(Response::STATUS_CODE_CREATED); $response->dynamic($user, Response::MODEL_USER); @@ -124,9 +120,7 @@ App::get('/v1/users') $queries[] = new Query('search', Query::TYPE_SEARCH, [$search]); } - $usage - ->setParam('users.read', 1) - ; + $usage->setParam('users.read', 1); $response->dynamic(new Document([ 'users' => $dbForProject->find('users', $queries, $limit, $offset, [], [$orderType], $cursorUser ?? null, $cursorDirection), @@ -157,9 +151,8 @@ App::get('/v1/users/:userId') throw new Exception('User not found', 404, Exception::USER_NOT_FOUND); } - $usage - ->setParam('users.read', 1) - ; + $usage->setParam('users.read', 1); + $response->dynamic($user, Response::MODEL_USER); }); @@ -188,9 +181,8 @@ App::get('/v1/users/:userId/prefs') $prefs = $user->getAttribute('prefs', new \stdClass()); - $usage - ->setParam('users.read', 1) - ; + $usage->setParam('users.read', 1); + $response->dynamic(new Document($prefs), Response::MODEL_PREFERENCES); }); @@ -230,9 +222,8 @@ App::get('/v1/users/:userId/sessions') $sessions[$key] = $session; } - $usage - ->setParam('users.read', 1) - ; + $usage->setParam('users.read', 1); + $response->dynamic(new Document([ 'sessions' => $sessions, 'total' => count($sessions), @@ -350,9 +341,7 @@ App::get('/v1/users/:userId/logs') } } - $usage - ->setParam('users.read', 1) - ; + $usage->setParam('users.read', 1); $response->dynamic(new Document([ 'total' => $audit->countLogsByUser($user->getId()), @@ -388,13 +377,9 @@ App::patch('/v1/users/:userId/status') $user = $dbForProject->updateDocument('users', $user->getId(), $user->setAttribute('status', (bool) $status)); - $usage - ->setParam('users.update', 1) - ; + $usage->setParam('users.update', 1); - $events - ->setParam('userId', $user->getId()) - ; + $events->setParam('userId', $user->getId()); $response->dynamic($user, Response::MODEL_USER); }); @@ -427,13 +412,9 @@ App::patch('/v1/users/:userId/verification') $user = $dbForProject->updateDocument('users', $user->getId(), $user->setAttribute('emailVerification', $emailVerification)); - $usage - ->setParam('users.update', 1) - ; + $usage->setParam('users.update', 1); - $events - ->setParam('userId', $user->getId()) - ; + $events->setParam('userId', $user->getId()); $response->dynamic($user, Response::MODEL_USER); }); @@ -466,13 +447,9 @@ App::patch('/v1/users/:userId/verification/phone') $user = $dbForProject->updateDocument('users', $user->getId(), $user->setAttribute('phoneVerification', $phoneVerification)); - $usage - ->setParam('users.update', 1) - ; + $usage->setParam('users.update', 1); - $events - ->setParam('userId', $user->getId()) - ; + $events->setParam('userId', $user->getId()); $response->dynamic($user, Response::MODEL_USER); }); @@ -669,13 +646,9 @@ App::patch('/v1/users/:userId/prefs') $user = $dbForProject->updateDocument('users', $user->getId(), $user->setAttribute('prefs', $prefs)); - $usage - ->setParam('users.update', 1) - ; + $usage->setParam('users.update', 1); - $events - ->setParam('userId', $user->getId()) - ; + $events->setParam('userId', $user->getId()); $response->dynamic(new Document($prefs), Response::MODEL_PREFERENCES); }); @@ -814,9 +787,7 @@ App::delete('/v1/users/:userId') ->setPayload($response->output($clone, Response::MODEL_USER)) ; - $usage - ->setParam('users.delete', 1) - ; + $usage->setParam('users.delete', 1); $response->noContent(); }); diff --git a/app/controllers/shared/api.php b/app/controllers/shared/api.php index 42f9866fc2..f82197dcd0 100644 --- a/app/controllers/shared/api.php +++ b/app/controllers/shared/api.php @@ -229,11 +229,13 @@ App::shutdown() if ($project->getId() !== 'console') { $allEvents = Event::generateEvents($events->getEvent(), $events->getParams()); $payload = new Document($events->getPayload()); + $db = $events->getContext('database'); $collection = $events->getContext('collection'); $bucket = $events->getContext('bucket'); + $target = Realtime::fromPayload( - // Pass first, most verbose event pattern + // Pass first, most verbose event pattern event: $allEvents[0], payload: $payload, project: $project, @@ -249,6 +251,7 @@ App::shutdown() channels: $target['channels'], roles: $target['roles'], options: [ + 'permissionsChanged' => $target['permissionsChanged'], 'userId' => $events->getParam('userId') ] ); @@ -277,7 +280,7 @@ App::shutdown() $parts = explode('.', $match); if(count($parts) !== 2){ - throw new Exception('Too less or more parts', 400, Exception::GENERAL_ARGUMENT_INVALID); + throw new Exception('Too less or too many parts', 400, Exception::GENERAL_ARGUMENT_INVALID); } $namespace = $parts[0]; @@ -296,28 +299,34 @@ App::shutdown() return $label; }; - $auditsResource = $route->getLabel('audits.resource', null); - if (!empty($auditsResource)) { - $resource = $parseLabel($auditsResource); - if (!empty($resource) && $resource !== $auditsResource) { + $pattern = $route->getLabel('audits.resource', null); + if (!empty($pattern)) { + $resource = $parseLabel($pattern); + if (!empty($resource) && $resource !== $pattern) { $audits->setResource($resource); } } + $pattern = $route->getLabel('audits.userId', null); + if(!empty($pattern)) { + $userId = $parseLabel($pattern); + $user = $dbForProject->getDocument('users', $userId); + $audits->setUser($user); + } + if (!empty($audits->getResource())) { /** * audits.payload is switched to default true * in order to auto audit payload for all endpoints */ - $auditsPayload = $route->getLabel('audits.payload', true); - if (!empty($auditsPayload)) { + $pattern = $route->getLabel('audits.payload', true); + if (!empty($pattern)) { $audits->setPayload($responsePayload); } foreach ($events->getParams() as $key => $value) { $audits->setParam($key, $value); } - $audits->trigger(); } From e86aab5e881d95a59dfbd469d134d7255ff1d132 Mon Sep 17 00:00:00 2001 From: shimon Date: Thu, 11 Aug 2022 16:47:53 +0300 Subject: [PATCH 17/46] ident --- app/controllers/shared/api.php | 39 +++++++++++++++------------------- 1 file changed, 17 insertions(+), 22 deletions(-) diff --git a/app/controllers/shared/api.php b/app/controllers/shared/api.php index f82197dcd0..881d79181a 100644 --- a/app/controllers/shared/api.php +++ b/app/controllers/shared/api.php @@ -81,8 +81,7 @@ App::init() $response ->addHeader('X-RateLimit-Limit', $timeLimit->limit()) ->addHeader('X-RateLimit-Remaining', $timeLimit->remaining()) - ->addHeader('X-RateLimit-Reset', $timeLimit->time() + $route->getLabel('abuse-time', 3600)) - ; + ->addHeader('X-RateLimit-Reset', $timeLimit->time() + $route->getLabel('abuse-time', 3600)); } if ( @@ -100,13 +99,11 @@ App::init() $events ->setEvent($route->getLabel('event', '')) ->setProject($project) - ->setUser($user) - ; + ->setUser($user); $mails ->setProject($project) - ->setUser($user) - ; + ->setUser($user); $audits ->setMode($mode) @@ -114,8 +111,7 @@ App::init() ->setIP($request->getIP()) ->setEvent($route->getLabel('event', '')) ->setProject($project) - ->setUser($user) - ; + ->setUser($user); $usage ->setParam('projectId', $project->getId()) @@ -125,8 +121,7 @@ App::init() ->setParam('httpPath', $route->getPath()) ->setParam('networkRequestSize', 0) ->setParam('networkResponseSize', 0) - ->setParam('storage', 0) - ; + ->setParam('storage', 0); $deletes->setProject($project); $database->setProject($project); @@ -235,7 +230,7 @@ App::shutdown() $bucket = $events->getContext('bucket'); $target = Realtime::fromPayload( - // Pass first, most verbose event pattern + // Pass first, most verbose event pattern event: $allEvents[0], payload: $payload, project: $project, @@ -260,38 +255,38 @@ App::shutdown() $route = $utopia->match($request); - $getRequestParams = function() use ($route, $request) { - $url = \parse_url($request->getURI(),PHP_URL_PATH); + $getRequestParams = function () use ($route, $request) { + $url = \parse_url($request->getURI(), PHP_URL_PATH); $regex = '@' . \preg_replace('@:[^/]+@', '([^/]+)', $route->getPath()) . '@'; - \preg_match($regex, $url,$matches); + \preg_match($regex, $url, $matches); \array_shift($matches); $url = $route->getIsAlias() ? $route->getAliasPath() : $route->getPath(); - $keyRegex = '@^' . \preg_replace('@:[^/]+@',':([^/]+)', $url) . '$@'; - \preg_match($keyRegex, $url,$keys); + $keyRegex = '@^' . \preg_replace('@:[^/]+@', ':([^/]+)', $url) . '$@'; + \preg_match($keyRegex, $url, $keys); \array_shift($keys); return \array_combine($keys, $matches) ?? []; }; - $parseLabel = function ($label) use ($responsePayload, $getRequestParams) { - preg_match_all('/{(.*?)}/', $label,$matches); + $parseLabel = function ($label) use ($responsePayload, $getRequestParams) { + preg_match_all('/{(.*?)}/', $label, $matches); foreach ($matches[1] ?? [] as $pos => $match) { $find = $matches[0][$pos]; $parts = explode('.', $match); - if(count($parts) !== 2){ + if (count($parts) !== 2) { throw new Exception('Too less or too many parts', 400, Exception::GENERAL_ARGUMENT_INVALID); } $namespace = $parts[0]; - $replace = $parts[1]; + $replace = $parts[1]; $params = match ($namespace) { 'request' => $getRequestParams(), default => $responsePayload, }; - if(array_key_exists($replace, $params)){ + if (array_key_exists($replace, $params)) { $label = \str_replace($find, $params[$replace], $label); } } @@ -308,7 +303,7 @@ App::shutdown() } $pattern = $route->getLabel('audits.userId', null); - if(!empty($pattern)) { + if (!empty($pattern)) { $userId = $parseLabel($pattern); $user = $dbForProject->getDocument('users', $userId); $audits->setUser($user); From 90cfac9b527e9c197d301cb36b322b8aa77371cf Mon Sep 17 00:00:00 2001 From: shimon Date: Fri, 12 Aug 2022 14:01:12 +0300 Subject: [PATCH 18/46] replace request param extractions --- app/controllers/api/account.php | 10 +++++++++- app/controllers/api/databases.php | 1 - app/controllers/api/teams.php | 2 ++ app/controllers/shared/api.php | 20 +++++--------------- 4 files changed, 16 insertions(+), 17 deletions(-) diff --git a/app/controllers/api/account.php b/app/controllers/api/account.php index 95f6a41e8d..a279981271 100644 --- a/app/controllers/api/account.php +++ b/app/controllers/api/account.php @@ -544,7 +544,9 @@ App::get('/v1/account/sessions/oauth2/:provider/redirect') $dbForProject->deleteCachedDocument('users', $user->getId()); - $audits->setResource('user/' . $user->getId()); + $audits->setResource('user/' . $user->getId()) + ->setUser($user) + ; $usage ->setParam('users.sessions.create', 1) @@ -715,6 +717,7 @@ App::put('/v1/account/sessions/magic-url') ->label('scope', 'public') ->label('event', 'users.[userId].sessions.[sessionId].create') ->label('audits.resource', 'user/{response.userId}') + ->label('audits.userId', '{response.userId}') ->label('sdk.auth', []) ->label('sdk.namespace', 'account') ->label('sdk.method', 'updateMagicURLSession') @@ -941,6 +944,7 @@ App::put('/v1/account/sessions/phone') ->label('scope', 'public') ->label('event', 'users.[userId].sessions.[sessionId].create') ->label('audits.resource', 'user/{response.userId}') + ->label('audits.userId', '{response.userId}') ->label('sdk.auth', []) ->label('sdk.namespace', 'account') ->label('sdk.method', 'updatePhoneSession') @@ -1050,6 +1054,7 @@ App::post('/v1/account/sessions/anonymous') ->label('scope', 'public') ->label('auth.type', 'anonymous') ->label('audits.resource', 'user/{response.userId}') + ->label('audits.userId', '{userId}') ->label('sdk.auth', []) ->label('sdk.namespace', 'account') ->label('sdk.method', 'createAnonymousSession') @@ -1722,6 +1727,7 @@ App::patch('/v1/account/sessions/:sessionId') ->label('scope', 'account') ->label('event', 'users.[userId].sessions.[sessionId].update') ->label('audits.resource', 'user/{response.userId}') + ->label('audits.userId', '{response.userId}') ->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_JWT]) ->label('sdk.namespace', 'account') ->label('sdk.method', 'updateSession') @@ -1979,6 +1985,7 @@ App::put('/v1/account/recovery') ->label('scope', 'public') ->label('event', 'users.[userId].recovery.[tokenId].update') ->label('audits.resource', 'user/{response.userId}') + ->label('audits.userId', '{response.userId}') ->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_JWT]) ->label('sdk.namespace', 'account') ->label('sdk.method', 'updateRecovery') @@ -2047,6 +2054,7 @@ App::post('/v1/account/verification') ->label('scope', 'account') ->label('event', 'users.[userId].verification.[tokenId].create') ->label('audits.resource', 'user/{response.userId}') + ->label('audits.userId', '{userId}') ->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_JWT]) ->label('sdk.namespace', 'account') ->label('sdk.method', 'createVerification') diff --git a/app/controllers/api/databases.php b/app/controllers/api/databases.php index a25752f1da..1d7929ba91 100644 --- a/app/controllers/api/databases.php +++ b/app/controllers/api/databases.php @@ -720,7 +720,6 @@ App::put('/v1/databases/:databaseId/collections/:collectionId') ->label('scope', 'collections.write') ->label('event', 'databases.[databaseId].collections.[collectionId].update') ->label('audits.resource', 'database/{request.databaseId}/collection/{request.collectionId}') - ->label('audits-payload', true) ->label('sdk.auth', [APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'databases') ->label('sdk.method', 'updateCollection') diff --git a/app/controllers/api/teams.php b/app/controllers/api/teams.php index 6c58ac2a91..7a4e26f2db 100644 --- a/app/controllers/api/teams.php +++ b/app/controllers/api/teams.php @@ -264,6 +264,7 @@ App::post('/v1/teams/:teamId/memberships') ->label('scope', 'teams.write') ->label('auth.type', 'invites') ->label('audits.resource', 'team/{request.teamId}') + ->label('audits.userId', '{request.userId}') ->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_KEY, APP_AUTH_TYPE_JWT]) ->label('sdk.namespace', 'teams') ->label('sdk.method', 'createMembership') @@ -613,6 +614,7 @@ App::patch('/v1/teams/:teamId/memberships/:membershipId/status') ->label('event', 'teams.[teamId].memberships.[membershipId].update.status') ->label('scope', 'public') ->label('audits.resource', 'team/{request.teamId}') + ->label('audits.userId', '{request.userId}') ->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_JWT]) ->label('sdk.namespace', 'teams') ->label('sdk.method', 'updateMembershipStatus') diff --git a/app/controllers/shared/api.php b/app/controllers/shared/api.php index 881d79181a..7c3792c88d 100644 --- a/app/controllers/shared/api.php +++ b/app/controllers/shared/api.php @@ -254,21 +254,11 @@ App::shutdown() } $route = $utopia->match($request); + $requestParams = array_combine( + array_keys($route->getParams()), array_column($route->getParams(), 'value') + ); - $getRequestParams = function () use ($route, $request) { - $url = \parse_url($request->getURI(), PHP_URL_PATH); - $regex = '@' . \preg_replace('@:[^/]+@', '([^/]+)', $route->getPath()) . '@'; - \preg_match($regex, $url, $matches); - \array_shift($matches); - $url = $route->getIsAlias() ? $route->getAliasPath() : $route->getPath(); - $keyRegex = '@^' . \preg_replace('@:[^/]+@', ':([^/]+)', $url) . '$@'; - \preg_match($keyRegex, $url, $keys); - \array_shift($keys); - - return \array_combine($keys, $matches) ?? []; - }; - - $parseLabel = function ($label) use ($responsePayload, $getRequestParams) { + $parseLabel = function ($label) use ($responsePayload, $requestParams) { preg_match_all('/{(.*?)}/', $label, $matches); foreach ($matches[1] ?? [] as $pos => $match) { $find = $matches[0][$pos]; @@ -282,7 +272,7 @@ App::shutdown() $replace = $parts[1]; $params = match ($namespace) { - 'request' => $getRequestParams(), + 'request' => $requestParams, default => $responsePayload, }; From 1af95fcdaa015b5d59823e2a005f790949aab465 Mon Sep 17 00:00:00 2001 From: shimon Date: Fri, 12 Aug 2022 16:21:32 +0300 Subject: [PATCH 19/46] Tidy up --- app/controllers/api/account.php | 22 +++++++--------------- app/controllers/api/databases.php | 26 +++++--------------------- app/controllers/api/storage.php | 6 +----- app/controllers/api/teams.php | 6 +----- app/controllers/shared/api.php | 6 +++--- 5 files changed, 17 insertions(+), 49 deletions(-) diff --git a/app/controllers/api/account.php b/app/controllers/api/account.php index a279981271..24787fb484 100644 --- a/app/controllers/api/account.php +++ b/app/controllers/api/account.php @@ -135,6 +135,8 @@ App::post('/v1/account/sessions/email') ->label('event', 'users.[userId].sessions.[sessionId].create') ->label('scope', 'public') ->label('auth.type', 'emailPassword') + ->label('audits.resource', 'user/{response.userId}') + ->label('audits.userId', '{response.userId}') ->label('sdk.auth', []) ->label('sdk.namespace', 'account') ->label('sdk.method', 'createEmailSession') @@ -151,10 +153,9 @@ App::post('/v1/account/sessions/email') ->inject('dbForProject') ->inject('locale') ->inject('geodb') - ->inject('audits') ->inject('usage') ->inject('events') - ->action(function (string $email, string $password, Request $request, Response $response, Database $dbForProject, Locale $locale, Reader $geodb, Audit $audits, Stats $usage, Event $events) { + ->action(function (string $email, string $password, Request $request, Response $response, Database $dbForProject, Locale $locale, Reader $geodb, Stats $usage, Event $events) { $email = \strtolower($email); $protocol = $request->getProtocol(); @@ -200,11 +201,6 @@ App::post('/v1/account/sessions/email') $dbForProject->deleteCachedDocument('users', $profile->getId()); - $audits - ->setResource('user/' . $profile->getId()) - ->setUser($profile) - ; - if (!Config::getParam('domainVerification')) { $response ->addHeader('X-Fallback-Cookies', \json_encode([Auth::$cookieName => Auth::encodeSession($profile->getId(), $secret)])) @@ -1649,6 +1645,7 @@ App::delete('/v1/account/sessions/:sessionId') ->groups(['api', 'account']) ->label('scope', 'account') ->label('event', 'users.[userId].sessions.[sessionId].delete') + ->label('audits.resource', 'user/{user.$id}') ->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_JWT]) ->label('sdk.namespace', 'account') ->label('sdk.method', 'deleteSession') @@ -1662,10 +1659,9 @@ App::delete('/v1/account/sessions/:sessionId') ->inject('user') ->inject('dbForProject') ->inject('locale') - ->inject('audits') ->inject('events') ->inject('usage') - ->action(function (?string $sessionId, Request $request, Response $response, Document $user, Database $dbForProject, Locale $locale, Audit $audits, Event $events, Stats $usage) { + ->action(function (?string $sessionId, Request $request, Response $response, Document $user, Database $dbForProject, Locale $locale, Event $events, Stats $usage) { $protocol = $request->getProtocol(); $sessionId = ($sessionId === 'current') @@ -1680,8 +1676,6 @@ App::delete('/v1/account/sessions/:sessionId') $dbForProject->deleteDocument('sessions', $session->getId()); - $audits->setResource('user/' . $user->getId()); - $session->setAttribute('current', false); if ($session->getAttribute('secret') == Auth::hash(Auth::$secret)) { // If current session delete the cookies too @@ -1812,6 +1806,7 @@ App::delete('/v1/account/sessions') ->groups(['api', 'account']) ->label('scope', 'account') ->label('event', 'users.[userId].sessions.[sessionId].delete') + ->label('audits.resource', 'user/{user.$id}') ->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_JWT]) ->label('sdk.namespace', 'account') ->label('sdk.method', 'deleteSessions') @@ -1824,10 +1819,9 @@ App::delete('/v1/account/sessions') ->inject('user') ->inject('dbForProject') ->inject('locale') - ->inject('audits') ->inject('events') ->inject('usage') - ->action(function (Request $request, Response $response, Document $user, Database $dbForProject, Locale $locale, Audit $audits, Event $events, Stats $usage) { + ->action(function (Request $request, Response $response, Document $user, Database $dbForProject, Locale $locale, Event $events, Stats $usage) { $protocol = $request->getProtocol(); $sessions = $user->getAttribute('sessions', []); @@ -1835,8 +1829,6 @@ App::delete('/v1/account/sessions') foreach ($sessions as $session) {/** @var Document $session */ $dbForProject->deleteDocument('sessions', $session->getId()); - $audits->setResource('user/' . $user->getId()); - if (!Config::getParam('domainVerification')) { $response->addHeader('X-Fallback-Cookies', \json_encode([])); } diff --git a/app/controllers/api/databases.php b/app/controllers/api/databases.php index 1d7929ba91..30bf6f81d7 100644 --- a/app/controllers/api/databases.php +++ b/app/controllers/api/databases.php @@ -36,7 +36,6 @@ use Appwrite\Utopia\Database\Validator\Queries as QueriesValidator; use Appwrite\Utopia\Database\Validator\OrderAttributes; use Appwrite\Utopia\Response; use Appwrite\Detector\Detector; -use Appwrite\Event\Audit as EventAudit; use Appwrite\Event\Database as EventDatabase; use Appwrite\Event\Event; use Appwrite\Stats\Stats; @@ -430,10 +429,9 @@ App::delete('/v1/databases/:databaseId') ->inject('response') ->inject('dbForProject') ->inject('events') - ->inject('audits') ->inject('deletes') ->inject('usage') - ->action(function (string $databaseId, Response $response, Database $dbForProject, Event $events, EventAudit $audits, Delete $deletes, Stats $usage) { + ->action(function (string $databaseId, Response $response, Database $dbForProject, Event $events, Delete $deletes, Stats $usage) { $database = $dbForProject->getDocument('databases', $databaseId); @@ -457,8 +455,6 @@ App::delete('/v1/databases/:databaseId') ->setPayload($response->output($database, Response::MODEL_DATABASE)) ; - $audits->setPayload($database->getArrayCopy()); - $usage->setParam('databases.delete', 1); $response->noContent(); @@ -799,10 +795,9 @@ App::delete('/v1/databases/:databaseId/collections/:collectionId') ->inject('response') ->inject('dbForProject') ->inject('events') - ->inject('audits') ->inject('deletes') ->inject('usage') - ->action(function (string $databaseId, string $collectionId, Response $response, Database $dbForProject, Event $events, EventAudit $audits, Delete $deletes, Stats $usage) { + ->action(function (string $databaseId, string $collectionId, Response $response, Database $dbForProject, Event $events, Delete $deletes, Stats $usage) { $database = Authorization::skip(fn () => $dbForProject->getDocument('databases', $databaseId)); @@ -834,8 +829,6 @@ App::delete('/v1/databases/:databaseId/collections/:collectionId') ->setPayload($response->output($collection, Response::MODEL_COLLECTION)) ; - $audits->setPayload($collection->getArrayCopy()); - $usage ->setParam('databaseId', $databaseId) ->setParam('databases.collections.delete', 1); @@ -1386,9 +1379,8 @@ App::delete('/v1/databases/:databaseId/collections/:collectionId/attributes/:key ->inject('dbForProject') ->inject('database') ->inject('events') - ->inject('audits') ->inject('usage') - ->action(function (string $databaseId, string $collectionId, string $key, Response $response, Database $dbForProject, EventDatabase $database, Event $events, EventAudit $audits, Stats $usage) { + ->action(function (string $databaseId, string $collectionId, string $key, Response $response, Database $dbForProject, EventDatabase $database, Event $events, Stats $usage) { $db = Authorization::skip(fn () => $dbForProject->getDocument('databases', $databaseId)); @@ -1453,8 +1445,6 @@ App::delete('/v1/databases/:databaseId/collections/:collectionId/attributes/:key ->setPayload($response->output($attribute, $model)) ; - $audits->setPayload($attribute->getArrayCopy()); - $response->noContent(); }); @@ -1722,9 +1712,8 @@ App::delete('/v1/databases/:databaseId/collections/:collectionId/indexes/:key') ->inject('dbForProject') ->inject('database') ->inject('events') - ->inject('audits') ->inject('usage') - ->action(function (string $databaseId, string $collectionId, string $key, Response $response, Database $dbForProject, EventDatabase $database, Event $events, EventAudit $audits, Stats $usage) { + ->action(function (string $databaseId, string $collectionId, string $key, Response $response, Database $dbForProject, EventDatabase $database, Event $events, Stats $usage) { $db = Authorization::skip(fn () => $dbForProject->getDocument('databases', $databaseId)); @@ -1770,8 +1759,6 @@ App::delete('/v1/databases/:databaseId/collections/:collectionId/indexes/:key') ->setPayload($response->output($index, Response::MODEL_INDEX)) ; - $audits->setPayload($index->getArrayCopy()); - $response->noContent(); }); @@ -2324,11 +2311,10 @@ App::delete('/v1/databases/:databaseId/collections/:collectionId/documents/:docu ->inject('response') ->inject('dbForProject') ->inject('events') - ->inject('audits') ->inject('deletes') ->inject('usage') ->inject('mode') - ->action(function (string $databaseId, string $collectionId, string $documentId, Response $response, Database $dbForProject, Event $events, EventAudit $audits, Delete $deletes, Stats $usage, string $mode) { + ->action(function (string $databaseId, string $collectionId, string $documentId, Response $response, Database $dbForProject, Event $events, Delete $deletes, Stats $usage, string $mode) { $database = Authorization::skip(fn () => $dbForProject->getDocument('databases', $databaseId)); @@ -2398,8 +2384,6 @@ App::delete('/v1/databases/:databaseId/collections/:collectionId/documents/:docu ->setPayload($response->output($document, Response::MODEL_DOCUMENT)) ; - $audits->setPayload($document->getArrayCopy()); - $response->noContent(); }); diff --git a/app/controllers/api/storage.php b/app/controllers/api/storage.php index 06cc659261..9393d32b4f 100644 --- a/app/controllers/api/storage.php +++ b/app/controllers/api/storage.php @@ -35,7 +35,6 @@ use Utopia\Storage\Validator\Upload; use Utopia\Validator\ArrayList; use Utopia\Validator\Boolean; use Utopia\Validator\HexColor; -use Utopia\Validator\Integer; use Utopia\Validator\Range; use Utopia\Validator\Text; use Utopia\Validator\WhiteList; @@ -281,11 +280,10 @@ App::delete('/v1/storage/buckets/:bucketId') ->param('bucketId', '', new UID(), 'Bucket unique ID.') ->inject('response') ->inject('dbForProject') - ->inject('audits') ->inject('deletes') ->inject('events') ->inject('usage') - ->action(function (string $bucketId, Response $response, Database $dbForProject, Audit $audits, Delete $deletes, Event $events, Stats $usage) { + ->action(function (string $bucketId, Response $response, Database $dbForProject, Delete $deletes, Event $events, Stats $usage) { $bucket = $dbForProject->getDocument('buckets', $bucketId); if ($bucket->isEmpty()) { @@ -305,8 +303,6 @@ App::delete('/v1/storage/buckets/:bucketId') ->setPayload($response->output($bucket, Response::MODEL_BUCKET)) ; - $audits->setPayload($bucket->getArrayCopy()); - $usage->setParam('storage.buckets.delete', 1); $response->noContent(); diff --git a/app/controllers/api/teams.php b/app/controllers/api/teams.php index 7a4e26f2db..76e99969bf 100644 --- a/app/controllers/api/teams.php +++ b/app/controllers/api/teams.php @@ -2,7 +2,6 @@ use Appwrite\Auth\Auth; use Appwrite\Detector\Detector; -use Appwrite\Event\Audit as EventAudit; use Appwrite\Event\Delete; use Appwrite\Event\Event; use Appwrite\Event\Mail; @@ -219,8 +218,7 @@ App::delete('/v1/teams/:teamId') ->inject('dbForProject') ->inject('events') ->inject('deletes') - ->inject('audits') - ->action(function (string $teamId, Response $response, Database $dbForProject, Event $events, Delete $deletes, EventAudit $audits) { + ->action(function (string $teamId, Response $response, Database $dbForProject, Event $events, Delete $deletes) { $team = $dbForProject->getDocument('teams', $teamId); @@ -252,8 +250,6 @@ App::delete('/v1/teams/:teamId') ->setPayload($response->output($team, Response::MODEL_TEAM)) ; - $audits->setParam('data', $team->getArrayCopy()); - $response->noContent(); }); diff --git a/app/controllers/shared/api.php b/app/controllers/shared/api.php index 7c3792c88d..ff4be68c7c 100644 --- a/app/controllers/shared/api.php +++ b/app/controllers/shared/api.php @@ -17,8 +17,6 @@ use Utopia\Abuse\Adapters\TimeLimit; use Utopia\Database\Database; use Utopia\Database\Document; use Utopia\Database\Validator\Authorization; -use Utopia\Registry\Registry; -use Utopia\Route; App::init() ->groups(['api']) @@ -257,8 +255,9 @@ App::shutdown() $requestParams = array_combine( array_keys($route->getParams()), array_column($route->getParams(), 'value') ); + $user = $audits->getUser(); - $parseLabel = function ($label) use ($responsePayload, $requestParams) { + $parseLabel = function ($label) use ($responsePayload, $requestParams, $user) { preg_match_all('/{(.*?)}/', $label, $matches); foreach ($matches[1] ?? [] as $pos => $match) { $find = $matches[0][$pos]; @@ -272,6 +271,7 @@ App::shutdown() $replace = $parts[1]; $params = match ($namespace) { + 'user' => $user, 'request' => $requestParams, default => $responsePayload, }; From cc9dad6bb8ffa2c51ca62071a27b86b61cd2723d Mon Sep 17 00:00:00 2001 From: shimon Date: Sat, 13 Aug 2022 10:34:03 +0300 Subject: [PATCH 20/46] Tidy up --- app/controllers/api/account.php | 4 ++-- app/controllers/api/functions.php | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/app/controllers/api/account.php b/app/controllers/api/account.php index 24787fb484..d02bcd8751 100644 --- a/app/controllers/api/account.php +++ b/app/controllers/api/account.php @@ -1050,7 +1050,7 @@ App::post('/v1/account/sessions/anonymous') ->label('scope', 'public') ->label('auth.type', 'anonymous') ->label('audits.resource', 'user/{response.userId}') - ->label('audits.userId', '{userId}') + ->label('audits.userId', '{user.userId}') ->label('sdk.auth', []) ->label('sdk.namespace', 'account') ->label('sdk.method', 'createAnonymousSession') @@ -2046,7 +2046,7 @@ App::post('/v1/account/verification') ->label('scope', 'account') ->label('event', 'users.[userId].verification.[tokenId].create') ->label('audits.resource', 'user/{response.userId}') - ->label('audits.userId', '{userId}') + ->label('audits.userId', '{user.userId}') ->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_JWT]) ->label('sdk.namespace', 'account') ->label('sdk.method', 'createVerification') diff --git a/app/controllers/api/functions.php b/app/controllers/api/functions.php index 8b81b60f57..d1271beb44 100644 --- a/app/controllers/api/functions.php +++ b/app/controllers/api/functions.php @@ -347,7 +347,7 @@ App::patch('/v1/functions/:functionId/deployments/:deploymentId') ->desc('Update Function Deployment') ->label('scope', 'functions.write') ->label('event', 'functions.[functionId].deployments.[deploymentId].update') - ->label('audits.resource', 'function/{request.functionId}/deployment/{request.deploymentId}') + ->label('audits.resource', 'function/{request.functionId}') ->label('sdk.auth', [APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'functions') ->label('sdk.method', 'updateDeployment') @@ -451,7 +451,7 @@ App::post('/v1/functions/:functionId/deployments') ->desc('Create Deployment') ->label('scope', 'functions.write') ->label('event', 'functions.[functionId].deployments.[deploymentId].create') - ->label('audits.resource', 'function/{request.functionId}/deployment/{response.$id}') + ->label('audits.resource', 'function/{request.functionId}') ->label('sdk.auth', [APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'functions') ->label('sdk.method', 'createDeployment') @@ -733,7 +733,7 @@ App::delete('/v1/functions/:functionId/deployments/:deploymentId') ->desc('Delete Deployment') ->label('scope', 'functions.write') ->label('event', 'functions.[functionId].deployments.[deploymentId].delete') - ->label('audits.resource', 'function/{request.functionId}/deployment/{request.deploymentId}') + ->label('audits.resource', 'function/{request.functionId}') ->label('sdk.auth', [APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'functions') ->label('sdk.method', 'deleteDeployment') @@ -1069,7 +1069,7 @@ App::post('/v1/functions/:functionId/deployments/:deploymentId/builds/:buildId') ->desc('Retry Build') ->label('scope', 'functions.write') ->label('event', 'functions.[functionId].deployments.[deploymentId].update') - ->label('audits.resource', 'function/{request.functionId}/deployment/{request.deploymentId}/build/{request.buildId}') + ->label('audits.resource', 'function/{request.functionId}') ->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_KEY, APP_AUTH_TYPE_JWT]) ->label('sdk.namespace', 'functions') ->label('sdk.method', 'retryBuild') From 45c46c1794b72b29550c6df936b33f93d7d01465 Mon Sep 17 00:00:00 2001 From: shimon Date: Sat, 13 Aug 2022 11:02:00 +0300 Subject: [PATCH 21/46] sync with 0.16 --- app/controllers/shared/api.php | 86 +++++++++++++++++----------------- 1 file changed, 42 insertions(+), 44 deletions(-) diff --git a/app/controllers/shared/api.php b/app/controllers/shared/api.php index ff4be68c7c..8e028697db 100644 --- a/app/controllers/shared/api.php +++ b/app/controllers/shared/api.php @@ -252,9 +252,7 @@ App::shutdown() } $route = $utopia->match($request); - $requestParams = array_combine( - array_keys($route->getParams()), array_column($route->getParams(), 'value') - ); + $requestParams = array_combine(array_keys($route->getParams()), array_column($route->getParams(), 'value')); $user = $audits->getUser(); $parseLabel = function ($label) use ($responsePayload, $requestParams, $user) { @@ -284,54 +282,54 @@ App::shutdown() return $label; }; - $pattern = $route->getLabel('audits.resource', null); + $pattern = $route->getLabel('audits.resource', null); + if (!empty($pattern)) { + $resource = $parseLabel($pattern); + if (!empty($resource) && $resource !== $pattern) { + $audits->setResource($resource); + } + } + + $pattern = $route->getLabel('audits.userId', null); + if (!empty($pattern)) { + $userId = $parseLabel($pattern); + $user = $dbForProject->getDocument('users', $userId); + $audits->setUser($user); + } + + if (!empty($audits->getResource())) { + /** + * audits.payload is switched to default true + * in order to auto audit payload for all endpoints + */ + $pattern = $route->getLabel('audits.payload', true); if (!empty($pattern)) { - $resource = $parseLabel($pattern); - if (!empty($resource) && $resource !== $pattern) { - $audits->setResource($resource); - } + $audits->setPayload($responsePayload); } - $pattern = $route->getLabel('audits.userId', null); - if (!empty($pattern)) { - $userId = $parseLabel($pattern); - $user = $dbForProject->getDocument('users', $userId); - $audits->setUser($user); + foreach ($events->getParams() as $key => $value) { + $audits->setParam($key, $value); } + $audits->trigger(); + } - if (!empty($audits->getResource())) { - /** - * audits.payload is switched to default true - * in order to auto audit payload for all endpoints - */ - $pattern = $route->getLabel('audits.payload', true); - if (!empty($pattern)) { - $audits->setPayload($responsePayload); - } + if (!empty($deletes->getType())) { + $deletes->trigger(); + } - foreach ($events->getParams() as $key => $value) { - $audits->setParam($key, $value); - } - $audits->trigger(); - } + if (!empty($database->getType())) { + $database->trigger(); + } - if (!empty($deletes->getType())) { - $deletes->trigger(); - } - - if (!empty($database->getType())) { - $database->trigger(); - } - - if ( - App::getEnv('_APP_USAGE_STATS', 'enabled') == 'enabled' - && $project->getId() - && $mode !== APP_MODE_ADMIN // TODO: add check to make sure user is admin - && !empty($route->getLabel('sdk.namespace', null)) + if ( + App::getEnv('_APP_USAGE_STATS', 'enabled') == 'enabled' + && $project->getId() + && $mode !== APP_MODE_ADMIN // TODO: add check to make sure user is admin + && !empty($route->getLabel('sdk.namespace', null)) ) { // Don't calculate console usage on admin mode $usage - ->setParam('networkRequestSize', $request->getSize() + $usage->getParam('storage')) - ->setParam('networkResponseSize', $response->getSize()) - ->submit(); - } + ->setParam('networkRequestSize', $request->getSize() + $usage->getParam('storage')) + ->setParam('networkResponseSize', $response->getSize()) + ->submit(); + } }); From 3ded17badf7691532707434b205382dc838758c7 Mon Sep 17 00:00:00 2001 From: Christy Jacob Date: Sat, 13 Aug 2022 13:40:39 +0530 Subject: [PATCH 22/46] fix: linter --- app/controllers/shared/api.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/controllers/shared/api.php b/app/controllers/shared/api.php index 8e028697db..30d77cd35d 100644 --- a/app/controllers/shared/api.php +++ b/app/controllers/shared/api.php @@ -326,7 +326,7 @@ App::shutdown() && $project->getId() && $mode !== APP_MODE_ADMIN // TODO: add check to make sure user is admin && !empty($route->getLabel('sdk.namespace', null)) - ) { // Don't calculate console usage on admin mode + ) { // Don't calculate console usage on admin mode $usage ->setParam('networkRequestSize', $request->getSize() + $usage->getParam('storage')) ->setParam('networkResponseSize', $response->getSize()) From 51e3fc8cabea308805091b14b639342b5c978311 Mon Sep 17 00:00:00 2001 From: shimon Date: Sat, 13 Aug 2022 12:59:34 +0300 Subject: [PATCH 23/46] some fixes --- app/controllers/api/account.php | 2 +- app/controllers/api/users.php | 7 +++++++ app/controllers/shared/api.php | 2 +- 3 files changed, 9 insertions(+), 2 deletions(-) diff --git a/app/controllers/api/account.php b/app/controllers/api/account.php index 720c6feee5..412af21e99 100644 --- a/app/controllers/api/account.php +++ b/app/controllers/api/account.php @@ -1321,7 +1321,7 @@ App::get('/v1/account/logs') ->action(function (int $limit, int $offset, Response $response, Document $user, Locale $locale, Reader $geodb, Database $dbForProject, Stats $usage) { $audit = new EventAudit($dbForProject); - + var_dump($user); $logs = $audit->getLogsByUser($user->getId(), $limit, $offset); $output = []; diff --git a/app/controllers/api/users.php b/app/controllers/api/users.php index af58c5ca63..4750c35901 100644 --- a/app/controllers/api/users.php +++ b/app/controllers/api/users.php @@ -354,6 +354,7 @@ App::patch('/v1/users/:userId/status') ->groups(['api', 'users']) ->label('event', 'users.[userId].update.status') ->label('scope', 'users.write') + ->label('audits.resource', 'user/{response.$id}') ->label('sdk.auth', [APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'users') ->label('sdk.method', 'updateStatus') @@ -389,6 +390,7 @@ App::patch('/v1/users/:userId/verification') ->groups(['api', 'users']) ->label('event', 'users.[userId].update.verification') ->label('scope', 'users.write') + ->label('audits.resource', 'user/{response.$id}') ->label('sdk.auth', [APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'users') ->label('sdk.method', 'updateEmailVerification') @@ -424,6 +426,7 @@ App::patch('/v1/users/:userId/verification/phone') ->groups(['api', 'users']) ->label('event', 'users.[userId].update.verification') ->label('scope', 'users.write') + ->label('audits.resource', 'user/{response.$id}') ->label('sdk.auth', [APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'users') ->label('sdk.method', 'updatePhoneVerification') @@ -624,6 +627,7 @@ App::patch('/v1/users/:userId/prefs') ->groups(['api', 'users']) ->label('event', 'users.[userId].update.prefs') ->label('scope', 'users.write') + ->label('audits.resource', 'user/{request.userId}') ->label('sdk.auth', [APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'users') ->label('sdk.method', 'updatePrefs') @@ -659,6 +663,7 @@ App::delete('/v1/users/:userId/sessions/:sessionId') ->groups(['api', 'users']) ->label('event', 'users.[userId].sessions.[sessionId].delete') ->label('scope', 'users.write') + ->label('audits.resource', 'user/{request.userId}') ->label('sdk.auth', [APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'users') ->label('sdk.method', 'deleteSession') @@ -707,6 +712,7 @@ App::delete('/v1/users/:userId/sessions') ->groups(['api', 'users']) ->label('event', 'users.[userId].sessions.[sessionId].delete') ->label('scope', 'users.write') + ->label('audits.resource', 'user/{user.$id}') ->label('sdk.auth', [APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'users') ->label('sdk.method', 'deleteSessions') @@ -753,6 +759,7 @@ App::delete('/v1/users/:userId') ->groups(['api', 'users']) ->label('event', 'users.[userId].delete') ->label('scope', 'users.write') + ->label('audits.resource', 'user/{request.userId}') ->label('sdk.auth', [APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'users') ->label('sdk.method', 'delete') diff --git a/app/controllers/shared/api.php b/app/controllers/shared/api.php index 30d77cd35d..4921437916 100644 --- a/app/controllers/shared/api.php +++ b/app/controllers/shared/api.php @@ -269,7 +269,7 @@ App::shutdown() $replace = $parts[1]; $params = match ($namespace) { - 'user' => $user, + 'user' => (array)$user, 'request' => $requestParams, default => $responsePayload, }; From 630954c94edba7cc6583ce620a27c8eb7d35dc67 Mon Sep 17 00:00:00 2001 From: shimon Date: Sat, 13 Aug 2022 17:55:27 +0300 Subject: [PATCH 24/46] some fixes --- app/controllers/api/account.php | 1 - app/controllers/api/users.php | 1 + 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/app/controllers/api/account.php b/app/controllers/api/account.php index 412af21e99..0290d46527 100644 --- a/app/controllers/api/account.php +++ b/app/controllers/api/account.php @@ -1321,7 +1321,6 @@ App::get('/v1/account/logs') ->action(function (int $limit, int $offset, Response $response, Document $user, Locale $locale, Reader $geodb, Database $dbForProject, Stats $usage) { $audit = new EventAudit($dbForProject); - var_dump($user); $logs = $audit->getLogsByUser($user->getId(), $limit, $offset); $output = []; diff --git a/app/controllers/api/users.php b/app/controllers/api/users.php index 4750c35901..ecf21a22bd 100644 --- a/app/controllers/api/users.php +++ b/app/controllers/api/users.php @@ -33,6 +33,7 @@ App::post('/v1/users') ->groups(['api', 'users']) ->label('event', 'users.[userId].create') ->label('scope', 'users.write') + ->label('audits.resource', 'user/{response.$id}') ->label('sdk.auth', [APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'users') ->label('sdk.method', 'create') From 1109004727196e693b8f8ff7d739135c3c9b9817 Mon Sep 17 00:00:00 2001 From: shimon Date: Sun, 14 Aug 2022 22:27:43 +0300 Subject: [PATCH 25/46] some fixes --- app/controllers/api/storage.php | 103 +++++++++++++++++--------------- app/controllers/shared/api.php | 2 +- composer.json | 2 +- composer.lock | 16 ++--- 4 files changed, 66 insertions(+), 57 deletions(-) diff --git a/app/controllers/api/storage.php b/app/controllers/api/storage.php index 9393d32b4f..ff5819c414 100644 --- a/app/controllers/api/storage.php +++ b/app/controllers/api/storage.php @@ -9,6 +9,7 @@ use Appwrite\Utopia\Database\Validator\CustomId; use Appwrite\OpenSSL\OpenSSL; use Appwrite\Stats\Stats; use Appwrite\Utopia\Response; +use phpDocumentor\Reflection\Project; use Utopia\App; use Utopia\Cache\Adapter\Filesystem; use Utopia\Cache\Cache; @@ -35,6 +36,7 @@ use Utopia\Storage\Validator\Upload; use Utopia\Validator\ArrayList; use Utopia\Validator\Boolean; use Utopia\Validator\HexColor; +use Utopia\Validator\Integer; use Utopia\Validator\Range; use Utopia\Validator\Text; use Utopia\Validator\WhiteList; @@ -45,7 +47,6 @@ App::post('/v1/storage/buckets') ->groups(['api', 'storage']) ->label('scope', 'buckets.write') ->label('event', 'buckets.[bucketId].create') - ->label('audits.resource', 'storage/buckets/{response.$id}') ->label('sdk.auth', [APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'storage') ->label('sdk.method', 'createBucket') @@ -65,9 +66,10 @@ App::post('/v1/storage/buckets') ->param('antivirus', true, new Boolean(true), 'Is virus scanning enabled? For file size above ' . Storage::human(APP_LIMIT_ANTIVIRUS, 0) . ' AntiVirus scanning is skipped even if it\'s enabled', true) ->inject('response') ->inject('dbForProject') + ->inject('audits') ->inject('usage') ->inject('events') - ->action(function (string $bucketId, string $name, string $permission, ?array $read, ?array $write, bool $enabled, int $maximumFileSize, array $allowedFileExtensions, bool $encryption, bool $antivirus, Response $response, Database $dbForProject, Stats $usage, Event $events) { + ->action(function (string $bucketId, string $name, string $permission, ?array $read, ?array $write, bool $enabled, int $maximumFileSize, array $allowedFileExtensions, bool $encryption, bool $antivirus, Response $response, Database $dbForProject, Audit $audits, Stats $usage, Event $events) { $bucketId = $bucketId === 'unique()' ? $dbForProject->getId() : $bucketId; try { @@ -125,6 +127,11 @@ App::post('/v1/storage/buckets') throw new Exception('Bucket already exists', 409, Exception::STORAGE_BUCKET_ALREADY_EXISTS); } + $audits + ->setResource('storage/buckets/' . $bucket->getId()) + ->setPayload($bucket->getArrayCopy()) + ; + $events ->setParam('bucketId', $bucket->getId()) ; @@ -208,7 +215,6 @@ App::put('/v1/storage/buckets/:bucketId') ->groups(['api', 'storage']) ->label('scope', 'buckets.write') ->label('event', 'buckets.[bucketId].update') - ->label('audits.resource', 'storage/buckets/{response.$id}') ->label('sdk.auth', [APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'storage') ->label('sdk.method', 'updateBucket') @@ -228,9 +234,10 @@ App::put('/v1/storage/buckets/:bucketId') ->param('antivirus', true, new Boolean(true), 'Is virus scanning enabled? For file size above ' . Storage::human(APP_LIMIT_ANTIVIRUS, 0) . ' AntiVirus scanning is skipped even if it\'s enabled', true) ->inject('response') ->inject('dbForProject') + ->inject('audits') ->inject('usage') ->inject('events') - ->action(function (string $bucketId, string $name, string $permission, ?array $read, ?array $write, bool $enabled, ?int $maximumFileSize, array $allowedFileExtensions, bool $encryption, bool $antivirus, Response $response, Database $dbForProject, Stats $usage, Event $events) { + ->action(function (string $bucketId, string $name, string $permission, ?array $read, ?array $write, bool $enabled, ?int $maximumFileSize, array $allowedFileExtensions, bool $encryption, bool $antivirus, Response $response, Database $dbForProject, Audit $audits, Stats $usage, Event $events) { $bucket = $dbForProject->getDocument('buckets', $bucketId); if ($bucket->isEmpty()) { @@ -246,15 +253,20 @@ App::put('/v1/storage/buckets/:bucketId') $antivirus ??= $bucket->getAttribute('antivirus', true); $bucket = $dbForProject->updateDocument('buckets', $bucket->getId(), $bucket - ->setAttribute('name', $name) - ->setAttribute('$read', $read) - ->setAttribute('$write', $write) - ->setAttribute('maximumFileSize', $maximumFileSize) - ->setAttribute('allowedFileExtensions', $allowedFileExtensions) - ->setAttribute('enabled', (bool) filter_var($enabled, FILTER_VALIDATE_BOOLEAN)) - ->setAttribute('encryption', (bool) filter_var($encryption, FILTER_VALIDATE_BOOLEAN)) - ->setAttribute('permission', $permission) - ->setAttribute('antivirus', (bool) filter_var($antivirus, FILTER_VALIDATE_BOOLEAN))); + ->setAttribute('name', $name) + ->setAttribute('$read', $read) + ->setAttribute('$write', $write) + ->setAttribute('maximumFileSize', $maximumFileSize) + ->setAttribute('allowedFileExtensions', $allowedFileExtensions) + ->setAttribute('enabled', (bool) filter_var($enabled, FILTER_VALIDATE_BOOLEAN)) + ->setAttribute('encryption', (bool) filter_var($encryption, FILTER_VALIDATE_BOOLEAN)) + ->setAttribute('permission', $permission) + ->setAttribute('antivirus', (bool) filter_var($antivirus, FILTER_VALIDATE_BOOLEAN))); + + $audits + ->setResource('storage/buckets/' . $bucket->getId()) + ->setPayload($bucket->getArrayCopy()) + ; $events ->setParam('bucketId', $bucket->getId()) @@ -270,7 +282,6 @@ App::delete('/v1/storage/buckets/:bucketId') ->groups(['api', 'storage']) ->label('scope', 'buckets.write') ->label('event', 'buckets.[bucketId].delete') - ->label('audits.resource', 'storage/buckets/{request.bucketId}') ->label('sdk.auth', [APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'storage') ->label('sdk.method', 'deleteBucket') @@ -280,10 +291,11 @@ App::delete('/v1/storage/buckets/:bucketId') ->param('bucketId', '', new UID(), 'Bucket unique ID.') ->inject('response') ->inject('dbForProject') + ->inject('audits') ->inject('deletes') ->inject('events') ->inject('usage') - ->action(function (string $bucketId, Response $response, Database $dbForProject, Delete $deletes, Event $events, Stats $usage) { + ->action(function (string $bucketId, Response $response, Database $dbForProject, Audit $audits, Delete $deletes, Event $events, Stats $usage) { $bucket = $dbForProject->getDocument('buckets', $bucketId); if ($bucket->isEmpty()) { @@ -303,6 +315,11 @@ App::delete('/v1/storage/buckets/:bucketId') ->setPayload($response->output($bucket, Response::MODEL_BUCKET)) ; + $audits + ->setResource('storage/buckets/' . $bucket->getId()) + ->setPayload($bucket->getArrayCopy()) + ; + $usage->setParam('storage.buckets.delete', 1); $response->noContent(); @@ -314,7 +331,6 @@ App::post('/v1/storage/buckets/:bucketId/files') ->groups(['api', 'storage']) ->label('scope', 'files.write') ->label('event', 'buckets.[bucketId].files.[fileId].create') - ->label('audits.resource', 'storage/files/{response.$id}') ->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_KEY, APP_AUTH_TYPE_JWT]) ->label('sdk.namespace', 'storage') ->label('sdk.method', 'createFile') @@ -333,12 +349,14 @@ App::post('/v1/storage/buckets/:bucketId/files') ->inject('response') ->inject('dbForProject') ->inject('user') + ->inject('audits') ->inject('usage') ->inject('events') ->inject('mode') ->inject('deviceFiles') ->inject('deviceLocal') - ->action(function (string $bucketId, string $fileId, mixed $file, ?array $read, ?array $write, Request $request, Response $response, Database $dbForProject, Document $user, Stats $usage, Event $events, string $mode, Device $deviceFiles, Device $deviceLocal) { + ->inject('project') + ->action(function (string $bucketId, string $fileId, mixed $file, ?array $read, ?array $write, Request $request, Response $response, Database $dbForProject, Document $user, Audit $audits, Stats $usage, Event $events, string $mode, Device $deviceFiles, Device $deviceLocal, Document $project) { $bucket = Authorization::skip(fn () => $dbForProject->getDocument('buckets', $bucketId)); if ( @@ -424,8 +442,8 @@ App::post('/v1/storage/buckets/:bucketId/files') } /** - * Validators - */ + * Validators + */ // Check if file type is allowed $allowedFileExtensions = $bucket->getAttribute('allowedFileExtensions', []); $fileExt = new FileExt($allowedFileExtensions); @@ -578,6 +596,10 @@ App::post('/v1/storage/buckets/:bucketId/files') throw new Exception('Document already exists', 409, Exception::DOCUMENT_ALREADY_EXISTS); } + $audits + ->setResource('storage/files/' . $file->getId()) + ; + $usage ->setParam('storage', $sizeActual ?? 0) ->setParam('storage.files.create', 1) @@ -781,6 +803,7 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/preview') ->alias('/v1/storage/files/:fileId/preview', ['bucketId' => 'default']) ->desc('Get File Preview') ->groups(['api', 'storage']) + ->label('cache', true) ->label('scope', 'files.read') ->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_KEY, APP_AUTH_TYPE_JWT]) ->label('sdk.namespace', 'storage') @@ -841,9 +864,6 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/preview') $outputs = Config::getParam('storage-outputs'); $fileLogos = Config::getParam('storage-logos'); - $date = \date('D, d M Y H:i:s', \time() + (60 * 60 * 24 * 45)) . ' GMT'; // 45 days cache - $key = \md5($fileId . $width . $height . $gravity . $quality . $borderWidth . $borderColor . $borderRadius . $opacity . $rotation . $background . $output); - if ($bucket->getAttribute('permission') === 'bucket') { // skip authorization $file = Authorization::skip(fn () => $dbForProject->getDocument('bucket_' . $bucket->getInternalId(), $fileId)); @@ -860,7 +880,6 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/preview') $algorithm = $file->getAttribute('algorithm'); $cipher = $file->getAttribute('openSSLCipher'); $mime = $file->getAttribute('mimeType'); - if (!\in_array($mime, $inputs) || $file->getAttribute('sizeActual') > (int) App::getEnv('_APP_STORAGE_PREVIEW_LIMIT', 20000000)) { if (!\in_array($mime, $inputs)) { $path = (\array_key_exists($mime, $fileLogos)) ? $fileLogos[$mime] : $fileLogos['default']; @@ -873,7 +892,6 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/preview') $cipher = null; $background = (empty($background)) ? 'eceff1' : $background; $type = \strtolower(\pathinfo($path, PATHINFO_EXTENSION)); - $key = \md5($path . $width . $height . $gravity . $quality . $borderWidth . $borderColor . $borderRadius . $opacity . $rotation . $background . $output); $deviceFiles = $deviceLocal; } @@ -884,23 +902,12 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/preview') throw new Exception('File not found', 404, Exception::STORAGE_FILE_NOT_FOUND); } - $cache = new Cache(new Filesystem(APP_STORAGE_CACHE . DIRECTORY_SEPARATOR . 'app-' . $project->getId() . DIRECTORY_SEPARATOR . $bucketId . DIRECTORY_SEPARATOR . $fileId)); // Limit file number or size - $data = $cache->load($key, 60 * 60 * 24 * 30 * 3/* 3 months */); - if (empty($output)) { // when file extension is not provided and the mime type is not one of our supported outputs // we fallback to `jpg` output format $output = empty($type) ? (array_search($mime, $outputs) ?? 'jpg') : $type; } - if ($data) { - return $response - ->setContentType((\array_key_exists($output, $outputs)) ? $outputs[$output] : $outputs['jpg']) - ->addHeader('Expires', $date) - ->addHeader('X-Appwrite-Cache', 'hit') - ->send($data) - ; - } $source = $deviceFiles->read($path); @@ -945,20 +952,18 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/preview') $data = $image->output($output, $quality); - $cache->save($key, $data); - $usage ->setParam('storage.files.read', 1) ->setParam('bucketId', $bucketId) ; - $response - ->setContentType((\array_key_exists($output, $outputs)) ? $outputs[$output] : $outputs['jpg']) - ->addHeader('Expires', $date) - ->addHeader('X-Appwrite-Cache', 'miss') - ->send($data) - ; + $contentType = (\array_key_exists($output, $outputs)) ? $outputs[$output] : $outputs['jpg']; + $response + ->addHeader('Expires', \date('D, d M Y H:i:s', \time() + 60 * 60 * 24 * 30) . ' GMT') + ->setContentType($contentType) + ->file($data) + ; unset($image); }); @@ -1259,7 +1264,6 @@ App::put('/v1/storage/buckets/:bucketId/files/:fileId') ->groups(['api', 'storage']) ->label('scope', 'files.write') ->label('event', 'buckets.[bucketId].files.[fileId].update') - ->label('audits.resource', 'storage/files/{response.$id}') ->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_KEY, APP_AUTH_TYPE_JWT]) ->label('sdk.namespace', 'storage') ->label('sdk.method', 'updateFile') @@ -1274,10 +1278,11 @@ App::put('/v1/storage/buckets/:bucketId/files/:fileId') ->inject('response') ->inject('dbForProject') ->inject('user') + ->inject('audits') ->inject('usage') ->inject('mode') ->inject('events') - ->action(function (string $bucketId, string $fileId, ?array $read, ?array $write, Response $response, Database $dbForProject, Document $user, Stats $usage, string $mode, Event $events) { + ->action(function (string $bucketId, string $fileId, ?array $read, ?array $write, Response $response, Database $dbForProject, Document $user, Audit $audits, Stats $usage, string $mode, Event $events) { $bucket = Authorization::skip(fn () => $dbForProject->getDocument('buckets', $bucketId)); $read = (is_null($read) && !$user->isEmpty()) ? ['user:' . $user->getId()] : $read ?? []; // By default set read permissions for user $write = (is_null($write) && !$user->isEmpty()) ? ['user:' . $user->getId()] : $write ?? []; @@ -1340,6 +1345,8 @@ App::put('/v1/storage/buckets/:bucketId/files/:fileId') ->setContext('bucket', $bucket) ; + $audits->setResource('file/' . $file->getId()); + $usage ->setParam('storage.files.update', 1) ->setParam('bucketId', $bucketId) @@ -1354,7 +1361,6 @@ App::delete('/v1/storage/buckets/:bucketId/files/:fileId') ->groups(['api', 'storage']) ->label('scope', 'files.write') ->label('event', 'buckets.[bucketId].files.[fileId].delete') - ->label('audits.resource', 'file/{request.fileId}') ->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_KEY, APP_AUTH_TYPE_JWT]) ->label('sdk.namespace', 'storage') ->label('sdk.method', 'deleteFile') @@ -1366,11 +1372,12 @@ App::delete('/v1/storage/buckets/:bucketId/files/:fileId') ->inject('response') ->inject('dbForProject') ->inject('events') + ->inject('audits') ->inject('usage') ->inject('mode') ->inject('deviceFiles') ->inject('project') - ->action(function (string $bucketId, string $fileId, Response $response, Database $dbForProject, Event $events, Stats $usage, string $mode, Device $deviceFiles, Document $project) { + ->action(function (string $bucketId, string $fileId, Response $response, Database $dbForProject, Event $events, Audit $audits, Stats $usage, string $mode, Device $deviceFiles, Document $project) { $bucket = Authorization::skip(fn () => $dbForProject->getDocument('buckets', $bucketId)); if ( @@ -1426,6 +1433,8 @@ App::delete('/v1/storage/buckets/:bucketId/files/:fileId') throw new Exception('Failed to delete file from device', 500, Exception::GENERAL_SERVER_ERROR); } + $audits->setResource('file/' . $file->getId()); + $usage ->setParam('storage', $file->getAttribute('size', 0) * -1) ->setParam('storage.files.delete', 1) diff --git a/app/controllers/shared/api.php b/app/controllers/shared/api.php index 4921437916..a6dcbf706d 100644 --- a/app/controllers/shared/api.php +++ b/app/controllers/shared/api.php @@ -252,7 +252,7 @@ App::shutdown() } $route = $utopia->match($request); - $requestParams = array_combine(array_keys($route->getParams()), array_column($route->getParams(), 'value')); + $requestParams = $route->getParamsValues(); $user = $audits->getUser(); $parseLabel = function ($label) use ($responsePayload, $requestParams, $user) { diff --git a/composer.json b/composer.json index 12fcf99304..fa9b252909 100644 --- a/composer.json +++ b/composer.json @@ -42,7 +42,7 @@ "ext-sockets": "*", "appwrite/php-clamav": "1.1.*", "appwrite/php-runtimes": "0.10.*", - "utopia-php/framework": "0.20.*", + "utopia-php/framework": "0.21.*", "utopia-php/logger": "0.3.*", "utopia-php/abuse": "0.7.*", "utopia-php/analytics": "0.2.*", diff --git a/composer.lock b/composer.lock index 903b7476a4..2f646a3e78 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "993486075710ab0cdbba6c33f0b09218", + "content-hash": "b54c2126173a52cc14bb2d04aec44fb6", "packages": [ { "name": "adhocore/jwt", @@ -2169,16 +2169,16 @@ }, { "name": "utopia-php/framework", - "version": "0.20.0", + "version": "0.21.0", "source": { "type": "git", "url": "https://github.com/utopia-php/framework.git", - "reference": "beb5e861c7d0a6256a1272e6b9d70b060ca8629a" + "reference": "5aa5431788460a782065e42b0e8a35e7f139af2f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/utopia-php/framework/zipball/beb5e861c7d0a6256a1272e6b9d70b060ca8629a", - "reference": "beb5e861c7d0a6256a1272e6b9d70b060ca8629a", + "url": "https://api.github.com/repos/utopia-php/framework/zipball/5aa5431788460a782065e42b0e8a35e7f139af2f", + "reference": "5aa5431788460a782065e42b0e8a35e7f139af2f", "shasum": "" }, "require": { @@ -2212,9 +2212,9 @@ ], "support": { "issues": "https://github.com/utopia-php/framework/issues", - "source": "https://github.com/utopia-php/framework/tree/0.20.0" + "source": "https://github.com/utopia-php/framework/tree/0.21.0" }, - "time": "2022-07-30T09:55:28+00:00" + "time": "2022-08-12T11:37:21+00:00" }, { "name": "utopia-php/image", @@ -5370,5 +5370,5 @@ "platform-overrides": { "php": "8.0" }, - "plugin-api-version": "2.3.0" + "plugin-api-version": "2.2.0" } From 104e6564f79f48083c73e6e0ee374862b80475d1 Mon Sep 17 00:00:00 2001 From: shimon Date: Sun, 14 Aug 2022 23:06:21 +0300 Subject: [PATCH 26/46] some fixes --- app/controllers/api/storage.php | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/app/controllers/api/storage.php b/app/controllers/api/storage.php index ff5819c414..e88dd90f20 100644 --- a/app/controllers/api/storage.php +++ b/app/controllers/api/storage.php @@ -355,8 +355,7 @@ App::post('/v1/storage/buckets/:bucketId/files') ->inject('mode') ->inject('deviceFiles') ->inject('deviceLocal') - ->inject('project') - ->action(function (string $bucketId, string $fileId, mixed $file, ?array $read, ?array $write, Request $request, Response $response, Database $dbForProject, Document $user, Audit $audits, Stats $usage, Event $events, string $mode, Device $deviceFiles, Device $deviceLocal, Document $project) { + ->action(function (string $bucketId, string $fileId, mixed $file, ?array $read, ?array $write, Request $request, Response $response, Database $dbForProject, Document $user, Audit $audits, Stats $usage, Event $events, string $mode, Device $deviceFiles, Device $deviceLocal) { $bucket = Authorization::skip(fn () => $dbForProject->getDocument('buckets', $bucketId)); if ( From 9d02066615e3df5706531ad459777294af9c9539 Mon Sep 17 00:00:00 2001 From: shimon Date: Sun, 14 Aug 2022 23:19:52 +0300 Subject: [PATCH 27/46] some fixes --- .github/workflows/tests.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 2ed2b65ff7..a86f226dd7 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -38,6 +38,9 @@ jobs: - name: Run Tests run: docker compose exec -T appwrite test --debug + - name: Logs + run: docker compose logs appwrite + - name: Teardown if: always() run: | From c0d83374171ff1856072bd8c80416cf5cd6a0325 Mon Sep 17 00:00:00 2001 From: shimon Date: Sun, 14 Aug 2022 23:45:05 +0300 Subject: [PATCH 28/46] some fixes --- .github/workflows/tests.yml | 3 --- app/controllers/api/storage.php | 29 +++++++++++++++++++++++------ 2 files changed, 23 insertions(+), 9 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index a86f226dd7..2ed2b65ff7 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -38,9 +38,6 @@ jobs: - name: Run Tests run: docker compose exec -T appwrite test --debug - - name: Logs - run: docker compose logs appwrite - - name: Teardown if: always() run: | diff --git a/app/controllers/api/storage.php b/app/controllers/api/storage.php index e88dd90f20..eda55b6c8c 100644 --- a/app/controllers/api/storage.php +++ b/app/controllers/api/storage.php @@ -802,7 +802,6 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/preview') ->alias('/v1/storage/files/:fileId/preview', ['bucketId' => 'default']) ->desc('Get File Preview') ->groups(['api', 'storage']) - ->label('cache', true) ->label('scope', 'files.read') ->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_KEY, APP_AUTH_TYPE_JWT]) ->label('sdk.namespace', 'storage') @@ -863,6 +862,9 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/preview') $outputs = Config::getParam('storage-outputs'); $fileLogos = Config::getParam('storage-logos'); + $date = \date('D, d M Y H:i:s', \time() + (60 * 60 * 24 * 45)) . ' GMT'; // 45 days cache + $key = \md5($fileId . $width . $height . $gravity . $quality . $borderWidth . $borderColor . $borderRadius . $opacity . $rotation . $background . $output); + if ($bucket->getAttribute('permission') === 'bucket') { // skip authorization $file = Authorization::skip(fn () => $dbForProject->getDocument('bucket_' . $bucket->getInternalId(), $fileId)); @@ -879,6 +881,7 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/preview') $algorithm = $file->getAttribute('algorithm'); $cipher = $file->getAttribute('openSSLCipher'); $mime = $file->getAttribute('mimeType'); + if (!\in_array($mime, $inputs) || $file->getAttribute('sizeActual') > (int) App::getEnv('_APP_STORAGE_PREVIEW_LIMIT', 20000000)) { if (!\in_array($mime, $inputs)) { $path = (\array_key_exists($mime, $fileLogos)) ? $fileLogos[$mime] : $fileLogos['default']; @@ -891,6 +894,7 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/preview') $cipher = null; $background = (empty($background)) ? 'eceff1' : $background; $type = \strtolower(\pathinfo($path, PATHINFO_EXTENSION)); + $key = \md5($path . $width . $height . $gravity . $quality . $borderWidth . $borderColor . $borderRadius . $opacity . $rotation . $background . $output); $deviceFiles = $deviceLocal; } @@ -901,12 +905,23 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/preview') throw new Exception('File not found', 404, Exception::STORAGE_FILE_NOT_FOUND); } + $cache = new Cache(new Filesystem(APP_STORAGE_CACHE . DIRECTORY_SEPARATOR . 'app-' . $project->getId() . DIRECTORY_SEPARATOR . $bucketId . DIRECTORY_SEPARATOR . $fileId)); // Limit file number or size + $data = $cache->load($key, 60 * 60 * 24 * 30 * 3/* 3 months */); + if (empty($output)) { // when file extension is not provided and the mime type is not one of our supported outputs // we fallback to `jpg` output format $output = empty($type) ? (array_search($mime, $outputs) ?? 'jpg') : $type; } + if ($data) { + return $response + ->setContentType((\array_key_exists($output, $outputs)) ? $outputs[$output] : $outputs['jpg']) + ->addHeader('Expires', $date) + ->addHeader('X-Appwrite-Cache', 'hit') + ->send($data) + ; + } $source = $deviceFiles->read($path); @@ -951,18 +966,20 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/preview') $data = $image->output($output, $quality); + $cache->save($key, $data); + $usage ->setParam('storage.files.read', 1) ->setParam('bucketId', $bucketId) ; - $contentType = (\array_key_exists($output, $outputs)) ? $outputs[$output] : $outputs['jpg']; - $response - ->addHeader('Expires', \date('D, d M Y H:i:s', \time() + 60 * 60 * 24 * 30) . ' GMT') - ->setContentType($contentType) - ->file($data) + ->setContentType((\array_key_exists($output, $outputs)) ? $outputs[$output] : $outputs['jpg']) + ->addHeader('Expires', $date) + ->addHeader('X-Appwrite-Cache', 'miss') + ->send($data) ; + unset($image); }); From 5e476a2e5aebbcdabbc521be2d40fcf40566bbaa Mon Sep 17 00:00:00 2001 From: shimon Date: Mon, 15 Aug 2022 07:29:44 +0300 Subject: [PATCH 29/46] some fixes --- app/controllers/api/storage.php | 54 +++++++++------------------------ 1 file changed, 14 insertions(+), 40 deletions(-) diff --git a/app/controllers/api/storage.php b/app/controllers/api/storage.php index eda55b6c8c..4d8d2932e1 100644 --- a/app/controllers/api/storage.php +++ b/app/controllers/api/storage.php @@ -2,14 +2,12 @@ use Appwrite\Auth\Auth; use Appwrite\ClamAV\Network; -use Appwrite\Event\Audit; use Appwrite\Event\Delete; use Appwrite\Event\Event; use Appwrite\Utopia\Database\Validator\CustomId; use Appwrite\OpenSSL\OpenSSL; use Appwrite\Stats\Stats; use Appwrite\Utopia\Response; -use phpDocumentor\Reflection\Project; use Utopia\App; use Utopia\Cache\Adapter\Filesystem; use Utopia\Cache\Cache; @@ -36,7 +34,6 @@ use Utopia\Storage\Validator\Upload; use Utopia\Validator\ArrayList; use Utopia\Validator\Boolean; use Utopia\Validator\HexColor; -use Utopia\Validator\Integer; use Utopia\Validator\Range; use Utopia\Validator\Text; use Utopia\Validator\WhiteList; @@ -47,6 +44,7 @@ App::post('/v1/storage/buckets') ->groups(['api', 'storage']) ->label('scope', 'buckets.write') ->label('event', 'buckets.[bucketId].create') + ->label('audits.resource', 'storage/buckets/{response.$id}') ->label('sdk.auth', [APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'storage') ->label('sdk.method', 'createBucket') @@ -66,10 +64,9 @@ App::post('/v1/storage/buckets') ->param('antivirus', true, new Boolean(true), 'Is virus scanning enabled? For file size above ' . Storage::human(APP_LIMIT_ANTIVIRUS, 0) . ' AntiVirus scanning is skipped even if it\'s enabled', true) ->inject('response') ->inject('dbForProject') - ->inject('audits') ->inject('usage') ->inject('events') - ->action(function (string $bucketId, string $name, string $permission, ?array $read, ?array $write, bool $enabled, int $maximumFileSize, array $allowedFileExtensions, bool $encryption, bool $antivirus, Response $response, Database $dbForProject, Audit $audits, Stats $usage, Event $events) { + ->action(function (string $bucketId, string $name, string $permission, ?array $read, ?array $write, bool $enabled, int $maximumFileSize, array $allowedFileExtensions, bool $encryption, bool $antivirus, Response $response, Database $dbForProject, Stats $usage, Event $events) { $bucketId = $bucketId === 'unique()' ? $dbForProject->getId() : $bucketId; try { @@ -127,11 +124,6 @@ App::post('/v1/storage/buckets') throw new Exception('Bucket already exists', 409, Exception::STORAGE_BUCKET_ALREADY_EXISTS); } - $audits - ->setResource('storage/buckets/' . $bucket->getId()) - ->setPayload($bucket->getArrayCopy()) - ; - $events ->setParam('bucketId', $bucket->getId()) ; @@ -215,6 +207,7 @@ App::put('/v1/storage/buckets/:bucketId') ->groups(['api', 'storage']) ->label('scope', 'buckets.write') ->label('event', 'buckets.[bucketId].update') + ->label('audits.resource', 'storage/buckets/{response.$id}') ->label('sdk.auth', [APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'storage') ->label('sdk.method', 'updateBucket') @@ -234,10 +227,9 @@ App::put('/v1/storage/buckets/:bucketId') ->param('antivirus', true, new Boolean(true), 'Is virus scanning enabled? For file size above ' . Storage::human(APP_LIMIT_ANTIVIRUS, 0) . ' AntiVirus scanning is skipped even if it\'s enabled', true) ->inject('response') ->inject('dbForProject') - ->inject('audits') ->inject('usage') ->inject('events') - ->action(function (string $bucketId, string $name, string $permission, ?array $read, ?array $write, bool $enabled, ?int $maximumFileSize, array $allowedFileExtensions, bool $encryption, bool $antivirus, Response $response, Database $dbForProject, Audit $audits, Stats $usage, Event $events) { + ->action(function (string $bucketId, string $name, string $permission, ?array $read, ?array $write, bool $enabled, ?int $maximumFileSize, array $allowedFileExtensions, bool $encryption, bool $antivirus, Response $response, Database $dbForProject, Stats $usage, Event $events) { $bucket = $dbForProject->getDocument('buckets', $bucketId); if ($bucket->isEmpty()) { @@ -263,11 +255,6 @@ App::put('/v1/storage/buckets/:bucketId') ->setAttribute('permission', $permission) ->setAttribute('antivirus', (bool) filter_var($antivirus, FILTER_VALIDATE_BOOLEAN))); - $audits - ->setResource('storage/buckets/' . $bucket->getId()) - ->setPayload($bucket->getArrayCopy()) - ; - $events ->setParam('bucketId', $bucket->getId()) ; @@ -282,6 +269,7 @@ App::delete('/v1/storage/buckets/:bucketId') ->groups(['api', 'storage']) ->label('scope', 'buckets.write') ->label('event', 'buckets.[bucketId].delete') + ->label('audits.resource', 'storage/buckets/{request.bucketId}') ->label('sdk.auth', [APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'storage') ->label('sdk.method', 'deleteBucket') @@ -291,11 +279,10 @@ App::delete('/v1/storage/buckets/:bucketId') ->param('bucketId', '', new UID(), 'Bucket unique ID.') ->inject('response') ->inject('dbForProject') - ->inject('audits') ->inject('deletes') ->inject('events') ->inject('usage') - ->action(function (string $bucketId, Response $response, Database $dbForProject, Audit $audits, Delete $deletes, Event $events, Stats $usage) { + ->action(function (string $bucketId, Response $response, Database $dbForProject, Delete $deletes, Event $events, Stats $usage) { $bucket = $dbForProject->getDocument('buckets', $bucketId); if ($bucket->isEmpty()) { @@ -315,11 +302,6 @@ App::delete('/v1/storage/buckets/:bucketId') ->setPayload($response->output($bucket, Response::MODEL_BUCKET)) ; - $audits - ->setResource('storage/buckets/' . $bucket->getId()) - ->setPayload($bucket->getArrayCopy()) - ; - $usage->setParam('storage.buckets.delete', 1); $response->noContent(); @@ -331,6 +313,7 @@ App::post('/v1/storage/buckets/:bucketId/files') ->groups(['api', 'storage']) ->label('scope', 'files.write') ->label('event', 'buckets.[bucketId].files.[fileId].create') + ->label('audits.resource', 'storage/files/{response.$id}') ->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_KEY, APP_AUTH_TYPE_JWT]) ->label('sdk.namespace', 'storage') ->label('sdk.method', 'createFile') @@ -349,13 +332,12 @@ App::post('/v1/storage/buckets/:bucketId/files') ->inject('response') ->inject('dbForProject') ->inject('user') - ->inject('audits') ->inject('usage') ->inject('events') ->inject('mode') ->inject('deviceFiles') ->inject('deviceLocal') - ->action(function (string $bucketId, string $fileId, mixed $file, ?array $read, ?array $write, Request $request, Response $response, Database $dbForProject, Document $user, Audit $audits, Stats $usage, Event $events, string $mode, Device $deviceFiles, Device $deviceLocal) { + ->action(function (string $bucketId, string $fileId, mixed $file, ?array $read, ?array $write, Request $request, Response $response, Database $dbForProject, Document $user, Stats $usage, Event $events, string $mode, Device $deviceFiles, Device $deviceLocal) { $bucket = Authorization::skip(fn () => $dbForProject->getDocument('buckets', $bucketId)); if ( @@ -441,8 +423,8 @@ App::post('/v1/storage/buckets/:bucketId/files') } /** - * Validators - */ + * Validators + */ // Check if file type is allowed $allowedFileExtensions = $bucket->getAttribute('allowedFileExtensions', []); $fileExt = new FileExt($allowedFileExtensions); @@ -595,10 +577,6 @@ App::post('/v1/storage/buckets/:bucketId/files') throw new Exception('Document already exists', 409, Exception::DOCUMENT_ALREADY_EXISTS); } - $audits - ->setResource('storage/files/' . $file->getId()) - ; - $usage ->setParam('storage', $sizeActual ?? 0) ->setParam('storage.files.create', 1) @@ -1280,6 +1258,7 @@ App::put('/v1/storage/buckets/:bucketId/files/:fileId') ->groups(['api', 'storage']) ->label('scope', 'files.write') ->label('event', 'buckets.[bucketId].files.[fileId].update') + ->label('audits.resource', 'storage/files/{response.$id}') ->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_KEY, APP_AUTH_TYPE_JWT]) ->label('sdk.namespace', 'storage') ->label('sdk.method', 'updateFile') @@ -1294,11 +1273,10 @@ App::put('/v1/storage/buckets/:bucketId/files/:fileId') ->inject('response') ->inject('dbForProject') ->inject('user') - ->inject('audits') ->inject('usage') ->inject('mode') ->inject('events') - ->action(function (string $bucketId, string $fileId, ?array $read, ?array $write, Response $response, Database $dbForProject, Document $user, Audit $audits, Stats $usage, string $mode, Event $events) { + ->action(function (string $bucketId, string $fileId, ?array $read, ?array $write, Response $response, Database $dbForProject, Document $user, Stats $usage, string $mode, Event $events) { $bucket = Authorization::skip(fn () => $dbForProject->getDocument('buckets', $bucketId)); $read = (is_null($read) && !$user->isEmpty()) ? ['user:' . $user->getId()] : $read ?? []; // By default set read permissions for user $write = (is_null($write) && !$user->isEmpty()) ? ['user:' . $user->getId()] : $write ?? []; @@ -1361,8 +1339,6 @@ App::put('/v1/storage/buckets/:bucketId/files/:fileId') ->setContext('bucket', $bucket) ; - $audits->setResource('file/' . $file->getId()); - $usage ->setParam('storage.files.update', 1) ->setParam('bucketId', $bucketId) @@ -1377,6 +1353,7 @@ App::delete('/v1/storage/buckets/:bucketId/files/:fileId') ->groups(['api', 'storage']) ->label('scope', 'files.write') ->label('event', 'buckets.[bucketId].files.[fileId].delete') + ->label('audits.resource', 'file/{request.fileId}') ->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_KEY, APP_AUTH_TYPE_JWT]) ->label('sdk.namespace', 'storage') ->label('sdk.method', 'deleteFile') @@ -1388,12 +1365,11 @@ App::delete('/v1/storage/buckets/:bucketId/files/:fileId') ->inject('response') ->inject('dbForProject') ->inject('events') - ->inject('audits') ->inject('usage') ->inject('mode') ->inject('deviceFiles') ->inject('project') - ->action(function (string $bucketId, string $fileId, Response $response, Database $dbForProject, Event $events, Audit $audits, Stats $usage, string $mode, Device $deviceFiles, Document $project) { + ->action(function (string $bucketId, string $fileId, Response $response, Database $dbForProject, Event $events, Stats $usage, string $mode, Device $deviceFiles, Document $project) { $bucket = Authorization::skip(fn () => $dbForProject->getDocument('buckets', $bucketId)); if ( @@ -1449,8 +1425,6 @@ App::delete('/v1/storage/buckets/:bucketId/files/:fileId') throw new Exception('Failed to delete file from device', 500, Exception::GENERAL_SERVER_ERROR); } - $audits->setResource('file/' . $file->getId()); - $usage ->setParam('storage', $file->getAttribute('size', 0) * -1) ->setParam('storage.files.delete', 1) From f12ccfa02aac58fd2df16f61b9549162fd4c47b1 Mon Sep 17 00:00:00 2001 From: shimon Date: Mon, 15 Aug 2022 16:59:58 +0300 Subject: [PATCH 30/46] prefix removed from storage audits label --- app/controllers/api/storage.php | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/app/controllers/api/storage.php b/app/controllers/api/storage.php index 4d8d2932e1..9bc0f4d6b3 100644 --- a/app/controllers/api/storage.php +++ b/app/controllers/api/storage.php @@ -44,7 +44,7 @@ App::post('/v1/storage/buckets') ->groups(['api', 'storage']) ->label('scope', 'buckets.write') ->label('event', 'buckets.[bucketId].create') - ->label('audits.resource', 'storage/buckets/{response.$id}') + ->label('audits.resource', 'buckets/{response.$id}') ->label('sdk.auth', [APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'storage') ->label('sdk.method', 'createBucket') @@ -207,7 +207,7 @@ App::put('/v1/storage/buckets/:bucketId') ->groups(['api', 'storage']) ->label('scope', 'buckets.write') ->label('event', 'buckets.[bucketId].update') - ->label('audits.resource', 'storage/buckets/{response.$id}') + ->label('audits.resource', 'buckets/{response.$id}') ->label('sdk.auth', [APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'storage') ->label('sdk.method', 'updateBucket') @@ -269,7 +269,7 @@ App::delete('/v1/storage/buckets/:bucketId') ->groups(['api', 'storage']) ->label('scope', 'buckets.write') ->label('event', 'buckets.[bucketId].delete') - ->label('audits.resource', 'storage/buckets/{request.bucketId}') + ->label('audits.resource', 'buckets/{request.bucketId}') ->label('sdk.auth', [APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'storage') ->label('sdk.method', 'deleteBucket') @@ -313,7 +313,7 @@ App::post('/v1/storage/buckets/:bucketId/files') ->groups(['api', 'storage']) ->label('scope', 'files.write') ->label('event', 'buckets.[bucketId].files.[fileId].create') - ->label('audits.resource', 'storage/files/{response.$id}') + ->label('audits.resource', 'files/{response.$id}') ->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_KEY, APP_AUTH_TYPE_JWT]) ->label('sdk.namespace', 'storage') ->label('sdk.method', 'createFile') @@ -1258,7 +1258,7 @@ App::put('/v1/storage/buckets/:bucketId/files/:fileId') ->groups(['api', 'storage']) ->label('scope', 'files.write') ->label('event', 'buckets.[bucketId].files.[fileId].update') - ->label('audits.resource', 'storage/files/{response.$id}') + ->label('audits.resource', 'files/{response.$id}') ->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_KEY, APP_AUTH_TYPE_JWT]) ->label('sdk.namespace', 'storage') ->label('sdk.method', 'updateFile') From f091774afd163eadfd63c7d8583dcc843dfd4a76 Mon Sep 17 00:00:00 2001 From: shimon Date: Mon, 15 Aug 2022 20:04:23 +0300 Subject: [PATCH 31/46] fill gaps from merge --- app/controllers/api/account.php | 76 ++++++++++----------------------- app/controllers/api/users.php | 8 ++-- 2 files changed, 26 insertions(+), 58 deletions(-) diff --git a/app/controllers/api/account.php b/app/controllers/api/account.php index 9f0a2b46bc..4610572014 100644 --- a/app/controllers/api/account.php +++ b/app/controllers/api/account.php @@ -236,6 +236,7 @@ App::patch('/v1/account/name') ->groups(['api', 'account']) ->label('event', 'users.[userId].update.name') ->label('scope', 'account') + ->label('audits.resource', 'user/{response.$id}') ->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_JWT]) ->label('sdk.namespace', 'account') ->label('sdk.method', 'updateName') @@ -247,20 +248,14 @@ App::patch('/v1/account/name') ->inject('response') ->inject('user') ->inject('dbForProject') - ->inject('audits') ->inject('usage') ->inject('events') - ->action(function (string $name, Response $response, Document $user, Database $dbForProject, Audit $audits, Stats $usage, Event $events) { + ->action(function (string $name, Response $response, Document $user, Database $dbForProject, Stats $usage, Event $events) { $user = $dbForProject->updateDocument('users', $user->getId(), $user ->setAttribute('name', $name) ->setAttribute('search', implode(' ', [$user->getId(), $name, $user->getAttribute('email')]))); - $audits - ->setResource('user/' . $user->getId()) - ->setUser($user) - ; - $usage->setParam('users.update', 1); $events->setParam('userId', $user->getId()); @@ -272,6 +267,7 @@ App::patch('/v1/account/password') ->groups(['api', 'account']) ->label('event', 'users.[userId].update.password') ->label('scope', 'account') + ->label('audits.resource', 'user/{response.$id}') ->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_JWT]) ->label('sdk.namespace', 'account') ->label('sdk.method', 'updatePassword') @@ -284,10 +280,9 @@ App::patch('/v1/account/password') ->inject('response') ->inject('user') ->inject('dbForProject') - ->inject('audits') ->inject('usage') ->inject('events') - ->action(function (string $password, string $oldPassword, Response $response, Document $user, Database $dbForProject, Audit $audits, Stats $usage, Event $events) { + ->action(function (string $password, string $oldPassword, Response $response, Document $user, Database $dbForProject, Stats $usage, Event $events) { // Check old password only if its an existing user. if ($user->getAttribute('passwordUpdate') !== 0 && !Auth::passwordVerify($oldPassword, $user->getAttribute('password'))) { // Double check user password @@ -302,11 +297,6 @@ App::patch('/v1/account/password') ->setAttribute('passwordUpdate', \time()) ); - $audits - ->setResource('user/' . $user->getId()) - ->setUser($user) - ; - $usage->setParam('users.update', 1); $events->setParam('userId', $user->getId()); @@ -318,6 +308,7 @@ App::patch('/v1/account/email') ->groups(['api', 'account']) ->label('event', 'users.[userId].update.email') ->label('scope', 'account') + ->label('audits.resource', 'user/{response.$id}') ->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_JWT]) ->label('sdk.namespace', 'account') ->label('sdk.method', 'updateEmail') @@ -330,10 +321,9 @@ App::patch('/v1/account/email') ->inject('response') ->inject('user') ->inject('dbForProject') - ->inject('audits') ->inject('usage') ->inject('events') - ->action(function (string $email, string $password, Response $response, Document $user, Database $dbForProject, Audit $audits, Stats $usage, Event $events) { + ->action(function (string $email, string $password, Response $response, Document $user, Database $dbForProject, Stats $usage, Event $events) { $isAnonymousUser = Auth::isAnonymousUser($user); // Check if request is from an anonymous account for converting @@ -358,11 +348,6 @@ App::patch('/v1/account/email') throw new Exception(Exception::USER_EMAIL_ALREADY_EXISTS); } - $audits - ->setResource('user/' . $user->getId()) - ->setUser($user) - ; - $usage->setParam('users.update', 1); $events->setParam('userId', $user->getId()); @@ -374,6 +359,7 @@ App::patch('/v1/account/prefs') ->groups(['api', 'account']) ->label('event', 'users.[userId].update.prefs') ->label('scope', 'account') + ->label('audits.resource', 'user/{response.$id}') ->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_JWT]) ->label('sdk.namespace', 'account') ->label('sdk.method', 'updatePrefs') @@ -385,14 +371,12 @@ App::patch('/v1/account/prefs') ->inject('response') ->inject('user') ->inject('dbForProject') - ->inject('audits') ->inject('usage') ->inject('events') - ->action(function (array $prefs, Response $response, Document $user, Database $dbForProject, Audit $audits, Stats $usage, Event $events) { + ->action(function (array $prefs, Response $response, Document $user, Database $dbForProject, Stats $usage, Event $events) { $user = $dbForProject->updateDocument('users', $user->getId(), $user->setAttribute('prefs', $prefs)); - $audits->setResource('user/' . $user->getId()); $usage->setParam('users.update', 1); $events->setParam('userId', $user->getId()); @@ -404,6 +388,7 @@ App::patch('/v1/account/status') ->groups(['api', 'account']) ->label('event', 'users.[userId].update.status') ->label('scope', 'account') + ->label('audits.resource', 'user/{response.$id}') ->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_JWT]) ->label('sdk.namespace', 'account') ->label('sdk.method', 'updateStatus') @@ -415,17 +400,12 @@ App::patch('/v1/account/status') ->inject('response') ->inject('user') ->inject('dbForProject') - ->inject('audits') ->inject('events') ->inject('usage') - ->action(function (Request $request, Response $response, Document $user, Database $dbForProject, Audit $audits, Event $events, Stats $usage) { + ->action(function (Request $request, Response $response, Document $user, Database $dbForProject, Event $events, Stats $usage) { $user = $dbForProject->updateDocument('users', $user->getId(), $user->setAttribute('status', false)); - $audits - ->setResource('user/' . $user->getId()) - ->setPayload($response->output($user, Response::MODEL_USER)); - $events ->setParam('userId', $user->getId()) ->setPayload($response->output($user, Response::MODEL_USER)); @@ -444,6 +424,7 @@ App::patch('/v1/account/phone') ->groups(['api', 'account']) ->label('event', 'users.[userId].update.phone') ->label('scope', 'account') + ->label('audits.resource', 'user/{response.$id}') ->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_JWT]) ->label('sdk.namespace', 'account') ->label('sdk.method', 'updatePhone') @@ -456,10 +437,9 @@ App::patch('/v1/account/phone') ->inject('response') ->inject('user') ->inject('dbForProject') - ->inject('audits') ->inject('usage') ->inject('events') - ->action(function (string $phone, string $password, Response $response, Document $user, Database $dbForProject, Audit $audits, Stats $usage, Event $events) { + ->action(function (string $phone, string $password, Response $response, Document $user, Database $dbForProject, Stats $usage, Event $events) { $isAnonymousUser = Auth::isAnonymousUser($user); // Check if request is from an anonymous account for converting @@ -481,11 +461,6 @@ App::patch('/v1/account/phone') throw new Exception(Exception::USER_PHONE_ALREADY_EXISTS); } - $audits - ->setResource('user/' . $user->getId()) - ->setUser($user) - ; - $usage->setParam('users.update', 1); $events->setParam('userId', $user->getId()); @@ -712,6 +687,7 @@ App::get('/v1/account/sessions/oauth2/:provider/redirect') ->label('error', __DIR__ . '/../../views/general/error.phtml') ->label('event', 'users.[userId].sessions.[sessionId].create') ->label('scope', 'public') + ->label('audits.resource', 'user/{user.$id}') ->label('abuse-limit', 50) ->label('abuse-key', 'ip:{ip}') ->label('docs', false) @@ -724,10 +700,9 @@ App::get('/v1/account/sessions/oauth2/:provider/redirect') ->inject('user') ->inject('dbForProject') ->inject('geodb') - ->inject('audits') ->inject('events') ->inject('usage') - ->action(function (string $provider, string $code, string $state, Request $request, Response $response, Document $project, Document $user, Database $dbForProject, Reader $geodb, Audit $audits, Event $events, Stats $usage) use ($oauthDefaultSuccess) { + ->action(function (string $provider, string $code, string $state, Request $request, Response $response, Document $project, Document $user, Database $dbForProject, Reader $geodb, Event $events, Stats $usage) use ($oauthDefaultSuccess) { $protocol = $request->getProtocol(); $callback = $protocol . '://' . $request->getHostname() . '/v1/account/sessions/oauth2/callback/' . $provider . '/' . $project->getId(); @@ -904,10 +879,6 @@ App::get('/v1/account/sessions/oauth2/:provider/redirect') $dbForProject->deleteCachedDocument('users', $user->getId()); - $audits->setResource('user/' . $user->getId()) - ->setUser($user) - ; - $usage ->setParam('users.sessions.create', 1) ->setParam('projectId', $project->getId()) @@ -1190,6 +1161,7 @@ App::post('/v1/account/sessions/anonymous') ->label('event', 'users.[userId].sessions.[sessionId].create') ->label('scope', 'public') ->label('auth.type', 'anonymous') + ->label('audits.resource', 'user/{response.userId}') ->label('sdk.auth', []) ->label('sdk.namespace', 'account') ->label('sdk.method', 'createAnonymousSession') @@ -1206,10 +1178,9 @@ App::post('/v1/account/sessions/anonymous') ->inject('project') ->inject('dbForProject') ->inject('geodb') - ->inject('audits') ->inject('usage') ->inject('events') - ->action(function (Request $request, Response $response, Locale $locale, Document $user, Document $project, Database $dbForProject, Reader $geodb, Audit $audits, Stats $usage, Event $events) { + ->action(function (Request $request, Response $response, Locale $locale, Document $user, Document $project, Database $dbForProject, Reader $geodb, Stats $usage, Event $events) { $protocol = $request->getProtocol(); @@ -1282,8 +1253,6 @@ App::post('/v1/account/sessions/anonymous') $dbForProject->deleteCachedDocument('users', $user->getId()); - $audits->setResource('user/' . $user->getId()); - $usage ->setParam('users.sessions.create', 1) ->setParam('provider', 'anonymous') @@ -1568,11 +1537,11 @@ App::post('/v1/account/sessions/anonymous') $protocol = $request->getProtocol(); if ('console' === $project->getId()) { - throw new Exception('Failed to create anonymous user.', 401, Exception::USER_ANONYMOUS_CONSOLE_PROHIBITED); + throw new Exception(Exception::USER_ANONYMOUS_CONSOLE_PROHIBITED, 'Failed to create anonymous user.'); } if (!$user->isEmpty()) { - throw new Exception('Cannot create an anonymous user when logged in.', 401, Exception::USER_SESSION_ALREADY_EXISTS); + throw new Exception(Exception::USER_SESSION_ALREADY_EXISTS, 'Cannot create an anonymous user when logged in.'); } $limit = $project->getAttribute('auths', [])['limit'] ?? 0; @@ -1581,7 +1550,7 @@ App::post('/v1/account/sessions/anonymous') $total = $dbForProject->count('users', max: APP_LIMIT_USERS); if ($total >= $limit) { - throw new Exception('Project registration is restricted. Contact your administrator for more information.', 501, Exception::USER_COUNT_EXCEEDED); + throw new Exception(Exception::USER_COUNT_EXCEEDED, 'Project registration is restricted. Contact your administrator for more information.'); } } @@ -1696,7 +1665,7 @@ App::post('/v1/account/jwt') } if ($current->isEmpty()) { - throw new Exception('No valid session found', 404, Exception::USER_SESSION_NOT_FOUND); + throw new Exception(Exception::USER_SESSION_NOT_FOUND, 'No valid session found'); } $jwt = new JWT(App::getEnv('_APP_OPENSSL_KEY_V1'), 'HS256', 900, 10); // Instantiate with key, algo, maxAge and leeway. @@ -1833,7 +1802,6 @@ App::get('/v1/account/sessions/:sessionId') } throw new Exception(Exception::USER_SESSION_NOT_FOUND); - throw new Exception('Session not found', 404, Exception::USER_SESSION_NOT_FOUND); }); App::patch('/v1/account/name') @@ -1893,7 +1861,7 @@ App::patch('/v1/account/password') // Check old password only if its an existing user. if ($user->getAttribute('passwordUpdate') !== 0 && !Auth::passwordVerify($oldPassword, $user->getAttribute('password'))) { // Double check user password - throw new Exception('Invalid credentials', 401, Exception::USER_INVALID_CREDENTIALS); + throw new Exception(Exception::USER_INVALID_CREDENTIALS, 'Invalid credentials'); } $user = $dbForProject->updateDocument( @@ -1953,7 +1921,7 @@ App::patch('/v1/account/email') try { $user = $dbForProject->updateDocument('users', $user->getId(), $user); } catch (Duplicate $th) { - throw new Exception('Email already exists', 409, Exception::USER_EMAIL_ALREADY_EXISTS); + throw new Exception(Exception::USER_EMAIL_ALREADY_EXISTS, 'Email already exists'); } $usage->setParam('users.update', 1); diff --git a/app/controllers/api/users.php b/app/controllers/api/users.php index 2101045383..326e7dd728 100644 --- a/app/controllers/api/users.php +++ b/app/controllers/api/users.php @@ -374,7 +374,7 @@ App::patch('/v1/users/:userId/status') $user = $dbForProject->getDocument('users', $userId); if ($user->isEmpty()) { - throw new Exception('User not found', 404, Exception::USER_NOT_FOUND); + throw new Exception(Exception::USER_NOT_FOUND, 'User not found'); } $user = $dbForProject->updateDocument('users', $user->getId(), $user->setAttribute('status', (bool) $status)); @@ -410,7 +410,7 @@ App::patch('/v1/users/:userId/verification') $user = $dbForProject->getDocument('users', $userId); if ($user->isEmpty()) { - throw new Exception('User not found', 404, Exception::USER_NOT_FOUND); + throw new Exception(Exception::USER_NOT_FOUND, 'User not found'); } $user = $dbForProject->updateDocument('users', $user->getId(), $user->setAttribute('emailVerification', $emailVerification)); @@ -446,7 +446,7 @@ App::patch('/v1/users/:userId/verification/phone') $user = $dbForProject->getDocument('users', $userId); if ($user->isEmpty()) { - throw new Exception('User not found', 404, Exception::USER_NOT_FOUND); + throw new Exception(Exception::USER_NOT_FOUND, 'User not found'); } $user = $dbForProject->updateDocument('users', $user->getId(), $user->setAttribute('phoneVerification', $phoneVerification)); @@ -811,7 +811,7 @@ App::delete('/v1/users/:userId') $user = $dbForProject->getDocument('users', $userId); if ($user->isEmpty()) { - throw new Exception('User not found', 404, Exception::USER_NOT_FOUND); + throw new Exception(Exception::USER_NOT_FOUND, 'User not found'); } // clone user object to send to workers From 9770f10a8cf4fb1b68d7ae862b86b0747adff351 Mon Sep 17 00:00:00 2001 From: shimon Date: Mon, 15 Aug 2022 20:33:44 +0300 Subject: [PATCH 32/46] fill gaps from merge --- app/controllers/api/users.php | 40 +++++++++++++++++++++++++++++++++-- 1 file changed, 38 insertions(+), 2 deletions(-) diff --git a/app/controllers/api/users.php b/app/controllers/api/users.php index 326e7dd728..391a754703 100644 --- a/app/controllers/api/users.php +++ b/app/controllers/api/users.php @@ -157,6 +157,42 @@ App::get('/v1/users/:userId') $response->dynamic($user, Response::MODEL_USER); }); +App::patch('/v1/users/:userId/prefs') + ->desc('Update User Preferences') + ->groups(['api', 'users']) + ->label('event', 'users.[userId].update.prefs') + ->label('scope', 'users.write') + ->label('audits.resource', 'user/{request.userId}') + ->label('sdk.auth', [APP_AUTH_TYPE_KEY]) + ->label('sdk.namespace', 'users') + ->label('sdk.method', 'updatePrefs') + ->label('sdk.description', '/docs/references/users/update-user-prefs.md') + ->label('sdk.response.code', Response::STATUS_CODE_OK) + ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) + ->label('sdk.response.model', Response::MODEL_PREFERENCES) + ->param('userId', '', new UID(), 'User ID.') + ->param('prefs', '', new Assoc(), 'Prefs key-value JSON object.') + ->inject('response') + ->inject('dbForProject') + ->inject('usage') + ->inject('events') + ->action(function (string $userId, array $prefs, Response $response, Database $dbForProject, Stats $usage, Event $events) { + + $user = $dbForProject->getDocument('users', $userId); + + if ($user->isEmpty()) { + throw new Exception('User not found', 404, Exception::USER_NOT_FOUND); + } + + $user = $dbForProject->updateDocument('users', $user->getId(), $user->setAttribute('prefs', $prefs)); + + $usage->setParam('users.update', 1); + + $events->setParam('userId', $user->getId()); + + $response->dynamic(new Document($prefs), Response::MODEL_PREFERENCES); + }); + App::get('/v1/users/:userId/prefs') ->desc('Get User Preferences') ->groups(['api', 'users']) @@ -446,7 +482,7 @@ App::patch('/v1/users/:userId/verification/phone') $user = $dbForProject->getDocument('users', $userId); if ($user->isEmpty()) { - throw new Exception(Exception::USER_NOT_FOUND, 'User not found'); + throw new Exception(Exception::USER_NOT_FOUND); } $user = $dbForProject->updateDocument('users', $user->getId(), $user->setAttribute('phoneVerification', $phoneVerification)); @@ -811,7 +847,7 @@ App::delete('/v1/users/:userId') $user = $dbForProject->getDocument('users', $userId); if ($user->isEmpty()) { - throw new Exception(Exception::USER_NOT_FOUND, 'User not found'); + throw new Exception(Exception::USER_NOT_FOUND); } // clone user object to send to workers From 8f8f033d1add34fac53cecdc83d847f25b25f43a Mon Sep 17 00:00:00 2001 From: shimon Date: Tue, 16 Aug 2022 12:00:28 +0300 Subject: [PATCH 33/46] fill gaps from merge --- app/controllers/api/account.php | 165 +------------------------------- app/controllers/api/users.php | 7 ++ app/controllers/shared/api.php | 6 +- 3 files changed, 11 insertions(+), 167 deletions(-) diff --git a/app/controllers/api/account.php b/app/controllers/api/account.php index 4610572014..ec9f35a930 100644 --- a/app/controllers/api/account.php +++ b/app/controllers/api/account.php @@ -20,7 +20,6 @@ use Appwrite\Utopia\Response; use Appwrite\Utopia\Database\Validator\CustomId; use MaxMind\Db\Reader; use Utopia\App; -use Appwrite\Event\Audit; use Appwrite\Event\Phone as EventPhone; use Utopia\Audit\Audit as EventAudit; use Utopia\Config\Config; @@ -916,7 +915,6 @@ App::get('/v1/account/sessions/oauth2/:provider/redirect') ; }); - App::post('/v1/account/sessions/magic-url') ->desc('Create Magic URL Session') ->groups(['api', 'account']) @@ -1155,134 +1153,6 @@ App::put('/v1/account/sessions/magic-url') $response->dynamic($session, Response::MODEL_SESSION); }); -App::post('/v1/account/sessions/anonymous') - ->desc('Create Anonymous Session') - ->groups(['api', 'account', 'auth']) - ->label('event', 'users.[userId].sessions.[sessionId].create') - ->label('scope', 'public') - ->label('auth.type', 'anonymous') - ->label('audits.resource', 'user/{response.userId}') - ->label('sdk.auth', []) - ->label('sdk.namespace', 'account') - ->label('sdk.method', 'createAnonymousSession') - ->label('sdk.description', '/docs/references/account/create-session-anonymous.md') - ->label('sdk.response.code', Response::STATUS_CODE_CREATED) - ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) - ->label('sdk.response.model', Response::MODEL_SESSION) - ->label('abuse-limit', 50) - ->label('abuse-key', 'ip:{ip}') - ->inject('request') - ->inject('response') - ->inject('locale') - ->inject('user') - ->inject('project') - ->inject('dbForProject') - ->inject('geodb') - ->inject('usage') - ->inject('events') - ->action(function (Request $request, Response $response, Locale $locale, Document $user, Document $project, Database $dbForProject, Reader $geodb, Stats $usage, Event $events) { - - $protocol = $request->getProtocol(); - - if ('console' === $project->getId()) { - throw new Exception(Exception::USER_ANONYMOUS_CONSOLE_PROHIBITED, 'Failed to create anonymous user'); - } - - if (!$user->isEmpty()) { - throw new Exception(Exception::USER_SESSION_ALREADY_EXISTS, 'Cannot create an anonymous user when logged in'); - } - - $limit = $project->getAttribute('auths', [])['limit'] ?? 0; - - if ($limit !== 0) { - $total = $dbForProject->count('users', max: APP_LIMIT_USERS); - - if ($total >= $limit) { - throw new Exception(Exception::USER_COUNT_EXCEEDED); - } - } - - $userId = $dbForProject->getId(); - $user = Authorization::skip(fn() => $dbForProject->createDocument('users', new Document([ - '$id' => $userId, - '$read' => ['role:all'], - '$write' => ['user:' . $userId], - 'email' => null, - 'emailVerification' => false, - 'status' => true, - 'password' => null, - 'passwordUpdate' => 0, - 'registration' => \time(), - 'reset' => false, - 'name' => null, - 'prefs' => new \stdClass(), - 'sessions' => null, - 'tokens' => null, - 'memberships' => null, - 'search' => $userId - ]))); - - // Create session token - - $detector = new Detector($request->getUserAgent('UNKNOWN')); - $record = $geodb->get($request->getIP()); - $secret = Auth::tokenGenerator(); - $expiry = \time() + Auth::TOKEN_EXPIRATION_LOGIN_LONG; - $session = new Document(array_merge( - [ - '$id' => $dbForProject->getId(), - 'userId' => $user->getId(), - 'userInternalId' => $user->getInternalId(), - 'provider' => Auth::SESSION_PROVIDER_ANONYMOUS, - 'secret' => Auth::hash($secret), // One way hash encryption to protect DB leak - 'expire' => $expiry, - 'userAgent' => $request->getUserAgent('UNKNOWN'), - 'ip' => $request->getIP(), - 'countryCode' => ($record) ? \strtolower($record['country']['iso_code']) : '--', - ], - $detector->getOS(), - $detector->getClient(), - $detector->getDevice() - )); - - Authorization::setRole('user:' . $user->getId()); - - $session = $dbForProject->createDocument('sessions', $session - ->setAttribute('$read', ['user:' . $user->getId()]) - ->setAttribute('$write', ['user:' . $user->getId()])); - - $dbForProject->deleteCachedDocument('users', $user->getId()); - - $usage - ->setParam('users.sessions.create', 1) - ->setParam('provider', 'anonymous') - ; - - $events - ->setParam('userId', $user->getId()) - ->setParam('sessionId', $session->getId()) - ; - - if (!Config::getParam('domainVerification')) { - $response->addHeader('X-Fallback-Cookies', \json_encode([Auth::$cookieName => Auth::encodeSession($user->getId(), $secret)])); - } - - $response - ->addCookie(Auth::$cookieName . '_legacy', Auth::encodeSession($user->getId(), $secret), $expiry, '/', Config::getParam('cookieDomain'), ('https' == $protocol), true, null) - ->addCookie(Auth::$cookieName, Auth::encodeSession($user->getId(), $secret), $expiry, '/', Config::getParam('cookieDomain'), ('https' == $protocol), true, Config::getParam('cookieSamesite')) - ->setStatusCode(Response::STATUS_CODE_CREATED) - ; - - $countryName = $locale->getText('countries.' . strtolower($session->getAttribute('countryCode')), $locale->getText('locale.country.unknown')); - - $session - ->setAttribute('current', true) - ->setAttribute('countryName', $countryName) - ; - - $response->dynamic($session, Response::MODEL_SESSION); - }); - App::post('/v1/account/sessions/phone') ->desc('Create Phone Session') ->groups(['api', 'account']) @@ -1513,7 +1383,7 @@ App::post('/v1/account/sessions/anonymous') ->label('scope', 'public') ->label('auth.type', 'anonymous') ->label('audits.resource', 'user/{response.userId}') - ->label('audits.userId', '{user.userId}') + ->label('audits.userId', '{response.userId}') ->label('sdk.auth', []) ->label('sdk.namespace', 'account') ->label('sdk.method', 'createAnonymousSession') @@ -1804,38 +1674,6 @@ App::get('/v1/account/sessions/:sessionId') throw new Exception(Exception::USER_SESSION_NOT_FOUND); }); -App::patch('/v1/account/name') - ->desc('Update Account Name') - ->groups(['api', 'account']) - ->label('event', 'users.[userId].update.name') - ->label('scope', 'account') - ->label('audits.resource', 'user/{response.$id}') - ->label('audits.userId', '{response.$id}') - ->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_JWT]) - ->label('sdk.namespace', 'account') - ->label('sdk.method', 'updateName') - ->label('sdk.description', '/docs/references/account/update-name.md') - ->label('sdk.response.code', Response::STATUS_CODE_OK) - ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) - ->label('sdk.response.model', Response::MODEL_USER) - ->param('name', '', new Text(128), 'User name. Max length: 128 chars.') - ->inject('response') - ->inject('user') - ->inject('dbForProject') - ->inject('usage') - ->inject('events') - ->action(function (string $name, Response $response, Document $user, Database $dbForProject, Stats $usage, Event $events) { - - $user = $dbForProject->updateDocument('users', $user->getId(), $user - ->setAttribute('name', $name) - ->setAttribute('search', implode(' ', [$user->getId(), $name, $user->getAttribute('email', ''), $user->getAttribute('phone', '')]))); - - $usage->setParam('users.update', 1); - $events->setParam('userId', $user->getId()); - - $response->dynamic($user, Response::MODEL_USER); - }); - App::patch('/v1/account/password') ->desc('Update Account Password') ->groups(['api', 'account']) @@ -2450,7 +2288,6 @@ App::post('/v1/account/verification') ->label('scope', 'account') ->label('event', 'users.[userId].verification.[tokenId].create') ->label('audits.resource', 'user/{response.userId}') - ->label('audits.userId', '{user.userId}') ->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_JWT]) ->label('sdk.namespace', 'account') ->label('sdk.method', 'createVerification') diff --git a/app/controllers/api/users.php b/app/controllers/api/users.php index 391a754703..67d498c0ba 100644 --- a/app/controllers/api/users.php +++ b/app/controllers/api/users.php @@ -34,6 +34,7 @@ App::post('/v1/users') ->label('event', 'users.[userId].create') ->label('scope', 'users.write') ->label('audits.resource', 'user/{response.$id}') + ->label('audits.userId', '{response.$id}') ->label('sdk.auth', [APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'users') ->label('sdk.method', 'create') @@ -163,6 +164,7 @@ App::patch('/v1/users/:userId/prefs') ->label('event', 'users.[userId].update.prefs') ->label('scope', 'users.write') ->label('audits.resource', 'user/{request.userId}') + ->label('audits.userId', '{request.userId}') ->label('sdk.auth', [APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'users') ->label('sdk.method', 'updatePrefs') @@ -392,6 +394,7 @@ App::patch('/v1/users/:userId/status') ->label('event', 'users.[userId].update.status') ->label('scope', 'users.write') ->label('audits.resource', 'user/{response.$id}') + ->label('audits.userId', '{response.$id}') ->label('sdk.auth', [APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'users') ->label('sdk.method', 'updateStatus') @@ -500,6 +503,7 @@ App::patch('/v1/users/:userId/name') ->label('event', 'users.[userId].update.name') ->label('scope', 'users.write') ->label('audits.resource', 'user/{response.$id}') + ->label('audits.userId', '{response.$id}') ->label('sdk.auth', [APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'users') ->label('sdk.method', 'updateName') @@ -538,6 +542,7 @@ App::patch('/v1/users/:userId/password') ->label('event', 'users.[userId].update.password') ->label('scope', 'users.write') ->label('audits.resource', 'user/{response.$id}') + ->label('audits.userId', '{response.$id}') ->label('sdk.auth', [APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'users') ->label('sdk.method', 'updatePassword') @@ -575,6 +580,7 @@ App::patch('/v1/users/:userId/email') ->label('event', 'users.[userId].update.email') ->label('scope', 'users.write') ->label('audits.resource', 'user/{response.$id}') + ->label('audits.userId', '{response.$id}') ->label('sdk.auth', [APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'users') ->label('sdk.method', 'updateEmail') @@ -662,6 +668,7 @@ App::patch('/v1/users/:userId/verification') ->label('event', 'users.[userId].update.verification') ->label('scope', 'users.write') ->label('audits.resource', 'user/{request.userId}') + ->label('audits.userId', '{request.userId}') ->label('sdk.auth', [APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'users') ->label('sdk.method', 'updateEmailVerification') diff --git a/app/controllers/shared/api.php b/app/controllers/shared/api.php index f60734e20d..4243700fd3 100644 --- a/app/controllers/shared/api.php +++ b/app/controllers/shared/api.php @@ -265,8 +265,8 @@ App::shutdown() throw new Exception('Too less or too many parts', 400, Exception::GENERAL_ARGUMENT_INVALID); } - $namespace = $parts[0]; - $replace = $parts[1]; + $namespace = $parts[0] ?? ''; + $replace = $parts[1] ?? ''; $params = match ($namespace) { 'user' => (array)$user, @@ -297,7 +297,7 @@ App::shutdown() $audits->setUser($user); } - if (!empty($audits->getResource())) { + if (!empty($audits->getResource()) && !empty($audits->getUser()->getId())) { /** * audits.payload is switched to default true * in order to auto audit payload for all endpoints From beaad6c49d44fa942a491547b922e9df1f8c6fda Mon Sep 17 00:00:00 2001 From: shimon Date: Tue, 16 Aug 2022 13:19:38 +0300 Subject: [PATCH 34/46] fill gaps from merge --- app/controllers/api/users.php | 2 -- 1 file changed, 2 deletions(-) diff --git a/app/controllers/api/users.php b/app/controllers/api/users.php index 8a5137bd03..10ce8b912c 100644 --- a/app/controllers/api/users.php +++ b/app/controllers/api/users.php @@ -700,8 +700,6 @@ App::patch('/v1/users/:userId/verification') $response->dynamic($user, Response::MODEL_USER); }); -App::patch('/v1/users/:userId/verification/phone') - ->desc('Update Phone Verification') App::patch('/v1/users/:userId/prefs') ->desc('Update User Preferences') ->groups(['api', 'users']) From de4289509694cc900dea31c5cd904a513eb56171 Mon Sep 17 00:00:00 2001 From: shimon Date: Tue, 16 Aug 2022 14:27:50 +0300 Subject: [PATCH 35/46] fill gaps from merge --- app/controllers/api/account.php | 6 +++--- app/controllers/api/users.php | 1 - tests/e2e/Services/Webhooks/WebhooksCustomServerTest.php | 2 +- 3 files changed, 4 insertions(+), 5 deletions(-) diff --git a/app/controllers/api/account.php b/app/controllers/api/account.php index 949d5f4928..1c0d7f4b05 100644 --- a/app/controllers/api/account.php +++ b/app/controllers/api/account.php @@ -1407,11 +1407,11 @@ App::post('/v1/account/sessions/anonymous') $protocol = $request->getProtocol(); if ('console' === $project->getId()) { - throw new Exception(Exception::USER_ANONYMOUS_CONSOLE_PROHIBITED, 'Failed to create anonymous user.'); + throw new Exception(Exception::USER_ANONYMOUS_CONSOLE_PROHIBITED, 'Failed to create anonymous user'); } if (!$user->isEmpty()) { - throw new Exception(Exception::USER_SESSION_ALREADY_EXISTS, 'Cannot create an anonymous user when logged in.'); + throw new Exception(Exception::USER_SESSION_ALREADY_EXISTS, 'Cannot create an anonymous user when logged in'); } $limit = $project->getAttribute('auths', [])['limit'] ?? 0; @@ -1420,7 +1420,7 @@ App::post('/v1/account/sessions/anonymous') $total = $dbForProject->count('users', max: APP_LIMIT_USERS); if ($total >= $limit) { - throw new Exception(Exception::USER_COUNT_EXCEEDED, 'Project registration is restricted. Contact your administrator for more information.'); + throw new Exception(Exception::USER_COUNT_EXCEEDED); } } diff --git a/app/controllers/api/users.php b/app/controllers/api/users.php index 10ce8b912c..d1d42512a7 100644 --- a/app/controllers/api/users.php +++ b/app/controllers/api/users.php @@ -734,7 +734,6 @@ App::patch('/v1/users/:userId/prefs') $response->dynamic(new Document($prefs), Response::MODEL_PREFERENCES); $response->dynamic($user, Response::MODEL_USER); - }); App::delete('/v1/users/:userId/sessions/:sessionId') diff --git a/tests/e2e/Services/Webhooks/WebhooksCustomServerTest.php b/tests/e2e/Services/Webhooks/WebhooksCustomServerTest.php index fd34c8bcb9..594d5c9f76 100644 --- a/tests/e2e/Services/Webhooks/WebhooksCustomServerTest.php +++ b/tests/e2e/Services/Webhooks/WebhooksCustomServerTest.php @@ -289,7 +289,7 @@ class WebhooksCustomServerTest extends Scope $this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Id'] ?? '', $this->getProject()['webhookId']); $this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Project-Id'] ?? '', $this->getProject()['$id']); $this->assertEquals(empty($webhook['headers']['X-Appwrite-Webhook-User-Id'] ?? ''), ('server' === $this->getSide())); - $this->assertEquals($webhook['data']['a'], 'b'); + $this->assertEquals($webhook['data']['prefs']['a'], 'b'); return $data; } From 51cb03a93e2cc8d8d89ff5b6fcff045cba15a521 Mon Sep 17 00:00:00 2001 From: Christy Jacob Date: Tue, 16 Aug 2022 17:58:30 +0530 Subject: [PATCH 36/46] feat: linter fix --- app/controllers/shared/api.php | 138 ++++++++++++++++----------------- 1 file changed, 67 insertions(+), 71 deletions(-) diff --git a/app/controllers/shared/api.php b/app/controllers/shared/api.php index 4243700fd3..7e8ad22a3f 100644 --- a/app/controllers/shared/api.php +++ b/app/controllers/shared/api.php @@ -18,6 +18,32 @@ use Utopia\Database\Database; use Utopia\Database\Document; use Utopia\Database\Validator\Authorization; +$parseLabel = function (string $label, array $responsePayload, array $requestParams, Document $user) { + preg_match_all('/{(.*?)}/', $label, $matches); + foreach ($matches[1] ?? [] as $pos => $match) { + $find = $matches[0][$pos]; + $parts = explode('.', $match); + + if (count($parts) !== 2) { + throw new Exception('Too less or too many parts', 400, Exception::GENERAL_ARGUMENT_INVALID); + } + + $namespace = $parts[0] ?? ''; + $replace = $parts[1] ?? ''; + + $params = match ($namespace) { + 'user' => (array)$user, + 'request' => $requestParams, + default => $responsePayload, + }; + + if (array_key_exists($replace, $params)) { + $label = \str_replace($find, $params[$replace], $label); + } + } + return $label; +}; + App::init() ->groups(['api']) ->inject('utopia') @@ -34,7 +60,6 @@ App::init() ->inject('dbForProject') ->inject('mode') ->action(function (App $utopia, Request $request, Response $response, Document $project, Document $user, Event $events, Audit $audits, Mail $mails, Stats $usage, Delete $deletes, EventDatabase $database, Database $dbForProject, string $mode) { - $route = $utopia->match($request); if ($project->isEmpty() && $route->getLabel('abuse-limit', 0) > 0) { // Abuse limit requires an active project scope @@ -131,7 +156,6 @@ App::init() ->inject('request') ->inject('project') ->action(function (App $utopia, Request $request, Document $project) { - $route = $utopia->match($request); $isPrivilegedUser = Auth::isPrivilegedUser(Authorization::getRoles()); @@ -192,8 +216,7 @@ App::shutdown() ->inject('database') ->inject('mode') ->inject('dbForProject') - ->action(function (App $utopia, Request $request, Response $response, Document $project, Event $events, Audit $audits, Stats $usage, Delete $deletes, EventDatabase $database, string $mode, Database $dbForProject) { - + ->action(function (App $utopia, Request $request, Response $response, Document $project, Event $events, Audit $audits, Stats $usage, Delete $deletes, EventDatabase $database, string $mode, Database $dbForProject) use ($parseLabel) { $responsePayload = $response->getPayload(); if (!empty($events->getEvent())) { @@ -255,81 +278,54 @@ App::shutdown() $requestParams = $route->getParamsValues(); $user = $audits->getUser(); - $parseLabel = function ($label) use ($responsePayload, $requestParams, $user) { - preg_match_all('/{(.*?)}/', $label, $matches); - foreach ($matches[1] ?? [] as $pos => $match) { - $find = $matches[0][$pos]; - $parts = explode('.', $match); + $pattern = $route->getLabel('audits.resource', null); + if (!empty($pattern)) { + $resource = $parseLabel($pattern, $responsePayload, $requestParams, $user); + if (!empty($resource) && $resource !== $pattern) { + $audits->setResource($resource); + } + } - if (count($parts) !== 2) { - throw new Exception('Too less or too many parts', 400, Exception::GENERAL_ARGUMENT_INVALID); - } + $pattern = $route->getLabel('audits.userId', null); + if (!empty($pattern)) { + $userId = $parseLabel($pattern, $responsePayload, $requestParams, $user); + $user = $dbForProject->getDocument('users', $userId); + $audits->setUser($user); + } - $namespace = $parts[0] ?? ''; - $replace = $parts[1] ?? ''; - - $params = match ($namespace) { - 'user' => (array)$user, - 'request' => $requestParams, - default => $responsePayload, - }; - - if (array_key_exists($replace, $params)) { - $label = \str_replace($find, $params[$replace], $label); - } + if (!empty($audits->getResource()) && !empty($audits->getUser()->getId())) { + /** + * audits.payload is switched to default true + * in order to auto audit payload for all endpoints + */ + $pattern = $route->getLabel('audits.payload', true); + if (!empty($pattern)) { + $audits->setPayload($responsePayload); } - return $label; - }; - - $pattern = $route->getLabel('audits.resource', null); - if (!empty($pattern)) { - $resource = $parseLabel($pattern); - if (!empty($resource) && $resource !== $pattern) { - $audits->setResource($resource); - } - } - - $pattern = $route->getLabel('audits.userId', null); - if (!empty($pattern)) { - $userId = $parseLabel($pattern); - $user = $dbForProject->getDocument('users', $userId); - $audits->setUser($user); - } - - if (!empty($audits->getResource()) && !empty($audits->getUser()->getId())) { - /** - * audits.payload is switched to default true - * in order to auto audit payload for all endpoints - */ - $pattern = $route->getLabel('audits.payload', true); - if (!empty($pattern)) { - $audits->setPayload($responsePayload); + foreach ($events->getParams() as $key => $value) { + $audits->setParam($key, $value); + } + $audits->trigger(); } - foreach ($events->getParams() as $key => $value) { - $audits->setParam($key, $value); + if (!empty($deletes->getType())) { + $deletes->trigger(); } - $audits->trigger(); - } - if (!empty($deletes->getType())) { - $deletes->trigger(); - } + if (!empty($database->getType())) { + $database->trigger(); + } - if (!empty($database->getType())) { - $database->trigger(); - } - - if ( - App::getEnv('_APP_USAGE_STATS', 'enabled') == 'enabled' - && $project->getId() - && $mode !== APP_MODE_ADMIN // TODO: add check to make sure user is admin - && !empty($route->getLabel('sdk.namespace', null)) - ) { // Don't calculate console usage on admin mode + if ( + App::getEnv('_APP_USAGE_STATS', 'enabled') == 'enabled' + && $project->getId() + && $mode !== APP_MODE_ADMIN // TODO: add check to make sure user is admin + && !empty($route->getLabel('sdk.namespace', null)) + ) { // Don't calculate console usage on admin mode $usage - ->setParam('networkRequestSize', $request->getSize() + $usage->getParam('storage')) - ->setParam('networkResponseSize', $response->getSize()) - ->submit(); - } + ->setParam('networkRequestSize', $request->getSize() + $usage->getParam('storage')) + ->setParam('networkResponseSize', $response->getSize()) + ->submit(); + } }); From 5d284b8c27d8ceb9afb1425ce9cd8a1e744bf853 Mon Sep 17 00:00:00 2001 From: shimon Date: Tue, 16 Aug 2022 16:20:35 +0300 Subject: [PATCH 37/46] fill gaps from merge --- app/controllers/api/account.php | 94 +++++++-------------------------- app/controllers/shared/api.php | 2 + 2 files changed, 22 insertions(+), 74 deletions(-) diff --git a/app/controllers/api/account.php b/app/controllers/api/account.php index 1c0d7f4b05..4d81f33ad6 100644 --- a/app/controllers/api/account.php +++ b/app/controllers/api/account.php @@ -47,7 +47,6 @@ App::post('/v1/account') ->label('scope', 'public') ->label('auth.type', 'emailPassword') ->label('audits.resource', 'user/{response.$id}') - ->label('audits.userId', '{response.$id}') ->label('sdk.auth', []) ->label('sdk.namespace', 'account') ->label('sdk.method', 'create') @@ -916,7 +915,7 @@ App::get('/v1/account/sessions/oauth2/:provider/redirect') }); App::post('/v1/account/sessions/magic-url') - ->desc('Create Magic URL session') + ->desc('Create Magic URL Session') ->groups(['api', 'account']) ->label('scope', 'public') ->label('auth.type', 'magic-url') @@ -941,10 +940,10 @@ App::post('/v1/account/sessions/magic-url') ->inject('locale') ->inject('events') ->inject('mails') - ->action(function (string $userId, string $email, string $url, Request $request, Response $response, Document $project, Database $dbForProject, Locale $locale, Event $events, Mail $mails) { + ->action(function (string $userId, string $email, string $url, Request $request, Response $response, Document $project, Database $dbForProject, Locale $locale, Audit $audits, Event $events, Mail $mails) { if (empty(App::getEnv('_APP_SMTP_HOST'))) { - throw new Exception(Exception::GENERAL_SMTP_DISABLED, 'SMTP disabled'); + throw new Exception(Exception::GENERAL_SMTP_DISABLED); } $roles = Authorization::getRoles(); @@ -1034,6 +1033,11 @@ App::post('/v1/account/sessions/magic-url') // Hide secret for clients $token->setAttribute('secret', ($isPrivilegedUser || $isAppUser) ? $loginSecret : ''); + $audits + ->setResource('user/' . $user->getId()) + ->setUser($user) + ; + $response ->setStatusCode(Response::STATUS_CODE_CREATED) ->dynamic($token, Response::MODEL_TOKEN) @@ -1175,12 +1179,13 @@ App::post('/v1/account/sessions/phone') ->inject('response') ->inject('project') ->inject('dbForProject') + ->inject('audits') ->inject('events') ->inject('messaging') ->inject('phone') - ->action(function (string $userId, string $number, Request $request, Response $response, Document $project, Database $dbForProject, Event $events, EventPhone $messaging, Phone $phone) { + ->action(function (string $userId, string $number, Request $request, Response $response, Document $project, Database $dbForProject, Audit $audits, Event $events, EventPhone $messaging, Phone $phone) { if (empty(App::getEnv('_APP_PHONE_PROVIDER'))) { - throw new Exception(Exception::GENERAL_PHONE_DISABLED, 'Phone provider not configured'); + throw new Exception(Exception::GENERAL_PHONE_DISABLED); } $roles = Authorization::getRoles(); @@ -1261,6 +1266,11 @@ App::post('/v1/account/sessions/phone') // Hide secret for clients $token->setAttribute('secret', ($isPrivilegedUser || $isAppUser) ? $secret : ''); + $audits + ->setResource('user/' . $user->getId()) + ->setUser($user) + ; + $response ->setStatusCode(Response::STATUS_CODE_CREATED) ->dynamic($token, Response::MODEL_TOKEN) @@ -1268,12 +1278,10 @@ App::post('/v1/account/sessions/phone') }); App::put('/v1/account/sessions/phone') - ->desc('Create Phone session (confirmation)') + ->desc('Create Phone Session (confirmation)') ->groups(['api', 'account']) ->label('scope', 'public') ->label('event', 'users.[userId].sessions.[sessionId].create') - ->label('audits.resource', 'user/{response.userId}') - ->label('audits.userId', '{response.userId}') ->label('sdk.auth', []) ->label('sdk.namespace', 'account') ->label('sdk.method', 'updatePhoneSession') @@ -1407,11 +1415,11 @@ App::post('/v1/account/sessions/anonymous') $protocol = $request->getProtocol(); if ('console' === $project->getId()) { - throw new Exception(Exception::USER_ANONYMOUS_CONSOLE_PROHIBITED, 'Failed to create anonymous user'); + throw new Exception(Exception::USER_ANONYMOUS_CONSOLE_PROHIBITED, 'Failed to create anonymous user.'); } if (!$user->isEmpty()) { - throw new Exception(Exception::USER_SESSION_ALREADY_EXISTS, 'Cannot create an anonymous user when logged in'); + throw new Exception(Exception::USER_SESSION_ALREADY_EXISTS, 'Cannot create an anonymous user when logged in.'); } $limit = $project->getAttribute('auths', [])['limit'] ?? 0; @@ -1420,7 +1428,7 @@ App::post('/v1/account/sessions/anonymous') $total = $dbForProject->count('users', max: APP_LIMIT_USERS); if ($total >= $limit) { - throw new Exception(Exception::USER_COUNT_EXCEEDED); + throw new Exception(Exception::USER_COUNT_EXCEEDED, 'Project registration is restricted. Contact your administrator for more information.'); } } @@ -1632,65 +1640,6 @@ App::get('/v1/account/sessions') ]), Response::MODEL_SESSION_LIST); }); -App::get('/v1/account/logs') - ->desc('Get Account Logs') - ->groups(['api', 'account']) - ->label('scope', 'account') - ->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_JWT]) - ->label('sdk.namespace', 'account') - ->label('sdk.method', 'getLogs') - ->label('sdk.description', '/docs/references/account/get-logs.md') - ->label('sdk.response.code', Response::STATUS_CODE_OK) - ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) - ->label('sdk.response.model', Response::MODEL_LOG_LIST) - ->param('limit', 25, new Range(0, 100), 'Maximum number of logs to return in response. By default will return maximum 25 results. Maximum of 100 results allowed per request.', true) - ->param('offset', 0, new Range(0, APP_LIMIT_COUNT), 'Offset value. The default value is 0. Use this value to manage pagination. [learn more about pagination](https://appwrite.io/docs/pagination)', true) - ->inject('response') - ->inject('user') - ->inject('locale') - ->inject('geodb') - ->inject('dbForProject') - ->inject('usage') - ->action(function (int $limit, int $offset, Response $response, Document $user, Locale $locale, Reader $geodb, Database $dbForProject, Stats $usage) { - - $audit = new EventAudit($dbForProject); - - $logs = $audit->getLogsByUser($user->getId(), $limit, $offset); - - $output = []; - - foreach ($logs as $i => &$log) { - $log['userAgent'] = (!empty($log['userAgent'])) ? $log['userAgent'] : 'UNKNOWN'; - - $detector = new Detector($log['userAgent']); - - $output[$i] = new Document(array_merge( - $log->getArrayCopy(), - $log['data'], - $detector->getOS(), - $detector->getClient(), - $detector->getDevice() - )); - - $record = $geodb->get($log['ip']); - - if ($record) { - $output[$i]['countryCode'] = $locale->getText('countries.' . strtolower($record['country']['iso_code']), false) ? \strtolower($record['country']['iso_code']) : '--'; - $output[$i]['countryName'] = $locale->getText('countries.' . strtolower($record['country']['iso_code']), $locale->getText('locale.country.unknown')); - } else { - $output[$i]['countryCode'] = '--'; - $output[$i]['countryName'] = $locale->getText('locale.country.unknown'); - } - } - - $usage->setParam('users.read', 1); - - $response->dynamic(new Document([ - 'total' => $audit->countLogsByUser($user->getId()), - 'logs' => $output, - ]), Response::MODEL_LOG_LIST); - }); - App::get('/v1/account/sessions/:sessionId') ->desc('Get Session By ID') ->groups(['api', 'account']) @@ -1739,7 +1688,6 @@ App::patch('/v1/account/password') ->label('event', 'users.[userId].update.password') ->label('scope', 'account') ->label('audits.resource', 'user/{response.$id}') - ->label('audits.userId', '{response.$id}') ->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_JWT]) ->label('sdk.namespace', 'account') ->label('sdk.method', 'updatePassword') @@ -1781,7 +1729,6 @@ App::patch('/v1/account/email') ->label('event', 'users.[userId].update.email') ->label('scope', 'account') ->label('audits.resource', 'user/{response.$id}') - ->label('audits.userId', '{response.$id}') ->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_JWT]) ->label('sdk.namespace', 'account') ->label('sdk.method', 'updateEmail') @@ -1833,7 +1780,6 @@ App::patch('/v1/account/phone') ->label('event', 'users.[userId].update.phone') ->label('scope', 'account') ->label('audits.resource', 'user/{response.$id}') - ->label('audits.userId', '{response.$id}') ->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_JWT]) ->label('sdk.namespace', 'account') ->label('sdk.method', 'updatePhone') diff --git a/app/controllers/shared/api.php b/app/controllers/shared/api.php index 7e8ad22a3f..c70515d116 100644 --- a/app/controllers/shared/api.php +++ b/app/controllers/shared/api.php @@ -60,6 +60,7 @@ App::init() ->inject('dbForProject') ->inject('mode') ->action(function (App $utopia, Request $request, Response $response, Document $project, Document $user, Event $events, Audit $audits, Mail $mails, Stats $usage, Delete $deletes, EventDatabase $database, Database $dbForProject, string $mode) { + $route = $utopia->match($request); if ($project->isEmpty() && $route->getLabel('abuse-limit', 0) > 0) { // Abuse limit requires an active project scope @@ -156,6 +157,7 @@ App::init() ->inject('request') ->inject('project') ->action(function (App $utopia, Request $request, Document $project) { + $route = $utopia->match($request); $isPrivilegedUser = Auth::isPrivilegedUser(Authorization::getRoles()); From 7ad7d1807e7c846bd59684449f6b5958cc627690 Mon Sep 17 00:00:00 2001 From: shimon Date: Tue, 16 Aug 2022 17:56:05 +0300 Subject: [PATCH 38/46] fill gaps from merge --- app/controllers/api/account.php | 18 +++++------------- 1 file changed, 5 insertions(+), 13 deletions(-) diff --git a/app/controllers/api/account.php b/app/controllers/api/account.php index 4d81f33ad6..939a41a3ba 100644 --- a/app/controllers/api/account.php +++ b/app/controllers/api/account.php @@ -47,6 +47,7 @@ App::post('/v1/account') ->label('scope', 'public') ->label('auth.type', 'emailPassword') ->label('audits.resource', 'user/{response.$id}') + ->label('audits.userId', '{response.$id}') ->label('sdk.auth', []) ->label('sdk.namespace', 'account') ->label('sdk.method', 'create') @@ -189,6 +190,7 @@ App::get('/v1/account/logs') ->inject('geodb') ->inject('dbForProject') ->inject('usage') + ->action(function (int $limit, int $offset, Response $response, Document $user, Locale $locale, Reader $geodb, Database $dbForProject, Stats $usage) { $audit = new EventAudit($dbForProject); @@ -940,7 +942,7 @@ App::post('/v1/account/sessions/magic-url') ->inject('locale') ->inject('events') ->inject('mails') - ->action(function (string $userId, string $email, string $url, Request $request, Response $response, Document $project, Database $dbForProject, Locale $locale, Audit $audits, Event $events, Mail $mails) { + ->action(function (string $userId, string $email, string $url, Request $request, Response $response, Document $project, Database $dbForProject, Locale $locale, Event $events, Mail $mails) { if (empty(App::getEnv('_APP_SMTP_HOST'))) { throw new Exception(Exception::GENERAL_SMTP_DISABLED); @@ -1033,11 +1035,6 @@ App::post('/v1/account/sessions/magic-url') // Hide secret for clients $token->setAttribute('secret', ($isPrivilegedUser || $isAppUser) ? $loginSecret : ''); - $audits - ->setResource('user/' . $user->getId()) - ->setUser($user) - ; - $response ->setStatusCode(Response::STATUS_CODE_CREATED) ->dynamic($token, Response::MODEL_TOKEN) @@ -1179,11 +1176,10 @@ App::post('/v1/account/sessions/phone') ->inject('response') ->inject('project') ->inject('dbForProject') - ->inject('audits') ->inject('events') ->inject('messaging') ->inject('phone') - ->action(function (string $userId, string $number, Request $request, Response $response, Document $project, Database $dbForProject, Audit $audits, Event $events, EventPhone $messaging, Phone $phone) { + ->action(function (string $userId, string $number, Request $request, Response $response, Document $project, Database $dbForProject, Event $events, EventPhone $messaging, Phone $phone) { if (empty(App::getEnv('_APP_PHONE_PROVIDER'))) { throw new Exception(Exception::GENERAL_PHONE_DISABLED); } @@ -1266,11 +1262,6 @@ App::post('/v1/account/sessions/phone') // Hide secret for clients $token->setAttribute('secret', ($isPrivilegedUser || $isAppUser) ? $secret : ''); - $audits - ->setResource('user/' . $user->getId()) - ->setUser($user) - ; - $response ->setStatusCode(Response::STATUS_CODE_CREATED) ->dynamic($token, Response::MODEL_TOKEN) @@ -1688,6 +1679,7 @@ App::patch('/v1/account/password') ->label('event', 'users.[userId].update.password') ->label('scope', 'account') ->label('audits.resource', 'user/{response.$id}') + ->label('audits.userId', '{response.$id}') ->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_JWT]) ->label('sdk.namespace', 'account') ->label('sdk.method', 'updatePassword') From cc887beae9ebe6766d6eb8ef9d43f26588b7711c Mon Sep 17 00:00:00 2001 From: shimon Date: Wed, 17 Aug 2022 10:32:42 +0300 Subject: [PATCH 39/46] sync with 0.16 --- app/controllers/api/account.php | 12 +++++------- composer.json | 2 +- composer.lock | 26 +++++++++++++------------- 3 files changed, 19 insertions(+), 21 deletions(-) diff --git a/app/controllers/api/account.php b/app/controllers/api/account.php index 4e234fff53..c7bf0097d3 100644 --- a/app/controllers/api/account.php +++ b/app/controllers/api/account.php @@ -853,10 +853,11 @@ App::post('/v1/account/sessions/phone') ->inject('dbForProject') ->inject('events') ->inject('messaging') - ->inject('phone') - ->action(function (string $userId, string $number, Request $request, Response $response, Document $project, Database $dbForProject, Event $events, EventPhone $messaging) { - if (empty(App::getEnv('_APP_PHONE_PROVIDER'))) { - throw new Exception(Exception::GENERAL_PHONE_DISABLED); + ->action(function (string $userId, string $phone, Request $request, Response $response, Document $project, Database $dbForProject, Event $events, EventPhone $messaging) { + + if (empty(App::getEnv('_APP_SMS_PROVIDER'))) { + throw new Exception(Exception::GENERAL_PHONE_DISABLED, 'Phone provider not configured'); + } $roles = Authorization::getRoles(); $isPrivilegedUser = Auth::isPrivilegedUser($roles); @@ -1461,8 +1462,6 @@ App::patch('/v1/account/password') ->action(function (string $password, string $oldPassword, Response $response, Document $user, Database $dbForProject, Stats $usage, Event $events) { // Check old password only if its an existing user. - if ($user->getAttribute('passwordUpdate') !== 0 && !Auth::passwordVerify($oldPassword, $user->getAttribute('password'))) { // Double check user password - throw new Exception(Exception::USER_INVALID_CREDENTIALS, 'Invalid credentials'); if ($user->getAttribute('passwordUpdate') !== 0 && !Auth::passwordVerify($oldPassword, $user->getAttribute('password'), $user->getAttribute('hash'), $user->getAttribute('hashOptions'))) { // Double check user password throw new Exception(Exception::USER_INVALID_CREDENTIALS); } @@ -2217,7 +2216,6 @@ App::post('/v1/account/verification/phone') ->inject('usage') ->inject('messaging') ->action(function (Request $request, Response $response, Document $user, Database $dbForProject, Event $events, Stats $usage, EventPhone $messaging) { - ->action(function (Request $request, Response $response, Phone $phone, Document $user, Database $dbForProject, Event $events, Stats $usage, EventPhone $messaging) { if (empty(App::getEnv('_APP_SMS_PROVIDER'))) { throw new Exception(Exception::GENERAL_PHONE_DISABLED); diff --git a/composer.json b/composer.json index 6fae230a1a..4da6f8d303 100644 --- a/composer.json +++ b/composer.json @@ -43,7 +43,7 @@ "ext-sockets": "*", "appwrite/php-clamav": "1.1.*", "appwrite/php-runtimes": "0.11.*", - "utopia-php/framework": "0.20.*", + "utopia-php/framework": "0.21.*", "utopia-php/logger": "0.3.*", "utopia-php/abuse": "0.7.*", "utopia-php/analytics": "0.2.*", diff --git a/composer.lock b/composer.lock index 740c907ab8..c14764f7ce 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "bbe0a04899feee1909b5924a2131dbee", + "content-hash": "80fda8d774d2c31a3daf2d4c2290d83d", "packages": [ { "name": "adhocore/jwt", @@ -2169,16 +2169,16 @@ }, { "name": "utopia-php/framework", - "version": "0.20.0", + "version": "0.21.0", "source": { "type": "git", "url": "https://github.com/utopia-php/framework.git", - "reference": "beb5e861c7d0a6256a1272e6b9d70b060ca8629a" + "reference": "5aa5431788460a782065e42b0e8a35e7f139af2f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/utopia-php/framework/zipball/beb5e861c7d0a6256a1272e6b9d70b060ca8629a", - "reference": "beb5e861c7d0a6256a1272e6b9d70b060ca8629a", + "url": "https://api.github.com/repos/utopia-php/framework/zipball/5aa5431788460a782065e42b0e8a35e7f139af2f", + "reference": "5aa5431788460a782065e42b0e8a35e7f139af2f", "shasum": "" }, "require": { @@ -2212,9 +2212,9 @@ ], "support": { "issues": "https://github.com/utopia-php/framework/issues", - "source": "https://github.com/utopia-php/framework/tree/0.20.0" + "source": "https://github.com/utopia-php/framework/tree/0.21.0" }, - "time": "2022-07-30T09:55:28+00:00" + "time": "2022-08-12T11:37:21+00:00" }, { "name": "utopia-php/image", @@ -2948,16 +2948,16 @@ }, { "name": "matthiasmullie/minify", - "version": "1.3.68", + "version": "1.3.69", "source": { "type": "git", "url": "https://github.com/matthiasmullie/minify.git", - "reference": "c00fb02f71b2ef0a5f53fe18c5a8b9aa30f48297" + "reference": "a61c949cccd086808063611ef9698eabe42ef22f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/matthiasmullie/minify/zipball/c00fb02f71b2ef0a5f53fe18c5a8b9aa30f48297", - "reference": "c00fb02f71b2ef0a5f53fe18c5a8b9aa30f48297", + "url": "https://api.github.com/repos/matthiasmullie/minify/zipball/a61c949cccd086808063611ef9698eabe42ef22f", + "reference": "a61c949cccd086808063611ef9698eabe42ef22f", "shasum": "" }, "require": { @@ -3006,7 +3006,7 @@ ], "support": { "issues": "https://github.com/matthiasmullie/minify/issues", - "source": "https://github.com/matthiasmullie/minify/tree/1.3.68" + "source": "https://github.com/matthiasmullie/minify/tree/1.3.69" }, "funding": [ { @@ -3014,7 +3014,7 @@ "type": "github" } ], - "time": "2022-04-19T08:28:56+00:00" + "time": "2022-08-01T09:00:18+00:00" }, { "name": "matthiasmullie/path-converter", From 88f6a67802779e0d3c3510c9ffbb7d4d39a4b599 Mon Sep 17 00:00:00 2001 From: shimon Date: Wed, 17 Aug 2022 10:36:38 +0300 Subject: [PATCH 40/46] sync with 0.16 --- app/controllers/api/users.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/controllers/api/users.php b/app/controllers/api/users.php index f9127f198d..1493210536 100644 --- a/app/controllers/api/users.php +++ b/app/controllers/api/users.php @@ -787,7 +787,7 @@ App::patch('/v1/users/:userId/password') ->inject('events') ->action(function (string $userId, string $password, Response $response, Database $dbForProject, Event $events) { - $user = $dbForProject->getDocument('users', $userId); + $user = $dbForProject->getDocument('users', $userId); if ($user->isEmpty()) { throw new Exception(Exception::USER_NOT_FOUND); From 1e404e379be11c98f1e2e7ef38625bee43b110bf Mon Sep 17 00:00:00 2001 From: shimon Date: Wed, 17 Aug 2022 10:59:23 +0300 Subject: [PATCH 41/46] sync with 0.16 --- tests/e2e/Services/Webhooks/WebhooksCustomServerTest.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/e2e/Services/Webhooks/WebhooksCustomServerTest.php b/tests/e2e/Services/Webhooks/WebhooksCustomServerTest.php index 594d5c9f76..22f58de931 100644 --- a/tests/e2e/Services/Webhooks/WebhooksCustomServerTest.php +++ b/tests/e2e/Services/Webhooks/WebhooksCustomServerTest.php @@ -289,7 +289,8 @@ class WebhooksCustomServerTest extends Scope $this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Id'] ?? '', $this->getProject()['webhookId']); $this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Project-Id'] ?? '', $this->getProject()['$id']); $this->assertEquals(empty($webhook['headers']['X-Appwrite-Webhook-User-Id'] ?? ''), ('server' === $this->getSide())); - $this->assertEquals($webhook['data']['prefs']['a'], 'b'); + + $this->assertEquals($webhook['data']['a'], 'b'); return $data; } From e94c7eba83806d2ce1a93c244b194599f3183f10 Mon Sep 17 00:00:00 2001 From: shimon Date: Wed, 17 Aug 2022 13:01:16 +0300 Subject: [PATCH 42/46] more audit labels on users new routes --- app/controllers/api/users.php | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/app/controllers/api/users.php b/app/controllers/api/users.php index 1493210536..de04cdb1fb 100644 --- a/app/controllers/api/users.php +++ b/app/controllers/api/users.php @@ -80,7 +80,6 @@ App::post('/v1/users') ->label('event', 'users.[userId].create') ->label('scope', 'users.write') ->label('audits.resource', 'user/{response.$id}') - ->label('audits.userId', '{response.$id}') ->label('sdk.auth', [APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'users') ->label('sdk.method', 'create') @@ -109,6 +108,7 @@ App::post('/v1/users/bcrypt') ->groups(['api', 'users']) ->label('event', 'users.[userId].create') ->label('scope', 'users.write') + ->label('audits.resource', 'user/{response.$id}') ->label('sdk.auth', [APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'users') ->label('sdk.method', 'createBcryptUser') @@ -136,6 +136,7 @@ App::post('/v1/users/md5') ->groups(['api', 'users']) ->label('event', 'users.[userId].create') ->label('scope', 'users.write') + ->label('audits.resource', 'user/{response.$id}') ->label('sdk.auth', [APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'users') ->label('sdk.method', 'createMD5User') @@ -163,6 +164,7 @@ App::post('/v1/users/argon2') ->groups(['api', 'users']) ->label('event', 'users.[userId].create') ->label('scope', 'users.write') + ->label('audits.resource', 'user/{response.$id}') ->label('sdk.auth', [APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'users') ->label('sdk.method', 'createArgon2User') @@ -190,6 +192,7 @@ App::post('/v1/users/sha') ->groups(['api', 'users']) ->label('event', 'users.[userId].create') ->label('scope', 'users.write') + ->label('audits.resource', 'user/{response.$id}') ->label('sdk.auth', [APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'users') ->label('sdk.method', 'createSHAUser') @@ -224,6 +227,7 @@ App::post('/v1/users/phpass') ->groups(['api', 'users']) ->label('event', 'users.[userId].create') ->label('scope', 'users.write') + ->label('audits.resource', 'user/{response.$id}') ->label('sdk.auth', [APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'users') ->label('sdk.method', 'createPHPassUser') @@ -251,6 +255,7 @@ App::post('/v1/users/scrypt') ->groups(['api', 'users']) ->label('event', 'users.[userId].create') ->label('scope', 'users.write') + ->label('audits.resource', 'user/{response.$id}') ->label('sdk.auth', [APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'users') ->label('sdk.method', 'createScryptUser') @@ -291,6 +296,7 @@ App::post('/v1/users/scrypt-modified') ->groups(['api', 'users']) ->label('event', 'users.[userId].create') ->label('scope', 'users.write') + ->label('audits.resource', 'user/{response.$id}') ->label('sdk.auth', [APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'users') ->label('sdk.method', 'createScryptModifiedUser') From f52bfacf0ed41e1e84ed2f4643050b490ca424d7 Mon Sep 17 00:00:00 2001 From: Christy Jacob Date: Wed, 17 Aug 2022 19:25:42 +0530 Subject: [PATCH 43/46] Update tests/e2e/Services/Webhooks/WebhooksCustomServerTest.php --- tests/e2e/Services/Webhooks/WebhooksCustomServerTest.php | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/e2e/Services/Webhooks/WebhooksCustomServerTest.php b/tests/e2e/Services/Webhooks/WebhooksCustomServerTest.php index 22f58de931..fd34c8bcb9 100644 --- a/tests/e2e/Services/Webhooks/WebhooksCustomServerTest.php +++ b/tests/e2e/Services/Webhooks/WebhooksCustomServerTest.php @@ -289,7 +289,6 @@ class WebhooksCustomServerTest extends Scope $this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Id'] ?? '', $this->getProject()['webhookId']); $this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Project-Id'] ?? '', $this->getProject()['$id']); $this->assertEquals(empty($webhook['headers']['X-Appwrite-Webhook-User-Id'] ?? ''), ('server' === $this->getSide())); - $this->assertEquals($webhook['data']['a'], 'b'); return $data; From 9fc2e4c3a59d63c9ead844751027f64654d652ae Mon Sep 17 00:00:00 2001 From: shimon Date: Wed, 17 Aug 2022 17:29:22 +0300 Subject: [PATCH 44/46] sync with 0.16 --- app/controllers/api/storage.php | 4 +--- app/controllers/shared/api.php | 12 +++++++----- app/workers/deletes.php | 2 +- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/app/controllers/api/storage.php b/app/controllers/api/storage.php index 45f546ea67..5ed7756067 100644 --- a/app/controllers/api/storage.php +++ b/app/controllers/api/storage.php @@ -1353,15 +1353,13 @@ App::delete('/v1/storage/buckets/:bucketId/files/:fileId') ->param('bucketId', null, new UID(), 'Storage bucket unique ID. You can create a new storage bucket using the Storage service [server integration](/docs/server/storage#createBucket).') ->param('fileId', '', new UID(), 'File ID.') ->inject('response') - ->inject('request') ->inject('dbForProject') ->inject('events') ->inject('usage') ->inject('mode') ->inject('deviceFiles') - ->inject('project') ->inject('deletes') - ->action(function (string $bucketId, string $fileId, Response $response, Database $dbForProject, Event $events, Stats $usage, string $mode, Device $deviceFiles, Document $project, Delete $deletes) { + ->action(function (string $bucketId, string $fileId, Response $response, Database $dbForProject, Event $events, Stats $usage, string $mode, Device $deviceFiles, Delete $deletes) { $bucket = Authorization::skip(fn () => $dbForProject->getDocument('buckets', $bucketId)); if ( diff --git a/app/controllers/shared/api.php b/app/controllers/shared/api.php index 2d90003310..5e77424e30 100644 --- a/app/controllers/shared/api.php +++ b/app/controllers/shared/api.php @@ -69,7 +69,7 @@ App::init() throw new Exception(Exception::PROJECT_UNKNOWN); } - /* + /** * Abuse Check */ $abuseKeyLabel = $route->getLabel('abuse-key', 'url:{url},ip:{ip}'); @@ -308,6 +308,9 @@ App::shutdown() $requestParams = $route->getParamsValues(); $user = $audits->getUser(); + /** + * Audit labels + */ $pattern = $route->getLabel('audits.resource', null); if (!empty($pattern)) { $resource = $parseLabel($pattern, $responsePayload, $requestParams, $user); @@ -347,10 +350,9 @@ App::shutdown() $database->trigger(); } - $route = $utopia->match($request); - $requestParams = $route->getParamsValues(); - $user = $audits->getUser(); - + /** + * Cache label + */ $useCache = $route->getLabel('cache', false); if ($useCache) { $resource = null; diff --git a/app/workers/deletes.php b/app/workers/deletes.php index 3d77cc3236..15b5b555e7 100644 --- a/app/workers/deletes.php +++ b/app/workers/deletes.php @@ -138,7 +138,7 @@ class DeletesV1 extends Worker protected function deleteCacheByTimestamp(): void { $this->deleteCacheFiles([ - new Query('accessedAt', Query::TYPE_LESSER, [$this->args['timestamp']]) + new Query('accessedAt', Query::TYPE_LESSER, [$this->args['timestamp']]) ]); } From a2af9fef2db9ae84c844895ecb89b4af24a7e398 Mon Sep 17 00:00:00 2001 From: shimon Date: Wed, 17 Aug 2022 17:57:56 +0300 Subject: [PATCH 45/46] sync with 0.16 --- app/controllers/api/avatars.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/controllers/api/avatars.php b/app/controllers/api/avatars.php index e9ef7e5eb6..6bd1360739 100644 --- a/app/controllers/api/avatars.php +++ b/app/controllers/api/avatars.php @@ -301,7 +301,7 @@ App::get('/v1/avatars/qr') ->desc('Get QR Code') ->groups(['api', 'avatars']) ->label('scope', 'avatars.read') - ->label('cache', true) + ->label('cache', false) ->label('cache.resource', 'avatar/qr') ->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_KEY, APP_AUTH_TYPE_JWT]) ->label('sdk.namespace', 'avatars') @@ -336,7 +336,7 @@ App::get('/v1/avatars/qr') $response ->addHeader('Expires', \date('D, d M Y H:i:s', \time() + (60 * 60 * 24 * 45)) . ' GMT') // 45 days cache ->setContentType('image/png') - ->file($image->output('png', 9)) + ->send($image->output('png', 9)) ; }); From d1aa3fea4f0efd310b9557d82f73a3e470c133d7 Mon Sep 17 00:00:00 2001 From: shimon Date: Wed, 17 Aug 2022 18:03:53 +0300 Subject: [PATCH 46/46] sync with 0.16 --- app/controllers/api/avatars.php | 2 -- 1 file changed, 2 deletions(-) diff --git a/app/controllers/api/avatars.php b/app/controllers/api/avatars.php index 6bd1360739..6dc31787b5 100644 --- a/app/controllers/api/avatars.php +++ b/app/controllers/api/avatars.php @@ -301,8 +301,6 @@ App::get('/v1/avatars/qr') ->desc('Get QR Code') ->groups(['api', 'avatars']) ->label('scope', 'avatars.read') - ->label('cache', false) - ->label('cache.resource', 'avatar/qr') ->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_KEY, APP_AUTH_TYPE_JWT]) ->label('sdk.namespace', 'avatars') ->label('sdk.method', 'getQR')