diff --git a/CHANGES.md b/CHANGES.md index 233301df9..ce47a2678 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -18,6 +18,7 @@ - Upgraded Redis Resque queue library to version 1.3.6 - Added container names to docker-compose.yml (@drandell) - Upgraded ClamAV container image to version 1.0.9 +- Optimised function execution by using fully-qualified function calls ## Bug Fixes @@ -31,6 +32,11 @@ - Fixed update form labels and tooltips for Flutter Android apps - Fixed missing custom scopes param for OAuth2 session create API route - Fixed wrong JSON validation when creating and updating database documnets +- Fixed bug where max file size was limited to max of 10MB +- Fixed bug preventing the deletion of the project logo +- Fixed Bug when trying to overwrite OAuth cookie in the Flutter SDK +- Fixed OAuth redirect when using the self-hosted instance default success URL ([#454](https://github.com/appwrite/appwrite/issues/454)) +- Fixed bug denying authentication with Github OAuth provider ## Security diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index d497b3652..b722a0b19 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -171,6 +171,16 @@ Improve PHP exeution time by using [fully-qualified function calls](https://veew php-cs-fixer fix src/ --rules=native_function_invocation --allow-risky=yes ``` +Coding Standards: + +```bash +php-cs-fixer fix app/controllers --rules='{"braces": {"allow_single_line_closure": true}}' +``` + +```bash +php-cs-fixer fix src --rules='{"braces": {"allow_single_line_closure": true}}' +``` + ## Tutorials From time to time, our team will add tutorials that will help contributors find their way in the Appwrite source code. Below is a list of currently available tutorials: diff --git a/Dockerfile b/Dockerfile index c4e7e72c8..8a86a910f 100644 --- a/Dockerfile +++ b/Dockerfile @@ -130,13 +130,12 @@ RUN \ # Set Upload Limit (default to 100MB) RUN echo "upload_max_filesize = ${_APP_STORAGE_LIMIT}" >> /etc/php/$PHP_VERSION/fpm/conf.d/appwrite.ini RUN echo "post_max_size = ${_APP_STORAGE_LIMIT}" >> /etc/php/$PHP_VERSION/fpm/conf.d/appwrite.ini -RUN echo "env[TESTME] = your-secret-key" >> /etc/php/$PHP_VERSION/fpm/conf.d/appwrite.ini # Add logs file RUN echo "" >> /var/log/appwrite.log # Nginx Configuration (with self-signed ssl certificates) -COPY ./docker/nginx.conf /etc/nginx/nginx.conf +COPY ./docker/nginx.conf.template /etc/nginx/nginx.conf.template COPY ./docker/ssl/cert.pem /etc/nginx/ssl/cert.pem COPY ./docker/ssl/key.pem /etc/nginx/ssl/key.pem diff --git a/app/app.php b/app/app.php index 64a496756..e92660b5a 100644 --- a/app/app.php +++ b/app/app.php @@ -1,9 +1,8 @@ init(function () use ($utopia, $request, $response, &$user, $project, $console, $roles, $webhook, $mail, $audit, $usage, $clients) { +$utopia->init(function () use ($utopia, $request, $response, &$user, $project, $console, $webhook, $mail, $audit, $usage, $clients) { $route = $utopia->match($request); @@ -142,6 +138,7 @@ $utopia->init(function () use ($utopia, $request, $response, &$user, $project, $ } } + $roles = Config::getParam('roles', []); $scope = $route->getLabel('scope', 'none'); // Allowed scope for chosen route $scopes = $roles[$role]['scopes']; // Allowed scopes for user role @@ -426,14 +423,11 @@ $utopia->get('/.well-known/acme-challenge') } ); -$name = APP_NAME; +include_once __DIR__ . '/controllers/shared/api.php'; +include_once __DIR__ . '/controllers/shared/web.php'; -if (\array_key_exists($service, $services)) { /** @noinspection PhpIncludeInspection */ - include_once $services[$service]['controller']; - $name = APP_NAME.' '.\ucfirst($services[$service]['name']); -} else { - /** @noinspection PhpIncludeInspection */ - include_once $services['/']['controller']; +foreach(Config::getParam('services', []) as $service) { + include_once $service['controller']; } $utopia->run($request, $response); \ No newline at end of file diff --git a/app/controllers/api/account.php b/app/controllers/api/account.php index a7c1c2c53..516a2a258 100644 --- a/app/controllers/api/account.php +++ b/app/controllers/api/account.php @@ -29,10 +29,8 @@ use DeviceDetector\DeviceDetector; use GeoIp2\Database\Reader; use Utopia\Validator\ArrayList; -include_once __DIR__ . '/../shared/api.php'; - -$oauthDefaultSuccess = $request->getServer('_APP_HOME').'/auth/oauth2/success'; -$oauthDefaultFailure = $request->getServer('_APP_HOME').'/auth/oauth2/failure'; +$oauthDefaultSuccess = '/auth/oauth2/success'; +$oauthDefaultFailure = '/auth/oauth2/failure'; $oauth2Keys = []; @@ -45,11 +43,11 @@ $utopia->init(function() use (&$oauth2Keys) { $oauth2Keys[] = 'oauth2'.\ucfirst($key); $oauth2Keys[] = 'oauth2'.\ucfirst($key).'AccessToken'; } - -}); +}, 'account'); $utopia->post('/v1/account') ->desc('Create Account') + ->groups(['api', 'account']) ->label('webhook', 'account.create') ->label('scope', 'public') ->label('sdk.platform', [APP_PLATFORM_CLIENT]) @@ -150,6 +148,7 @@ $utopia->post('/v1/account') $utopia->post('/v1/account/sessions') ->desc('Create Account Session') + ->groups(['api', 'account']) ->label('webhook', 'account.sessions.create') ->label('scope', 'public') ->label('sdk.platform', [APP_PLATFORM_CLIENT]) @@ -223,7 +222,7 @@ $utopia->post('/v1/account/sessions') ->setParam('resource', 'users/'.$profile->getId()) ; - if(!Config::getParam('domainVerification')) { + if (!Config::getParam('domainVerification')) { $response ->addHeader('X-Fallback-Cookies', \json_encode([Auth::$cookieName => Auth::encodeSession($profile->getId(), $secret)])) ; @@ -240,6 +239,7 @@ $utopia->post('/v1/account/sessions') $utopia->get('/v1/account/sessions/oauth2/:provider') ->desc('Create Account Session with OAuth2') + ->groups(['api', 'account']) ->label('error', __DIR__.'/../../views/general/error.phtml') ->label('scope', 'public') ->label('sdk.platform', [APP_PLATFORM_CLIENT]) @@ -290,6 +290,7 @@ $utopia->get('/v1/account/sessions/oauth2/:provider') $utopia->get('/v1/account/sessions/oauth2/callback/:provider/:projectId') ->desc('OAuth2 Callback') + ->groups(['api', 'account']) ->label('error', __DIR__.'/../../views/general/error.phtml') ->label('scope', 'public') ->label('docs', false) @@ -312,6 +313,7 @@ $utopia->get('/v1/account/sessions/oauth2/callback/:provider/:projectId') $utopia->post('/v1/account/sessions/oauth2/callback/:provider/:projectId') ->desc('OAuth2 Callback') + ->groups(['api', 'account']) ->label('error', __DIR__.'/../../views/general/error.phtml') ->label('scope', 'public') ->label('origin', '*') @@ -335,6 +337,7 @@ $utopia->post('/v1/account/sessions/oauth2/callback/:provider/:projectId') $utopia->get('/v1/account/sessions/oauth2/:provider/redirect') ->desc('OAuth2 Redirect') + ->groups(['api', 'account']) ->label('error', __DIR__.'/../../views/general/error.phtml') ->label('webhook', 'account.sessions.create') ->label('scope', 'public') @@ -500,13 +503,14 @@ $utopia->get('/v1/account/sessions/oauth2/:provider/redirect') ->setParam('data', ['provider' => $provider]) ; - if(!Config::getParam('domainVerification')) { + if (!Config::getParam('domainVerification')) { $response ->addHeader('X-Fallback-Cookies', \json_encode([Auth::$cookieName => Auth::encodeSession($user->getId(), $secret)])) ; } - - if($state['success'] === $oauthDefaultSuccess) { // Add keys for non-web platforms + + // Add keys for non-web platforms - TODO - add verification phase to aviod session sniffing + if (parse_url($state['success'], PHP_URL_PATH) === $oauthDefaultSuccess) { $state['success'] = URLParser::parse($state['success']); $query = URLParser::parseQuery($state['success']['query']); $query['project'] = $project->getId(); @@ -529,6 +533,7 @@ $utopia->get('/v1/account/sessions/oauth2/:provider/redirect') $utopia->get('/v1/account') ->desc('Get Account') + ->groups(['api', 'account']) ->label('scope', 'account') ->label('sdk.platform', [APP_PLATFORM_CLIENT]) ->label('sdk.namespace', 'account') @@ -552,6 +557,7 @@ $utopia->get('/v1/account') $utopia->get('/v1/account/prefs') ->desc('Get Account Preferences') + ->groups(['api', 'account']) ->label('scope', 'account') ->label('sdk.platform', [APP_PLATFORM_CLIENT]) ->label('sdk.namespace', 'account') @@ -574,6 +580,7 @@ $utopia->get('/v1/account/prefs') $utopia->get('/v1/account/sessions') ->desc('Get Account Sessions') + ->groups(['api', 'account']) ->label('scope', 'account') ->label('sdk.platform', [APP_PLATFORM_CLIENT]) ->label('sdk.namespace', 'account') @@ -632,6 +639,7 @@ $utopia->get('/v1/account/sessions') $utopia->get('/v1/account/logs') ->desc('Get Account Logs') + ->groups(['api', 'account']) ->label('scope', 'account') ->label('sdk.platform', [APP_PLATFORM_CLIENT]) ->label('sdk.namespace', 'account') @@ -704,6 +712,7 @@ $utopia->get('/v1/account/logs') $utopia->patch('/v1/account/name') ->desc('Update Account Name') + ->groups(['api', 'account']) ->label('webhook', 'account.update.name') ->label('scope', 'account') ->label('sdk.platform', [APP_PLATFORM_CLIENT]) @@ -741,6 +750,7 @@ $utopia->patch('/v1/account/name') $utopia->patch('/v1/account/password') ->desc('Update Account Password') + ->groups(['api', 'account']) ->label('webhook', 'account.update.password') ->label('scope', 'account') ->label('sdk.platform', [APP_PLATFORM_CLIENT]) @@ -783,6 +793,7 @@ $utopia->patch('/v1/account/password') $utopia->patch('/v1/account/email') ->desc('Update Account Email') + ->groups(['api', 'account']) ->label('webhook', 'account.update.email') ->label('scope', 'account') ->label('sdk.platform', [APP_PLATFORM_CLIENT]) @@ -841,6 +852,7 @@ $utopia->patch('/v1/account/email') $utopia->patch('/v1/account/prefs') ->desc('Update Account Preferences') + ->groups(['api', 'account']) ->label('webhook', 'account.update.prefs') ->label('scope', 'account') ->label('sdk.platform', [APP_PLATFORM_CLIENT]) @@ -881,6 +893,7 @@ $utopia->patch('/v1/account/prefs') $utopia->delete('/v1/account') ->desc('Delete Account') + ->groups(['api', 'account']) ->label('webhook', 'account.delete') ->label('scope', 'account') ->label('sdk.platform', [APP_PLATFORM_CLIENT]) @@ -920,7 +933,7 @@ $utopia->delete('/v1/account') ]) ; - if(!Config::getParam('domainVerification')) { + if (!Config::getParam('domainVerification')) { $response ->addHeader('X-Fallback-Cookies', \json_encode([])) ; @@ -936,6 +949,7 @@ $utopia->delete('/v1/account') $utopia->delete('/v1/account/sessions/:sessionId') ->desc('Delete Account Session') + ->groups(['api', 'account']) ->label('scope', 'account') ->label('webhook', 'account.sessions.delete') ->label('sdk.platform', [APP_PLATFORM_CLIENT]) @@ -972,7 +986,7 @@ $utopia->delete('/v1/account/sessions/:sessionId') ]) ; - if(!Config::getParam('domainVerification')) { + if (!Config::getParam('domainVerification')) { $response ->addHeader('X-Fallback-Cookies', \json_encode([])) ; @@ -995,6 +1009,7 @@ $utopia->delete('/v1/account/sessions/:sessionId') $utopia->delete('/v1/account/sessions') ->desc('Delete All Account Sessions') + ->groups(['api', 'account']) ->label('scope', 'account') ->label('webhook', 'account.sessions.delete') ->label('sdk.platform', [APP_PLATFORM_CLIENT]) @@ -1025,7 +1040,7 @@ $utopia->delete('/v1/account/sessions') ]) ; - if(!Config::getParam('domainVerification')) { + if (!Config::getParam('domainVerification')) { $response ->addHeader('X-Fallback-Cookies', \json_encode([])) ; @@ -1045,6 +1060,7 @@ $utopia->delete('/v1/account/sessions') $utopia->post('/v1/account/recovery') ->desc('Create Password Recovery') + ->groups(['api', 'account']) ->label('scope', 'public') ->label('sdk.platform', [APP_PLATFORM_CLIENT]) ->label('sdk.namespace', 'account') @@ -1144,6 +1160,7 @@ $utopia->post('/v1/account/recovery') $utopia->put('/v1/account/recovery') ->desc('Complete Password Recovery') + ->groups(['api', 'account']) ->label('scope', 'public') ->label('sdk.platform', [APP_PLATFORM_CLIENT]) ->label('sdk.namespace', 'account') @@ -1214,6 +1231,7 @@ $utopia->put('/v1/account/recovery') $utopia->post('/v1/account/verification') ->desc('Create Email Verification') + ->groups(['api', 'account']) ->label('scope', 'account') ->label('sdk.platform', [APP_PLATFORM_CLIENT]) ->label('sdk.namespace', 'account') @@ -1300,6 +1318,7 @@ $utopia->post('/v1/account/verification') $utopia->put('/v1/account/verification') ->desc('Complete Email Verification') + ->groups(['api', 'account']) ->label('scope', 'public') ->label('sdk.platform', [APP_PLATFORM_CLIENT]) ->label('sdk.namespace', 'account') diff --git a/app/controllers/api/avatars.php b/app/controllers/api/avatars.php index b3486f358..9e888f7f7 100644 --- a/app/controllers/api/avatars.php +++ b/app/controllers/api/avatars.php @@ -19,15 +19,13 @@ use BaconQrCode\Writer; use Utopia\Config\Config; use Utopia\Validator\HexColor; -include_once __DIR__ . '/../shared/api.php'; - $types = [ 'browsers' => include __DIR__.'/../../config/avatars/browsers.php', 'credit-cards' => include __DIR__.'/../../config/avatars/credit-cards.php', 'flags' => include __DIR__.'/../../config/avatars/flags.php', ]; -$avatarCallback = function ($type, $code, $width, $height, $quality) use ($types, $response, $request) { +$avatarCallback = function ($type, $code, $width, $height, $quality) use ($types, $response) { $code = \strtolower($code); $type = \strtolower($type); @@ -87,12 +85,11 @@ $avatarCallback = function ($type, $code, $width, $height, $quality) use ($types echo $data; unset($resize); - - exit(0); }; $utopia->get('/v1/avatars/credit-cards/:code') ->desc('Get Credit Card Icon') + ->groups(['api', 'avatars']) ->param('code', '', function () use ($types) { return new WhiteList(\array_keys($types['credit-cards'])); }, 'Credit Card Code. Possible values: '.\implode(', ', \array_keys($types['credit-cards'])).'.') ->param('width', 100, function () { return new Range(0, 2000); }, 'Image width. Pass an integer between 0 to 2000. Defaults to 100.', true) ->param('height', 100, function () { return new Range(0, 2000); }, 'Image height. Pass an integer between 0 to 2000. Defaults to 100.', true) @@ -103,11 +100,13 @@ $utopia->get('/v1/avatars/credit-cards/:code') ->label('sdk.method', 'getCreditCard') ->label('sdk.methodType', 'location') ->label('sdk.description', '/docs/references/avatars/get-credit-card.md') - ->action(function ($code, $width, $height, $quality) use ($avatarCallback) { return $avatarCallback('credit-cards', $code, $width, $height, $quality); + ->action(function ($code, $width, $height, $quality) use ($avatarCallback) { + return $avatarCallback('credit-cards', $code, $width, $height, $quality); }); $utopia->get('/v1/avatars/browsers/:code') ->desc('Get Browser Icon') + ->groups(['api', 'avatars']) ->param('code', '', function () use ($types) { return new WhiteList(\array_keys($types['browsers'])); }, 'Browser Code.') ->param('width', 100, function () { return new Range(0, 2000); }, 'Image width. Pass an integer between 0 to 2000. Defaults to 100.', true) ->param('height', 100, function () { return new Range(0, 2000); }, 'Image height. Pass an integer between 0 to 2000. Defaults to 100.', true) @@ -118,11 +117,13 @@ $utopia->get('/v1/avatars/browsers/:code') ->label('sdk.method', 'getBrowser') ->label('sdk.methodType', 'location') ->label('sdk.description', '/docs/references/avatars/get-browser.md') - ->action(function ($code, $width, $height, $quality) use ($avatarCallback) { return $avatarCallback('browsers', $code, $width, $height, $quality); + ->action(function ($code, $width, $height, $quality) use ($avatarCallback) { + return $avatarCallback('browsers', $code, $width, $height, $quality); }); $utopia->get('/v1/avatars/flags/:code') ->desc('Get Country Flag') + ->groups(['api', 'avatars']) ->param('code', '', function () use ($types) { return new WhiteList(\array_keys($types['flags'])); }, 'Country Code. ISO Alpha-2 country code format.') ->param('width', 100, function () { return new Range(0, 2000); }, 'Image width. Pass an integer between 0 to 2000. Defaults to 100.', true) ->param('height', 100, function () { return new Range(0, 2000); }, 'Image height. Pass an integer between 0 to 2000. Defaults to 100.', true) @@ -133,11 +134,13 @@ $utopia->get('/v1/avatars/flags/:code') ->label('sdk.method', 'getFlag') ->label('sdk.methodType', 'location') ->label('sdk.description', '/docs/references/avatars/get-flag.md') - ->action(function ($code, $width, $height, $quality) use ($avatarCallback) { return $avatarCallback('flags', $code, $width, $height, $quality); + ->action(function ($code, $width, $height, $quality) use ($avatarCallback) { + return $avatarCallback('flags', $code, $width, $height, $quality); }); $utopia->get('/v1/avatars/image') ->desc('Get Image from URL') + ->groups(['api', 'avatars']) ->param('url', '', function () { return new URL(); }, 'Image URL which you want to crop.') ->param('width', 400, function () { return new Range(0, 2000); }, 'Resize preview image width, Pass an integer between 0 to 2000.', true) ->param('height', 400, function () { return new Range(0, 2000); }, 'Resize preview image height, Pass an integer between 0 to 2000.', true) @@ -200,13 +203,12 @@ $utopia->get('/v1/avatars/image') echo $data; unset($resize); - - exit(0); } ); $utopia->get('/v1/avatars/favicon') ->desc('Get Favicon') + ->groups(['api', 'avatars']) ->param('url', '', function () { return new URL(); }, 'Website URL which you want to fetch the favicon from.') ->label('scope', 'avatars.read') ->label('sdk.platform', [APP_PLATFORM_CLIENT, APP_PLATFORM_SERVER]) @@ -354,13 +356,12 @@ $utopia->get('/v1/avatars/favicon') echo $data; unset($resize); - - exit(0); } ); $utopia->get('/v1/avatars/qr') ->desc('Get QR Code') + ->groups(['api', 'avatars']) ->param('text', '', function () { return new Text(512); }, 'Plain text to be converted to QR code image.') ->param('size', 400, function () { return new Range(0, 1000); }, 'QR code size. Pass an integer between 0 to 1000. Defaults to 400.', true) ->param('margin', 1, function () { return new Range(0, 10); }, 'Margin from edge. Pass an integer between 0 to 10. Defaults to 1.', true) @@ -396,6 +397,7 @@ $utopia->get('/v1/avatars/qr') $utopia->get('/v1/avatars/initials') ->desc('Get User Initials') + ->groups(['api', 'avatars']) ->param('name', '', function () { return new Text(512); }, 'Full Name. When empty, current user name or email will be used.', true) ->param('width', 500, function () { return new Range(0, 2000); }, 'Image width. Pass an integer between 0 to 2000. Defaults to 100.', true) ->param('height', 500, function () { return new Range(0, 2000); }, 'Image height. Pass an integer between 0 to 2000. Defaults to 100.', true) @@ -433,7 +435,7 @@ $utopia->get('/v1/avatars/initials') $initials .= (isset($w[0])) ? $w[0] : ''; $code += (isset($w[0])) ? \ord($w[0]) : 0; - if($key == 1) { + if ($key == 1) { break; } } diff --git a/app/controllers/api/database.php b/app/controllers/api/database.php index 5e5a52146..0e4867a06 100644 --- a/app/controllers/api/database.php +++ b/app/controllers/api/database.php @@ -27,12 +27,9 @@ use Appwrite\Database\Exception\Structure as StructureException; // use DeviceDetector\DeviceDetector; // use GeoIp2\Database\Reader; -include_once __DIR__ . '/../shared/api.php'; - -$isDev = (App::MODE_TYPE_PRODUCTION !== $utopia->getMode()); - $utopia->post('/v1/database/collections') ->desc('Create Collection') + ->groups(['api', 'database']) ->label('webhook', 'database.collections.create') ->label('scope', 'collections.write') ->label('sdk.namespace', 'database') @@ -106,6 +103,7 @@ $utopia->post('/v1/database/collections') $utopia->get('/v1/database/collections') ->desc('List Collections') + ->groups(['api', 'database']) ->label('scope', 'collections.read') ->label('sdk.namespace', 'database') ->label('sdk.platform', [APP_PLATFORM_SERVER]) @@ -154,6 +152,7 @@ $utopia->get('/v1/database/collections') $utopia->get('/v1/database/collections/:collectionId') ->desc('Get Collection') + ->groups(['api', 'database']) ->label('scope', 'collections.read') ->label('sdk.namespace', 'database') ->label('sdk.platform', [APP_PLATFORM_SERVER]) @@ -174,6 +173,7 @@ $utopia->get('/v1/database/collections/:collectionId') // $utopia->get('/v1/database/collections/:collectionId/logs') // ->desc('Get Collection Logs') +// ->groups(['api', 'database']) // ->label('scope', 'collections.read') // ->label('sdk.platform', [APP_PLATFORM_SERVER]) // ->label('sdk.namespace', 'database') @@ -182,7 +182,7 @@ $utopia->get('/v1/database/collections/:collectionId') // ->param('collectionId', '', function () { return new UID(); }, 'Collection unique ID.') // ->action( // function ($collectionId) use ($response, $register, $projectDB, $project) { -// $collection = $projectDB->getDocument($collectionId); +// $collection = $projectDB->getDocument($collectionId, false); // if (empty($collection->getId()) || Database::SYSTEM_COLLECTION_COLLECTIONS != $collection->getCollection()) { // throw new Exception('Collection not found', 404); @@ -238,6 +238,7 @@ $utopia->get('/v1/database/collections/:collectionId') $utopia->put('/v1/database/collections/:collectionId') ->desc('Update Collection') + ->groups(['api', 'database']) ->label('scope', 'collections.write') ->label('webhook', 'database.collections.update') ->label('sdk.namespace', 'database') @@ -310,6 +311,7 @@ $utopia->put('/v1/database/collections/:collectionId') $utopia->delete('/v1/database/collections/:collectionId') ->desc('Delete Collection') + ->groups(['api', 'database']) ->label('scope', 'collections.write') ->label('webhook', 'database.collections.delete') ->label('sdk.namespace', 'database') @@ -347,6 +349,7 @@ $utopia->delete('/v1/database/collections/:collectionId') $utopia->post('/v1/database/collections/:collectionId/documents') ->desc('Create Document') + ->groups(['api', 'database']) ->label('webhook', 'database.documents.create') ->label('scope', 'documents.write') ->label('sdk.namespace', 'database') @@ -372,7 +375,7 @@ $utopia->post('/v1/database/collections/:collectionId/documents') throw new Exception('$id is not allowed for creating new documents, try update instead', 400); } - $collection = $projectDB->getDocument($collectionId/*, $isDev*/); + $collection = $projectDB->getDocument($collectionId, false); if (\is_null($collection->getId()) || Database::SYSTEM_COLLECTION_COLLECTIONS != $collection->getCollection()) { throw new Exception('Collection not found', 404); @@ -387,7 +390,7 @@ $utopia->post('/v1/database/collections/:collectionId/documents') // Read parent document + validate not 404 + validate read / write permission like patch method // Add payload to parent document property if ((!empty($parentDocument)) && (!empty($parentProperty))) { - $parentDocument = $projectDB->getDocument($parentDocument); + $parentDocument = $projectDB->getDocument($parentDocument, false); if (empty($parentDocument->getArrayCopy())) { // Check empty throw new Exception('No parent document found', 404); @@ -427,7 +430,7 @@ $utopia->post('/v1/database/collections/:collectionId/documents') $key = (isset($rule['key'])) ? $rule['key'] : ''; $default = (isset($rule['default'])) ? $rule['default'] : null; - if(!isset($data[$key])) { + if (!isset($data[$key])) { $data[$key] = $default; } } @@ -466,6 +469,7 @@ $utopia->post('/v1/database/collections/:collectionId/documents') $utopia->get('/v1/database/collections/:collectionId/documents') ->desc('List Documents') + ->groups(['api', 'database']) ->label('scope', 'documents.read') ->label('sdk.namespace', 'database') ->label('sdk.platform', [APP_PLATFORM_CLIENT, APP_PLATFORM_SERVER]) @@ -482,8 +486,8 @@ $utopia->get('/v1/database/collections/:collectionId/documents') ->param('first', false, function () { return new Boolean(true); }, 'Return only the first document. Pass 1 for true or 0 for false. The default value is 0. This option refers to the first element in your current documents range (limit/offset), and not the entire collection.', true) ->param('last', false, function () { return new Boolean(true); }, 'Return only the last document. Pass 1 for true or 0 for false. The default value is 0. This option refers to the last element in your current documents range (limit/offset), and not the entire collection.', true) ->action( - function ($collectionId, $filters, $offset, $limit, $orderField, $orderType, $orderCast, $search, $first, $last) use ($response, $projectDB, $isDev) { - $collection = $projectDB->getDocument($collectionId, $isDev); + function ($collectionId, $filters, $offset, $limit, $orderField, $orderType, $orderCast, $search, $first, $last) use ($response, $projectDB, $utopia) { + $collection = $projectDB->getDocument($collectionId, false); $first = ($first === '1' || $first === 'true' || $first === 1 || $first === true); $last = ($last === '1' || $last === 'true' || $last === 1 || $last === true); @@ -508,7 +512,7 @@ $utopia->get('/v1/database/collections/:collectionId/documents') if ($first || $last) { $response->json((!empty($list) ? $list->getArrayCopy() : [])); } else { - if ($isDev) { + if ($utopia->isDevelopment()) { $collection ->setAttribute('debug', $projectDB->getDebug()) ->setAttribute('limit', $limit) @@ -535,6 +539,7 @@ $utopia->get('/v1/database/collections/:collectionId/documents') $utopia->get('/v1/database/collections/:collectionId/documents/:documentId') ->desc('Get Document') + ->groups(['api', 'database']) ->label('scope', 'documents.read') ->label('sdk.namespace', 'database') ->label('sdk.platform', [APP_PLATFORM_CLIENT, APP_PLATFORM_SERVER]) @@ -543,9 +548,9 @@ $utopia->get('/v1/database/collections/:collectionId/documents/:documentId') ->param('collectionId', null, function () { return new UID(); }, 'Collection unique ID. You can create a new collection with validation rules using the Database service [server integration](/docs/server/database#createCollection).') ->param('documentId', null, function () { return new UID(); }, 'Document unique ID.') ->action( - function ($collectionId, $documentId) use ($response, $request, $projectDB, $isDev) { - $document = $projectDB->getDocument($documentId, $isDev); - $collection = $projectDB->getDocument($collectionId, $isDev); + function ($collectionId, $documentId) use ($response, $request, $projectDB) { + $document = $projectDB->getDocument($documentId, false); + $collection = $projectDB->getDocument($collectionId, false); if (empty($document->getArrayCopy()) || $document->getCollection() != $collection->getId()) { // Check empty throw new Exception('No document found', 404); @@ -580,6 +585,7 @@ $utopia->get('/v1/database/collections/:collectionId/documents/:documentId') $utopia->patch('/v1/database/collections/:collectionId/documents/:documentId') ->desc('Update Document') + ->groups(['api', 'database']) ->label('webhook', 'database.documents.update') ->label('scope', 'documents.write') ->label('sdk.namespace', 'database') @@ -592,9 +598,9 @@ $utopia->patch('/v1/database/collections/:collectionId/documents/:documentId') ->param('read', [], function () { return new ArrayList(new Text(64)); }, 'An array of strings with read permissions. By default no user is granted with any read permissions. [learn more about permissions](/docs/permissions) and get a full list of available permissions.') ->param('write', [], function () { return new ArrayList(new Text(64)); }, 'An array of strings with write permissions. By default no user is granted with any write permissions. [learn more about permissions](/docs/permissions) and get a full list of available permissions.') ->action( - function ($collectionId, $documentId, $data, $read, $write) use ($response, $projectDB, &$output, $webhook, $audit, $isDev) { - $collection = $projectDB->getDocument($collectionId/*, $isDev*/); - $document = $projectDB->getDocument($documentId, $isDev); + function ($collectionId, $documentId, $data, $read, $write) use ($response, $projectDB, $webhook, $audit) { + $collection = $projectDB->getDocument($collectionId, false); + $document = $projectDB->getDocument($documentId, false); $data = (\is_string($data)) ? \json_decode($data, true) : $data; // Cast to JSON array @@ -659,6 +665,7 @@ $utopia->patch('/v1/database/collections/:collectionId/documents/:documentId') $utopia->delete('/v1/database/collections/:collectionId/documents/:documentId') ->desc('Delete Document') + ->groups(['api', 'database']) ->label('scope', 'documents.write') ->label('webhook', 'database.documents.delete') ->label('sdk.namespace', 'database') @@ -668,9 +675,9 @@ $utopia->delete('/v1/database/collections/:collectionId/documents/:documentId') ->param('collectionId', null, function () { return new UID(); }, 'Collection unique ID. You can create a new collection with validation rules using the Database service [server integration](/docs/server/database#createCollection).') ->param('documentId', null, function () { return new UID(); }, 'Document unique ID.') ->action( - function ($collectionId, $documentId) use ($response, $projectDB, $audit, $webhook, $isDev) { - $collection = $projectDB->getDocument($collectionId, $isDev); - $document = $projectDB->getDocument($documentId, $isDev); + function ($collectionId, $documentId) use ($response, $projectDB, $audit, $webhook) { + $collection = $projectDB->getDocument($collectionId, false); + $document = $projectDB->getDocument($documentId, false); if (empty($document->getArrayCopy()) || $document->getCollection() != $collectionId) { // Check empty throw new Exception('No document found', 404); diff --git a/app/controllers/api/graphql.php b/app/controllers/api/graphql.php index ce39d8e79..0eecb23e1 100644 --- a/app/controllers/api/graphql.php +++ b/app/controllers/api/graphql.php @@ -14,6 +14,7 @@ global $utopia; $utopia->post('/v1/graphql') ->desc('GraphQL Endpoint') + ->groups(['api', 'graphql']) ->label('scope', 'public') ->action( function () { diff --git a/app/controllers/api/health.php b/app/controllers/api/health.php index 94c99bc82..76727563a 100644 --- a/app/controllers/api/health.php +++ b/app/controllers/api/health.php @@ -9,6 +9,7 @@ use Appwrite\ClamAV\Network; $utopia->get('/v1/health') ->desc('Get HTTP') + ->groups(['api', 'health']) ->label('scope', 'health.read') ->label('sdk.platform', [APP_PLATFORM_SERVER]) ->label('sdk.namespace', 'health') @@ -22,6 +23,7 @@ $utopia->get('/v1/health') $utopia->get('/v1/health/version') ->desc('Get Version') + ->groups(['api', 'health']) ->label('scope', 'public') ->action( function () use ($response) { @@ -31,6 +33,7 @@ $utopia->get('/v1/health/version') $utopia->get('/v1/health/db') ->desc('Get DB') + ->groups(['api', 'health']) ->label('scope', 'health.read') ->label('sdk.platform', [APP_PLATFORM_SERVER]) ->label('sdk.namespace', 'health') @@ -46,6 +49,7 @@ $utopia->get('/v1/health/db') $utopia->get('/v1/health/cache') ->desc('Get Cache') + ->groups(['api', 'health']) ->label('scope', 'health.read') ->label('sdk.platform', [APP_PLATFORM_SERVER]) ->label('sdk.namespace', 'health') @@ -61,6 +65,7 @@ $utopia->get('/v1/health/cache') $utopia->get('/v1/health/time') ->desc('Get Time') + ->groups(['api', 'health']) ->label('scope', 'health.read') ->label('sdk.platform', [APP_PLATFORM_SERVER]) ->label('sdk.namespace', 'health') @@ -108,6 +113,7 @@ $utopia->get('/v1/health/time') $utopia->get('/v1/health/queue/webhooks') ->desc('Get Webhooks Queue') + ->groups(['api', 'health']) ->label('scope', 'health.read') ->label('sdk.platform', [APP_PLATFORM_SERVER]) ->label('sdk.namespace', 'health') @@ -121,6 +127,7 @@ $utopia->get('/v1/health/queue/webhooks') $utopia->get('/v1/health/queue/tasks') ->desc('Get Tasks Queue') + ->groups(['api', 'health']) ->label('scope', 'health.read') ->label('sdk.platform', [APP_PLATFORM_SERVER]) ->label('sdk.namespace', 'health') @@ -134,6 +141,7 @@ $utopia->get('/v1/health/queue/tasks') $utopia->get('/v1/health/queue/logs') ->desc('Get Logs Queue') + ->groups(['api', 'health']) ->label('scope', 'health.read') ->label('sdk.platform', [APP_PLATFORM_SERVER]) ->label('sdk.namespace', 'health') @@ -147,6 +155,7 @@ $utopia->get('/v1/health/queue/logs') $utopia->get('/v1/health/queue/usage') ->desc('Get Usage Queue') + ->groups(['api', 'health']) ->label('scope', 'health.read') ->label('sdk.platform', [APP_PLATFORM_SERVER]) ->label('sdk.namespace', 'health') @@ -160,6 +169,7 @@ $utopia->get('/v1/health/queue/usage') $utopia->get('/v1/health/queue/certificates') ->desc('Get Certificate Queue') + ->groups(['api', 'health']) ->label('scope', 'health.read') ->label('sdk.platform', [APP_PLATFORM_SERVER]) ->label('sdk.namespace', 'health') @@ -173,6 +183,7 @@ $utopia->get('/v1/health/queue/certificates') $utopia->get('/v1/health/queue/functions') ->desc('Get Functions Queue') + ->groups(['api', 'health']) ->label('scope', 'health.read') ->label('sdk.platform', [APP_PLATFORM_SERVER]) ->label('sdk.namespace', 'health') @@ -186,6 +197,7 @@ $utopia->get('/v1/health/queue/functions') $utopia->get('/v1/health/storage/local') ->desc('Get Local Storage') + ->groups(['api', 'health']) ->label('scope', 'health.read') ->label('sdk.platform', [APP_PLATFORM_SERVER]) ->label('sdk.namespace', 'health') @@ -193,7 +205,6 @@ $utopia->get('/v1/health/storage/local') ->label('sdk.description', '/docs/references/health/get-storage-local.md') ->action( function () use ($response) { - foreach ([ 'Uploads' => APP_STORAGE_UPLOADS, 'Cache' => APP_STORAGE_CACHE, @@ -217,6 +228,7 @@ $utopia->get('/v1/health/storage/local') $utopia->get('/v1/health/anti-virus') ->desc('Get Anti virus') + ->groups(['api', 'health']) ->label('scope', 'health.read') ->label('sdk.platform', [APP_PLATFORM_SERVER]) ->label('sdk.namespace', 'health') @@ -224,7 +236,7 @@ $utopia->get('/v1/health/anti-virus') ->label('sdk.description', '/docs/references/health/get-storage-anti-virus.md') ->action( function () use ($request, $response) { - if($request->getServer('_APP_STORAGE_ANTIVIRUS') === 'disabled') { // Check if scans are enabled + if ($request->getServer('_APP_STORAGE_ANTIVIRUS') === 'disabled') { // Check if scans are enabled throw new Exception('Anitvirus is disabled'); } @@ -239,6 +251,7 @@ $utopia->get('/v1/health/anti-virus') $utopia->get('/v1/health/stats') // Currently only used internally ->desc('Get System Stats') + ->groups(['api', 'health']) ->label('scope', 'god') // ->label('sdk.platform', [APP_PLATFORM_SERVER]) // ->label('sdk.namespace', 'health') diff --git a/app/controllers/api/locale.php b/app/controllers/api/locale.php index 30a1211e9..148ee3e8e 100644 --- a/app/controllers/api/locale.php +++ b/app/controllers/api/locale.php @@ -6,10 +6,9 @@ use Utopia\App; use Utopia\Locale\Locale; use GeoIp2\Database\Reader; -include_once __DIR__ . '/../shared/api.php'; - $utopia->get('/v1/locale') ->desc('Get User Locale') + ->groups(['api', 'locale']) ->label('scope', 'locale.read') ->label('sdk.platform', [APP_PLATFORM_CLIENT, APP_PLATFORM_SERVER]) ->label('sdk.namespace', 'locale') @@ -68,6 +67,7 @@ $utopia->get('/v1/locale') $utopia->get('/v1/locale/countries') ->desc('List Countries') + ->groups(['api', 'locale']) ->label('scope', 'locale.read') ->label('sdk.platform', [APP_PLATFORM_CLIENT, APP_PLATFORM_SERVER]) ->label('sdk.namespace', 'locale') @@ -85,6 +85,7 @@ $utopia->get('/v1/locale/countries') $utopia->get('/v1/locale/countries/eu') ->desc('List EU Countries') + ->groups(['api', 'locale']) ->label('scope', 'locale.read') ->label('sdk.platform', [APP_PLATFORM_CLIENT, APP_PLATFORM_SERVER]) ->label('sdk.namespace', 'locale') @@ -110,6 +111,7 @@ $utopia->get('/v1/locale/countries/eu') $utopia->get('/v1/locale/countries/phones') ->desc('List Countries Phone Codes') + ->groups(['api', 'locale']) ->label('scope', 'locale.read') ->label('sdk.platform', [APP_PLATFORM_CLIENT, APP_PLATFORM_SERVER]) ->label('sdk.namespace', 'locale') @@ -135,6 +137,7 @@ $utopia->get('/v1/locale/countries/phones') $utopia->get('/v1/locale/continents') ->desc('List Continents') + ->groups(['api', 'locale']) ->label('scope', 'locale.read') ->label('sdk.platform', [APP_PLATFORM_CLIENT, APP_PLATFORM_SERVER]) ->label('sdk.namespace', 'locale') @@ -153,6 +156,7 @@ $utopia->get('/v1/locale/continents') $utopia->get('/v1/locale/currencies') ->desc('List Currencies') + ->groups(['api', 'locale']) ->label('scope', 'locale.read') ->label('sdk.platform', [APP_PLATFORM_CLIENT, APP_PLATFORM_SERVER]) ->label('sdk.namespace', 'locale') @@ -169,6 +173,7 @@ $utopia->get('/v1/locale/currencies') $utopia->get('/v1/locale/languages') ->desc('List Languages') + ->groups(['api', 'locale']) ->label('scope', 'locale.read') ->label('sdk.platform', [APP_PLATFORM_CLIENT, APP_PLATFORM_SERVER]) ->label('sdk.namespace', 'locale') diff --git a/app/controllers/api/projects.php b/app/controllers/api/projects.php index 799987114..bd4942239 100644 --- a/app/controllers/api/projects.php +++ b/app/controllers/api/projects.php @@ -21,12 +21,11 @@ use Appwrite\OpenSSL\OpenSSL; use Appwrite\Network\Validator\CNAME; use Cron\CronExpression; -include_once __DIR__ . '/../shared/api.php'; - $scopes = include __DIR__.'/../../../app/config/scopes.php'; $utopia->post('/v1/projects') ->desc('Create Project') + ->groups(['api', 'projects']) ->label('scope', 'projects.write') ->label('sdk.namespace', 'projects') ->label('sdk.method', 'create') @@ -89,6 +88,7 @@ $utopia->post('/v1/projects') $utopia->get('/v1/projects') ->desc('List Projects') + ->groups(['api', 'projects']) ->label('scope', 'projects.read') ->label('sdk.namespace', 'projects') ->label('sdk.method', 'list') @@ -122,6 +122,7 @@ $utopia->get('/v1/projects') $utopia->get('/v1/projects/:projectId') ->desc('Get Project') + ->groups(['api', 'projects']) ->label('scope', 'projects.read') ->label('sdk.namespace', 'projects') ->label('sdk.method', 'get') @@ -149,6 +150,7 @@ $utopia->get('/v1/projects/:projectId') $utopia->get('/v1/projects/:projectId/usage') ->desc('Get Project') + ->groups(['api', 'projects']) ->label('scope', 'projects.read') ->label('sdk.namespace', 'projects') ->label('sdk.method', 'getUsage') @@ -310,6 +312,7 @@ $utopia->get('/v1/projects/:projectId/usage') $utopia->patch('/v1/projects/:projectId') ->desc('Update Project') + ->groups(['api', 'projects']) ->label('scope', 'projects.write') ->label('sdk.namespace', 'projects') ->label('sdk.method', 'update') @@ -355,6 +358,7 @@ $utopia->patch('/v1/projects/:projectId') $utopia->patch('/v1/projects/:projectId/oauth2') ->desc('Update Project OAuth2') + ->groups(['api', 'projects']) ->label('scope', 'projects.write') ->label('sdk.namespace', 'projects') ->label('sdk.method', 'updateOAuth2') @@ -396,6 +400,7 @@ $utopia->patch('/v1/projects/:projectId/oauth2') $utopia->delete('/v1/projects/:projectId') ->desc('Delete Project') + ->groups(['api', 'projects']) ->label('scope', 'projects.write') ->label('sdk.namespace', 'projects') ->label('sdk.method', 'delete') @@ -415,7 +420,7 @@ $utopia->delete('/v1/projects/:projectId') $deletes->setParam('document', $project->getArrayCopy()); - foreach(['keys', 'webhooks', 'tasks', 'platforms', 'domains'] as $key) { // Delete all children (keys, webhooks, tasks [stop tasks?], platforms) + foreach (['keys', 'webhooks', 'tasks', 'platforms', 'domains'] as $key) { // Delete all children (keys, webhooks, tasks [stop tasks?], platforms) $list = $project->getAttribute('webhooks', []); foreach ($list as $document) { /* @var $document Document */ @@ -441,6 +446,7 @@ $utopia->delete('/v1/projects/:projectId') $utopia->post('/v1/projects/:projectId/webhooks') ->desc('Create Webhook') + ->groups(['api', 'projects']) ->label('scope', 'projects.write') ->label('sdk.namespace', 'projects') ->label('sdk.method', 'createWebhook') @@ -506,6 +512,7 @@ $utopia->post('/v1/projects/:projectId/webhooks') $utopia->get('/v1/projects/:projectId/webhooks') ->desc('List Webhooks') + ->groups(['api', 'projects']) ->label('scope', 'projects.read') ->label('sdk.namespace', 'projects') ->label('sdk.method', 'listWebhooks') @@ -538,6 +545,7 @@ $utopia->get('/v1/projects/:projectId/webhooks') $utopia->get('/v1/projects/:projectId/webhooks/:webhookId') ->desc('Get Webhook') + ->groups(['api', 'projects']) ->label('scope', 'projects.read') ->label('sdk.namespace', 'projects') ->label('sdk.method', 'getWebhook') @@ -571,6 +579,7 @@ $utopia->get('/v1/projects/:projectId/webhooks/:webhookId') $utopia->put('/v1/projects/:projectId/webhooks/:webhookId') ->desc('Update Webhook') + ->groups(['api', 'projects']) ->label('scope', 'projects.write') ->label('sdk.namespace', 'projects') ->label('sdk.method', 'updateWebhook') @@ -626,6 +635,7 @@ $utopia->put('/v1/projects/:projectId/webhooks/:webhookId') $utopia->delete('/v1/projects/:projectId/webhooks/:webhookId') ->desc('Delete Webhook') + ->groups(['api', 'projects']) ->label('scope', 'projects.write') ->label('sdk.namespace', 'projects') ->label('sdk.method', 'deleteWebhook') @@ -657,6 +667,7 @@ $utopia->delete('/v1/projects/:projectId/webhooks/:webhookId') $utopia->post('/v1/projects/:projectId/keys') ->desc('Create Key') + ->groups(['api', 'projects']) ->label('scope', 'projects.write') ->label('sdk.namespace', 'projects') ->label('sdk.method', 'createKey') @@ -703,6 +714,7 @@ $utopia->post('/v1/projects/:projectId/keys') $utopia->get('/v1/projects/:projectId/keys') ->desc('List Keys') + ->groups(['api', 'projects']) ->label('scope', 'projects.read') ->label('sdk.namespace', 'projects') ->label('sdk.method', 'listKeys') @@ -721,6 +733,7 @@ $utopia->get('/v1/projects/:projectId/keys') $utopia->get('/v1/projects/:projectId/keys/:keyId') ->desc('Get Key') + ->groups(['api', 'projects']) ->label('scope', 'projects.read') ->label('sdk.namespace', 'projects') ->label('sdk.method', 'getKey') @@ -746,6 +759,7 @@ $utopia->get('/v1/projects/:projectId/keys/:keyId') $utopia->put('/v1/projects/:projectId/keys/:keyId') ->desc('Update Key') + ->groups(['api', 'projects']) ->label('scope', 'projects.write') ->label('sdk.namespace', 'projects') ->label('sdk.method', 'updateKey') @@ -782,6 +796,7 @@ $utopia->put('/v1/projects/:projectId/keys/:keyId') $utopia->delete('/v1/projects/:projectId/keys/:keyId') ->desc('Delete Key') + ->groups(['api', 'projects']) ->label('scope', 'projects.write') ->label('sdk.namespace', 'projects') ->label('sdk.method', 'deleteKey') @@ -813,6 +828,7 @@ $utopia->delete('/v1/projects/:projectId/keys/:keyId') $utopia->post('/v1/projects/:projectId/tasks') ->desc('Create Task') + ->groups(['api', 'projects']) ->label('scope', 'projects.write') ->label('sdk.namespace', 'projects') ->label('sdk.method', 'createTask') @@ -895,6 +911,7 @@ $utopia->post('/v1/projects/:projectId/tasks') $utopia->get('/v1/projects/:projectId/tasks') ->desc('List Tasks') + ->groups(['api', 'projects']) ->label('scope', 'projects.read') ->label('sdk.namespace', 'projects') ->label('sdk.method', 'listTasks') @@ -927,6 +944,7 @@ $utopia->get('/v1/projects/:projectId/tasks') $utopia->get('/v1/projects/:projectId/tasks/:taskId') ->desc('Get Task') + ->groups(['api', 'projects']) ->label('scope', 'projects.read') ->label('sdk.namespace', 'projects') ->label('sdk.method', 'getTask') @@ -959,6 +977,7 @@ $utopia->get('/v1/projects/:projectId/tasks/:taskId') $utopia->put('/v1/projects/:projectId/tasks/:taskId') ->desc('Update Task') + ->groups(['api', 'projects']) ->label('scope', 'projects.write') ->label('sdk.namespace', 'projects') ->label('sdk.method', 'updateTask') @@ -1030,6 +1049,7 @@ $utopia->put('/v1/projects/:projectId/tasks/:taskId') $utopia->delete('/v1/projects/:projectId/tasks/:taskId') ->desc('Delete Task') + ->groups(['api', 'projects']) ->label('scope', 'projects.write') ->label('sdk.namespace', 'projects') ->label('sdk.method', 'deleteTask') @@ -1061,6 +1081,7 @@ $utopia->delete('/v1/projects/:projectId/tasks/:taskId') $utopia->post('/v1/projects/:projectId/platforms') ->desc('Create Platform') + ->groups(['api', 'projects']) ->label('scope', 'projects.write') ->label('sdk.namespace', 'projects') ->label('sdk.method', 'createPlatform') @@ -1114,6 +1135,7 @@ $utopia->post('/v1/projects/:projectId/platforms') $utopia->get('/v1/projects/:projectId/platforms') ->desc('List Platforms') + ->groups(['api', 'projects']) ->label('scope', 'projects.read') ->label('sdk.namespace', 'projects') ->label('sdk.method', 'listPlatforms') @@ -1134,6 +1156,7 @@ $utopia->get('/v1/projects/:projectId/platforms') $utopia->get('/v1/projects/:projectId/platforms/:platformId') ->desc('Get Platform') + ->groups(['api', 'projects']) ->label('scope', 'projects.read') ->label('sdk.namespace', 'projects') ->label('sdk.method', 'getPlatform') @@ -1159,6 +1182,7 @@ $utopia->get('/v1/projects/:projectId/platforms/:platformId') $utopia->put('/v1/projects/:projectId/platforms/:platformId') ->desc('Update Platform') + ->groups(['api', 'projects']) ->label('scope', 'projects.write') ->label('sdk.namespace', 'projects') ->label('sdk.method', 'updatePlatform') @@ -1200,6 +1224,7 @@ $utopia->put('/v1/projects/:projectId/platforms/:platformId') $utopia->delete('/v1/projects/:projectId/platforms/:platformId') ->desc('Delete Platform') + ->groups(['api', 'projects']) ->label('scope', 'projects.write') ->label('sdk.namespace', 'projects') ->label('sdk.method', 'deletePlatform') @@ -1231,6 +1256,7 @@ $utopia->delete('/v1/projects/:projectId/platforms/:platformId') $utopia->post('/v1/projects/:projectId/domains') ->desc('Create Domain') + ->groups(['api', 'projects']) ->label('scope', 'projects.write') ->label('sdk.namespace', 'projects') ->label('sdk.method', 'createDomain') @@ -1252,7 +1278,7 @@ $utopia->post('/v1/projects/:projectId/domains') $target = new Domain($request->getServer('_APP_DOMAIN_TARGET', '')); - if(!$target->isKnown() || $target->isTest()) { + if (!$target->isKnown() || $target->isTest()) { throw new Exception('Unreachable CNAME target ('.$target->get().'), plesse use a domain with a public suffix.', 500); } @@ -1293,6 +1319,7 @@ $utopia->post('/v1/projects/:projectId/domains') $utopia->get('/v1/projects/:projectId/domains') ->desc('List Domains') + ->groups(['api', 'projects']) ->label('scope', 'projects.read') ->label('sdk.namespace', 'projects') ->label('sdk.method', 'listDomains') @@ -1313,6 +1340,7 @@ $utopia->get('/v1/projects/:projectId/domains') $utopia->get('/v1/projects/:projectId/domains/:domainId') ->desc('Get Domain') + ->groups(['api', 'projects']) ->label('scope', 'projects.read') ->label('sdk.namespace', 'projects') ->label('sdk.method', 'getDomain') @@ -1338,6 +1366,7 @@ $utopia->get('/v1/projects/:projectId/domains/:domainId') $utopia->patch('/v1/projects/:projectId/domains/:domainId/verification') ->desc('Update Domain Verification Status') + ->groups(['api', 'projects']) ->label('scope', 'projects.write') ->label('sdk.namespace', 'projects') ->label('sdk.method', 'updateDomainVerification') @@ -1359,18 +1388,18 @@ $utopia->patch('/v1/projects/:projectId/domains/:domainId/verification') $target = new Domain($request->getServer('_APP_DOMAIN_TARGET', '')); - if(!$target->isKnown() || $target->isTest()) { + if (!$target->isKnown() || $target->isTest()) { throw new Exception('Unreachable CNAME target ('.$target->get().'), plesse use a domain with a public suffix.', 500); } - if($domain->getAttribute('verification') === true) { + if ($domain->getAttribute('verification') === true) { return $response->json($domain->getArrayCopy()); } // Verify Domain with DNS records $validator = new CNAME($target->get()); - if(!$validator->isValid($domain->getAttribute('domain', ''))) { + if (!$validator->isValid($domain->getAttribute('domain', ''))) { throw new Exception('Failed to verify domain', 401); } @@ -1394,6 +1423,7 @@ $utopia->patch('/v1/projects/:projectId/domains/:domainId/verification') $utopia->delete('/v1/projects/:projectId/domains/:domainId') ->desc('Delete Domain') + ->groups(['api', 'projects']) ->label('scope', 'projects.write') ->label('sdk.namespace', 'projects') ->label('sdk.method', 'deleteDomain') diff --git a/app/controllers/api/storage.php b/app/controllers/api/storage.php index 6ffcfbf98..9a12b5604 100644 --- a/app/controllers/api/storage.php +++ b/app/controllers/api/storage.php @@ -23,8 +23,6 @@ use Appwrite\Storage\Compression\Algorithms\GZIP; use Appwrite\Resize\Resize; use Appwrite\OpenSSL\OpenSSL; -include_once __DIR__ . '/../shared/api.php'; - Storage::addDevice('local', new Local(APP_STORAGE_UPLOADS.'/app-'.$project->getId())); $fileLogos = [ // Based on this list @see http://stackoverflow.com/a/4212908/2299554 @@ -135,6 +133,7 @@ $mimes = [ $utopia->post('/v1/storage/files') ->desc('Create File') + ->groups(['api', 'storage']) ->label('scope', 'files.write') ->label('webhook', 'storage.files.create') ->label('sdk.platform', [APP_PLATFORM_CLIENT, APP_PLATFORM_SERVER]) @@ -198,7 +197,7 @@ $utopia->post('/v1/storage/files') $mimeType = $device->getFileMimeType($path); // Get mime-type before compression and encryption - if($request->getServer('_APP_STORAGE_ANTIVIRUS') === 'enabled') { // Check if scans are enabled + if ($request->getServer('_APP_STORAGE_ANTIVIRUS') === 'enabled') { // Check if scans are enabled $antiVirus = new Network('clamav', 3310); // Check if file size is exceeding allowed limit @@ -216,7 +215,7 @@ $utopia->post('/v1/storage/files') $iv = OpenSSL::randomPseudoBytes(OpenSSL::cipherIVLength(OpenSSL::CIPHER_AES_128_GCM)); $data = OpenSSL::encrypt($data, OpenSSL::CIPHER_AES_128_GCM, $key, 0, $iv, $tag); - if(!$device->write($path, $data)) { + if (!$device->write($path, $data)) { throw new Exception('Failed to save file', 500); } @@ -271,6 +270,7 @@ $utopia->post('/v1/storage/files') $utopia->get('/v1/storage/files') ->desc('List Files') + ->groups(['api', 'storage']) ->label('scope', 'files.read') ->label('sdk.platform', [APP_PLATFORM_CLIENT, APP_PLATFORM_SERVER]) ->label('sdk.namespace', 'storage') @@ -304,6 +304,7 @@ $utopia->get('/v1/storage/files') $utopia->get('/v1/storage/files/:fileId') ->desc('Get File') + ->groups(['api', 'storage']) ->label('scope', 'files.read') ->label('sdk.platform', [APP_PLATFORM_CLIENT, APP_PLATFORM_SERVER]) ->label('sdk.namespace', 'storage') @@ -324,6 +325,7 @@ $utopia->get('/v1/storage/files/:fileId') $utopia->get('/v1/storage/files/:fileId/preview') ->desc('Get File Preview') + ->groups(['api', 'storage']) ->label('scope', 'files.read') ->label('sdk.platform', [APP_PLATFORM_CLIENT, APP_PLATFORM_SERVER]) ->label('sdk.namespace', 'storage') @@ -337,8 +339,6 @@ $utopia->get('/v1/storage/files/:fileId/preview') ->param('quality', 100, function () { return new Range(0, 100); }, 'Preview image quality. Pass an integer between 0 to 100. Defaults to 100.', true) ->param('background', '', function () { return new HexColor(); }, 'Preview image background color. Only works with transparent images (png). Use a valid HEX color, no # is needed for prefix.', true) ->param('output', null, function () use ($outputs) { return new WhiteList(\array_merge(\array_keys($outputs), [null])); }, 'Output format type (jpeg, jpg, png, gif and webp).', true) - //->param('storage', 'local', function () {return new WhiteList(array('local'));}, 'Selected storage device. defaults to local') - //->param('token', '', function () {return new Text(128);}, 'Preview token', true) ->action( function ($fileId, $width, $height, $quality, $background, $output) use ($request, $response, $projectDB, $project, $inputs, $outputs, $fileLogos) { $storage = 'local'; @@ -370,7 +370,7 @@ $utopia->get('/v1/storage/files/:fileId/preview') $cipher = $file->getAttribute('fileOpenSSLCipher'); $mime = $file->getAttribute('mimeType'); - if(!\in_array($mime, $inputs)) { + if (!\in_array($mime, $inputs)) { $path = (\array_key_exists($mime, $fileLogos)) ? $fileLogos[$mime] : $fileLogos['default']; $algorithm = null; $cipher = null; @@ -448,6 +448,7 @@ $utopia->get('/v1/storage/files/:fileId/preview') $utopia->get('/v1/storage/files/:fileId/download') ->desc('Get File for Download') + ->groups(['api', 'storage']) ->label('scope', 'files.read') ->label('sdk.platform', [APP_PLATFORM_CLIENT, APP_PLATFORM_SERVER]) ->label('sdk.namespace', 'storage') @@ -501,6 +502,7 @@ $utopia->get('/v1/storage/files/:fileId/download') $utopia->get('/v1/storage/files/:fileId/view') ->desc('Get File for View') + ->groups(['api', 'storage']) ->label('scope', 'files.read') ->label('sdk.platform', [APP_PLATFORM_CLIENT, APP_PLATFORM_SERVER]) ->label('sdk.namespace', 'storage') @@ -571,6 +573,7 @@ $utopia->get('/v1/storage/files/:fileId/view') $utopia->put('/v1/storage/files/:fileId') ->desc('Update File') + ->groups(['api', 'storage']) ->label('scope', 'files.write') ->label('webhook', 'storage.files.update') ->label('sdk.platform', [APP_PLATFORM_CLIENT, APP_PLATFORM_SERVER]) @@ -616,6 +619,7 @@ $utopia->put('/v1/storage/files/:fileId') $utopia->delete('/v1/storage/files/:fileId') ->desc('Delete File') + ->groups(['api', 'storage']) ->label('scope', 'files.write') ->label('webhook', 'storage.files.delete') ->label('sdk.platform', [APP_PLATFORM_CLIENT, APP_PLATFORM_SERVER]) @@ -658,6 +662,7 @@ $utopia->delete('/v1/storage/files/:fileId') // $utopia->get('/v1/storage/files/:fileId/scan') // ->desc('Scan Storage') +// ->groups(['api', 'storage']) // ->label('scope', 'god') // ->label('sdk.platform', [APP_PLATFORM_CLIENT, APP_PLATFORM_SERVER]) // ->label('sdk.namespace', 'storage') diff --git a/app/controllers/api/teams.php b/app/controllers/api/teams.php index b8e0bf119..67b4599b2 100644 --- a/app/controllers/api/teams.php +++ b/app/controllers/api/teams.php @@ -20,10 +20,9 @@ use Appwrite\Database\Validator\Authorization; use Appwrite\Database\Exception\Duplicate; use Appwrite\Template\Template; -include_once __DIR__ . '/../shared/api.php'; - $utopia->post('/v1/teams') ->desc('Create Team') + ->groups(['api', 'teams']) ->label('scope', 'teams.write') ->label('sdk.platform', [APP_PLATFORM_CLIENT, APP_PLATFORM_SERVER]) ->label('sdk.namespace', 'teams') @@ -87,6 +86,7 @@ $utopia->post('/v1/teams') $utopia->get('/v1/teams') ->desc('List Teams') + ->groups(['api', 'teams']) ->label('scope', 'teams.read') ->label('sdk.platform', [APP_PLATFORM_CLIENT, APP_PLATFORM_SERVER]) ->label('sdk.namespace', 'teams') @@ -116,6 +116,7 @@ $utopia->get('/v1/teams') $utopia->get('/v1/teams/:teamId') ->desc('Get Team') + ->groups(['api', 'teams']) ->label('scope', 'teams.read') ->label('sdk.platform', [APP_PLATFORM_CLIENT, APP_PLATFORM_SERVER]) ->label('sdk.namespace', 'teams') @@ -136,6 +137,7 @@ $utopia->get('/v1/teams/:teamId') $utopia->put('/v1/teams/:teamId') ->desc('Update Team') + ->groups(['api', 'teams']) ->label('scope', 'teams.write') ->label('sdk.platform', [APP_PLATFORM_CLIENT, APP_PLATFORM_SERVER]) ->label('sdk.namespace', 'teams') @@ -165,6 +167,7 @@ $utopia->put('/v1/teams/:teamId') $utopia->delete('/v1/teams/:teamId') ->desc('Delete Team') + ->groups(['api', 'teams']) ->label('scope', 'teams.write') ->label('sdk.platform', [APP_PLATFORM_CLIENT, APP_PLATFORM_SERVER]) ->label('sdk.namespace', 'teams') @@ -204,6 +207,7 @@ $utopia->delete('/v1/teams/:teamId') $utopia->post('/v1/teams/:teamId/memberships') ->desc('Create Team Membership') + ->groups(['api', 'teams']) ->label('scope', 'teams.write') ->label('sdk.platform', [APP_PLATFORM_CLIENT, APP_PLATFORM_SERVER]) ->label('sdk.namespace', 'teams') @@ -306,12 +310,11 @@ $utopia->post('/v1/teams/:teamId/memberships') 'secret' => Auth::hash($secret), ]); - if(APP_MODE_ADMIN === $mode) { // Allow admin to create membership + if (APP_MODE_ADMIN === $mode) { // Allow admin to create membership Authorization::disable(); $membership = $projectDB->createDocument($membership->getArrayCopy()); Authorization::reset(); - } - else { + } else { $membership = $projectDB->createDocument($membership->getArrayCopy()); } @@ -344,7 +347,7 @@ $utopia->post('/v1/teams/:teamId/memberships') ->setParam('{{text-cta}}', '#ffffff') ; - if(APP_MODE_ADMIN !== $mode) { // No need in comfirmation when in admin mode + if (APP_MODE_ADMIN !== $mode) { // No need in comfirmation when in admin mode $mail ->setParam('event', 'teams.membership.create') ->setParam('recipient', $email) @@ -381,6 +384,7 @@ $utopia->post('/v1/teams/:teamId/memberships') $utopia->get('/v1/teams/:teamId/memberships') ->desc('Get Team Memberships') + ->groups(['api', 'teams']) ->label('scope', 'teams.read') ->label('sdk.platform', [APP_PLATFORM_CLIENT, APP_PLATFORM_SERVER]) ->label('sdk.namespace', 'teams') @@ -433,12 +437,12 @@ $utopia->get('/v1/teams/:teamId/memberships') } $response->json(['sum' => $projectDB->getSum(), 'memberships' => $users]); - } ); $utopia->patch('/v1/teams/:teamId/memberships/:inviteId/status') ->desc('Update Team Membership Status') + ->groups(['api', 'teams']) ->label('scope', 'public') ->label('sdk.platform', [APP_PLATFORM_CLIENT]) ->label('sdk.namespace', 'teams') @@ -544,7 +548,7 @@ $utopia->patch('/v1/teams/:teamId/memberships/:inviteId/status') ->setParam('resource', 'teams/'.$teamId) ; - if(!Config::getParam('domainVerification')) { + if (!Config::getParam('domainVerification')) { $response ->addHeader('X-Fallback-Cookies', \json_encode([Auth::$cookieName => Auth::encodeSession($user->getId(), $secret)])) ; @@ -571,6 +575,7 @@ $utopia->patch('/v1/teams/:teamId/memberships/:inviteId/status') $utopia->delete('/v1/teams/:teamId/memberships/:inviteId') ->desc('Delete Team Membership') + ->groups(['api', 'teams']) ->label('scope', 'teams.write') ->label('sdk.platform', [APP_PLATFORM_CLIENT, APP_PLATFORM_SERVER]) ->label('sdk.namespace', 'teams') diff --git a/app/controllers/api/users.php b/app/controllers/api/users.php index d032cef94..d1744bf48 100644 --- a/app/controllers/api/users.php +++ b/app/controllers/api/users.php @@ -21,10 +21,9 @@ use Appwrite\Database\Validator\UID; use DeviceDetector\DeviceDetector; use GeoIp2\Database\Reader; -include_once __DIR__ . '/../shared/api.php'; - $utopia->post('/v1/users') ->desc('Create User') + ->groups(['api', 'users']) ->label('scope', 'users.write') ->label('sdk.platform', [APP_PLATFORM_SERVER]) ->label('sdk.namespace', 'users') @@ -94,6 +93,7 @@ $utopia->post('/v1/users') $utopia->get('/v1/users') ->desc('List Users') + ->groups(['api', 'users']) ->label('scope', 'users.read') ->label('sdk.platform', [APP_PLATFORM_SERVER]) ->label('sdk.namespace', 'users') @@ -148,6 +148,7 @@ $utopia->get('/v1/users') $utopia->get('/v1/users/:userId') ->desc('Get User') + ->groups(['api', 'users']) ->label('scope', 'users.read') ->label('sdk.platform', [APP_PLATFORM_SERVER]) ->label('sdk.namespace', 'users') @@ -189,6 +190,7 @@ $utopia->get('/v1/users/:userId') $utopia->get('/v1/users/:userId/prefs') ->desc('Get User Preferences') + ->groups(['api', 'users']) ->label('scope', 'users.read') ->label('sdk.platform', [APP_PLATFORM_SERVER]) ->label('sdk.namespace', 'users') @@ -218,6 +220,7 @@ $utopia->get('/v1/users/:userId/prefs') $utopia->get('/v1/users/:userId/sessions') ->desc('Get User Sessions') + ->groups(['api', 'users']) ->label('scope', 'users.read') ->label('sdk.platform', [APP_PLATFORM_SERVER]) ->label('sdk.namespace', 'users') @@ -281,6 +284,7 @@ $utopia->get('/v1/users/:userId/sessions') $utopia->get('/v1/users/:userId/logs') ->desc('Get User Logs') + ->groups(['api', 'users']) ->label('scope', 'users.read') ->label('sdk.platform', [APP_PLATFORM_SERVER]) ->label('sdk.namespace', 'users') @@ -361,6 +365,7 @@ $utopia->get('/v1/users/:userId/logs') $utopia->patch('/v1/users/:userId/status') ->desc('Update User Status') + ->groups(['api', 'users']) ->label('scope', 'users.write') ->label('sdk.platform', [APP_PLATFORM_SERVER]) ->label('sdk.namespace', 'users') @@ -409,6 +414,7 @@ $utopia->patch('/v1/users/:userId/status') $utopia->patch('/v1/users/:userId/prefs') ->desc('Update User Preferences') + ->groups(['api', 'users']) ->label('scope', 'users.write') ->label('sdk.platform', [APP_PLATFORM_SERVER]) ->label('sdk.namespace', 'users') @@ -451,6 +457,7 @@ $utopia->patch('/v1/users/:userId/prefs') $utopia->delete('/v1/users/:userId/sessions/:sessionId') ->desc('Delete User Session') + ->groups(['api', 'users']) ->label('scope', 'users.write') ->label('sdk.platform', [APP_PLATFORM_SERVER]) ->label('sdk.namespace', 'users') @@ -483,6 +490,7 @@ $utopia->delete('/v1/users/:userId/sessions/:sessionId') $utopia->delete('/v1/users/:userId/sessions') ->desc('Delete User Sessions') + ->groups(['api', 'users']) ->label('scope', 'users.write') ->label('sdk.platform', [APP_PLATFORM_SERVER]) ->label('sdk.namespace', 'users') diff --git a/app/controllers/mock.php b/app/controllers/mock.php index 67e0776a9..097501fbb 100644 --- a/app/controllers/mock.php +++ b/app/controllers/mock.php @@ -22,7 +22,6 @@ $utopia->get('/v1/mock/tests/foo') ->param('z', null, function () { return new ArrayList(new Text(256)); }, 'Sample array param') ->action( function ($x, $y, $z) { - } ); @@ -37,7 +36,6 @@ $utopia->post('/v1/mock/tests/foo') ->param('z', null, function () { return new ArrayList(new Text(256)); }, 'Sample array param') ->action( function ($x, $y, $z) { - } ); @@ -52,7 +50,6 @@ $utopia->patch('/v1/mock/tests/foo') ->param('z', null, function () { return new ArrayList(new Text(256)); }, 'Sample array param') ->action( function ($x, $y, $z) { - } ); @@ -67,7 +64,6 @@ $utopia->put('/v1/mock/tests/foo') ->param('z', null, function () { return new ArrayList(new Text(256)); }, 'Sample array param') ->action( function ($x, $y, $z) { - } ); @@ -82,7 +78,6 @@ $utopia->delete('/v1/mock/tests/foo') ->param('z', null, function () { return new ArrayList(new Text(256)); }, 'Sample array param') ->action( function ($x, $y, $z) { - } ); @@ -97,7 +92,6 @@ $utopia->get('/v1/mock/tests/bar') ->param('z', null, function () { return new ArrayList(new Text(256)); }, 'Sample array param') ->action( function ($x, $y, $z) { - } ); @@ -112,7 +106,6 @@ $utopia->post('/v1/mock/tests/bar') ->param('z', null, function () { return new ArrayList(new Text(256)); }, 'Sample array param') ->action( function ($x, $y, $z) { - } ); @@ -127,7 +120,6 @@ $utopia->patch('/v1/mock/tests/bar') ->param('z', null, function () { return new ArrayList(new Text(256)); }, 'Sample array param') ->action( function ($x, $y, $z) { - } ); @@ -142,7 +134,6 @@ $utopia->put('/v1/mock/tests/bar') ->param('z', null, function () { return new ArrayList(new Text(256)); }, 'Sample array param') ->action( function ($x, $y, $z) { - } ); @@ -157,7 +148,6 @@ $utopia->delete('/v1/mock/tests/bar') ->param('z', null, function () { return new ArrayList(new Text(256)); }, 'Sample array param') ->action( function ($x, $y, $z) { - } ); @@ -180,19 +170,19 @@ $utopia->post('/v1/mock/tests/general/upload') $file['size'] = (\is_array($file['size'])) ? $file['size'] : [$file['size']]; foreach ($file['name'] as $i => $name) { - if($name !== 'file.png') { + if ($name !== 'file.png') { throw new Exception('Wrong file name', 400); } } foreach ($file['size'] as $i => $size) { - if($size !== 38756) { + if ($size !== 38756) { throw new Exception('Wrong file size', 400); } } foreach ($file['tmp_name'] as $i => $tmpName) { - if(\md5(\file_get_contents($tmpName)) !== 'd80e7e6999a3eb2ae0d631a96fe135a4') { + if (\md5(\file_get_contents($tmpName)) !== 'd80e7e6999a3eb2ae0d631a96fe135a4') { throw new Exception('Wrong file uploaded', 400); } } @@ -242,7 +232,7 @@ $utopia->get('/v1/mock/tests/general/get-cookie') ->label('sdk.description', 'Mock a get cookie request for SDK tests') ->action( function () use ($request) { - if($request->getCookie('cookieName', '') !== 'cookieValue') { + if ($request->getCookie('cookieName', '') !== 'cookieValue') { throw new Exception('Missing cookie value', 400); } } @@ -285,15 +275,15 @@ $utopia->get('/v1/mock/tests/general/oauth2/token') ->param('code', '', function () { return new Text(100); }, 'OAuth2 state.') ->action( function ($clientId, $redirectURI, $clientSecret, $code) use ($response) { - if($clientId != '1') { + if ($clientId != '1') { throw new Exception('Invalid client ID'); } - if($clientSecret != '123456') { + if ($clientSecret != '123456') { throw new Exception('Invalid client secret'); } - if($code != 'abcdef') { + if ($code != 'abcdef') { throw new Exception('Invalid token'); } @@ -308,7 +298,7 @@ $utopia->get('/v1/mock/tests/general/oauth2/user') ->param('token', '', function () { return new Text(100); }, 'OAuth2 Access Token.') ->action( function ($token) use ($response) { - if($token != '123456') { + if ($token != '123456') { throw new Exception('Invalid token'); } @@ -345,12 +335,11 @@ $utopia->get('/v1/mock/tests/general/oauth2/failure') ); $utopia->shutdown(function() use ($response, $request, &$result, $utopia) { - $route = $utopia->match($request); $path = APP_STORAGE_CACHE.'/tests.json'; $tests = (\file_exists($path)) ? \json_decode(\file_get_contents($path), true) : []; - if(!\is_array($tests)) { + if (!\is_array($tests)) { throw new Exception('Failed to read results', 500); } @@ -358,9 +347,9 @@ $utopia->shutdown(function() use ($response, $request, &$result, $utopia) { $tests = \array_merge($tests, $result); - if(!\file_put_contents($path, \json_encode($tests), LOCK_EX)) { + if (!\file_put_contents($path, \json_encode($tests), LOCK_EX)) { throw new Exception('Failed to save resutls', 500); } $response->json(['result' => $route->getMethod() . ':' . $route->getURL() . ':passed']); -}); \ No newline at end of file +}, 'mock'); \ No newline at end of file diff --git a/app/controllers/shared/api.php b/app/controllers/shared/api.php index 97da51031..e911c2c55 100644 --- a/app/controllers/shared/api.php +++ b/app/controllers/shared/api.php @@ -7,10 +7,9 @@ use Utopia\Abuse\Adapters\TimeLimit; global $utopia, $request, $response, $register, $user, $project; $utopia->init(function () use ($utopia, $request, $response, $register, $user, $project) { - $route = $utopia->match($request); - if(empty($project->getId()) && $route->getLabel('abuse-limit', 0) > 0) { // Abuse limit requires an active project scope + if (empty($project->getId()) && $route->getLabel('abuse-limit', 0) > 0) { // Abuse limit requires an active project scope throw new Exception('Missing or unknown project ID', 400); } @@ -37,7 +36,6 @@ $utopia->init(function () use ($utopia, $request, $response, $register, $user, $ $abuse = new Abuse($timeLimit); if ($timeLimit->limit()) { - $response ->addHeader('X-RateLimit-Limit', $timeLimit->limit()) ->addHeader('X-RateLimit-Remaining', $timeLimit->remaining()) @@ -48,4 +46,4 @@ $utopia->init(function () use ($utopia, $request, $response, $register, $user, $ if ($abuse->check() && $request->getServer('_APP_OPTIONS_ABUSE', 'enabled') !== 'disabled') { throw new Exception('Too many requests', 429); } -}); \ No newline at end of file +}, 'api'); \ No newline at end of file diff --git a/app/controllers/shared/web.php b/app/controllers/shared/web.php index fced2de4d..a2f85bcb0 100644 --- a/app/controllers/shared/web.php +++ b/app/controllers/shared/web.php @@ -2,36 +2,31 @@ use Utopia\View; use Utopia\Config\Config; -use Utopia\Locale\Locale; - -Locale::$exceptions = false; - -$roles = [ - ['type' => 'owner', 'label' => 'Owner'], - ['type' => 'developer', 'label' => 'Developer'], - ['type' => 'admin', 'label' => 'Admin'], -]; $layout = new View(__DIR__.'/../../views/layouts/default.phtml'); -/* AJAX check */ -if (!empty($request->getQuery('version', ''))) { - $layout->setPath(__DIR__.'/../../views/layouts/empty.phtml'); -} - -$layout - ->setParam('title', APP_NAME) - ->setParam('protocol', Config::getParam('protocol')) - ->setParam('domain', $domain) - ->setParam('home', $request->getServer('_APP_HOME')) - ->setParam('setup', $request->getServer('_APP_SETUP')) - ->setParam('class', 'unknown') - ->setParam('icon', '/images/favicon.png') - ->setParam('roles', $roles) - ->setParam('env', $utopia->getMode()) -; - $utopia->init(function () use ($utopia, $response, $request, $layout) { + + /* AJAX check */ + if (!empty($request->getQuery('version', ''))) { + $layout->setPath(__DIR__.'/../../views/layouts/empty.phtml'); + } + $layout + ->setParam('title', APP_NAME) + ->setParam('protocol', Config::getParam('protocol')) + ->setParam('domain', Config::getParam('domain')) + ->setParam('home', $request->getServer('_APP_HOME')) + ->setParam('setup', $request->getServer('_APP_SETUP')) + ->setParam('class', 'unknown') + ->setParam('icon', '/images/favicon.png') + ->setParam('roles', [ + ['type' => 'owner', 'label' => 'Owner'], + ['type' => 'developer', 'label' => 'Developer'], + ['type' => 'admin', 'label' => 'Admin'], + ]) + ->setParam('env', $utopia->getMode()) + ; + $time = (60 * 60 * 24 * 45); // 45 days cache $isDev = (\Utopia\App::MODE_TYPE_DEVELOPMENT == Config::getParam('env')); @@ -47,4 +42,4 @@ $utopia->init(function () use ($utopia, $response, $request, $layout) { ->setParam('isDev', $isDev) ->setParam('class', $scope) ; -}); +}, 'web'); diff --git a/app/controllers/web/console.php b/app/controllers/web/console.php index ff59b0307..595d36d33 100644 --- a/app/controllers/web/console.php +++ b/app/controllers/web/console.php @@ -1,7 +1,5 @@ init(function () use ($layout) { ->setParam('description', 'Appwrite Console allows you to easily manage, monitor, and control your entire backend API and tools.') ->setParam('analytics', 'UA-26264668-5') ; -}); +}, 'console'); $utopia->shutdown(function () use ($response, $request, $layout) { $header = new View(__DIR__.'/../../views/console/comps/header.phtml'); @@ -34,10 +32,10 @@ $utopia->shutdown(function () use ($response, $request, $layout) { ; $response->send($layout->render()); -}); +}, 'console'); $utopia->get('/error/:code') - ->desc('Error page') + ->groups(['web', 'console']) ->label('permission', 'public') ->label('scope', 'home') ->param('code', null, new \Utopia\Validator\Numeric(), 'Valid status code number', false) @@ -54,6 +52,7 @@ $utopia->get('/error/:code') }); $utopia->get('/console') + ->groups(['web', 'console']) ->label('permission', 'public') ->label('scope', 'console') ->action(function () use ($layout, $request) { @@ -69,6 +68,7 @@ $utopia->get('/console') }); $utopia->get('/console/account') + ->groups(['web', 'console']) ->label('permission', 'public') ->label('scope', 'console') ->action(function () use ($layout) { @@ -86,7 +86,7 @@ $utopia->get('/console/account') }); $utopia->get('/console/notifications') - ->desc('Platform console notifications') + ->groups(['web', 'console']) ->label('permission', 'public') ->label('scope', 'console') ->action(function () use ($layout) { @@ -98,7 +98,7 @@ $utopia->get('/console/notifications') }); $utopia->get('/console/home') - ->desc('Platform console project home') + ->groups(['web', 'console']) ->label('permission', 'public') ->label('scope', 'console') ->action(function () use ($layout) { @@ -110,7 +110,7 @@ $utopia->get('/console/home') }); $utopia->get('/console/settings') - ->desc('Platform console project settings') + ->groups(['web', 'console']) ->label('permission', 'public') ->label('scope', 'console') ->action(function () use ($request, $layout) { @@ -129,7 +129,7 @@ $utopia->get('/console/settings') }); $utopia->get('/console/webhooks') - ->desc('Platform console project webhooks') + ->groups(['web', 'console']) ->label('permission', 'public') ->label('scope', 'console') ->action(function () use ($layout) { @@ -145,7 +145,7 @@ $utopia->get('/console/webhooks') }); $utopia->get('/console/keys') - ->desc('Platform console project keys') + ->groups(['web', 'console']) ->label('permission', 'public') ->label('scope', 'console') ->action(function () use ($layout) { @@ -160,7 +160,7 @@ $utopia->get('/console/keys') }); $utopia->get('/console/tasks') - ->desc('Platform console project tasks') + ->groups(['web', 'console']) ->label('permission', 'public') ->label('scope', 'console') ->action(function () use ($layout) { @@ -172,7 +172,7 @@ $utopia->get('/console/tasks') }); $utopia->get('/console/database') - ->desc('Platform console project settings') + ->groups(['web', 'console']) ->label('permission', 'public') ->label('scope', 'console') ->action(function () use ($layout) { @@ -184,7 +184,7 @@ $utopia->get('/console/database') }); $utopia->get('/console/database/collection') - ->desc('Platform console project database collection') + ->groups(['web', 'console']) ->label('permission', 'public') ->label('scope', 'console') ->param('id', '', function () { return new UID(); }, 'Collection unique ID.') @@ -213,11 +213,10 @@ $utopia->get('/console/database/collection') ->addHeader('Expires', 0) ->addHeader('Pragma', 'no-cache') ; - }); $utopia->get('/console/database/document') - ->desc('Platform console project database document') + ->groups(['web', 'console']) ->label('permission', 'public') ->label('scope', 'console') ->param('collection', '', function () { return new UID(); }, 'Collection unique ID.') @@ -247,7 +246,7 @@ $utopia->get('/console/database/document') }); $utopia->get('/console/storage') - ->desc('Platform console project settings') + ->groups(['web', 'console']) ->label('permission', 'public') ->label('scope', 'console') ->action(function () use ($request, $layout) { @@ -265,7 +264,7 @@ $utopia->get('/console/storage') }); $utopia->get('/console/users') - ->desc('Platform console project settings') + ->groups(['web', 'console']) ->label('permission', 'public') ->label('scope', 'console') ->action(function () use ($layout) { @@ -279,7 +278,7 @@ $utopia->get('/console/users') }); $utopia->get('/console/users/user') - ->desc('Platform console project user') + ->groups(['web', 'console']) ->label('permission', 'public') ->label('scope', 'console') ->action(function () use ($layout) { @@ -291,7 +290,7 @@ $utopia->get('/console/users/user') }); $utopia->get('/console/users/teams/team') - ->desc('Platform console project team') + ->groups(['web', 'console']) ->label('permission', 'public') ->label('scope', 'console') ->action(function () use ($layout) { diff --git a/app/controllers/web/home.php b/app/controllers/web/home.php index 8dda07111..5d8a7aefc 100644 --- a/app/controllers/web/home.php +++ b/app/controllers/web/home.php @@ -1,7 +1,5 @@ init(function () use ($layout) { + $header = new View(__DIR__.'/../../views/home/comps/header.phtml'); + $footer = new View(__DIR__.'/../../views/home/comps/footer.phtml'); -$footer - ->setParam('version', Config::getParam('version')) -; + $footer + ->setParam('version', Config::getParam('version')) + ; -$layout - ->setParam('title', APP_NAME) - ->setParam('description', '') - ->setParam('class', 'home') - ->setParam('platforms', Config::getParam('platforms')) - ->setParam('header', [$header]) - ->setParam('footer', [$footer]) -; + $layout + ->setParam('title', APP_NAME) + ->setParam('description', '') + ->setParam('class', 'home') + ->setParam('platforms', Config::getParam('platforms')) + ->setParam('header', [$header]) + ->setParam('footer', [$footer]) + ; +}, 'home'); $utopia->shutdown(function () use ($response, $layout) { $response->send($layout->render()); -}); +}, 'home'); $utopia->get('/') + ->groups(['web', 'home']) ->label('permission', 'public') ->label('scope', 'home') ->action( @@ -39,7 +40,7 @@ $utopia->get('/') ); $utopia->get('/auth/signin') - ->desc('Login page') + ->groups(['web', 'home']) ->label('permission', 'public') ->label('scope', 'home') ->action(function () use ($layout) { @@ -51,7 +52,7 @@ $utopia->get('/auth/signin') }); $utopia->get('/auth/signup') - ->desc('Registration page') + ->groups(['web', 'home']) ->label('permission', 'public') ->label('scope', 'home') ->action(function () use ($layout) { @@ -63,7 +64,7 @@ $utopia->get('/auth/signup') }); $utopia->get('/auth/recovery') - ->desc('Password recovery page') + ->groups(['web', 'home']) ->label('permission', 'public') ->label('scope', 'home') ->action(function () use ($request, $layout) { @@ -75,7 +76,7 @@ $utopia->get('/auth/recovery') }); $utopia->get('/auth/confirm') - ->desc('Account confirmation page') + ->groups(['web', 'home']) ->label('permission', 'public') ->label('scope', 'home') ->action(function () use ($layout) { @@ -87,7 +88,7 @@ $utopia->get('/auth/confirm') }); $utopia->get('/auth/join') - ->desc('Account team join page') + ->groups(['web', 'home']) ->label('permission', 'public') ->label('scope', 'home') ->action(function () use ($layout) { @@ -99,7 +100,7 @@ $utopia->get('/auth/join') }); $utopia->get('/auth/recovery/reset') - ->desc('Password recovery page') + ->groups(['web', 'home']) ->label('permission', 'public') ->label('scope', 'home') ->action(function () use ($layout) { @@ -112,7 +113,7 @@ $utopia->get('/auth/recovery/reset') $utopia->get('/auth/oauth2/success') - ->desc('Registration page') + ->groups(['web', 'home']) ->label('permission', 'public') ->label('scope', 'home') ->action(function () use ($layout) { @@ -127,7 +128,7 @@ $utopia->get('/auth/oauth2/success') }); $utopia->get('/auth/oauth2/failure') - ->desc('Registration page') + ->groups(['web', 'home']) ->label('permission', 'public') ->label('scope', 'home') ->action(function () use ($layout) { @@ -142,7 +143,7 @@ $utopia->get('/auth/oauth2/failure') }); $utopia->get('/error/:code') - ->desc('Error page') + ->groups(['web', 'home']) ->label('permission', 'public') ->label('scope', 'home') ->param('code', null, new \Utopia\Validator\Numeric(), 'Valid status code number', false) @@ -159,13 +160,16 @@ $utopia->get('/error/:code') }); $utopia->get('/open-api-2.json') + ->groups(['web', 'home']) ->label('scope', 'public') ->label('docs', false) ->param('platform', APP_PLATFORM_CLIENT, function () {return new WhiteList([APP_PLATFORM_CLIENT, APP_PLATFORM_SERVER, APP_PLATFORM_CONSOLE]);}, 'Choose target platform.', true) ->param('extensions', 0, function () {return new Range(0, 1);}, 'Show extra data.', true) ->param('tests', 0, function () {return new Range(0, 1);}, 'Include only test services.', true) ->action( - function ($platform, $extensions, $tests) use ($response, $request, $utopia, $services) { + function ($platform, $extensions, $tests) use ($response, $request, $utopia) { + $services = Config::getParam('services', []); + function fromCamelCase($input) { \preg_match_all('!([A-Z][A-Z0-9]*(?=$|[A-Z][a-z0-9])|[A-Za-z][a-z0-9]+)!', $input, $matches); @@ -183,11 +187,11 @@ $utopia->get('/open-api-2.json') } foreach ($services as $service) { /* @noinspection PhpIncludeInspection */ - if($tests && !isset($service['tests'])) { + if ($tests && !isset($service['tests'])) { continue; } - if($tests && !$service['tests']) { + if ($tests && !$service['tests']) { continue; } @@ -347,19 +351,19 @@ $utopia->get('/open-api-2.json') ]; if ($extensions) { - if(isset($output['securityDefinitions']['Project'])) { + if (isset($output['securityDefinitions']['Project'])) { $output['securityDefinitions']['Project']['extensions'] = ['demo' => '5df5acd0d48c2']; } - if(isset($output['securityDefinitions']['Key'])) { + if (isset($output['securityDefinitions']['Key'])) { $output['securityDefinitions']['Key']['extensions'] = ['demo' => '919c2d18fb5d4...a2ae413da83346ad2']; } - if(isset($output['securityDefinitions']['Locale'])) { + if (isset($output['securityDefinitions']['Locale'])) { $output['securityDefinitions']['Locale']['extensions'] = ['demo' => 'en']; } - if(isset($output['securityDefinitions']['Mode'])) { + if (isset($output['securityDefinitions']['Mode'])) { $output['securityDefinitions']['Mode']['extensions'] = ['demo' => '']; } } @@ -374,7 +378,7 @@ $utopia->get('/open-api-2.json') continue; } - if($platform !== APP_PLATFORM_CONSOLE && !\in_array($platforms[$platform], $route->getLabel('sdk.platform', []))) { + if ($platform !== APP_PLATFORM_CONSOLE && !\in_array($platforms[$platform], $route->getLabel('sdk.platform', []))) { continue; } diff --git a/app/init.php b/app/init.php index c58895859..ca378a2b0 100644 --- a/app/init.php +++ b/app/init.php @@ -62,6 +62,8 @@ Config::load('providers', __DIR__.'/../app/config/providers.php'); Config::load('platforms', __DIR__.'/../app/config/platforms.php'); Config::load('locales', __DIR__.'/../app/config/locales.php'); Config::load('collections', __DIR__.'/../app/config/collections.php'); +Config::load('roles', __DIR__.'/../app/config/roles.php'); // User roles and scopes +Config::load('services', __DIR__.'/../app/config/services.php'); // List of services Config::setParam('env', $utopia->getMode()); Config::setParam('domain', $request->getServer('HTTP_HOST', '')); diff --git a/bin/start b/bin/start index 931aa101f..4b0616978 100755 --- a/bin/start +++ b/bin/start @@ -4,6 +4,8 @@ export PHP_VERSION=$PHP_VERSION chown -Rf www-data.www-data /usr/share/nginx/html/ +sed 's/%_APP_STORAGE_LIMIT%/'$_APP_STORAGE_LIMIT'/g' /etc/nginx/nginx.conf.template > /etc/nginx/nginx.conf + # Function to update the fpm configuration to make the service environment variables available function setEnvironmentVariable() { if [ -z "$2" ]; then diff --git a/composer.json b/composer.json index 51bf3762d..dbb78bfb1 100644 --- a/composer.json +++ b/composer.json @@ -32,7 +32,11 @@ "appwrite/php-clamav": "1.0.*", +<<<<<<< HEAD "utopia-php/framework": "0.3.7", +======= + "utopia-php/framework": "0.4.0", +>>>>>>> 17b9dc76a60403ef4e680ee92f3c845a5762effd "utopia-php/abuse": "0.2.*", "utopia-php/audit": "0.3.*", "utopia-php/cache": "0.2.*", diff --git a/composer.lock b/composer.lock index 7c452fe45..957ddf5d1 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,11 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], +<<<<<<< HEAD "content-hash": "1df9fdb337c6030db4bb5f0e9868f9c3", +======= + "content-hash": "7f6cbe77fe2e0f8bdff33c37a4d9ca11", +>>>>>>> 17b9dc76a60403ef4e680ee92f3c845a5762effd "packages": [ { "name": "appwrite/php-clamav", @@ -459,24 +463,24 @@ "source": { "type": "git", "url": "https://github.com/guzzle/promises.git", - "reference": "89b1a76b7fda5853401297dc4b2a093cba1fda23" + "reference": "bbf3b200bc83c1e9298580a9f99b9be248543467" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/guzzle/promises/zipball/89b1a76b7fda5853401297dc4b2a093cba1fda23", - "reference": "89b1a76b7fda5853401297dc4b2a093cba1fda23", + "url": "https://api.github.com/repos/guzzle/promises/zipball/bbf3b200bc83c1e9298580a9f99b9be248543467", + "reference": "bbf3b200bc83c1e9298580a9f99b9be248543467", "shasum": "" }, "require": { - "php": ">=5.6" + "php": ">=5.5" }, "require-dev": { - "phpunit/phpunit": "^5.7.27 || ^7.5" + "phpunit/phpunit": "^4.8.36 || ^5.7.27 || ^7.5" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.4-dev" + "dev-master": "1.3-dev" } }, "autoload": { @@ -502,7 +506,7 @@ "keywords": [ "promise" ], - "time": "2020-02-15T23:33:03+00:00" + "time": "2020-06-21T23:10:57+00:00" }, { "name": "guzzlehttp/psr7", @@ -1596,6 +1600,7 @@ }, { "name": "utopia-php/framework", +<<<<<<< HEAD "version": "0.3.7", "source": { "type": "git", @@ -1606,6 +1611,18 @@ "type": "zip", "url": "https://api.github.com/repos/utopia-php/framework/zipball/23156b3d604fd9586f2e8c6c449b2fc6a82c10bc", "reference": "23156b3d604fd9586f2e8c6c449b2fc6a82c10bc", +======= + "version": "0.4.0", + "source": { + "type": "git", + "url": "https://github.com/utopia-php/framework.git", + "reference": "30aeb2aeecf8ea2ab83242efad0f5f9fab8d4be5" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/utopia-php/framework/zipball/30aeb2aeecf8ea2ab83242efad0f5f9fab8d4be5", + "reference": "30aeb2aeecf8ea2ab83242efad0f5f9fab8d4be5", +>>>>>>> 17b9dc76a60403ef4e680ee92f3c845a5762effd "shasum": "" }, "require": { @@ -1636,7 +1653,11 @@ "php", "upf" ], +<<<<<<< HEAD "time": "2020-06-21T11:29:58+00:00" +======= + "time": "2020-06-25T18:21:48+00:00" +>>>>>>> 17b9dc76a60403ef4e680ee92f3c845a5762effd }, { "name": "utopia-php/locale", @@ -2141,24 +2162,23 @@ "source": { "type": "git", "url": "https://github.com/phpDocumentor/ReflectionDocBlock.git", - "reference": "790426f28bfcbfc1a6f1d59ee8c986edfa45395c" + "reference": "664187301bfbc87e686df212094e6817805c3ab8" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/790426f28bfcbfc1a6f1d59ee8c986edfa45395c", - "reference": "790426f28bfcbfc1a6f1d59ee8c986edfa45395c", + "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/664187301bfbc87e686df212094e6817805c3ab8", + "reference": "664187301bfbc87e686df212094e6817805c3ab8", "shasum": "" }, "require": { - "ext-filter": "^7.1", - "php": "^7.2", + "ext-filter": "*", + "php": "^7.2 || ^8.0", "phpdocumentor/reflection-common": "^2.0", "phpdocumentor/type-resolver": "^1.0", "webmozart/assert": "^1" }, "require-dev": { - "doctrine/instantiator": "^1", - "mockery/mockery": "^1" + "mockery/mockery": "1.3.*" }, "type": "library", "extra": { @@ -2186,7 +2206,7 @@ } ], "description": "With this component, a library can provide support for annotations via DocBlocks or otherwise retrieve information that is embedded in a DocBlock.", - "time": "2020-06-19T18:58:43+00:00" + "time": "2020-06-27T17:33:53+00:00" }, { "name": "phpdocumentor/type-resolver", @@ -3307,12 +3327,12 @@ "source": { "type": "git", "url": "https://github.com/twigphp/Twig.git", - "reference": "3beabd64bdc91558b41f140cc4b14925f0416cb2" + "reference": "f32950c872a995a93807909bab69387f47afaa25" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/twigphp/Twig/zipball/3beabd64bdc91558b41f140cc4b14925f0416cb2", - "reference": "3beabd64bdc91558b41f140cc4b14925f0416cb2", + "url": "https://api.github.com/repos/twigphp/Twig/zipball/f32950c872a995a93807909bab69387f47afaa25", + "reference": "f32950c872a995a93807909bab69387f47afaa25", "shasum": "" }, "require": { @@ -3364,7 +3384,7 @@ "keywords": [ "templating" ], - "time": "2020-06-08T10:41:25+00:00" + "time": "2020-06-22T15:25:21+00:00" }, { "name": "webmozart/assert", diff --git a/docker-compose.yml b/docker-compose.yml index ae7c46ed8..0ec0701b7 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -50,11 +50,10 @@ services: - ./phpunit.xml:/usr/share/nginx/html/phpunit.xml - ./tests:/usr/share/nginx/html/tests - ./app:/usr/share/nginx/html/app - # - ./vendor:/usr/share/nginx/html/vendor + # - ./vendor:/usr/share/nginx/html/vendor - ./docs:/usr/share/nginx/html/docs - ./public:/usr/share/nginx/html/public - ./src:/usr/share/nginx/html/src - - ./docker/nginx.conf:/etc/nginx/nginx.conf depends_on: - mariadb - redis diff --git a/docker/nginx.conf b/docker/nginx.conf.template similarity index 98% rename from docker/nginx.conf rename to docker/nginx.conf.template index 7b62ec9a5..f0f748d94 100644 --- a/docker/nginx.conf +++ b/docker/nginx.conf.template @@ -16,7 +16,7 @@ http { tcp_nodelay on; keepalive_timeout 65; types_hash_max_size 2048; - client_max_body_size 10M; + client_max_body_size %_APP_STORAGE_LIMIT%; # server_names_hash_bucket_size 64; # server_name_in_redirect off; diff --git a/docs/references/account/create-verification.md b/docs/references/account/create-verification.md index eaf6a402e..54e0bf77b 100644 --- a/docs/references/account/create-verification.md +++ b/docs/references/account/create-verification.md @@ -1,3 +1,3 @@ -Use this endpoint to send a verification message to your user email address to confirm they are the valid owners of that address. Both the **userId** and **secret** arguments will be passed as query parameters to the URL you have provider to be attached to the verification email. The provided URL should redirect the user back for your app and allow you to complete the verification process by verifying both the **userId** and **secret** parameters. Learn more about how to [complete the verification process](/docs/client/account#updateAccountVerification). +Use this endpoint to send a verification message to your user email address to confirm they are the valid owners of that address. Both the **userId** and **secret** arguments will be passed as query parameters to the URL you have provided to be attached to the verification email. The provided URL should redirect the user back to your app and allow you to complete the verification process by verifying both the **userId** and **secret** parameters. Learn more about how to [complete the verification process](/docs/client/account#updateAccountVerification). -Please note that in order to avoid a [Redirect Attack](https://github.com/OWASP/CheatSheetSeries/blob/master/cheatsheets/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.md) the only valid redirect URLs are the ones from domains you have set when adding your platforms in the console interface. \ No newline at end of file +Please note that in order to avoid a [Redirect Attack](https://github.com/OWASP/CheatSheetSeries/blob/master/cheatsheets/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.md), the only valid redirect URLs are the ones from domains you have set when adding your platforms in the console interface. diff --git a/public/index.php b/public/index.php index f6cd63710..c87b14a26 100644 --- a/public/index.php +++ b/public/index.php @@ -16,19 +16,8 @@ ini_set('display_errors', 0); // error_reporting(E_ALL); $path = (isset($_GET['q'])) ? explode('/', $_GET['q']) : []; -$domain = (isset($_SERVER['HTTP_HOST'])) ? $_SERVER['HTTP_HOST'] : ''; array_shift($path); $version = array_shift($path); -switch ($version) { // Switch between API version - case 'v1': - $service = $version . '/' . array_shift($path); - include __DIR__ . '/../app/app.php'; - break; - case 'console': - default: - $service = $version . '/'; - include __DIR__ . '/../app/app.php'; - break; -} +include __DIR__ . '/../app/app.php'; diff --git a/src/Appwrite/Auth/OAuth2.php b/src/Appwrite/Auth/OAuth2.php index 8547edc75..5a92049fc 100644 --- a/src/Appwrite/Auth/OAuth2.php +++ b/src/Appwrite/Auth/OAuth2.php @@ -44,7 +44,7 @@ abstract class OAuth2 $this->appSecret = $appSecret; $this->callback = $callback; $this->state = $state; - foreach($scopes as $scope) { + foreach ($scopes as $scope) { $this->addScope($scope); } } @@ -89,21 +89,21 @@ abstract class OAuth2 /** * @param $scope - * + * * @return $this */ protected function addScope(string $scope):OAuth2 { - // Add a scope to the scopes array if it isn't already present - if (!\in_array($scope, $this->scopes)){ - $this->scopes[] = $scope; + // Add a scope to the scopes array if it isn't already present + if (!\in_array($scope, $this->scopes)) { + $this->scopes[] = $scope; } return $this; } - /** - * @return array - */ + /** + * @return array + */ protected function getScopes():array { return $this->scopes; @@ -138,7 +138,7 @@ abstract class OAuth2 \curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $method); \curl_setopt($ch, CURLOPT_HEADER, 0); \curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); - \curl_setopt($ch, CURLOPT_USERAGENT, ''); + \curl_setopt($ch, CURLOPT_USERAGENT, 'Appwrite OAuth2'); if (!empty($payload)) { \curl_setopt($ch, CURLOPT_POSTFIELDS, $payload); diff --git a/src/Appwrite/Auth/OAuth2/Apple.php b/src/Appwrite/Auth/OAuth2/Apple.php index 9fdf2ab22..11a0b0c69 100644 --- a/src/Appwrite/Auth/OAuth2/Apple.php +++ b/src/Appwrite/Auth/OAuth2/Apple.php @@ -19,7 +19,7 @@ class Apple extends OAuth2 * @var array */ protected $scopes = [ - "name", + "name", "email" ]; @@ -166,7 +166,9 @@ class Apple extends OAuth2 $success = \openssl_sign($payload, $signature, $pkey, OPENSSL_ALGO_SHA256); - if (!$success) return ''; + if (!$success) { + return ''; + } return $payload.'.'.$this->encode($this->fromDER($signature, 64)); } @@ -205,8 +207,7 @@ class Apple extends OAuth2 if ('81' === \mb_substr($hex, 2, 2, '8bit')) { // LENGTH > 128 $hex = \mb_substr($hex, 6, null, '8bit'); - } - else { + } else { $hex = \mb_substr($hex, 4, null, '8bit'); } if ('02' !== \mb_substr($hex, 0, 2, '8bit')) { // INTEGER diff --git a/src/Appwrite/Auth/OAuth2/Facebook.php b/src/Appwrite/Auth/OAuth2/Facebook.php index 6a2982242..543fbaa1d 100644 --- a/src/Appwrite/Auth/OAuth2/Facebook.php +++ b/src/Appwrite/Auth/OAuth2/Facebook.php @@ -58,7 +58,7 @@ class Facebook extends OAuth2 'redirect_uri' => $this->callback, 'client_secret' => $this->appSecret, 'code' => $code - ]) + ]) ); $accessToken = \json_decode($accessToken, true); diff --git a/src/Appwrite/Auth/OAuth2/GitHub.php b/src/Appwrite/Auth/OAuth2/Github.php similarity index 97% rename from src/Appwrite/Auth/OAuth2/GitHub.php rename to src/Appwrite/Auth/OAuth2/Github.php index 9f571da3a..cd0225209 100644 --- a/src/Appwrite/Auth/OAuth2/GitHub.php +++ b/src/Appwrite/Auth/OAuth2/Github.php @@ -15,7 +15,7 @@ class Github extends OAuth2 * @var array */ protected $scopes = [ - 'user:email' + 'user:email', ]; /** @@ -37,7 +37,6 @@ class Github extends OAuth2 'scope' => \implode(' ', $this->getScopes()), 'state' => \json_encode($this->state) ]); - } /** @@ -79,6 +78,7 @@ class Github extends OAuth2 { $user = $this->getUser($accessToken); + var_dump($user); if (isset($user['id'])) { return $user['id']; } @@ -126,7 +126,7 @@ class Github extends OAuth2 * @return array */ protected function getUser(string $accessToken) - { + { if (empty($this->user)) { $this->user = \json_decode($this->request('GET', 'https://api.github.com/user', ['Authorization: token '.\urlencode($accessToken)]), true); } diff --git a/src/Appwrite/Auth/OAuth2/Gitlab.php b/src/Appwrite/Auth/OAuth2/Gitlab.php index 93f27db51..369fe0e56 100644 --- a/src/Appwrite/Auth/OAuth2/Gitlab.php +++ b/src/Appwrite/Auth/OAuth2/Gitlab.php @@ -4,7 +4,7 @@ namespace Appwrite\Auth\OAuth2; use Appwrite\Auth\OAuth2; -// Reference Material +// Reference Material // https://docs.gitlab.com/ee/api/oauth2.html class Gitlab extends OAuth2 diff --git a/src/Appwrite/Auth/OAuth2/Google.php b/src/Appwrite/Auth/OAuth2/Google.php index 2f4a4febc..506680910 100644 --- a/src/Appwrite/Auth/OAuth2/Google.php +++ b/src/Appwrite/Auth/OAuth2/Google.php @@ -4,7 +4,7 @@ namespace Appwrite\Auth\OAuth2; use Appwrite\Auth\OAuth2; -// Reference Material +// Reference Material // https://developers.google.com/oauthplayground/ // https://developers.google.com/identity/protocols/OAuth2 // https://developers.google.com/identity/protocols/OAuth2WebServer diff --git a/src/Appwrite/Auth/OAuth2/Microsoft.php b/src/Appwrite/Auth/OAuth2/Microsoft.php index 8f543c796..349446ead 100644 --- a/src/Appwrite/Auth/OAuth2/Microsoft.php +++ b/src/Appwrite/Auth/OAuth2/Microsoft.php @@ -19,7 +19,7 @@ class Microsoft extends OAuth2 * @var array */ protected $scopes = [ - 'offline_access', + 'offline_access', 'user.read' ]; diff --git a/src/Appwrite/Auth/OAuth2/Mock.php b/src/Appwrite/Auth/OAuth2/Mock.php index e1744343f..d7f996293 100644 --- a/src/Appwrite/Auth/OAuth2/Mock.php +++ b/src/Appwrite/Auth/OAuth2/Mock.php @@ -134,4 +134,4 @@ class Mock extends OAuth2 return $this->user; } -} \ No newline at end of file +} diff --git a/src/Appwrite/Auth/OAuth2/Slack.php b/src/Appwrite/Auth/OAuth2/Slack.php index 684804686..20a67456e 100644 --- a/src/Appwrite/Auth/OAuth2/Slack.php +++ b/src/Appwrite/Auth/OAuth2/Slack.php @@ -15,8 +15,8 @@ class Slack extends OAuth2 * @var array */ protected $scopes = [ - 'identity.avatar', - 'identity.basic', + 'identity.avatar', + 'identity.basic', 'identity.email', 'identity.team' ]; @@ -125,7 +125,6 @@ class Slack extends OAuth2 */ protected function getUser(string $accessToken):array { - if (empty($this->user)) { // https://api.slack.com/methods/users.identity $user = $this->request( diff --git a/src/Appwrite/Auth/OAuth2/Spotify.php b/src/Appwrite/Auth/OAuth2/Spotify.php index 1bc3d5190..7962386b0 100644 --- a/src/Appwrite/Auth/OAuth2/Spotify.php +++ b/src/Appwrite/Auth/OAuth2/Spotify.php @@ -137,8 +137,11 @@ class Spotify extends OAuth2 protected function getUser(string $accessToken) { if (empty($this->user)) { - $this->user = \json_decode($this->request('GET', - $this->resourceEndpoint . "me", ['Authorization: Bearer '.\urlencode($accessToken)]), true); + $this->user = \json_decode($this->request( + 'GET', + $this->resourceEndpoint . "me", + ['Authorization: Bearer '.\urlencode($accessToken)] + ), true); } return $this->user; diff --git a/src/Appwrite/Auth/OAuth2/Twitch.php b/src/Appwrite/Auth/OAuth2/Twitch.php index 94f735b50..463bbf917 100644 --- a/src/Appwrite/Auth/OAuth2/Twitch.php +++ b/src/Appwrite/Auth/OAuth2/Twitch.php @@ -139,8 +139,11 @@ class Twitch extends OAuth2 protected function getUser(string $accessToken) { if (empty($this->user)) { - $this->user = \json_decode($this->request('GET', - $this->resourceEndpoint, ['Authorization: Bearer '.\urlencode($accessToken)]), true)['data']['0']; + $this->user = \json_decode($this->request( + 'GET', + $this->resourceEndpoint, + ['Authorization: Bearer '.\urlencode($accessToken)] + ), true)['data']['0']; } return $this->user; diff --git a/src/Appwrite/Auth/OAuth2/Yahoo.php b/src/Appwrite/Auth/OAuth2/Yahoo.php index 41100132f..8593c41ce 100644 --- a/src/Appwrite/Auth/OAuth2/Yahoo.php +++ b/src/Appwrite/Auth/OAuth2/Yahoo.php @@ -153,8 +153,11 @@ class Yahoo extends OAuth2 protected function getUser(string $accessToken) { if (empty($this->user)) { - $this->user = \json_decode($this->request('GET', - $this->resourceEndpoint, ['Authorization: Bearer '.\urlencode($accessToken)]), true); + $this->user = \json_decode($this->request( + 'GET', + $this->resourceEndpoint, + ['Authorization: Bearer '.\urlencode($accessToken)] + ), true); } return $this->user; diff --git a/src/Appwrite/Database/Adapter/MySQL.php b/src/Appwrite/Database/Adapter/MySQL.php index 461d2a29e..f76666630 100644 --- a/src/Appwrite/Database/Adapter/MySQL.php +++ b/src/Appwrite/Database/Adapter/MySQL.php @@ -175,7 +175,7 @@ class MySQL extends Adapter $result = $st->fetch(); - if($result && isset($result['signature'])) { + if ($result && isset($result['signature'])) { $oldSignature = $result['signature']; if ($signature === $oldSignature) { @@ -187,14 +187,14 @@ class MySQL extends Adapter /** * Check Unique Keys */ - foreach($unique as $key => $value) { + foreach ($unique as $key => $value) { $st = $this->getPDO()->prepare('INSERT INTO `'.$this->getNamespace().'.database.unique` SET `key` = :key; '); $st->bindValue(':key', \md5($data['$collection'].':'.$key.'='.$value), PDO::PARAM_STR); - if(!$st->execute()) { + if (!$st->execute()) { throw new Duplicate('Duplicated Property: '.$key.'='.$value); } } diff --git a/src/Appwrite/Database/Document.php b/src/Appwrite/Database/Document.php index a0445702e..bd085c2fa 100644 --- a/src/Appwrite/Database/Document.php +++ b/src/Appwrite/Database/Document.php @@ -134,7 +134,7 @@ class Document extends ArrayObject */ public function removeAttribute($key) { - if(isset($this[$key])) { + if (isset($this[$key])) { unset($this[$key]); } diff --git a/src/Appwrite/Database/Validator/Authorization.php b/src/Appwrite/Database/Validator/Authorization.php index 3225251bb..444f651be 100644 --- a/src/Appwrite/Database/Validator/Authorization.php +++ b/src/Appwrite/Database/Validator/Authorization.php @@ -111,7 +111,7 @@ class Authorization extends Validator /** * Default value in case we need * to reset Authorization status - * + * * @var bool */ public static $statusDefault = true; @@ -119,9 +119,10 @@ class Authorization extends Validator /** * Change default status. * This will be used for the - * value set on the self::reset() method + * value set on the self::reset() method */ - public static function setDefaultStatus($status) { + public static function setDefaultStatus($status) + { self::$statusDefault = $status; self::$status = $status; } diff --git a/src/Appwrite/Database/Validator/DocumentId.php b/src/Appwrite/Database/Validator/DocumentId.php index 0c89e8865..56041dc34 100644 --- a/src/Appwrite/Database/Validator/DocumentId.php +++ b/src/Appwrite/Database/Validator/DocumentId.php @@ -60,19 +60,19 @@ class DocumentId extends Validator { $document = $this->database->getDocument($id); - if(!$document) { + if (!$document) { return false; } - if(!$document instanceof Document) { + if (!$document instanceof Document) { return false; } - if(!$document->getId()) { + if (!$document->getId()) { return false; } - if($document->getCollection() !== $this->collection) { + if ($document->getCollection() !== $this->collection) { return false; } diff --git a/src/Appwrite/Database/Validator/Key.php b/src/Appwrite/Database/Validator/Key.php index a71425a52..53cdc3eb7 100644 --- a/src/Appwrite/Database/Validator/Key.php +++ b/src/Appwrite/Database/Validator/Key.php @@ -34,7 +34,7 @@ class Key extends Validator */ public function isValid($value) { - if(!\is_string($value)) { + if (!\is_string($value)) { return false; } diff --git a/src/Appwrite/Network/Validator/CNAME.php b/src/Appwrite/Network/Validator/CNAME.php index f9a8e5a13..54e4987f1 100644 --- a/src/Appwrite/Network/Validator/CNAME.php +++ b/src/Appwrite/Network/Validator/CNAME.php @@ -26,7 +26,7 @@ class CNAME extends Validator /** * Check if CNAME record target value matches selected target - * + * * @param string $domain * * @return bool @@ -39,12 +39,12 @@ class CNAME extends Validator return false; } - if(!$records || !\is_array($records)) { + if (!$records || !\is_array($records)) { return false; } - foreach($records as $record) { - if(isset($record['target']) && $record['target'] === $this->target) { + foreach ($records as $record) { + if (isset($record['target']) && $record['target'] === $this->target) { return true; } } diff --git a/src/Appwrite/Network/Validator/Origin.php b/src/Appwrite/Network/Validator/Origin.php index a0c06503a..d1368a1c3 100644 --- a/src/Appwrite/Network/Validator/Origin.php +++ b/src/Appwrite/Network/Validator/Origin.php @@ -56,7 +56,7 @@ class Origin extends Validator */ public function __construct($platforms) { - foreach($platforms as $platform) { + foreach ($platforms as $platform) { $type = (isset($platform['type'])) ? $platform['type'] : ''; switch ($type) { @@ -81,7 +81,7 @@ class Origin extends Validator public function getDescription() { - if(!\array_key_exists($this->client, $this->platforms)) { + if (!\array_key_exists($this->client, $this->platforms)) { return 'Unsupported platform'; } @@ -92,7 +92,7 @@ class Origin extends Validator /** * Check if Origin has been whiltlisted * for access to the API - * + * * @param string $origin * * @return bool @@ -105,11 +105,11 @@ class Origin extends Validator $this->host = $host; $this->client = $scheme; - if(empty($host)) { + if (empty($host)) { return true; } - if(\in_array($host, $this->clients)) { + if (\in_array($host, $this->clients)) { return true; } diff --git a/src/Appwrite/Storage/Device/Local.php b/src/Appwrite/Storage/Device/Local.php index 961daee38..d786e2b07 100644 --- a/src/Appwrite/Storage/Device/Local.php +++ b/src/Appwrite/Storage/Device/Local.php @@ -157,16 +157,15 @@ class Local extends Device */ public function delete(string $path, bool $recursive = false):bool { - if(\is_dir($path) && $recursive) { + if (\is_dir($path) && $recursive) { $files = \glob($path.'*', GLOB_MARK); // GLOB_MARK adds a slash to directories returned - foreach($files as $file) { - $this->delete($file, true); + foreach ($files as $file) { + $this->delete($file, true); } \rmdir($path); - } - elseif(\is_file($path)) { + } elseif (\is_file($path)) { return \unlink($path); } diff --git a/src/Appwrite/Storage/Storage.php b/src/Appwrite/Storage/Storage.php index 800c90b43..40c288973 100644 --- a/src/Appwrite/Storage/Storage.php +++ b/src/Appwrite/Storage/Storage.php @@ -78,7 +78,7 @@ class Storage * * @return string */ - static public function human($bytes, $decimals = 2) + public static function human($bytes, $decimals = 2) { $units = array('B','kB','MB','GB','TB','PB','EB','ZB','YB'); $step = 1024; diff --git a/src/Appwrite/Storage/Validator/FileType.php b/src/Appwrite/Storage/Validator/FileType.php index c66631e73..164e59924 100644 --- a/src/Appwrite/Storage/Validator/FileType.php +++ b/src/Appwrite/Storage/Validator/FileType.php @@ -64,7 +64,7 @@ class FileType extends Validator */ public function isValid($path) { - if(!\is_readable($path)) { + if (!\is_readable($path)) { return false; } diff --git a/src/Appwrite/URL/URL.php b/src/Appwrite/URL/URL.php index b4e55039e..5f2b54a65 100644 --- a/src/Appwrite/URL/URL.php +++ b/src/Appwrite/URL/URL.php @@ -6,14 +6,14 @@ class URL { /** * Parse URL - * + * * Take a URL string and split it to array parts - * + * * @param string $url - * + * * @return array */ - static public function parse(string $url):array + public static function parse(string $url):array { $default = [ 'scheme' => '', @@ -31,15 +31,15 @@ class URL /** * Un-Parse URL - * + * * Take URL parts and combine them to a valid string - * + * * @param array $url * @param array $ommit - * + * * @return string */ - static public function unparse(array $url, array $ommit = []):string + public static function unparse(array $url, array $ommit = []):string { if (isset($url['path']) && \mb_substr($url['path'], 0, 1) !== '/') { $url['path'] = '/'.$url['path']; @@ -78,14 +78,14 @@ class URL /** * Parse Query String - * + * * Convert query string to array - * + * * @param string $query - * + * * @return array */ - static public function parseQuery(string $query):array + public static function parseQuery(string $query):array { \parse_str($query, $result); @@ -94,15 +94,15 @@ class URL /** * Un-Parse Query String - * + * * Convert query string array to string - * + * * @param string $query - * + * * @return array */ - static public function unparseQuery(array $query):string + public static function unparseQuery(array $query):string { return \http_build_query($query); } -} \ No newline at end of file +} diff --git a/tests/e2e/Services/Health/HealthCustomServerTest.php b/tests/e2e/Services/Health/HealthCustomServerTest.php index bf55b41a3..572ad2906 100644 --- a/tests/e2e/Services/Health/HealthCustomServerTest.php +++ b/tests/e2e/Services/Health/HealthCustomServerTest.php @@ -173,7 +173,7 @@ class HealthCustomClientTest extends Scope $this->assertEquals(200, $response['headers']['status-code']); $this->assertIsInt($response['body']['size']); - $this->assertLessThan(100, $response['body']['size']); + $this->assertLessThan(120, $response['body']['size']); /** * Test for FAILURE