From ec39ff267c834aaf0fb2d2f4f90feff0ae68a72a Mon Sep 17 00:00:00 2001 From: shimon Date: Sun, 7 Aug 2022 17:30:47 +0300 Subject: [PATCH] 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()