From 1bbce77c92a4d50764c5aaa5eac8ab39c2125e0b Mon Sep 17 00:00:00 2001 From: Christy Jacob Date: Thu, 18 Jul 2024 01:18:15 +0400 Subject: [PATCH 01/40] chore: poc for new roles --- app/config/roles.php | 102 ++++++++++------ app/controllers/shared/api.php | 25 ++++ docker-compose.yml | 2 +- src/Appwrite/Auth/Auth.php | 3 + tests/e2e/Services/Teams/TeamsBase.php | 3 + .../Services/Teams/TeamsConsoleClientTest.php | 115 +++++++++++++++++- 6 files changed, 207 insertions(+), 43 deletions(-) diff --git a/app/config/roles.php b/app/config/roles.php index 65b9643b89..cf2de4cb5b 100644 --- a/app/config/roles.php +++ b/app/config/roles.php @@ -2,34 +2,42 @@ use Appwrite\Auth\Auth; -$member = [ +$guest = [ 'global', 'public', 'home', 'console', 'graphql', 'sessions.write', - 'account', - 'teams.read', - 'teams.write', 'documents.read', 'documents.write', 'files.read', 'files.write', - 'projects.read', - 'projects.write', 'locale.read', 'avatars.read', - 'execution.read', - 'execution.write', - 'targets.read', - 'targets.write', - 'subscribers.write', - 'subscribers.read', - 'assistant.read', + 'execution.write' ]; -$admins = [ +$member = array_merge($guest, [ + 'account', + 'teams.read', + 'teams.write', + 'projects.read', + 'projects.write', + 'execution.read', + 'targets.read', + 'targets.write', + 'subscribers.read', + 'subscribers.write', + 'assistant.read' +]); + +$billing = array_merge($guest, [ + 'teams.read', + 'teams.write' +]); + +$admin = [ 'global', 'graphql', 'sessions.write', @@ -78,40 +86,62 @@ $admins = [ 'subscribers.read' ]; +# Same as owner but without the ability to modify teams and projects +$developer = array_diff($admin, ['teams.write', 'projects.write']); + +# Same as developer but without the ability to modify collections, buckets, topics, providers, migrations, rules, subscribers, and messages +$editor = array_diff($developer, [ + 'collections.write', + 'buckets.write', + 'topics.write', + 'providers.write', + 'migrations.write', + 'rules.write', + 'subscribers.write', + 'messages.write' +]); + +# Same as editor but without the ability to modify functions, execution, vcs, and webhooks +$analyst = array_diff($editor, [ + 'databases.write', + 'functions.write', + 'execution.write', + 'vcs.write', + 'webhooks.write' +]); + return [ Auth::USER_ROLE_GUESTS => [ 'label' => 'Guests', - 'scopes' => [ - 'global', - 'public', - 'home', - 'console', - 'graphql', - 'sessions.write', - 'documents.read', - 'documents.write', - 'files.read', - 'files.write', - 'locale.read', - 'avatars.read', - 'execution.write', - ], + 'scopes' => $guest, ], Auth::USER_ROLE_USERS => [ 'label' => 'Users', - 'scopes' => \array_merge($member), + 'scopes' => $member, ], Auth::USER_ROLE_ADMIN => [ 'label' => 'Admin', - 'scopes' => \array_merge($admins), - ], - Auth::USER_ROLE_DEVELOPER => [ - 'label' => 'Developer', - 'scopes' => \array_merge($admins), + 'scopes' => $admin, ], Auth::USER_ROLE_OWNER => [ 'label' => 'Owner', - 'scopes' => \array_merge($member, $admins), + 'scopes' => \array_merge($member, $admin), + ], + Auth::USER_ROLE_DEVELOPER => [ + 'label' => 'Developer', + 'scopes' => $developer, + ], + Auth::USER_ROLE_EDITOR => [ + 'label' => 'Editor', + 'scopes' => $editor, + ], + Auth::USER_ROLE_ANALYST => [ + 'label' => 'Analyst', + 'scopes' => $analyst, + ], + Auth::USER_ROLE_BILLING => [ + 'label' => 'Billing', + 'scopes' => $billing, ], Auth::USER_ROLE_APPS => [ 'label' => 'Applications', diff --git a/app/controllers/shared/api.php b/app/controllers/shared/api.php index 2b0013db29..57f58f0168 100644 --- a/app/controllers/shared/api.php +++ b/app/controllers/shared/api.php @@ -172,6 +172,17 @@ App::init() ? Role::guests()->toString() : Role::users()->toString(); + + var_dump('###########'); + var_dump("Project ID : " . $project->getId()); + var_dump($project->getAttribute('teamId')); + $memberships = $user->getAttribute('memberships', []); + foreach($memberships as $membership) { + var_dump($membership['teamId']); + var_dump($membership['roles']); + } + var_dump('###########'); + // Add user roles $memberships = $user->find('teamId', $project->getAttribute('teamId'), 'memberships'); @@ -187,6 +198,15 @@ App::init() case 'developer': $role = Auth::USER_ROLE_DEVELOPER; break; + case 'editor': + $role = Auth::USER_ROLE_EDITOR; + break; + case 'analyst': + $role = Auth::USER_ROLE_ANALYST; + break; + case 'billing': + $role = Auth::USER_ROLE_BILLING; + break; } } } @@ -255,6 +275,11 @@ App::init() Authorization::setRole($authRole); } + var_dump('###########'); + var_dump(Authorization::getRoles()); + var_dump($scopes); + var_dump('###########'); + $service = $route->getLabel('sdk.namespace', ''); if (!empty($service)) { if ( diff --git a/docker-compose.yml b/docker-compose.yml index be46825992..1130916b4b 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -48,7 +48,7 @@ services: build: context: . args: - DEBUG: false + DEBUG: true TESTING: true VERSION: dev ports: diff --git a/src/Appwrite/Auth/Auth.php b/src/Appwrite/Auth/Auth.php index 1e8109622e..e0bbed3c5d 100644 --- a/src/Appwrite/Auth/Auth.php +++ b/src/Appwrite/Auth/Auth.php @@ -39,6 +39,9 @@ class Auth public const USER_ROLE_USERS = 'users'; public const USER_ROLE_ADMIN = 'admin'; public const USER_ROLE_DEVELOPER = 'developer'; + public const USER_ROLE_EDITOR = 'editor'; + public const USER_ROLE_ANALYST = 'analyst'; + public const USER_ROLE_BILLING = 'billing'; public const USER_ROLE_OWNER = 'owner'; public const USER_ROLE_APPS = 'apps'; public const USER_ROLE_SYSTEM = 'system'; diff --git a/tests/e2e/Services/Teams/TeamsBase.php b/tests/e2e/Services/Teams/TeamsBase.php index 2328e4cdbf..a2884f7b08 100644 --- a/tests/e2e/Services/Teams/TeamsBase.php +++ b/tests/e2e/Services/Teams/TeamsBase.php @@ -10,6 +10,9 @@ use Utopia\Database\Validator\Datetime as DatetimeValidator; trait TeamsBase { + /** + * @group testing + */ public function testCreateTeam(): array { /** diff --git a/tests/e2e/Services/Teams/TeamsConsoleClientTest.php b/tests/e2e/Services/Teams/TeamsConsoleClientTest.php index 61d0f6a027..3cb859a571 100644 --- a/tests/e2e/Services/Teams/TeamsConsoleClientTest.php +++ b/tests/e2e/Services/Teams/TeamsConsoleClientTest.php @@ -28,12 +28,13 @@ class TeamsConsoleClientTest extends Scope // Create a user account before we create a invite so we can check if the user has permissions when it shouldn't $user = $this->client->call(Client::METHOD_POST, '/account', [ 'content-type' => 'application/json', - 'x-appwrite-project' => 'console'], [ - 'userId' => 'unique()', - 'email' => $email, - 'password' => $password, - 'name' => $name, - ], false); + 'x-appwrite-project' => 'console' + ], [ + 'userId' => 'unique()', + 'email' => $email, + 'password' => $password, + 'name' => $name, + ], false); $this->assertEquals(201, $user['headers']['status-code']); @@ -76,4 +77,106 @@ class TeamsConsoleClientTest extends Scope return $data; } + + + /** + * @depends testCreateTeam + * @group testing + */ + public function testTeamMemberships($data) + { + $teamUid = $data['teamUid'] ?? ''; + $teamName = $data['teamName'] ?? ''; + $email = uniqid() . 'friend@localhost.test'; + $name = 'Friend User'; + $password = 'password'; + + /** + * Invite team member with developer role + */ + $response = $this->client->call(Client::METHOD_POST, '/teams/' . $teamUid . '/memberships', array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + ], $this->getHeaders()), [ + 'email' => $email, + 'name' => $name, + 'roles' => ['developer'], + 'url' => 'http://localhost:5000/join-us#title' + ]); + + $this->assertEquals(201, $response['headers']['status-code']); + + /** + * Accept the invite + */ + $lastEmail = $this->getLastEmail(); + $this->assertEquals($email, $lastEmail['to'][0]['address']); + $this->assertEquals($name, $lastEmail['to'][0]['name']); + $this->assertEquals('Invitation to ' . $teamName . ' Team at ' . $this->getProject()['name'], $lastEmail['subject']); + $secret = substr($lastEmail['text'], strpos($lastEmail['text'], '&secret=', 0) + 8, 256); + $membershipUid = substr($lastEmail['text'], strpos($lastEmail['text'], '?membershipId=', 0) + 14, 20); + $userUid = substr($lastEmail['text'], strpos($lastEmail['text'], '&userId=', 0) + 8, 20); + + $response = $this->client->call(Client::METHOD_PATCH, '/teams/' . $teamUid . '/memberships/' . $response['body']['$id'] . '/status', array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + ]), [ + 'userId' => $userUid, + 'secret' => $secret, + ]); + + $key = 'a_session_' . $this->getProject()['$id']; + $cookie = $key . '=' . $response['cookies'][$key]; + + $this->assertEquals(200, $response['headers']['status-code']); + + /** + * Test teams.read scope + */ + $response = $this->client->call(Client::METHOD_GET, '/teams', array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'cookie' => $cookie, + ]), []); + $this->assertEquals(200, $response['headers']['status-code']); + + /** + * Test teams.write scope + */ + $response = $this->client->call(Client::METHOD_PUT, '/teams/' . $teamUid, array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'cookie' => $cookie, + ]), [ + 'name' => 'Arsenal Updated', + ]); + + $this->assertEquals(401, $response['headers']['status-code']); + + /** + * Test projects.read scope + */ + $response = $this->client->call(Client::METHOD_GET, '/projects', array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'cookie' => $cookie, + ]), []); + + $this->assertEquals(200, $response['headers']['status-code']); + + /** + * Test projects.write scope + */ + $response = $this->client->call(Client::METHOD_POST, '/projects', array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'cookie' => $cookie, + ]), [ + 'projectId' => 'unique()', + 'name' => 'Project Name', + 'teamId' => $teamUid, + ]); + + $this->assertEquals(401, $response['headers']['status-code']); + } } From 3b7ce7691ef9d2e458c5d01f967e6ea2653d46b6 Mon Sep 17 00:00:00 2001 From: Christy Jacob Date: Tue, 23 Jul 2024 23:49:11 +0400 Subject: [PATCH 02/40] feat: add support for console role --- app/config/roles.php | 161 +++++++++--------- app/controllers/shared/api.php | 113 ++++++------ app/init.php | 22 ++- src/Appwrite/Auth/Auth.php | 5 +- .../Services/Teams/TeamsConsoleClientTest.php | 4 + 5 files changed, 157 insertions(+), 148 deletions(-) diff --git a/app/config/roles.php b/app/config/roles.php index cf2de4cb5b..d347e8f990 100644 --- a/app/config/roles.php +++ b/app/config/roles.php @@ -2,7 +2,13 @@ use Appwrite\Auth\Auth; -$guest = [ +$apps = [ + 'global', + 'health.read', + 'graphql', +]; + +$guests = [ 'global', 'public', 'home', @@ -15,118 +21,107 @@ $guest = [ 'files.write', 'locale.read', 'avatars.read', - 'execution.write' + 'execution.write', ]; -$member = array_merge($guest, [ - 'account', - 'teams.read', - 'teams.write', - 'projects.read', - 'projects.write', - 'execution.read', - 'targets.read', - 'targets.write', - 'subscribers.read', - 'subscribers.write', - 'assistant.read' -]); - -$billing = array_merge($guest, [ - 'teams.read', - 'teams.write' -]); - -$admin = [ +$member = [ 'global', + 'public', + 'home', + 'console', 'graphql', 'sessions.write', + 'account', 'teams.read', 'teams.write', 'documents.read', 'documents.write', 'files.read', 'files.write', - 'buckets.read', - 'buckets.write', - 'users.read', - 'users.write', - 'databases.read', - 'databases.write', - 'collections.read', - 'collections.write', - 'platforms.read', - 'platforms.write', - 'keys.read', - 'keys.write', - 'webhooks.read', - 'webhooks.write', + 'projects.read', + 'projects.write', 'locale.read', 'avatars.read', - 'health.read', - 'functions.read', - 'functions.write', 'execution.read', 'execution.write', - 'rules.read', - 'rules.write', - 'migrations.read', - 'migrations.write', - 'vcs.read', - 'vcs.write', 'targets.read', 'targets.write', - 'providers.write', - 'providers.read', - 'messages.write', - 'messages.read', - 'topics.write', - 'topics.read', 'subscribers.write', - 'subscribers.read' + 'subscribers.read', + 'assistant.read' ]; -# Same as owner but without the ability to modify teams and projects -$developer = array_diff($admin, ['teams.write', 'projects.write']); - -# Same as developer but without the ability to modify collections, buckets, topics, providers, migrations, rules, subscribers, and messages -$editor = array_diff($developer, [ - 'collections.write', - 'buckets.write', - 'topics.write', - 'providers.write', - 'migrations.write', - 'rules.write', - 'subscribers.write', - 'messages.write' +$analyst = array_merge($member, [ + 'users.read', + 'databases.read', + 'collections.read', + 'buckets.read', + 'execution.read', + 'targets.read', + 'subscribers.read', + 'assistant.read', + 'functions.read', + 'platforms.read', + 'keys.read', + 'webhooks.read', + 'rules.read', + 'migrations.read', + 'vcs.read', + 'providers.read', + 'messages.read', + 'topics.read' ]); -# Same as editor but without the ability to modify functions, execution, vcs, and webhooks -$analyst = array_diff($editor, [ - 'databases.write', - 'functions.write', +$editor = array_merge($analyst, [ + 'documents.write', + 'files.write', 'execution.write', + 'targets.write', + 'subscribers.write', +]); + +$developer = array_merge($editor, [ + 'projects.write', + 'buckets.write', + 'users.write', + 'databases.write', + 'collections.write', + 'platforms.write', + 'keys.write', + 'webhooks.write', + 'functions.write', + 'rules.write', + 'migrations.write', 'vcs.write', - 'webhooks.write' + 'targets.write', + 'providers.write', + 'messages.write', + 'topics.write', +]); + +$owner = array_merge($developer, [ + 'billing.read', + 'billing.write' +]); + +$billing = array_merge($member, [ + 'billing.read', + 'billing.write', ]); return [ + Auth::USER_ROLE_APPS => [ + 'label' => 'Applications', + 'scopes' => $apps, + ], Auth::USER_ROLE_GUESTS => [ 'label' => 'Guests', - 'scopes' => $guest, + 'scopes' => $guests, ], Auth::USER_ROLE_USERS => [ 'label' => 'Users', 'scopes' => $member, ], - Auth::USER_ROLE_ADMIN => [ - 'label' => 'Admin', - 'scopes' => $admin, - ], - Auth::USER_ROLE_OWNER => [ - 'label' => 'Owner', - 'scopes' => \array_merge($member, $admin), - ], Auth::USER_ROLE_DEVELOPER => [ 'label' => 'Developer', 'scopes' => $developer, @@ -143,8 +138,8 @@ return [ 'label' => 'Billing', 'scopes' => $billing, ], - Auth::USER_ROLE_APPS => [ - 'label' => 'Applications', - 'scopes' => ['global', 'health.read', 'graphql'], - ], + Auth::USER_ROLE_OWNER => [ + 'label' => 'Owner', + 'scopes' => $owner, + ] ]; diff --git a/app/controllers/shared/api.php b/app/controllers/shared/api.php index 57f58f0168..e3e123e5a3 100644 --- a/app/controllers/shared/api.php +++ b/app/controllers/shared/api.php @@ -165,59 +165,23 @@ App::init() throw new Exception(Exception::PROJECT_NOT_FOUND); } - /** - * ACL Check - */ + /** Default role */ $role = ($user->isEmpty()) ? Role::guests()->toString() : Role::users()->toString(); - - var_dump('###########'); - var_dump("Project ID : " . $project->getId()); - var_dump($project->getAttribute('teamId')); - $memberships = $user->getAttribute('memberships', []); - foreach($memberships as $membership) { - var_dump($membership['teamId']); - var_dump($membership['roles']); - } - var_dump('###########'); - - // Add user roles - $memberships = $user->find('teamId', $project->getAttribute('teamId'), 'memberships'); - - if ($memberships) { - foreach ($memberships->getAttribute('roles', []) as $memberRole) { - switch ($memberRole) { - case 'owner': - $role = Auth::USER_ROLE_OWNER; - break; - case 'admin': - $role = Auth::USER_ROLE_ADMIN; - break; - case 'developer': - $role = Auth::USER_ROLE_DEVELOPER; - break; - case 'editor': - $role = Auth::USER_ROLE_EDITOR; - break; - case 'analyst': - $role = Auth::USER_ROLE_ANALYST; - break; - case 'billing': - $role = Auth::USER_ROLE_BILLING; - break; - } - } - } - + /** Allowed Scopes for the role */ $roles = Config::getParam('roles', []); - $scope = $route->getLabel('scope', 'none'); // Allowed scope for chosen route - $scopes = $roles[$role]['scopes']; // Allowed scopes for user role + $scopes = $roles[$role]['scopes']; + var_dump("Mode : " . $mode); + var_dump(Auth::getRoles($user)); + + /** + * API Key Authentication + */ $authKey = $request->getHeader('x-appwrite-key', ''); - - if (!empty($authKey)) { // API Key authentication + if (!empty($authKey)) { // Do not allow API key and session to be set at the same time if (!$user->isEmpty()) { throw new Exception(Exception::USER_API_KEY_AND_SESSION_SET); @@ -268,6 +232,49 @@ App::init() } } } + /** + * Admin User Authentication + */ + elseif (APP_MODE_ADMIN === $mode && $project->getId() !== 'console') { + if ($user->isEmpty()) { + throw new Exception(Exception::USER_UNAUTHORIZED); + } + + $teamId = $project->getAttribute('teamId', null); + if (empty($teamId)) { + throw new Exception(Exception::USER_UNAUTHORIZED, 'APP_MODE : admin is not allowed for the console project'); + } + + $adminRoles = []; + $memberships = $user->getAttribute('memberships', []); + foreach ($memberships as $membership) { + if ($membership->getAttribute('teamId') === $teamId) { + $adminRoles = $membership->getAttribute('roles', []); + break; + } + } + + if (empty($adminRoles)) { + throw new Exception(Exception::USER_UNAUTHORIZED); + } + + /** Get scopes available to that role for this project */ + foreach ($adminRoles as $role) { + $scopes = \array_merge($scopes, $roles[$role]['scopes']); + } + + // Authorization::setRole(Auth::USER_ROLE_ADMIN); + // foreach ($membership['roles'] as $memberRole) { + // Authorization::setRole($memberRole); + // } + + Authorization::setRole(Auth::USER_ROLE_DEVELOPER); + Authorization::setDefaultStatus(false); + } + + $scopes = \array_unique($scopes); + var_dump("##### Admin Scopes ######"); + var_dump($scopes); Authorization::setRole($role); @@ -275,11 +282,7 @@ App::init() Authorization::setRole($authRole); } - var_dump('###########'); - var_dump(Authorization::getRoles()); - var_dump($scopes); - var_dump('###########'); - + /** Do not allow access to disabled services */ $service = $route->getLabel('sdk.namespace', ''); if (!empty($service)) { if ( @@ -290,14 +293,14 @@ App::init() throw new Exception(Exception::GENERAL_SERVICE_DISABLED); } } - if (!\in_array($scope, $scopes)) { - if ($project->isEmpty()) { // Check if permission is denied because project is missing - throw new Exception(Exception::PROJECT_NOT_FOUND); - } + /** Do now allow access if scope is not allowed */ + $scope = $route->getLabel('scope', 'none'); + if (!\in_array($scope, $scopes)) { throw new Exception(Exception::GENERAL_UNAUTHORIZED_SCOPE, $user->getAttribute('email', 'User') . ' (role: ' . \strtolower($roles[$role]['label']) . ') missing scope (' . $scope . ')'); } + /** Do not allow access to blocked accounts */ if (false === $user->getAttribute('status')) { // Account is blocked throw new Exception(Exception::USER_BLOCKED); } diff --git a/app/init.php b/app/init.php index 325c45a7e8..9b93e9541c 100644 --- a/app/init.php +++ b/app/init.php @@ -1169,6 +1169,9 @@ App::setResource('user', function ($mode, $project, $console, $request, $respons Auth::$unique = $session['id'] ?? ''; Auth::$secret = $session['secret'] ?? ''; + var_dump("####### Session ID ##########"); + var_dump(Auth::$unique); + if (APP_MODE_ADMIN !== $mode) { if ($project->isEmpty()) { $user = new Document([]); @@ -1183,6 +1186,9 @@ App::setResource('user', function ($mode, $project, $console, $request, $respons $user = $dbForConsole->getDocument('users', Auth::$unique); } + var_dump("####### User ##########"); + var_dump($user); + if ( $user->isEmpty() // Check a document has been found in the DB || !Auth::sessionVerify($user->getAttribute('sessions', []), Auth::$secret) @@ -1190,13 +1196,13 @@ App::setResource('user', function ($mode, $project, $console, $request, $respons $user = new Document([]); } - if (APP_MODE_ADMIN === $mode) { - if ($user->find('teamInternalId', $project->getAttribute('teamInternalId'), 'memberships')) { - Authorization::setDefaultStatus(false); // Cancel security segmentation for admin users. - } else { - $user = new Document([]); - } - } + // if (APP_MODE_ADMIN === $mode) { + // if ($user->find('teamInternalId', $project->getAttribute('teamInternalId'), 'memberships')) { + // Authorization::setDefaultStatus(false); // Cancel security segmentation for admin users. + // } else { + // $user = new Document([]); + // } + // } $authJWT = $request->getHeader('x-appwrite-jwt', ''); @@ -1272,7 +1278,7 @@ App::setResource('console', function () { '$collection' => ID::custom('projects'), 'description' => 'Appwrite core engine', 'logo' => '', - 'teamId' => -1, + 'teamId' => null, 'webhooks' => [], 'keys' => [], 'platforms' => [ diff --git a/src/Appwrite/Auth/Auth.php b/src/Appwrite/Auth/Auth.php index e0bbed3c5d..01da227b53 100644 --- a/src/Appwrite/Auth/Auth.php +++ b/src/Appwrite/Auth/Auth.php @@ -37,7 +37,6 @@ class Auth public const USER_ROLE_ANY = 'any'; public const USER_ROLE_GUESTS = 'guests'; public const USER_ROLE_USERS = 'users'; - public const USER_ROLE_ADMIN = 'admin'; public const USER_ROLE_DEVELOPER = 'developer'; public const USER_ROLE_EDITOR = 'editor'; public const USER_ROLE_ANALYST = 'analyst'; @@ -414,7 +413,9 @@ class Auth if ( in_array(self::USER_ROLE_OWNER, $roles) || in_array(self::USER_ROLE_DEVELOPER, $roles) || - in_array(self::USER_ROLE_ADMIN, $roles) + in_array(self::USER_ROLE_EDITOR, $roles) || + in_array(self::USER_ROLE_ANALYST, $roles) || + in_array(self::USER_ROLE_BILLING, $roles) ) { return true; } diff --git a/tests/e2e/Services/Teams/TeamsConsoleClientTest.php b/tests/e2e/Services/Teams/TeamsConsoleClientTest.php index 3cb859a571..9305c99725 100644 --- a/tests/e2e/Services/Teams/TeamsConsoleClientTest.php +++ b/tests/e2e/Services/Teams/TeamsConsoleClientTest.php @@ -135,6 +135,7 @@ class TeamsConsoleClientTest extends Scope */ $response = $this->client->call(Client::METHOD_GET, '/teams', array_merge([ 'content-type' => 'application/json', + 'x-appwrite-mode' => 'admin', 'x-appwrite-project' => $this->getProject()['$id'], 'cookie' => $cookie, ]), []); @@ -147,6 +148,7 @@ class TeamsConsoleClientTest extends Scope 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], 'cookie' => $cookie, + 'x-appwrite-mode' => 'admin' ]), [ 'name' => 'Arsenal Updated', ]); @@ -160,6 +162,7 @@ class TeamsConsoleClientTest extends Scope 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], 'cookie' => $cookie, + 'x-appwrite-mode' => 'admin' ]), []); $this->assertEquals(200, $response['headers']['status-code']); @@ -171,6 +174,7 @@ class TeamsConsoleClientTest extends Scope 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], 'cookie' => $cookie, + 'x-appwrite-mode' => 'admin' ]), [ 'projectId' => 'unique()', 'name' => 'Project Name', From eea5d610babe41422f060da4f65388fd9f2f3665 Mon Sep 17 00:00:00 2001 From: Christy Jacob Date: Tue, 23 Jul 2024 23:54:52 +0400 Subject: [PATCH 03/40] feat: linter --- app/controllers/shared/api.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/app/controllers/shared/api.php b/app/controllers/shared/api.php index e3e123e5a3..896df9bb37 100644 --- a/app/controllers/shared/api.php +++ b/app/controllers/shared/api.php @@ -177,7 +177,7 @@ App::init() var_dump("Mode : " . $mode); var_dump(Auth::getRoles($user)); - /** + /** * API Key Authentication */ $authKey = $request->getHeader('x-appwrite-key', ''); @@ -232,7 +232,7 @@ App::init() } } } - /** + /** * Admin User Authentication */ elseif (APP_MODE_ADMIN === $mode && $project->getId() !== 'console') { @@ -271,7 +271,7 @@ App::init() Authorization::setRole(Auth::USER_ROLE_DEVELOPER); Authorization::setDefaultStatus(false); } - + $scopes = \array_unique($scopes); var_dump("##### Admin Scopes ######"); var_dump($scopes); From c167201d7cf4180ccc9c90ebbce0ac0ce32f23cc Mon Sep 17 00:00:00 2001 From: Christy Jacob Date: Wed, 24 Jul 2024 02:47:46 +0400 Subject: [PATCH 04/40] feat: add role override for admins --- app/controllers/api/databases.php | 2 + app/controllers/api/teams.php | 3 +- app/controllers/shared/api.php | 41 +++++++++------- app/init.php | 6 --- src/Appwrite/Auth/Validator/Role.php | 71 ++++++++++++++++++++++++++++ 5 files changed, 98 insertions(+), 25 deletions(-) create mode 100644 src/Appwrite/Auth/Validator/Role.php diff --git a/app/controllers/api/databases.php b/app/controllers/api/databases.php index 54fc1cb08f..5081e01f64 100644 --- a/app/controllers/api/databases.php +++ b/app/controllers/api/databases.php @@ -416,6 +416,8 @@ App::post('/v1/databases') $databaseId = $databaseId == 'unique()' ? ID::unique() : $databaseId; + var_dump($databaseId); + try { $dbForProject->createDocument('databases', new Document([ '$id' => $databaseId, diff --git a/app/controllers/api/teams.php b/app/controllers/api/teams.php index 5891fb67f0..6edca76814 100644 --- a/app/controllers/api/teams.php +++ b/app/controllers/api/teams.php @@ -3,6 +3,7 @@ use Appwrite\Auth\Auth; use Appwrite\Auth\MFA\Type\TOTP; use Appwrite\Auth\Validator\Phone; +use Appwrite\Auth\Validator\Role as ValidatorRole; use Appwrite\Detector\Detector; use Appwrite\Event\Delete; use Appwrite\Event\Event; @@ -386,7 +387,7 @@ App::post('/v1/teams/:teamId/memberships') ->param('email', '', new Email(), 'Email of the new team member.', true) ->param('userId', '', new UID(), 'ID of the user to be added to a team.', true) ->param('phone', '', new Phone(), 'Phone number. Format this number with a leading \'+\' and a country code, e.g., +16175551212.', true) - ->param('roles', [], new ArrayList(new Key(), APP_LIMIT_ARRAY_PARAMS_SIZE), 'Array of strings. Use this param to set the user roles in the team. A role can be any string. Learn more about [roles and permissions](https://appwrite.io/docs/permissions). Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' roles are allowed, each 32 characters long.') + ->param('roles', [], new ArrayList(new ValidatorRole(), APP_LIMIT_ARRAY_PARAMS_SIZE), 'Array of strings. Use this param to set the user roles in the team. A role can be any string. Learn more about [roles and permissions](https://appwrite.io/docs/permissions). Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' roles are allowed, each 32 characters long.') ->param('url', '', fn ($clients) => new Host($clients), 'URL to redirect the user back to your app from the invitation email. This parameter is not required when an API key is supplied. Only URLs from hostnames in your project platform list are allowed. This requirement helps to prevent an [open redirect](https://cheatsheetseries.owasp.org/cheatsheets/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html) attack against your project API.', true, ['clients']) // TODO add our own built-in confirm page ->param('name', '', new Text(128), 'Name of the new team member. Max length: 128 chars.', true) ->inject('response') diff --git a/app/controllers/shared/api.php b/app/controllers/shared/api.php index 896df9bb37..819d038226 100644 --- a/app/controllers/shared/api.php +++ b/app/controllers/shared/api.php @@ -166,17 +166,14 @@ App::init() } /** Default role */ + $roles = Config::getParam('roles', []); $role = ($user->isEmpty()) ? Role::guests()->toString() : Role::users()->toString(); /** Allowed Scopes for the role */ - $roles = Config::getParam('roles', []); $scopes = $roles[$role]['scopes']; - var_dump("Mode : " . $mode); - var_dump(Auth::getRoles($user)); - /** * API Key Authentication */ @@ -235,7 +232,7 @@ App::init() /** * Admin User Authentication */ - elseif (APP_MODE_ADMIN === $mode && $project->getId() !== 'console') { + elseif (APP_MODE_ADMIN === $mode) { if ($user->isEmpty()) { throw new Exception(Exception::USER_UNAUTHORIZED); } @@ -248,7 +245,7 @@ App::init() $adminRoles = []; $memberships = $user->getAttribute('memberships', []); foreach ($memberships as $membership) { - if ($membership->getAttribute('teamId') === $teamId) { + if ($membership->getAttribute('confirm', false) === true && $membership->getAttribute('teamId') === $teamId) { $adminRoles = $membership->getAttribute('roles', []); break; } @@ -258,26 +255,34 @@ App::init() throw new Exception(Exception::USER_UNAUTHORIZED); } - /** Get scopes available to that role for this project */ - foreach ($adminRoles as $role) { - $scopes = \array_merge($scopes, $roles[$role]['scopes']); - } + $adminRoles = array_filter($adminRoles, function ($role) use ($project) { + return str_contains($role, $project->getId()) || str_contains($role, 'projects/all') || str_contains($role, 'owner'); + }); - // Authorization::setRole(Auth::USER_ROLE_ADMIN); - // foreach ($membership['roles'] as $memberRole) { - // Authorization::setRole($memberRole); + // if (empty($adminRoles)) { + // throw new Exception(Exception::USER_UNAUTHORIZED); // } - Authorization::setRole(Auth::USER_ROLE_DEVELOPER); - Authorization::setDefaultStatus(false); + var_dump("####### ADMIN ROLES #######"); + var_dump($adminRoles); + + foreach ($adminRoles as $adminRole) { + if (str_contains($adminRole, 'owner')) { + $role = Auth::USER_ROLE_OWNER; + $scopes = \array_merge($scopes, $roles[$role]['scopes']); + break; + } + $parts = explode('/', $adminRole); + $role = $parts[2] ?? Auth::USER_ROLE_GUESTS; + $scopes = \array_merge($scopes, $roles[$role]['scopes']); + } + + Authorization::setDefaultStatus(false); // Cancel security segmentation for admin users. } $scopes = \array_unique($scopes); - var_dump("##### Admin Scopes ######"); - var_dump($scopes); Authorization::setRole($role); - foreach (Auth::getRoles($user) as $authRole) { Authorization::setRole($authRole); } diff --git a/app/init.php b/app/init.php index 9b93e9541c..46a16d78c6 100644 --- a/app/init.php +++ b/app/init.php @@ -1169,9 +1169,6 @@ App::setResource('user', function ($mode, $project, $console, $request, $respons Auth::$unique = $session['id'] ?? ''; Auth::$secret = $session['secret'] ?? ''; - var_dump("####### Session ID ##########"); - var_dump(Auth::$unique); - if (APP_MODE_ADMIN !== $mode) { if ($project->isEmpty()) { $user = new Document([]); @@ -1186,9 +1183,6 @@ App::setResource('user', function ($mode, $project, $console, $request, $respons $user = $dbForConsole->getDocument('users', Auth::$unique); } - var_dump("####### User ##########"); - var_dump($user); - if ( $user->isEmpty() // Check a document has been found in the DB || !Auth::sessionVerify($user->getAttribute('sessions', []), Auth::$secret) diff --git a/src/Appwrite/Auth/Validator/Role.php b/src/Appwrite/Auth/Validator/Role.php new file mode 100644 index 0000000000..8d74077b8a --- /dev/null +++ b/src/Appwrite/Auth/Validator/Role.php @@ -0,0 +1,71 @@ +message; + } + + /** + * Expression constructor + */ + public function __construct() + { + } + + /** + * Is valid. + * + * Returns true if valid or false if not. + * + * @param $value + * + * @return bool + */ + public function isValid($value): bool + { + return true; + } + + /** + * Is array + * + * Function will return true if object is array. + * + * @return bool + */ + public function isArray(): bool + { + return false; + } + + /** + * Get Type + * + * Returns validator type. + * + * @return string + */ + public function getType(): string + { + return self::TYPE_STRING; + } +} From 1ca4904132799b312e8419e7dd10b4ac874aa687 Mon Sep 17 00:00:00 2001 From: Damodar Lohani Date: Wed, 21 Aug 2024 05:14:17 +0000 Subject: [PATCH 05/40] reset auth and roles --- app/config/roles.php | 145 +++++++++++++++---------------------- src/Appwrite/Auth/Auth.php | 10 +-- 2 files changed, 63 insertions(+), 92 deletions(-) diff --git a/app/config/roles.php b/app/config/roles.php index d347e8f990..cc1002d118 100644 --- a/app/config/roles.php +++ b/app/config/roles.php @@ -2,28 +2,6 @@ use Appwrite\Auth\Auth; -$apps = [ - 'global', - 'health.read', - 'graphql', -]; - -$guests = [ - 'global', - 'public', - 'home', - 'console', - 'graphql', - 'sessions.write', - 'documents.read', - 'documents.write', - 'files.read', - 'files.write', - 'locale.read', - 'avatars.read', - 'execution.write', -]; - $member = [ 'global', 'public', @@ -48,98 +26,95 @@ $member = [ 'targets.write', 'subscribers.write', 'subscribers.read', - 'assistant.read' + 'assistant.read', ]; -$analyst = array_merge($member, [ - 'users.read', - 'databases.read', - 'collections.read', - 'buckets.read', - 'execution.read', - 'targets.read', - 'subscribers.read', - 'assistant.read', - 'functions.read', - 'platforms.read', - 'keys.read', - 'webhooks.read', - 'rules.read', - 'migrations.read', - 'vcs.read', - 'providers.read', - 'messages.read', - 'topics.read' -]); - -$editor = array_merge($analyst, [ +$admins = [ + 'global', + 'graphql', + 'sessions.write', + 'teams.read', + 'teams.write', + 'documents.read', 'documents.write', + 'files.read', 'files.write', - 'execution.write', - 'targets.write', - 'subscribers.write', -]); - -$developer = array_merge($editor, [ - 'projects.write', + 'buckets.read', 'buckets.write', + 'users.read', 'users.write', + 'databases.read', 'databases.write', + 'collections.read', 'collections.write', + 'platforms.read', 'platforms.write', + 'keys.read', 'keys.write', + 'webhooks.read', 'webhooks.write', + 'locale.read', + 'avatars.read', + 'health.read', + 'functions.read', 'functions.write', + 'execution.read', + 'execution.write', + 'rules.read', 'rules.write', + 'migrations.read', 'migrations.write', + 'vcs.read', 'vcs.write', + 'targets.read', 'targets.write', 'providers.write', + 'providers.read', 'messages.write', + 'messages.read', 'topics.write', -]); - -$owner = array_merge($developer, [ - 'billing.read', - 'billing.write' -]); - -$billing = array_merge($member, [ - 'billing.read', - 'billing.write', -]); + 'topics.read', + 'subscribers.write', + 'subscribers.read' +]; return [ - Auth::USER_ROLE_APPS => [ - 'label' => 'Applications', - 'scopes' => $apps, - ], Auth::USER_ROLE_GUESTS => [ 'label' => 'Guests', - 'scopes' => $guests, + 'scopes' => [ + 'global', + 'public', + 'home', + 'console', + 'graphql', + 'sessions.write', + 'documents.read', + 'documents.write', + 'files.read', + 'files.write', + 'locale.read', + 'avatars.read', + 'execution.write', + ], ], Auth::USER_ROLE_USERS => [ 'label' => 'Users', - 'scopes' => $member, + 'scopes' => \array_merge($member), + ], + Auth::USER_ROLE_ADMIN => [ + 'label' => 'Admin', + 'scopes' => \array_merge($admins), ], Auth::USER_ROLE_DEVELOPER => [ 'label' => 'Developer', - 'scopes' => $developer, - ], - Auth::USER_ROLE_EDITOR => [ - 'label' => 'Editor', - 'scopes' => $editor, - ], - Auth::USER_ROLE_ANALYST => [ - 'label' => 'Analyst', - 'scopes' => $analyst, - ], - Auth::USER_ROLE_BILLING => [ - 'label' => 'Billing', - 'scopes' => $billing, + 'scopes' => \array_merge($admins), ], Auth::USER_ROLE_OWNER => [ 'label' => 'Owner', - 'scopes' => $owner, - ] -]; + 'scopes' => \array_merge($member, $admins), + ], + Auth::USER_ROLE_APPS => [ + 'label' => 'Applications', + 'scopes' => ['global', 'health.read', 'graphql'], + ], +]; \ No newline at end of file diff --git a/src/Appwrite/Auth/Auth.php b/src/Appwrite/Auth/Auth.php index 01da227b53..6a3960d1b2 100644 --- a/src/Appwrite/Auth/Auth.php +++ b/src/Appwrite/Auth/Auth.php @@ -37,10 +37,8 @@ class Auth public const USER_ROLE_ANY = 'any'; public const USER_ROLE_GUESTS = 'guests'; public const USER_ROLE_USERS = 'users'; + public const USER_ROLE_ADMIN = 'admin'; public const USER_ROLE_DEVELOPER = 'developer'; - public const USER_ROLE_EDITOR = 'editor'; - public const USER_ROLE_ANALYST = 'analyst'; - public const USER_ROLE_BILLING = 'billing'; public const USER_ROLE_OWNER = 'owner'; public const USER_ROLE_APPS = 'apps'; public const USER_ROLE_SYSTEM = 'system'; @@ -413,9 +411,7 @@ class Auth if ( in_array(self::USER_ROLE_OWNER, $roles) || in_array(self::USER_ROLE_DEVELOPER, $roles) || - in_array(self::USER_ROLE_EDITOR, $roles) || - in_array(self::USER_ROLE_ANALYST, $roles) || - in_array(self::USER_ROLE_BILLING, $roles) + in_array(self::USER_ROLE_ADMIN, $roles) ) { return true; } @@ -504,4 +500,4 @@ class Auth return is_null($user->getAttribute('email')) && is_null($user->getAttribute('phone')); } -} +} \ No newline at end of file From cd70d742338aa4c729730e9f6e8109cf79f25f41 Mon Sep 17 00:00:00 2001 From: Damodar Lohani Date: Wed, 21 Aug 2024 05:45:19 +0000 Subject: [PATCH 06/40] remove per project roles --- app/controllers/shared/api.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/app/controllers/shared/api.php b/app/controllers/shared/api.php index 819d038226..6fb1c1d386 100644 --- a/app/controllers/shared/api.php +++ b/app/controllers/shared/api.php @@ -255,9 +255,9 @@ App::init() throw new Exception(Exception::USER_UNAUTHORIZED); } - $adminRoles = array_filter($adminRoles, function ($role) use ($project) { - return str_contains($role, $project->getId()) || str_contains($role, 'projects/all') || str_contains($role, 'owner'); - }); + // $adminRoles = array_filter($adminRoles, function ($role) use ($project) { + // return str_contains($role, $project->getId()) || str_contains($role, 'projects/all') || str_contains($role, 'owner'); + // }); // if (empty($adminRoles)) { // throw new Exception(Exception::USER_UNAUTHORIZED); From 2491f5c70c8710916a11ecbda14bec99504393ea Mon Sep 17 00:00:00 2001 From: Damodar Lohani Date: Wed, 21 Aug 2024 05:51:37 +0000 Subject: [PATCH 07/40] fix scope merging --- app/controllers/shared/api.php | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/app/controllers/shared/api.php b/app/controllers/shared/api.php index 6fb1c1d386..370915656d 100644 --- a/app/controllers/shared/api.php +++ b/app/controllers/shared/api.php @@ -266,14 +266,7 @@ App::init() var_dump("####### ADMIN ROLES #######"); var_dump($adminRoles); - foreach ($adminRoles as $adminRole) { - if (str_contains($adminRole, 'owner')) { - $role = Auth::USER_ROLE_OWNER; - $scopes = \array_merge($scopes, $roles[$role]['scopes']); - break; - } - $parts = explode('/', $adminRole); - $role = $parts[2] ?? Auth::USER_ROLE_GUESTS; + foreach ($adminRoles as $role) { $scopes = \array_merge($scopes, $roles[$role]['scopes']); } From 7aacaad94d51074105ee829514539474662b50bd Mon Sep 17 00:00:00 2001 From: Damodar Lohani Date: Tue, 3 Sep 2024 02:07:41 +0000 Subject: [PATCH 08/40] remove dump --- app/console | 1 + app/controllers/shared/api.php | 11 ----------- 2 files changed, 1 insertion(+), 11 deletions(-) create mode 160000 app/console diff --git a/app/console b/app/console new file mode 160000 index 0000000000..112fccf5a0 --- /dev/null +++ b/app/console @@ -0,0 +1 @@ +Subproject commit 112fccf5a044c9795b31b264f5974224a3545a17 diff --git a/app/controllers/shared/api.php b/app/controllers/shared/api.php index ab9c436499..dc764bf906 100644 --- a/app/controllers/shared/api.php +++ b/app/controllers/shared/api.php @@ -299,17 +299,6 @@ App::init() throw new Exception(Exception::USER_UNAUTHORIZED); } - // $adminRoles = array_filter($adminRoles, function ($role) use ($project) { - // return str_contains($role, $project->getId()) || str_contains($role, 'projects/all') || str_contains($role, 'owner'); - // }); - - // if (empty($adminRoles)) { - // throw new Exception(Exception::USER_UNAUTHORIZED); - // } - - var_dump("####### ADMIN ROLES #######"); - var_dump($adminRoles); - foreach ($adminRoles as $role) { $scopes = \array_merge($scopes, $roles[$role]['scopes']); } From 413f3c20ab4d5c9a4abac419820109b5ba077c1e Mon Sep 17 00:00:00 2001 From: Damodar Lohani Date: Wed, 4 Sep 2024 01:51:32 +0000 Subject: [PATCH 09/40] use proper scope for platforms and keys endpoint --- app/controllers/api/projects.php | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/app/controllers/api/projects.php b/app/controllers/api/projects.php index 3a8c232195..aafd480398 100644 --- a/app/controllers/api/projects.php +++ b/app/controllers/api/projects.php @@ -1199,7 +1199,7 @@ App::delete('/v1/projects/:projectId/webhooks/:webhookId') App::post('/v1/projects/:projectId/keys') ->desc('Create key') ->groups(['api', 'projects']) - ->label('scope', 'projects.write') + ->label('scope', 'keys.write') ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN]) ->label('sdk.namespace', 'projects') ->label('sdk.method', 'createKey') @@ -1249,7 +1249,7 @@ App::post('/v1/projects/:projectId/keys') App::get('/v1/projects/:projectId/keys') ->desc('List keys') ->groups(['api', 'projects']) - ->label('scope', 'projects.read') + ->label('scope', 'keys.read') ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN]) ->label('sdk.namespace', 'projects') ->label('sdk.method', 'listKeys') @@ -1281,7 +1281,7 @@ App::get('/v1/projects/:projectId/keys') App::get('/v1/projects/:projectId/keys/:keyId') ->desc('Get key') ->groups(['api', 'projects']) - ->label('scope', 'projects.read') + ->label('scope', 'keys.read') ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN]) ->label('sdk.namespace', 'projects') ->label('sdk.method', 'getKey') @@ -1315,7 +1315,7 @@ App::get('/v1/projects/:projectId/keys/:keyId') App::put('/v1/projects/:projectId/keys/:keyId') ->desc('Update key') ->groups(['api', 'projects']) - ->label('scope', 'projects.write') + ->label('scope', 'keys.write') ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN]) ->label('sdk.namespace', 'projects') ->label('sdk.method', 'updateKey') @@ -1361,7 +1361,7 @@ App::put('/v1/projects/:projectId/keys/:keyId') App::delete('/v1/projects/:projectId/keys/:keyId') ->desc('Delete key') ->groups(['api', 'projects']) - ->label('scope', 'projects.write') + ->label('scope', 'keys.write') ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN]) ->label('sdk.namespace', 'projects') ->label('sdk.method', 'deleteKey') @@ -1436,7 +1436,7 @@ App::post('/v1/projects/:projectId/platforms') ->desc('Create platform') ->groups(['api', 'projects']) ->label('audits.event', 'platforms.create') - ->label('scope', 'projects.write') + ->label('scope', 'platforms.write') ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN]) ->label('sdk.namespace', 'projects') ->label('sdk.method', 'createPlatform') @@ -1486,7 +1486,7 @@ App::post('/v1/projects/:projectId/platforms') App::get('/v1/projects/:projectId/platforms') ->desc('List platforms') ->groups(['api', 'projects']) - ->label('scope', 'projects.read') + ->label('scope', 'platforms.read') ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN]) ->label('sdk.namespace', 'projects') ->label('sdk.method', 'listPlatforms') @@ -1518,7 +1518,7 @@ App::get('/v1/projects/:projectId/platforms') App::get('/v1/projects/:projectId/platforms/:platformId') ->desc('Get platform') ->groups(['api', 'projects']) - ->label('scope', 'projects.read') + ->label('scope', 'platforms.read') ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN]) ->label('sdk.namespace', 'projects') ->label('sdk.method', 'getPlatform') @@ -1552,7 +1552,7 @@ App::get('/v1/projects/:projectId/platforms/:platformId') App::put('/v1/projects/:projectId/platforms/:platformId') ->desc('Update platform') ->groups(['api', 'projects']) - ->label('scope', 'projects.write') + ->label('scope', 'platforms.write') ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN]) ->label('sdk.namespace', 'projects') ->label('sdk.method', 'updatePlatform') @@ -1600,7 +1600,7 @@ App::delete('/v1/projects/:projectId/platforms/:platformId') ->desc('Delete platform') ->groups(['api', 'projects']) ->label('audits.event', 'platforms.delete') - ->label('scope', 'projects.write') + ->label('scope', 'platforms.write') ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN]) ->label('sdk.namespace', 'projects') ->label('sdk.method', 'deletePlatform') From bc5ac28b846e3038b8964be365cb6b06edb73a6b Mon Sep 17 00:00:00 2001 From: Damodar Lohani Date: Wed, 4 Sep 2024 02:01:56 +0000 Subject: [PATCH 10/40] update validator and formatting --- app/config/roles.php | 2 +- app/controllers/api/teams.php | 14 ++++++++++++-- app/controllers/shared/api.php | 2 +- src/Appwrite/Auth/Auth.php | 2 +- src/Appwrite/Auth/Validator/Role.php | 1 - 5 files changed, 15 insertions(+), 6 deletions(-) diff --git a/app/config/roles.php b/app/config/roles.php index cc1002d118..65b9643b89 100644 --- a/app/config/roles.php +++ b/app/config/roles.php @@ -117,4 +117,4 @@ return [ 'label' => 'Applications', 'scopes' => ['global', 'health.read', 'graphql'], ], -]; \ No newline at end of file +]; diff --git a/app/controllers/api/teams.php b/app/controllers/api/teams.php index be50e283a3..2265492483 100644 --- a/app/controllers/api/teams.php +++ b/app/controllers/api/teams.php @@ -3,7 +3,6 @@ use Appwrite\Auth\Auth; use Appwrite\Auth\MFA\Type\TOTP; use Appwrite\Auth\Validator\Phone; -use Appwrite\Auth\Validator\Role as ValidatorRole; use Appwrite\Detector\Detector; use Appwrite\Event\Delete; use Appwrite\Event\Event; @@ -44,6 +43,7 @@ use Utopia\Validator\ArrayList; use Utopia\Validator\Assoc; use Utopia\Validator\Host; use Utopia\Validator\Text; +use Utopia\Validator\WhiteList; App::post('/v1/teams') ->desc('Create team') @@ -395,7 +395,17 @@ App::post('/v1/teams/:teamId/memberships') ->param('email', '', new Email(), 'Email of the new team member.', true) ->param('userId', '', new UID(), 'ID of the user to be added to a team.', true) ->param('phone', '', new Phone(), 'Phone number. Format this number with a leading \'+\' and a country code, e.g., +16175551212.', true) - ->param('roles', [], new ArrayList(new ValidatorRole(), APP_LIMIT_ARRAY_PARAMS_SIZE), 'Array of strings. Use this param to set the user roles in the team. A role can be any string. Learn more about [roles and permissions](https://appwrite.io/docs/permissions). Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' roles are allowed, each 32 characters long.') + ->param('roles', [], function (Document $project) { + if($project->getId() === 'console') { + ; + $roles = array_keys(Config::getParam('roles', [])); + array_filter($roles, function ($role) { + return !in_array($role, [Auth::USER_ROLE_APPS, Auth::USER_ROLE_GUESTS, Auth::USER_ROLE_USERS]); + }); + return new ArrayList(new WhiteList($roles), APP_LIMIT_ARRAY_PARAMS_SIZE); + } + return new ArrayList(new Key(), APP_LIMIT_ARRAY_PARAMS_SIZE); + }, 'Array of strings. Use this param to set the user roles in the team. A role can be any string. Learn more about [roles and permissions](https://appwrite.io/docs/permissions). Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' roles are allowed, each 32 characters long.', false, ['project']) ->param('url', '', fn ($clients) => new Host($clients), 'URL to redirect the user back to your app from the invitation email. This parameter is not required when an API key is supplied. Only URLs from hostnames in your project platform list are allowed. This requirement helps to prevent an [open redirect](https://cheatsheetseries.owasp.org/cheatsheets/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html) attack against your project API.', true, ['clients']) // TODO add our own built-in confirm page ->param('name', '', new Text(128), 'Name of the new team member. Max length: 128 chars.', true) ->inject('response') diff --git a/app/controllers/shared/api.php b/app/controllers/shared/api.php index dc764bf906..98532aef5e 100644 --- a/app/controllers/shared/api.php +++ b/app/controllers/shared/api.php @@ -302,7 +302,7 @@ App::init() foreach ($adminRoles as $role) { $scopes = \array_merge($scopes, $roles[$role]['scopes']); } - + Authorization::setDefaultStatus(false); // Cancel security segmentation for admin users. } diff --git a/src/Appwrite/Auth/Auth.php b/src/Appwrite/Auth/Auth.php index 6a3960d1b2..1e8109622e 100644 --- a/src/Appwrite/Auth/Auth.php +++ b/src/Appwrite/Auth/Auth.php @@ -500,4 +500,4 @@ class Auth return is_null($user->getAttribute('email')) && is_null($user->getAttribute('phone')); } -} \ No newline at end of file +} diff --git a/src/Appwrite/Auth/Validator/Role.php b/src/Appwrite/Auth/Validator/Role.php index 8d74077b8a..aea4c4e949 100644 --- a/src/Appwrite/Auth/Validator/Role.php +++ b/src/Appwrite/Auth/Validator/Role.php @@ -6,7 +6,6 @@ use Utopia\Validator; class Role extends Validator { - /** * @var string */ From 1f83dab9e19b271ff5acb847d652556c2ba86845 Mon Sep 17 00:00:00 2001 From: Damodar Lohani Date: Wed, 4 Sep 2024 02:16:18 +0000 Subject: [PATCH 11/40] fix roles for `/projects/:projectId` endpoints --- app/controllers/shared/api.php | 12 +++++------- app/init.php | 29 +++++++++++++++++++++++++++++ 2 files changed, 34 insertions(+), 7 deletions(-) diff --git a/app/controllers/shared/api.php b/app/controllers/shared/api.php index 98532aef5e..4df38f2d45 100644 --- a/app/controllers/shared/api.php +++ b/app/controllers/shared/api.php @@ -160,8 +160,10 @@ App::init() ->inject('session') ->inject('servers') ->inject('mode') - ->action(function (App $utopia, Request $request, Database $dbForConsole, Document $project, Document $user, ?Document $session, array $servers, string $mode) { + ->inject('team') + ->action(function (App $utopia, Request $request, Database $dbForConsole, Document $project, Document $user, ?Document $session, array $servers, string $mode, Document $team) { $route = $utopia->getRoute(); + $path = $route->getPath(); if ($project->isEmpty()) { throw new Exception(Exception::PROJECT_NOT_FOUND); @@ -276,16 +278,12 @@ App::init() /** * Admin User Authentication */ - elseif (APP_MODE_ADMIN === $mode) { + elseif (!$team->isEmpty()) { if ($user->isEmpty()) { throw new Exception(Exception::USER_UNAUTHORIZED); } - $teamId = $project->getAttribute('teamId', null); - if (empty($teamId)) { - throw new Exception(Exception::USER_UNAUTHORIZED, 'APP_MODE : admin is not allowed for the console project'); - } - + $teamId = $team->getId(); $adminRoles = []; $memberships = $user->getAttribute('memberships', []); foreach ($memberships as $membership) { diff --git a/app/init.php b/app/init.php index 32e270c7c9..fdc4bcd440 100644 --- a/app/init.php +++ b/app/init.php @@ -41,6 +41,7 @@ use Appwrite\Network\Validator\Email; use Appwrite\Network\Validator\Origin; use Appwrite\OpenSSL\OpenSSL; use Appwrite\URL\URL as AppwriteURL; +use Appwrite\Utopia\Request; use MaxMind\Db\Reader; use PHPMailer\PHPMailer\PHPMailer; use Swoole\Database\PDOProxy; @@ -1753,3 +1754,31 @@ App::setResource('requestTimestamp', function ($request) { App::setResource('plan', function (array $plan = []) { return []; }); + + +App::setResource('team', function (Document $project, Database $dbForConsole, App $utopia, Request $request) { + $teamInternalId = ''; + if ($project->getId() !== 'console') { + $teamInternalId = $project->getAttribute('teamInternalId'); + } else { + $route = $utopia->match($request); + $path = $route->getPath(); + if (str_starts_with($path, '/v1/projects/:projectId')) { + $uri = $request->getURI(); + $pid = explode('/', $uri)[3]; + $p = $dbForConsole->getDocument('projects', $pid); + $teamInternalId = $p->getAttribute('teamInternalId', ''); + } + } + + $team = Authorization::skip(function () use ($dbForConsole, $teamInternalId) { + return $dbForConsole->findOne('teams', [ + Query::equal('$internalId', [$teamInternalId]), + ]); + }); + + if (!$team) { + $team = new Document([]); + } + return $team; +}, ['project', 'dbForConsole', 'utopia', 'request']); From 1752c6be44766032b317b65ade641e89ae4de5d2 Mon Sep 17 00:00:00 2001 From: Damodar Lohani Date: Wed, 4 Sep 2024 02:40:53 +0000 Subject: [PATCH 12/40] fix team resource --- app/controllers/shared/api.php | 1 - app/init.php | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/app/controllers/shared/api.php b/app/controllers/shared/api.php index 4df38f2d45..bb467d4c5b 100644 --- a/app/controllers/shared/api.php +++ b/app/controllers/shared/api.php @@ -163,7 +163,6 @@ App::init() ->inject('team') ->action(function (App $utopia, Request $request, Database $dbForConsole, Document $project, Document $user, ?Document $session, array $servers, string $mode, Document $team) { $route = $utopia->getRoute(); - $path = $route->getPath(); if ($project->isEmpty()) { throw new Exception(Exception::PROJECT_NOT_FOUND); diff --git a/app/init.php b/app/init.php index fdc4bcd440..d1b703dcec 100644 --- a/app/init.php +++ b/app/init.php @@ -1766,7 +1766,7 @@ App::setResource('team', function (Document $project, Database $dbForConsole, Ap if (str_starts_with($path, '/v1/projects/:projectId')) { $uri = $request->getURI(); $pid = explode('/', $uri)[3]; - $p = $dbForConsole->getDocument('projects', $pid); + $p = Authorization::skip(fn () => $dbForConsole->getDocument('projects', $pid)); $teamInternalId = $p->getAttribute('teamInternalId', ''); } } From 107fc1d0696efd6a3444f1c52cd3edf7e6d64c4a Mon Sep 17 00:00:00 2001 From: Damodar Lohani Date: Wed, 4 Sep 2024 02:45:05 +0000 Subject: [PATCH 13/40] fix check --- app/controllers/shared/api.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/controllers/shared/api.php b/app/controllers/shared/api.php index bb467d4c5b..30af5e82b4 100644 --- a/app/controllers/shared/api.php +++ b/app/controllers/shared/api.php @@ -277,7 +277,7 @@ App::init() /** * Admin User Authentication */ - elseif (!$team->isEmpty()) { + elseif (($project->getId() === 'console' && !$team->isEmpty()) || $mode === APP_MODE_ADMIN) { if ($user->isEmpty()) { throw new Exception(Exception::USER_UNAUTHORIZED); } From 269efbe2f00e39bef069cea3b95ae7e46cac185e Mon Sep 17 00:00:00 2001 From: Damodar Lohani Date: Wed, 4 Sep 2024 12:25:51 +0545 Subject: [PATCH 14/40] Update api.php --- app/controllers/shared/api.php | 4 ---- 1 file changed, 4 deletions(-) diff --git a/app/controllers/shared/api.php b/app/controllers/shared/api.php index 30af5e82b4..992e0646a1 100644 --- a/app/controllers/shared/api.php +++ b/app/controllers/shared/api.php @@ -278,10 +278,6 @@ App::init() * Admin User Authentication */ elseif (($project->getId() === 'console' && !$team->isEmpty()) || $mode === APP_MODE_ADMIN) { - if ($user->isEmpty()) { - throw new Exception(Exception::USER_UNAUTHORIZED); - } - $teamId = $team->getId(); $adminRoles = []; $memberships = $user->getAttribute('memberships', []); From a89cf443aa8a13b8d801ff5f8950b00d9b82aa30 Mon Sep 17 00:00:00 2001 From: Damodar Lohani Date: Wed, 4 Sep 2024 12:28:52 +0545 Subject: [PATCH 15/40] Update api.php --- app/controllers/shared/api.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/controllers/shared/api.php b/app/controllers/shared/api.php index 992e0646a1..b52690a5ba 100644 --- a/app/controllers/shared/api.php +++ b/app/controllers/shared/api.php @@ -277,7 +277,7 @@ App::init() /** * Admin User Authentication */ - elseif (($project->getId() === 'console' && !$team->isEmpty()) || $mode === APP_MODE_ADMIN) { + elseif (($project->getId() === 'console' && !$team->isEmpty() && !$user->isEmpty) || (!$user->empty() && $mode === APP_MODE_ADMIN)) { $teamId = $team->getId(); $adminRoles = []; $memberships = $user->getAttribute('memberships', []); From 555f3f9406b7e592635bf985d2058e4a1ce47c3d Mon Sep 17 00:00:00 2001 From: Damodar Lohani Date: Wed, 4 Sep 2024 12:29:56 +0545 Subject: [PATCH 16/40] Update api.php --- app/controllers/shared/api.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/controllers/shared/api.php b/app/controllers/shared/api.php index b52690a5ba..b8fa3d49b2 100644 --- a/app/controllers/shared/api.php +++ b/app/controllers/shared/api.php @@ -277,7 +277,7 @@ App::init() /** * Admin User Authentication */ - elseif (($project->getId() === 'console' && !$team->isEmpty() && !$user->isEmpty) || (!$user->empty() && $mode === APP_MODE_ADMIN)) { + elseif (($project->getId() === 'console' && !$team->isEmpty() && !$user->isEmpty()) || (!$user->isEmpty() && $mode === APP_MODE_ADMIN)) { $teamId = $team->getId(); $adminRoles = []; $memberships = $user->getAttribute('memberships', []); From d633c3e278d4d04b59d4dffe61535f8ce2143109 Mon Sep 17 00:00:00 2001 From: Damodar Lohani Date: Wed, 4 Sep 2024 07:41:44 +0000 Subject: [PATCH 17/40] gitmodule --- app/console | 1 - 1 file changed, 1 deletion(-) delete mode 160000 app/console diff --git a/app/console b/app/console deleted file mode 160000 index 112fccf5a0..0000000000 --- a/app/console +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 112fccf5a044c9795b31b264f5974224a3545a17 From cb537534e35da5385d498b0d0fcdac828a63dd31 Mon Sep 17 00:00:00 2001 From: Damodar Lohani Date: Wed, 4 Sep 2024 07:42:35 +0000 Subject: [PATCH 18/40] remove dump --- app/controllers/api/databases.php | 2 -- 1 file changed, 2 deletions(-) diff --git a/app/controllers/api/databases.php b/app/controllers/api/databases.php index 5081e01f64..54fc1cb08f 100644 --- a/app/controllers/api/databases.php +++ b/app/controllers/api/databases.php @@ -416,8 +416,6 @@ App::post('/v1/databases') $databaseId = $databaseId == 'unique()' ? ID::unique() : $databaseId; - var_dump($databaseId); - try { $dbForProject->createDocument('databases', new Document([ '$id' => $databaseId, From c439fb08fdf2f8d48107e0a93fdf6031052e4065 Mon Sep 17 00:00:00 2001 From: Damodar Lohani Date: Wed, 4 Sep 2024 07:43:53 +0000 Subject: [PATCH 19/40] reset change --- docker-compose.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docker-compose.yml b/docker-compose.yml index ad493c07cb..3d3ac5c167 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -49,7 +49,7 @@ services: build: context: . args: - DEBUG: true + DEBUG: false TESTING: true VERSION: dev ports: From bad70b8257815226da405745327f084b922ce64b Mon Sep 17 00:00:00 2001 From: Damodar Lohani Date: Wed, 4 Sep 2024 07:44:39 +0000 Subject: [PATCH 20/40] remove comment --- tests/e2e/Services/Teams/TeamsBase.php | 3 --- 1 file changed, 3 deletions(-) diff --git a/tests/e2e/Services/Teams/TeamsBase.php b/tests/e2e/Services/Teams/TeamsBase.php index a2884f7b08..2328e4cdbf 100644 --- a/tests/e2e/Services/Teams/TeamsBase.php +++ b/tests/e2e/Services/Teams/TeamsBase.php @@ -10,9 +10,6 @@ use Utopia\Database\Validator\Datetime as DatetimeValidator; trait TeamsBase { - /** - * @group testing - */ public function testCreateTeam(): array { /** From fdc69e77f45dd409e2e7d56246166ba5eb392692 Mon Sep 17 00:00:00 2001 From: Damodar Lohani Date: Wed, 4 Sep 2024 07:45:51 +0000 Subject: [PATCH 21/40] remove validator --- src/Appwrite/Auth/Validator/Role.php | 70 ---------------------------- 1 file changed, 70 deletions(-) delete mode 100644 src/Appwrite/Auth/Validator/Role.php diff --git a/src/Appwrite/Auth/Validator/Role.php b/src/Appwrite/Auth/Validator/Role.php deleted file mode 100644 index aea4c4e949..0000000000 --- a/src/Appwrite/Auth/Validator/Role.php +++ /dev/null @@ -1,70 +0,0 @@ -message; - } - - /** - * Expression constructor - */ - public function __construct() - { - } - - /** - * Is valid. - * - * Returns true if valid or false if not. - * - * @param $value - * - * @return bool - */ - public function isValid($value): bool - { - return true; - } - - /** - * Is array - * - * Function will return true if object is array. - * - * @return bool - */ - public function isArray(): bool - { - return false; - } - - /** - * Get Type - * - * Returns validator type. - * - * @return string - */ - public function getType(): string - { - return self::TYPE_STRING; - } -} From 7c1c025f9ed575cb726841d3e5d28e257ad17441 Mon Sep 17 00:00:00 2001 From: Damodar Lohani Date: Wed, 4 Sep 2024 23:35:31 +0000 Subject: [PATCH 22/40] remove console roles test --- app/controllers/shared/api.php | 6 +- .../Services/Teams/TeamsConsoleClientTest.php | 108 +----------------- 2 files changed, 6 insertions(+), 108 deletions(-) diff --git a/app/controllers/shared/api.php b/app/controllers/shared/api.php index b8fa3d49b2..26f12ffcc3 100644 --- a/app/controllers/shared/api.php +++ b/app/controllers/shared/api.php @@ -277,8 +277,10 @@ App::init() /** * Admin User Authentication */ - elseif (($project->getId() === 'console' && !$team->isEmpty() && !$user->isEmpty()) || (!$user->isEmpty() && $mode === APP_MODE_ADMIN)) { + elseif (($project->getId() === 'console' && !$team->isEmpty() && !$user->isEmpty()) || ($project->getId() !== 'console' && !$user->isEmpty() && $mode === APP_MODE_ADMIN)) { $teamId = $team->getId(); + var_dump($team->getArrayCopy()); + var_dump($project->getId()); $adminRoles = []; $memberships = $user->getAttribute('memberships', []); foreach ($memberships as $membership) { @@ -287,6 +289,8 @@ App::init() break; } } + var_dump($memberships); + var_dump($adminRoles); if (empty($adminRoles)) { throw new Exception(Exception::USER_UNAUTHORIZED); diff --git a/tests/e2e/Services/Teams/TeamsConsoleClientTest.php b/tests/e2e/Services/Teams/TeamsConsoleClientTest.php index 9305c99725..29c7447378 100644 --- a/tests/e2e/Services/Teams/TeamsConsoleClientTest.php +++ b/tests/e2e/Services/Teams/TeamsConsoleClientTest.php @@ -47,7 +47,7 @@ class TeamsConsoleClientTest extends Scope ], $this->getHeaders()), [ 'email' => $email, 'name' => $name, - 'roles' => ['admin', 'editor'], + 'roles' => ['admin', 'developer'], 'url' => 'http://localhost:5000/join-us#title' ]); @@ -77,110 +77,4 @@ class TeamsConsoleClientTest extends Scope return $data; } - - - /** - * @depends testCreateTeam - * @group testing - */ - public function testTeamMemberships($data) - { - $teamUid = $data['teamUid'] ?? ''; - $teamName = $data['teamName'] ?? ''; - $email = uniqid() . 'friend@localhost.test'; - $name = 'Friend User'; - $password = 'password'; - - /** - * Invite team member with developer role - */ - $response = $this->client->call(Client::METHOD_POST, '/teams/' . $teamUid . '/memberships', array_merge([ - 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], - ], $this->getHeaders()), [ - 'email' => $email, - 'name' => $name, - 'roles' => ['developer'], - 'url' => 'http://localhost:5000/join-us#title' - ]); - - $this->assertEquals(201, $response['headers']['status-code']); - - /** - * Accept the invite - */ - $lastEmail = $this->getLastEmail(); - $this->assertEquals($email, $lastEmail['to'][0]['address']); - $this->assertEquals($name, $lastEmail['to'][0]['name']); - $this->assertEquals('Invitation to ' . $teamName . ' Team at ' . $this->getProject()['name'], $lastEmail['subject']); - $secret = substr($lastEmail['text'], strpos($lastEmail['text'], '&secret=', 0) + 8, 256); - $membershipUid = substr($lastEmail['text'], strpos($lastEmail['text'], '?membershipId=', 0) + 14, 20); - $userUid = substr($lastEmail['text'], strpos($lastEmail['text'], '&userId=', 0) + 8, 20); - - $response = $this->client->call(Client::METHOD_PATCH, '/teams/' . $teamUid . '/memberships/' . $response['body']['$id'] . '/status', array_merge([ - 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], - ]), [ - 'userId' => $userUid, - 'secret' => $secret, - ]); - - $key = 'a_session_' . $this->getProject()['$id']; - $cookie = $key . '=' . $response['cookies'][$key]; - - $this->assertEquals(200, $response['headers']['status-code']); - - /** - * Test teams.read scope - */ - $response = $this->client->call(Client::METHOD_GET, '/teams', array_merge([ - 'content-type' => 'application/json', - 'x-appwrite-mode' => 'admin', - 'x-appwrite-project' => $this->getProject()['$id'], - 'cookie' => $cookie, - ]), []); - $this->assertEquals(200, $response['headers']['status-code']); - - /** - * Test teams.write scope - */ - $response = $this->client->call(Client::METHOD_PUT, '/teams/' . $teamUid, array_merge([ - 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], - 'cookie' => $cookie, - 'x-appwrite-mode' => 'admin' - ]), [ - 'name' => 'Arsenal Updated', - ]); - - $this->assertEquals(401, $response['headers']['status-code']); - - /** - * Test projects.read scope - */ - $response = $this->client->call(Client::METHOD_GET, '/projects', array_merge([ - 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], - 'cookie' => $cookie, - 'x-appwrite-mode' => 'admin' - ]), []); - - $this->assertEquals(200, $response['headers']['status-code']); - - /** - * Test projects.write scope - */ - $response = $this->client->call(Client::METHOD_POST, '/projects', array_merge([ - 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], - 'cookie' => $cookie, - 'x-appwrite-mode' => 'admin' - ]), [ - 'projectId' => 'unique()', - 'name' => 'Project Name', - 'teamId' => $teamUid, - ]); - - $this->assertEquals(401, $response['headers']['status-code']); - } } From e0a30fd25a8597d7b312876c8849d8d30c7c5c1f Mon Sep 17 00:00:00 2001 From: Damodar Lohani Date: Wed, 4 Sep 2024 23:44:26 +0000 Subject: [PATCH 23/40] fix memberships test --- tests/e2e/Services/Teams/TeamsBaseClient.php | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/tests/e2e/Services/Teams/TeamsBaseClient.php b/tests/e2e/Services/Teams/TeamsBaseClient.php index 03dffac6aa..2197e50e67 100644 --- a/tests/e2e/Services/Teams/TeamsBaseClient.php +++ b/tests/e2e/Services/Teams/TeamsBaseClient.php @@ -203,7 +203,7 @@ trait TeamsBaseClient ], $this->getHeaders()), [ 'email' => $email, 'name' => $name, - 'roles' => ['admin', 'editor'], + 'roles' => ['admin', 'developer'], 'url' => 'http://localhost:5000/join-us#title' ]); @@ -255,7 +255,7 @@ trait TeamsBaseClient 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ 'userId' => 'abcdefdg', - 'roles' => ['admin', 'editor'], + 'roles' => ['admin', 'developer'], 'url' => 'http://localhost:5000/join-us#title' ]); @@ -270,7 +270,7 @@ trait TeamsBaseClient 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ 'userId' => $userId, - 'roles' => ['admin', 'editor'], + 'roles' => ['admin', 'developer'], 'url' => 'http://localhost:5000/join-us#title' ]); @@ -301,7 +301,7 @@ trait TeamsBaseClient ], $this->getHeaders()), [ 'email' => $email, 'name' => 'Friend User', - 'roles' => ['admin', 'editor'], + 'roles' => ['admin', 'developer'], 'url' => 'http://localhost:5000/join-us#title' ]); @@ -313,7 +313,7 @@ trait TeamsBaseClient ], $this->getHeaders()), [ 'email' => 'dasdkaskdjaskdjasjkd', 'name' => $name, - 'roles' => ['admin', 'editor'], + 'roles' => ['admin', 'developer'], 'url' => 'http://localhost:5000/join-us#title' ]); @@ -337,7 +337,7 @@ trait TeamsBaseClient ], $this->getHeaders()), [ 'email' => $email, 'name' => $name, - 'roles' => ['admin', 'editor'], + 'roles' => ['admin', 'developer'], 'url' => 'http://example.com/join-us#title' // bad url ]); From b263ed7ce656356050ad8276ae8f36dcbff1f9df Mon Sep 17 00:00:00 2001 From: Damodar Lohani Date: Wed, 4 Sep 2024 23:48:51 +0000 Subject: [PATCH 24/40] fix team res --- app/init.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/init.php b/app/init.php index d1b703dcec..5d6f4dac16 100644 --- a/app/init.php +++ b/app/init.php @@ -1759,7 +1759,7 @@ App::setResource('plan', function (array $plan = []) { App::setResource('team', function (Document $project, Database $dbForConsole, App $utopia, Request $request) { $teamInternalId = ''; if ($project->getId() !== 'console') { - $teamInternalId = $project->getAttribute('teamInternalId'); + $teamInternalId = $project->getAttribute('teamInternalId', ''); } else { $route = $utopia->match($request); $path = $route->getPath(); From 42b85fad541a34865f2a74dde9b0b53ee35b4c1f Mon Sep 17 00:00:00 2001 From: Damodar Lohani Date: Thu, 5 Sep 2024 07:12:59 +0545 Subject: [PATCH 25/40] remove dumps --- app/controllers/shared/api.php | 4 ---- 1 file changed, 4 deletions(-) diff --git a/app/controllers/shared/api.php b/app/controllers/shared/api.php index 26f12ffcc3..0b10452b1e 100644 --- a/app/controllers/shared/api.php +++ b/app/controllers/shared/api.php @@ -279,8 +279,6 @@ App::init() */ elseif (($project->getId() === 'console' && !$team->isEmpty() && !$user->isEmpty()) || ($project->getId() !== 'console' && !$user->isEmpty() && $mode === APP_MODE_ADMIN)) { $teamId = $team->getId(); - var_dump($team->getArrayCopy()); - var_dump($project->getId()); $adminRoles = []; $memberships = $user->getAttribute('memberships', []); foreach ($memberships as $membership) { @@ -289,8 +287,6 @@ App::init() break; } } - var_dump($memberships); - var_dump($adminRoles); if (empty($adminRoles)) { throw new Exception(Exception::USER_UNAUTHORIZED); From 59760bf5290551aeb24222aa8829dce286348f05 Mon Sep 17 00:00:00 2001 From: Damodar Lohani Date: Thu, 5 Sep 2024 08:28:47 +0545 Subject: [PATCH 26/40] Update api.php --- app/controllers/shared/api.php | 1 + 1 file changed, 1 insertion(+) diff --git a/app/controllers/shared/api.php b/app/controllers/shared/api.php index 0b10452b1e..cf7980b694 100644 --- a/app/controllers/shared/api.php +++ b/app/controllers/shared/api.php @@ -292,6 +292,7 @@ App::init() throw new Exception(Exception::USER_UNAUTHORIZED); } + $scopes = []; // reset scope if admin foreach ($adminRoles as $role) { $scopes = \array_merge($scopes, $roles[$role]['scopes']); } From 7dc64c12a6e214156614bc689b2a1a76650f54c9 Mon Sep 17 00:00:00 2001 From: Damodar Lohani Date: Thu, 5 Sep 2024 08:32:50 +0545 Subject: [PATCH 27/40] fix team resource --- app/init.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/app/init.php b/app/init.php index 5d6f4dac16..bac2f33462 100644 --- a/app/init.php +++ b/app/init.php @@ -1768,6 +1768,10 @@ App::setResource('team', function (Document $project, Database $dbForConsole, Ap $pid = explode('/', $uri)[3]; $p = Authorization::skip(fn () => $dbForConsole->getDocument('projects', $pid)); $teamInternalId = $p->getAttribute('teamInternalId', ''); + } elseif ($path === '/v1/projects') { + $teamId = $request->getParam('teamId', ''); + $team = Authorization::skip(fn () => $dbForConsole->getDocument('teams', $teamId)); + return $team; } } From 72d720f83e160f12a8fd27a91c2aa0934fb3d71f Mon Sep 17 00:00:00 2001 From: Damodar Lohani Date: Thu, 5 Sep 2024 03:20:19 +0000 Subject: [PATCH 28/40] remove projects.write from user scope --- app/config/roles.php | 1 - tests/e2e/Services/Projects/ProjectsConsoleClientTest.php | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/app/config/roles.php b/app/config/roles.php index 65b9643b89..3215303217 100644 --- a/app/config/roles.php +++ b/app/config/roles.php @@ -17,7 +17,6 @@ $member = [ 'files.read', 'files.write', 'projects.read', - 'projects.write', 'locale.read', 'avatars.read', 'execution.read', diff --git a/tests/e2e/Services/Projects/ProjectsConsoleClientTest.php b/tests/e2e/Services/Projects/ProjectsConsoleClientTest.php index c41d861f1d..9fb8296e05 100644 --- a/tests/e2e/Services/Projects/ProjectsConsoleClientTest.php +++ b/tests/e2e/Services/Projects/ProjectsConsoleClientTest.php @@ -101,7 +101,7 @@ class ProjectsConsoleClientTest extends Scope 'region' => 'default' ]); - $this->assertEquals(400, $response['headers']['status-code']); + $this->assertEquals(401, $response['headers']['status-code']); return [ 'projectId' => $projectId, From b2359786e6eb7bc8ac687377bfdfac66c6ec734a Mon Sep 17 00:00:00 2001 From: Damodar Lohani Date: Thu, 5 Sep 2024 03:22:10 +0000 Subject: [PATCH 29/40] fix test --- tests/e2e/Services/Projects/ProjectsConsoleClientTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/e2e/Services/Projects/ProjectsConsoleClientTest.php b/tests/e2e/Services/Projects/ProjectsConsoleClientTest.php index 9fb8296e05..05893be3a8 100644 --- a/tests/e2e/Services/Projects/ProjectsConsoleClientTest.php +++ b/tests/e2e/Services/Projects/ProjectsConsoleClientTest.php @@ -546,7 +546,7 @@ class ProjectsConsoleClientTest extends Scope 'name' => '', ]); - $this->assertEquals(400, $response['headers']['status-code']); + $this->assertEquals(401, $response['headers']['status-code']); return ['projectId' => $projectId]; } From d335aee549fabdf1df72e0e1c90fe1a5be134876 Mon Sep 17 00:00:00 2001 From: Damodar Lohani Date: Thu, 5 Sep 2024 03:24:57 +0000 Subject: [PATCH 30/40] fix --- tests/e2e/Services/Teams/TeamsConsoleClientTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/e2e/Services/Teams/TeamsConsoleClientTest.php b/tests/e2e/Services/Teams/TeamsConsoleClientTest.php index 29c7447378..d19f52debd 100644 --- a/tests/e2e/Services/Teams/TeamsConsoleClientTest.php +++ b/tests/e2e/Services/Teams/TeamsConsoleClientTest.php @@ -47,7 +47,7 @@ class TeamsConsoleClientTest extends Scope ], $this->getHeaders()), [ 'email' => $email, 'name' => $name, - 'roles' => ['admin', 'developer'], + 'roles' => ['developer'], 'url' => 'http://localhost:5000/join-us#title' ]); From 3075cbe626cff6009fcd65f868287e99e858ccec Mon Sep 17 00:00:00 2001 From: Damodar Lohani Date: Thu, 5 Sep 2024 03:28:17 +0000 Subject: [PATCH 31/40] make mock public --- app/controllers/mock.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/controllers/mock.php b/app/controllers/mock.php index fdb1d80dcc..bc071fc885 100644 --- a/app/controllers/mock.php +++ b/app/controllers/mock.php @@ -158,7 +158,7 @@ App::patch('/v1/mock/functions-v2') App::post('/v1/mock/api-key-unprefixed') ->desc('Create API Key (without standard prefix)') ->groups(['mock', 'api', 'projects']) - ->label('scope', 'projects.write') + ->label('scope', 'public') ->label('docs', false) ->param('projectId', '', new UID(), 'Project ID.') ->inject('response') From 59453873b7800831a7e968791d88bfcfa2cf29d8 Mon Sep 17 00:00:00 2001 From: Damodar Lohani Date: Thu, 5 Sep 2024 03:29:41 +0000 Subject: [PATCH 32/40] fix team test --- tests/e2e/Services/Teams/TeamsBaseClient.php | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/tests/e2e/Services/Teams/TeamsBaseClient.php b/tests/e2e/Services/Teams/TeamsBaseClient.php index 2197e50e67..89f581b2f7 100644 --- a/tests/e2e/Services/Teams/TeamsBaseClient.php +++ b/tests/e2e/Services/Teams/TeamsBaseClient.php @@ -203,7 +203,7 @@ trait TeamsBaseClient ], $this->getHeaders()), [ 'email' => $email, 'name' => $name, - 'roles' => ['admin', 'developer'], + 'roles' => ['developer'], 'url' => 'http://localhost:5000/join-us#title' ]); @@ -255,7 +255,7 @@ trait TeamsBaseClient 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ 'userId' => 'abcdefdg', - 'roles' => ['admin', 'developer'], + 'roles' => ['developer'], 'url' => 'http://localhost:5000/join-us#title' ]); @@ -270,7 +270,7 @@ trait TeamsBaseClient 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ 'userId' => $userId, - 'roles' => ['admin', 'developer'], + 'roles' => ['developer'], 'url' => 'http://localhost:5000/join-us#title' ]); @@ -301,7 +301,7 @@ trait TeamsBaseClient ], $this->getHeaders()), [ 'email' => $email, 'name' => 'Friend User', - 'roles' => ['admin', 'developer'], + 'roles' => ['developer'], 'url' => 'http://localhost:5000/join-us#title' ]); @@ -313,7 +313,7 @@ trait TeamsBaseClient ], $this->getHeaders()), [ 'email' => 'dasdkaskdjaskdjasjkd', 'name' => $name, - 'roles' => ['admin', 'developer'], + 'roles' => ['developer'], 'url' => 'http://localhost:5000/join-us#title' ]); @@ -337,7 +337,7 @@ trait TeamsBaseClient ], $this->getHeaders()), [ 'email' => $email, 'name' => $name, - 'roles' => ['admin', 'developer'], + 'roles' => ['developer'], 'url' => 'http://example.com/join-us#title' // bad url ]); @@ -571,7 +571,7 @@ trait TeamsBaseClient /** * Test for SUCCESS */ - $roles = ['admin', 'editor', 'uncle']; + $roles = ['editor', 'uncle']; $response = $this->client->call(Client::METHOD_PATCH, '/teams/' . $teamUid . '/memberships/' . $membershipUid, array_merge([ 'origin' => 'http://localhost', 'content-type' => 'application/json', From cd40df83887b3e163bd5e1985c5400a6d8717b8c Mon Sep 17 00:00:00 2001 From: Damodar Lohani Date: Thu, 5 Sep 2024 03:43:02 +0000 Subject: [PATCH 33/40] fix tests and membership update --- app/controllers/api/teams.php | 12 +++- tests/e2e/Services/Teams/TeamsBaseClient.php | 8 +-- .../Services/Teams/TeamsConsoleClientTest.php | 71 +++++++++++++++++++ 3 files changed, 86 insertions(+), 5 deletions(-) diff --git a/app/controllers/api/teams.php b/app/controllers/api/teams.php index 2265492483..b17cbbf4de 100644 --- a/app/controllers/api/teams.php +++ b/app/controllers/api/teams.php @@ -879,7 +879,17 @@ App::patch('/v1/teams/:teamId/memberships/:membershipId') ->label('sdk.response.model', Response::MODEL_MEMBERSHIP) ->param('teamId', '', new UID(), 'Team ID.') ->param('membershipId', '', new UID(), 'Membership ID.') - ->param('roles', [], new ArrayList(new Key(), APP_LIMIT_ARRAY_PARAMS_SIZE), 'An array of strings. Use this param to set the user\'s roles in the team. A role can be any string. Learn more about [roles and permissions](https://appwrite.io/docs/permissions). Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' roles are allowed, each 32 characters long.') + ->param('roles', [], function (Document $project) { + if($project->getId() === 'console') { + ; + $roles = array_keys(Config::getParam('roles', [])); + array_filter($roles, function ($role) { + return !in_array($role, [Auth::USER_ROLE_APPS, Auth::USER_ROLE_GUESTS, Auth::USER_ROLE_USERS]); + }); + return new ArrayList(new WhiteList($roles), APP_LIMIT_ARRAY_PARAMS_SIZE); + } + return new ArrayList(new Key(), APP_LIMIT_ARRAY_PARAMS_SIZE); + }, 'An array of strings. Use this param to set the user\'s roles in the team. A role can be any string. Learn more about [roles and permissions](https://appwrite.io/docs/permissions). Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' roles are allowed, each 32 characters long.', false, ['project']) ->inject('request') ->inject('response') ->inject('user') diff --git a/tests/e2e/Services/Teams/TeamsBaseClient.php b/tests/e2e/Services/Teams/TeamsBaseClient.php index 89f581b2f7..56adc67db2 100644 --- a/tests/e2e/Services/Teams/TeamsBaseClient.php +++ b/tests/e2e/Services/Teams/TeamsBaseClient.php @@ -161,7 +161,7 @@ trait TeamsBaseClient $this->assertNotEmpty($response['body']['userEmail']); $this->assertNotEmpty($response['body']['teamId']); $this->assertNotEmpty($response['body']['teamName']); - $this->assertCount(2, $response['body']['roles']); + $this->assertCount(1, $response['body']['roles']); $this->assertEquals(false, (new DatetimeValidator())->isValid($response['body']['joined'])); // is null in DB $this->assertEquals(false, $response['body']['confirm']); @@ -214,7 +214,7 @@ trait TeamsBaseClient $this->assertEquals($email, $response['body']['userEmail']); $this->assertNotEmpty($response['body']['teamId']); $this->assertNotEmpty($response['body']['teamName']); - $this->assertCount(2, $response['body']['roles']); + $this->assertCount(1, $response['body']['roles']); $this->assertEquals(false, (new DatetimeValidator())->isValid($response['body']['joined'])); // is null in DB $this->assertEquals(false, $response['body']['confirm']); @@ -281,7 +281,7 @@ trait TeamsBaseClient $this->assertEquals($secondEmail, $response['body']['userEmail']); $this->assertNotEmpty($response['body']['teamId']); $this->assertNotEmpty($response['body']['teamName']); - $this->assertCount(2, $response['body']['roles']); + $this->assertCount(1, $response['body']['roles']); $this->assertEquals(false, (new DateTimeValidator())->isValid($response['body']['joined'])); // is null in DB $this->assertEquals(false, $response['body']['confirm']); @@ -413,7 +413,7 @@ trait TeamsBaseClient $this->assertNotEmpty($response['body']['$id']); $this->assertNotEmpty($response['body']['userId']); $this->assertNotEmpty($response['body']['teamId']); - $this->assertCount(2, $response['body']['roles']); + $this->assertCount(1, $response['body']['roles']); $this->assertEquals(true, (new DatetimeValidator())->isValid($response['body']['joined'])); $this->assertEquals(true, $response['body']['confirm']); $session = $response['cookies']['a_session_' . $this->getProject()['$id']]; diff --git a/tests/e2e/Services/Teams/TeamsConsoleClientTest.php b/tests/e2e/Services/Teams/TeamsConsoleClientTest.php index d19f52debd..4b5ade7cbf 100644 --- a/tests/e2e/Services/Teams/TeamsConsoleClientTest.php +++ b/tests/e2e/Services/Teams/TeamsConsoleClientTest.php @@ -77,4 +77,75 @@ class TeamsConsoleClientTest extends Scope return $data; } + + /** @depends testUpdateTeamMembership */ + public function testUpdateTeamMembershipRoles($data): array + { + $teamUid = $data['teamUid'] ?? ''; + $membershipUid = $data['membershipUid'] ?? ''; + $session = $data['session'] ?? ''; + + /** + * Test for SUCCESS + */ + $roles = ['developer']; + $response = $this->client->call(Client::METHOD_PATCH, '/teams/' . $teamUid . '/memberships/' . $membershipUid, array_merge([ + 'origin' => 'http://localhost', + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + ], $this->getHeaders()), [ + 'roles' => $roles + ]); + + $this->assertEquals(200, $response['headers']['status-code']); + $this->assertNotEmpty($response['body']['$id']); + $this->assertNotEmpty($response['body']['userId']); + $this->assertNotEmpty($response['body']['teamId']); + $this->assertCount(count($roles), $response['body']['roles']); + $this->assertEquals($roles[0], $response['body']['roles'][0]); + + /** + * Test for unknown team + */ + $response = $this->client->call(Client::METHOD_PATCH, '/teams/' . 'abc' . '/memberships/' . $membershipUid, array_merge([ + 'origin' => 'http://localhost', + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + ], $this->getHeaders()), [ + 'roles' => $roles + ]); + + $this->assertEquals(404, $response['headers']['status-code']); + + /** + * Test for unknown membership ID + */ + $response = $this->client->call(Client::METHOD_PATCH, '/teams/' . $teamUid . '/memberships/' . 'abc', array_merge([ + 'origin' => 'http://localhost', + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + ], $this->getHeaders()), [ + 'roles' => $roles + ]); + + $this->assertEquals(404, $response['headers']['status-code']); + + + /** + * Test for when a user other than the owner tries to update membership + */ + $response = $this->client->call(Client::METHOD_PATCH, '/teams/' . $teamUid . '/memberships/' . $membershipUid, [ + 'origin' => 'http://localhost', + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $session, + ], [ + 'roles' => $roles + ]); + + $this->assertEquals(401, $response['headers']['status-code']); + $this->assertEquals('User is not allowed to modify roles', $response['body']['message']); + + return $data; + } } From 70bf8e2c415ccc9abe0c4bd2f42d7cb7b8f2e8f4 Mon Sep 17 00:00:00 2001 From: Damodar Lohani Date: Thu, 5 Sep 2024 03:47:58 +0000 Subject: [PATCH 34/40] fix project scope --- app/config/roles.php | 1 + 1 file changed, 1 insertion(+) diff --git a/app/config/roles.php b/app/config/roles.php index 3215303217..1b64067ecc 100644 --- a/app/config/roles.php +++ b/app/config/roles.php @@ -48,6 +48,7 @@ $admins = [ 'collections.write', 'platforms.read', 'platforms.write', + 'projects.write', 'keys.read', 'keys.write', 'webhooks.read', From b30e5d4cda543f67063d972514104b56714e4408 Mon Sep 17 00:00:00 2001 From: Damodar Lohani Date: Thu, 5 Sep 2024 03:52:00 +0000 Subject: [PATCH 35/40] fix test --- tests/e2e/Services/Teams/TeamsBaseClient.php | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/e2e/Services/Teams/TeamsBaseClient.php b/tests/e2e/Services/Teams/TeamsBaseClient.php index 56adc67db2..8a1fed028e 100644 --- a/tests/e2e/Services/Teams/TeamsBaseClient.php +++ b/tests/e2e/Services/Teams/TeamsBaseClient.php @@ -587,7 +587,6 @@ trait TeamsBaseClient $this->assertCount(count($roles), $response['body']['roles']); $this->assertEquals($roles[0], $response['body']['roles'][0]); $this->assertEquals($roles[1], $response['body']['roles'][1]); - $this->assertEquals($roles[2], $response['body']['roles'][2]); /** * Test for unknown team From c31e928def5a42180b004234f08b2f4b9019c2ae Mon Sep 17 00:00:00 2001 From: Damodar Lohani Date: Sun, 22 Sep 2024 02:44:53 +0000 Subject: [PATCH 36/40] fix linter --- app/controllers/api/teams.php | 4 ++-- app/controllers/shared/api.php | 3 +-- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/app/controllers/api/teams.php b/app/controllers/api/teams.php index b17cbbf4de..146b5d5f81 100644 --- a/app/controllers/api/teams.php +++ b/app/controllers/api/teams.php @@ -396,7 +396,7 @@ App::post('/v1/teams/:teamId/memberships') ->param('userId', '', new UID(), 'ID of the user to be added to a team.', true) ->param('phone', '', new Phone(), 'Phone number. Format this number with a leading \'+\' and a country code, e.g., +16175551212.', true) ->param('roles', [], function (Document $project) { - if($project->getId() === 'console') { + if ($project->getId() === 'console') { ; $roles = array_keys(Config::getParam('roles', [])); array_filter($roles, function ($role) { @@ -880,7 +880,7 @@ App::patch('/v1/teams/:teamId/memberships/:membershipId') ->param('teamId', '', new UID(), 'Team ID.') ->param('membershipId', '', new UID(), 'Membership ID.') ->param('roles', [], function (Document $project) { - if($project->getId() === 'console') { + if ($project->getId() === 'console') { ; $roles = array_keys(Config::getParam('roles', [])); array_filter($roles, function ($role) { diff --git a/app/controllers/shared/api.php b/app/controllers/shared/api.php index 8ef85254ea..8b288fd108 100644 --- a/app/controllers/shared/api.php +++ b/app/controllers/shared/api.php @@ -276,8 +276,7 @@ App::init() } /** * Admin User Authentication - */ - elseif (($project->getId() === 'console' && !$team->isEmpty() && !$user->isEmpty()) || ($project->getId() !== 'console' && !$user->isEmpty() && $mode === APP_MODE_ADMIN)) { + */ elseif (($project->getId() === 'console' && !$team->isEmpty() && !$user->isEmpty()) || ($project->getId() !== 'console' && !$user->isEmpty() && $mode === APP_MODE_ADMIN)) { $teamId = $team->getId(); $adminRoles = []; $memberships = $user->getAttribute('memberships', []); From f2eb1c3b3e23230d93ec0846b94972061be7ae6d Mon Sep 17 00:00:00 2001 From: Damodar Lohani Date: Tue, 24 Sep 2024 07:04:05 +0545 Subject: [PATCH 37/40] Update api.php --- app/controllers/shared/api.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/controllers/shared/api.php b/app/controllers/shared/api.php index 8b288fd108..5112794e40 100644 --- a/app/controllers/shared/api.php +++ b/app/controllers/shared/api.php @@ -276,7 +276,8 @@ App::init() } /** * Admin User Authentication - */ elseif (($project->getId() === 'console' && !$team->isEmpty() && !$user->isEmpty()) || ($project->getId() !== 'console' && !$user->isEmpty() && $mode === APP_MODE_ADMIN)) { + */ + elseif (($project->getId() === 'console' && !$team->isEmpty() && !$user->isEmpty()) || ($project->getId() !== 'console' && !$user->isEmpty() && $mode === APP_MODE_ADMIN)) { $teamId = $team->getId(); $adminRoles = []; $memberships = $user->getAttribute('memberships', []); From abe145dae2820be7ec87f9832aaa5492a5d16262 Mon Sep 17 00:00:00 2001 From: Damodar Lohani Date: Tue, 24 Sep 2024 02:40:01 +0000 Subject: [PATCH 38/40] fix formatting --- app/console | 1 + app/controllers/shared/api.php | 4 +--- 2 files changed, 2 insertions(+), 3 deletions(-) create mode 160000 app/console diff --git a/app/console b/app/console new file mode 160000 index 0000000000..112fccf5a0 --- /dev/null +++ b/app/console @@ -0,0 +1 @@ +Subproject commit 112fccf5a044c9795b31b264f5974224a3545a17 diff --git a/app/controllers/shared/api.php b/app/controllers/shared/api.php index 5112794e40..162b09b4dd 100644 --- a/app/controllers/shared/api.php +++ b/app/controllers/shared/api.php @@ -274,9 +274,7 @@ App::init() } } } - /** - * Admin User Authentication - */ + // Admin User Authentication elseif (($project->getId() === 'console' && !$team->isEmpty() && !$user->isEmpty()) || ($project->getId() !== 'console' && !$user->isEmpty() && $mode === APP_MODE_ADMIN)) { $teamId = $team->getId(); $adminRoles = []; From 3fe031d223326adaa0abc0e6378640ba38c9dd8c Mon Sep 17 00:00:00 2001 From: Damodar Lohani Date: Tue, 24 Sep 2024 02:44:04 +0000 Subject: [PATCH 39/40] remove console modules --- app/console | 1 - 1 file changed, 1 deletion(-) delete mode 160000 app/console diff --git a/app/console b/app/console deleted file mode 160000 index 112fccf5a0..0000000000 --- a/app/console +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 112fccf5a044c9795b31b264f5974224a3545a17 From 36cfc4bee07ba50903d8964b5ac843c3a9928243 Mon Sep 17 00:00:00 2001 From: Damodar Lohani Date: Sat, 28 Sep 2024 08:55:51 +0000 Subject: [PATCH 40/40] Fix webp --- Dockerfile | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Dockerfile b/Dockerfile index 22b37982d0..13b018df0f 100755 --- a/Dockerfile +++ b/Dockerfile @@ -28,6 +28,8 @@ RUN \ apk add boost boost-dev; \ fi +RUN apk add libwebp + WORKDIR /usr/src/code COPY --from=composer /usr/local/src/vendor /usr/src/code/vendor