From 312ab657946f24a5bb84a61ac920fd2b9df28c56 Mon Sep 17 00:00:00 2001 From: Torsten Dittmann Date: Fri, 19 Feb 2021 11:02:02 +0100 Subject: [PATCH 01/11] decouple oauth2 from user to tokens --- app/config/collections.php | 47 +++++++++++++++++++-------------- app/controllers/api/account.php | 10 ++++--- app/controllers/api/teams.php | 2 ++ src/Appwrite/Auth/Auth.php | 6 +++++ 4 files changed, 42 insertions(+), 23 deletions(-) diff --git a/app/config/collections.php b/app/config/collections.php index 9170b07573..9164cd93b4 100644 --- a/app/config/collections.php +++ b/app/config/collections.php @@ -318,6 +318,33 @@ $collections = [ 'required' => true, 'array' => false, ], + [ + '$collection' => Database::SYSTEM_COLLECTION_RULES, + 'label' => 'Provider', + 'key' => 'provider', + 'type' => Database::SYSTEM_VAR_TYPE_TEXT, + 'default' => '', + 'required' => false, + 'array' => false, + ], + [ + '$collection' => Database::SYSTEM_COLLECTION_RULES, + 'label' => 'Provider User Identifier', + 'key' => 'providerUid', + 'type' => Database::SYSTEM_VAR_TYPE_TEXT, + 'default' => '', + 'required' => false, + 'array' => false, + ], + [ + '$collection' => Database::SYSTEM_COLLECTION_RULES, + 'label' => 'Provider Token', + 'key' => 'providerToken', + 'type' => Database::SYSTEM_VAR_TYPE_TEXT, + 'default' => '', + 'required' => false, + 'array' => false, + ], [ '$collection' => Database::SYSTEM_COLLECTION_RULES, 'label' => 'Secret', @@ -1617,26 +1644,6 @@ foreach ($providers as $index => $provider) { 'array' => false, 'filter' => ['encrypt'], ]; - - $collections[Database::SYSTEM_COLLECTION_USERS]['rules'][] = [ - '$collection' => Database::SYSTEM_COLLECTION_RULES, - 'label' => 'OAuth2 '.\ucfirst($index).' ID', - 'key' => 'oauth2'.\ucfirst($index), - 'type' => Database::SYSTEM_VAR_TYPE_TEXT, - 'default' => '', - 'required' => false, - 'array' => false, - ]; - - $collections[Database::SYSTEM_COLLECTION_USERS]['rules'][] = [ - '$collection' => Database::SYSTEM_COLLECTION_RULES, - 'label' => 'OAuth2 '.\ucfirst($index).' Access Token', - 'key' => 'oauth2'.\ucfirst($index).'AccessToken', - 'type' => Database::SYSTEM_VAR_TYPE_TEXT, - 'default' => '', - 'required' => false, - 'array' => false, - ]; } return $collections; \ No newline at end of file diff --git a/app/controllers/api/account.php b/app/controllers/api/account.php index e8ae76312b..26c76a7f30 100644 --- a/app/controllers/api/account.php +++ b/app/controllers/api/account.php @@ -194,6 +194,8 @@ App::post('/v1/account/sessions') '$permissions' => ['read' => ['user:'.$profile->getId()], 'write' => ['user:'.$profile->getId()]], 'userId' => $profile->getId(), 'type' => Auth::TOKEN_TYPE_LOGIN, + 'provider' => Auth::TOKEN_PROVIDER_EMAIL, + 'providerUid' => $email, 'secret' => Auth::hash($secret), // One way hash encryption to protect DB leak 'expire' => $expiry, 'userAgent' => $request->getUserAgent('UNKNOWN'), @@ -449,7 +451,8 @@ App::get('/v1/account/sessions/oauth2/:provider/redirect') 'limit' => 1, 'filters' => [ '$collection='.Database::SYSTEM_COLLECTION_USERS, - 'oauth2'.\ucfirst($provider).'='.$oauth2ID, + 'tokens.provider='.$provider, + 'tokens.providerUid='.$oauth2ID ], ]) : $user; @@ -508,6 +511,9 @@ App::get('/v1/account/sessions/oauth2/:provider/redirect') '$permissions' => ['read' => ['user:'.$user['$id']], 'write' => ['user:'.$user['$id']]], 'userId' => $user->getId(), 'type' => Auth::TOKEN_TYPE_LOGIN, + 'provider' => $provider, + 'providerUid' => $oauth2ID, + 'providerToken' => $accessToken, 'secret' => Auth::hash($secret), // One way hash encryption to protect DB leak 'expire' => $expiry, 'userAgent' => $request->getUserAgent('UNKNOWN'), @@ -516,8 +522,6 @@ App::get('/v1/account/sessions/oauth2/:provider/redirect') ], $detector->getOS(), $detector->getClient(), $detector->getDevice())); $user - ->setAttribute('oauth2'.\ucfirst($provider), $oauth2ID) - ->setAttribute('oauth2'.\ucfirst($provider).'AccessToken', $accessToken) ->setAttribute('status', Auth::USER_STATUS_ACTIVATED) ->setAttribute('tokens', $session, Document::SET_TYPE_APPEND) ; diff --git a/app/controllers/api/teams.php b/app/controllers/api/teams.php index c4a9e4875d..a674eacf0d 100644 --- a/app/controllers/api/teams.php +++ b/app/controllers/api/teams.php @@ -599,6 +599,8 @@ App::patch('/v1/teams/:teamId/memberships/:inviteId/status') '$permissions' => ['read' => ['user:'.$user->getId()], 'write' => ['user:'.$user->getId()]], 'userId' => $user->getId(), 'type' => Auth::TOKEN_TYPE_LOGIN, + 'provider' => Auth::TOKEN_PROVIDER_EMAIL, + 'providerUid' => $user->getAttribute('email'), 'secret' => Auth::hash($secret), // One way hash encryption to protect DB leak 'expire' => $expiry, 'userAgent' => $request->getUserAgent('UNKNOWN'), diff --git a/src/Appwrite/Auth/Auth.php b/src/Appwrite/Auth/Auth.php index f2d786c937..b9da8cde7d 100644 --- a/src/Appwrite/Auth/Auth.php +++ b/src/Appwrite/Auth/Auth.php @@ -33,6 +33,12 @@ class Auth const TOKEN_TYPE_RECOVERY = 3; const TOKEN_TYPE_INVITE = 4; + /** + * Session Providers. + */ + const TOKEN_PROVIDER_EMAIL = 'email'; + const TOKEN_PROVIDER_ANONYMOUS = 'anonymous'; + /** * Token Expiration times. */ From d4bd9c0d06f3f8032ef166b989f2de58cd39a0d3 Mon Sep 17 00:00:00 2001 From: Torsten Dittmann Date: Fri, 19 Feb 2021 13:12:47 +0100 Subject: [PATCH 02/11] decouple user session from tokens --- app/config/collections.php | 93 ++++++++++++++++++++++++++---- app/controllers/api/account.php | 71 +++++++++++------------ app/controllers/api/teams.php | 7 +-- app/controllers/api/users.php | 17 +++--- app/init.php | 2 +- src/Appwrite/Auth/Auth.php | 30 +++++++++- src/Appwrite/Database/Database.php | 1 + tests/unit/Auth/AuthTest.php | 71 ++++++++++++++++++----- 8 files changed, 214 insertions(+), 78 deletions(-) diff --git a/app/config/collections.php b/app/config/collections.php index 9164cd93b4..92e687cd17 100644 --- a/app/config/collections.php +++ b/app/config/collections.php @@ -271,6 +271,16 @@ $collections = [ 'required' => true, 'array' => false, ], + [ + '$collection' => Database::SYSTEM_COLLECTION_RULES, + 'label' => 'Sessions', + 'key' => 'sessions', + 'type' => Database::SYSTEM_VAR_TYPE_DOCUMENT, + 'default' => [], + 'required' => false, + 'array' => true, + 'list' => [Database::SYSTEM_COLLECTION_SESSIONS], + ], [ '$collection' => Database::SYSTEM_COLLECTION_RULES, 'label' => 'Tokens', @@ -293,11 +303,11 @@ $collections = [ ], ], ], - Database::SYSTEM_COLLECTION_TOKENS => [ + Database::SYSTEM_COLLECTION_SESSIONS => [ '$collection' => Database::SYSTEM_COLLECTION_COLLECTIONS, - '$id' => Database::SYSTEM_COLLECTION_TOKENS, + '$id' => Database::SYSTEM_COLLECTION_SESSIONS, '$permissions' => ['read' => ['*']], - 'name' => 'Token', + 'name' => 'Sessions', 'structure' => true, 'rules' => [ [ @@ -306,15 +316,15 @@ $collections = [ 'key' => 'userId', 'type' => Database::SYSTEM_VAR_TYPE_TEXT, 'default' => null, - 'required' => false, + 'required' => true, 'array' => false, ], [ '$collection' => Database::SYSTEM_COLLECTION_RULES, - 'label' => 'Type', - 'key' => 'type', - 'type' => Database::SYSTEM_VAR_TYPE_NUMERIC, - 'default' => null, + 'label' => 'Secret', + 'key' => 'secret', + 'type' => Database::SYSTEM_VAR_TYPE_TEXT, + 'default' => '', 'required' => true, 'array' => false, ], @@ -324,7 +334,7 @@ $collections = [ 'key' => 'provider', 'type' => Database::SYSTEM_VAR_TYPE_TEXT, 'default' => '', - 'required' => false, + 'required' => true, 'array' => false, ], [ @@ -333,7 +343,7 @@ $collections = [ 'key' => 'providerUid', 'type' => Database::SYSTEM_VAR_TYPE_TEXT, 'default' => '', - 'required' => false, + 'required' => true, 'array' => false, ], [ @@ -500,6 +510,69 @@ $collections = [ ], ], ], + Database::SYSTEM_COLLECTION_TOKENS => [ + '$collection' => Database::SYSTEM_COLLECTION_COLLECTIONS, + '$id' => Database::SYSTEM_COLLECTION_TOKENS, + '$permissions' => ['read' => ['*']], + 'name' => 'Token', + 'structure' => true, + 'rules' => [ + [ + '$collection' => Database::SYSTEM_COLLECTION_RULES, + 'label' => 'User ID', + 'key' => 'userId', + 'type' => Database::SYSTEM_VAR_TYPE_TEXT, + 'default' => null, + 'required' => false, + 'array' => false, + ], + [ + '$collection' => Database::SYSTEM_COLLECTION_RULES, + 'label' => 'Type', + 'key' => 'type', + 'type' => Database::SYSTEM_VAR_TYPE_NUMERIC, + 'default' => null, + 'required' => true, + 'array' => false, + ], + [ + '$collection' => Database::SYSTEM_COLLECTION_RULES, + 'label' => 'Secret', + 'key' => 'secret', + 'type' => Database::SYSTEM_VAR_TYPE_TEXT, + 'default' => '', + 'required' => true, + 'array' => false, + ], + [ + '$collection' => Database::SYSTEM_COLLECTION_RULES, + 'label' => 'Expire', + 'key' => 'expire', + 'type' => Database::SYSTEM_VAR_TYPE_NUMERIC, + 'default' => 0, + 'required' => true, + 'array' => false, + ], + [ + '$collection' => Database::SYSTEM_COLLECTION_RULES, + 'label' => 'User Agent', + 'key' => 'userAgent', + 'type' => Database::SYSTEM_VAR_TYPE_TEXT, + 'default' => '', + 'required' => true, + 'array' => false, + ], + [ + '$collection' => Database::SYSTEM_COLLECTION_RULES, + 'label' => 'IP', + 'key' => 'ip', + 'type' => Database::SYSTEM_VAR_TYPE_IP, + 'default' => '', + 'required' => true, + 'array' => false, + ], + ], + ], Database::SYSTEM_COLLECTION_MEMBERSHIPS => [ '$collection' => Database::SYSTEM_COLLECTION_COLLECTIONS, '$id' => Database::SYSTEM_COLLECTION_MEMBERSHIPS, diff --git a/app/controllers/api/account.php b/app/controllers/api/account.php index 26c76a7f30..a81e38288a 100644 --- a/app/controllers/api/account.php +++ b/app/controllers/api/account.php @@ -190,11 +190,10 @@ App::post('/v1/account/sessions') $secret = Auth::tokenGenerator(); $session = new Document(array_merge( [ - '$collection' => Database::SYSTEM_COLLECTION_TOKENS, + '$collection' => Database::SYSTEM_COLLECTION_SESSIONS, '$permissions' => ['read' => ['user:'.$profile->getId()], 'write' => ['user:'.$profile->getId()]], 'userId' => $profile->getId(), - 'type' => Auth::TOKEN_TYPE_LOGIN, - 'provider' => Auth::TOKEN_PROVIDER_EMAIL, + 'provider' => Auth::SESSION_PROVIDER_EMAIL, 'providerUid' => $email, 'secret' => Auth::hash($secret), // One way hash encryption to protect DB leak 'expire' => $expiry, @@ -212,7 +211,7 @@ App::post('/v1/account/sessions') throw new Exception('Failed saving session to DB', 500); } - $profile->setAttribute('tokens', $session, Document::SET_TYPE_APPEND); + $profile->setAttribute('sessions', $session, Document::SET_TYPE_APPEND); $profile = $projectDB->updateDocument($profile->getArrayCopy()); @@ -441,7 +440,7 @@ App::get('/v1/account/sessions/oauth2/:provider/redirect') throw new Exception('Missing ID from OAuth2 provider', 400); } - $current = Auth::tokenVerify($user->getAttribute('tokens', []), Auth::TOKEN_TYPE_LOGIN, Auth::$secret); + $current = Auth::sessionVerify($user->getAttribute('sessions', []), Auth::$secret); if ($current) { $projectDB->deleteDocument($current); //throw new Exception('User already logged in', 401); @@ -451,8 +450,8 @@ App::get('/v1/account/sessions/oauth2/:provider/redirect') 'limit' => 1, 'filters' => [ '$collection='.Database::SYSTEM_COLLECTION_USERS, - 'tokens.provider='.$provider, - 'tokens.providerUid='.$oauth2ID + 'sessions.provider='.$provider, + 'sessions.providerUid='.$oauth2ID ], ]) : $user; @@ -507,10 +506,9 @@ App::get('/v1/account/sessions/oauth2/:provider/redirect') $secret = Auth::tokenGenerator(); $expiry = \time() + Auth::TOKEN_EXPIRATION_LOGIN_LONG; $session = new Document(array_merge([ - '$collection' => Database::SYSTEM_COLLECTION_TOKENS, + '$collection' => Database::SYSTEM_COLLECTION_SESSIONS, '$permissions' => ['read' => ['user:'.$user['$id']], 'write' => ['user:'.$user['$id']]], 'userId' => $user->getId(), - 'type' => Auth::TOKEN_TYPE_LOGIN, 'provider' => $provider, 'providerUid' => $oauth2ID, 'providerToken' => $accessToken, @@ -523,7 +521,7 @@ App::get('/v1/account/sessions/oauth2/:provider/redirect') $user ->setAttribute('status', Auth::USER_STATUS_ACTIVATED) - ->setAttribute('tokens', $session, Document::SET_TYPE_APPEND) + ->setAttribute('sessions', $session, Document::SET_TYPE_APPEND) ; Authorization::setRole('user:'.$user->getId()); @@ -585,16 +583,18 @@ App::post('/v1/account/jwt') /** @var Appwrite\Utopia\Response $response */ /** @var Appwrite\Database\Document $user */ - $tokens = $user->getAttribute('tokens', []); - $session = new Document(); + $sessions = $user->getAttribute('sessions', []); + $current = new Document(); - foreach ($tokens as $token) { /** @var Appwrite\Database\Document $token */ - if ($token->getAttribute('secret') == Auth::hash(Auth::$secret)) { // If current session delete the cookies too - $session = $token; + foreach ($sessions as $session) { + /** @var Appwrite\Database\Document $session */ + + if ($session->getAttribute('secret') == Auth::hash(Auth::$secret)) { // If current session delete the cookies too + $current = $session; } } - if($session->isEmpty()) { + if($current->isEmpty()) { throw new Exception('No valid session found', 401); } @@ -608,7 +608,7 @@ App::post('/v1/account/jwt') // 'scopes' => ['user'], // 'iss' => 'http://api.mysite.com', 'userId' => $user->getId(), - 'sessionId' => $session->getId(), + 'sessionId' => $current->getId(), ])]), Response::MODEL_JWT); }); @@ -673,22 +673,19 @@ App::get('/v1/account/sessions') /** @var Appwrite\Database\Document $user */ /** @var Utopia\Locale\Locale $locale */ - $tokens = $user->getAttribute('tokens', []); - $sessions = []; + $sessions = $user->getAttribute('sessions', []); $countries = $locale->getText('countries'); - $current = Auth::tokenVerify($tokens, Auth::TOKEN_TYPE_LOGIN, Auth::$secret); + $current = Auth::sessionVerify($sessions, Auth::$secret); - foreach ($tokens as $token) { /* @var $token Document */ - if (Auth::TOKEN_TYPE_LOGIN != $token->getAttribute('type')) { - continue; - } + foreach ($sessions as $key => $session) { + /** @var Document $session */ - $token->setAttribute('countryName', (isset($countries[$token->getAttribute('contryCode')])) - ? $countries[$token->getAttribute('contryCode')] + $session->setAttribute('countryName', (isset($countries[$session->getAttribute('contryCode')])) + ? $countries[$session->getAttribute('contryCode')] : $locale->getText('locale.country.unknown')); - $token->setAttribute('current', ($current == $token->getId()) ? true : false); + $session->setAttribute('current', ($current == $session->getId()) ? true : false); - $sessions[] = $token; + $sessions[$key] = $session; } $response->dynamic(new Document([ @@ -1052,14 +1049,14 @@ App::delete('/v1/account/sessions/:sessionId') $protocol = $request->getProtocol(); $sessionId = ($sessionId === 'current') - ? Auth::tokenVerify($user->getAttribute('tokens'), Auth::TOKEN_TYPE_LOGIN, Auth::$secret) + ? Auth::sessionVerify($user->getAttribute('sessions'), Auth::$secret) : $sessionId; - $tokens = $user->getAttribute('tokens', []); + $sessions = $user->getAttribute('sessions', []); - foreach ($tokens as $token) { /* @var $token Document */ - if (($sessionId == $token->getId()) && Auth::TOKEN_TYPE_LOGIN == $token->getAttribute('type')) { - if (!$projectDB->deleteDocument($token->getId())) { + foreach ($sessions as $session) { /** @var Document $session */ + if (($sessionId == $session->getId())) { + if (!$projectDB->deleteDocument($session->getId())) { throw new Exception('Failed to remove token from DB', 500); } @@ -1075,10 +1072,10 @@ App::delete('/v1/account/sessions/:sessionId') ; } - $token->setAttribute('current', false); + $session->setAttribute('current', false); - if ($token->getAttribute('secret') == Auth::hash(Auth::$secret)) { // If current session delete the cookies too - $token->setAttribute('current', true); + if ($session->getAttribute('secret') == Auth::hash(Auth::$secret)) { // If current session delete the cookies too + $session->setAttribute('current', true); $response ->addCookie(Auth::$cookieName.'_legacy', '', \time() - 3600, '/', Config::getParam('cookieDomain'), ('https' == $protocol), true, null) @@ -1087,7 +1084,7 @@ App::delete('/v1/account/sessions/:sessionId') } $events - ->setParam('payload', $response->output($token, Response::MODEL_SESSION)) + ->setParam('payload', $response->output($session, Response::MODEL_SESSION)) ; return $response->noContent(); diff --git a/app/controllers/api/teams.php b/app/controllers/api/teams.php index a674eacf0d..775d9b47a3 100644 --- a/app/controllers/api/teams.php +++ b/app/controllers/api/teams.php @@ -595,11 +595,10 @@ App::patch('/v1/teams/:teamId/memberships/:inviteId/status') $expiry = \time() + Auth::TOKEN_EXPIRATION_LOGIN_LONG; $secret = Auth::tokenGenerator(); $session = new Document(array_merge([ - '$collection' => Database::SYSTEM_COLLECTION_TOKENS, + '$collection' => Database::SYSTEM_COLLECTION_SESSIONS, '$permissions' => ['read' => ['user:'.$user->getId()], 'write' => ['user:'.$user->getId()]], 'userId' => $user->getId(), - 'type' => Auth::TOKEN_TYPE_LOGIN, - 'provider' => Auth::TOKEN_PROVIDER_EMAIL, + 'provider' => Auth::SESSION_PROVIDER_EMAIL, 'providerUid' => $user->getAttribute('email'), 'secret' => Auth::hash($secret), // One way hash encryption to protect DB leak 'expire' => $expiry, @@ -608,7 +607,7 @@ App::patch('/v1/teams/:teamId/memberships/:inviteId/status') 'countryCode' => ($record) ? \strtolower($record['country']['iso_code']) : '--', ], $detector->getOS(), $detector->getClient(), $detector->getDevice())); - $user->setAttribute('tokens', $session, Document::SET_TYPE_APPEND); + $user->setAttribute('sessions', $session, Document::SET_TYPE_APPEND); Authorization::setRole('user:'.$userId); diff --git a/app/controllers/api/users.php b/app/controllers/api/users.php index efb0041cee..b8e79ccb95 100644 --- a/app/controllers/api/users.php +++ b/app/controllers/api/users.php @@ -196,21 +196,18 @@ App::get('/v1/users/:userId/sessions') throw new Exception('User not found', 404); } - $tokens = $user->getAttribute('tokens', []); - $sessions = []; + $sessions = $user->getAttribute('sessions', []); $countries = $locale->getText('countries'); - foreach ($tokens as $token) { /* @var $token Document */ - if (Auth::TOKEN_TYPE_LOGIN != $token->getAttribute('type')) { - continue; - } + foreach ($sessions as $key => $session) { + /** @var Document $session */ - $token->setAttribute('countryName', (isset($countries[$token->getAttribute('contryCode')])) - ? $countries[$token->getAttribute('contryCode')] + $session->setAttribute('countryName', (isset($countries[$session->getAttribute('contryCode')])) + ? $countries[$session->getAttribute('contryCode')] : $locale->getText('locale.country.unknown')); - $token->setAttribute('current', false); + $session->setAttribute('current', false); - $sessions[] = $token; + $sessions[$key] = $session; } $response->dynamic(new Document([ diff --git a/app/init.php b/app/init.php index 7cf2f9f0fb..372a3857b0 100644 --- a/app/init.php +++ b/app/init.php @@ -419,7 +419,7 @@ App::setResource('user', function($mode, $project, $console, $request, $response if (empty($user->getId()) // Check a document has been found in the DB || Database::SYSTEM_COLLECTION_USERS !== $user->getCollection() // Validate returned document is really a user document - || !Auth::tokenVerify($user->getAttribute('tokens', []), Auth::TOKEN_TYPE_LOGIN, Auth::$secret)) { // Validate user has valid login token + || !Auth::sessionVerify($user->getAttribute('sessions', []), Auth::$secret)) { // Validate user has valid login token $user = new Document(['$id' => '', '$collection' => Database::SYSTEM_COLLECTION_USERS]); } diff --git a/src/Appwrite/Auth/Auth.php b/src/Appwrite/Auth/Auth.php index b9da8cde7d..18a2837f5a 100644 --- a/src/Appwrite/Auth/Auth.php +++ b/src/Appwrite/Auth/Auth.php @@ -28,7 +28,7 @@ class Auth /** * Token Types. */ - const TOKEN_TYPE_LOGIN = 1; + const TOKEN_TYPE_LOGIN = 1; // Deprecated const TOKEN_TYPE_VERIFICATION = 2; const TOKEN_TYPE_RECOVERY = 3; const TOKEN_TYPE_INVITE = 4; @@ -36,8 +36,8 @@ class Auth /** * Session Providers. */ - const TOKEN_PROVIDER_EMAIL = 'email'; - const TOKEN_PROVIDER_ANONYMOUS = 'anonymous'; + const SESSION_PROVIDER_EMAIL = 'email'; + const SESSION_PROVIDER_ANONYMOUS = 'anonymous'; /** * Token Expiration times. @@ -213,6 +213,30 @@ class Auth return false; } + /** + * Verify session and check that its not expired. + * + * @param array $sessions + * @param string $secret + * + * @return bool|string + */ + public static function sessionVerify(array $sessions, string $secret) + { + foreach ($sessions as $session) { /** @var Document $session */ + if ($session->isSet('secret') && + $session->isSet('expire') && + $session->isSet('provider') && + $session->isSet('providerUid') && + $session->getAttribute('secret') === self::hash($secret) && + $session->getAttribute('expire') >= \time()) { + return (string)$session->getId(); + } + } + + return false; + } + /** * Is Previligged User? * diff --git a/src/Appwrite/Database/Database.php b/src/Appwrite/Database/Database.php index 4154214b82..d0defdec03 100644 --- a/src/Appwrite/Database/Database.php +++ b/src/Appwrite/Database/Database.php @@ -27,6 +27,7 @@ class Database // Auth, Account and Users (private to user) const SYSTEM_COLLECTION_USERS = 'users'; + const SYSTEM_COLLECTION_SESSIONS = 'sessions'; const SYSTEM_COLLECTION_TOKENS = 'tokens'; // Teams (shared among team members) diff --git a/tests/unit/Auth/AuthTest.php b/tests/unit/Auth/AuthTest.php index 5860d1efb9..6a9b8ab3b0 100644 --- a/tests/unit/Auth/AuthTest.php +++ b/tests/unit/Auth/AuthTest.php @@ -62,41 +62,55 @@ class AuthTest extends TestCase $this->assertEquals(\mb_strlen(Auth::tokenGenerator(5)), 10); } - public function testTokenVerify() + public function testSessionVerify() { $secret = 'secret1'; $hash = Auth::hash($secret); $tokens1 = [ new Document([ '$id' => 'token1', - 'type' => Auth::TOKEN_TYPE_LOGIN, 'expire' => time() + 60 * 60 * 24, 'secret' => $hash, + 'provider' => Auth::SESSION_PROVIDER_EMAIL, + 'providerUid' => 'test@example.com', ]), new Document([ '$id' => 'token2', - 'type' => Auth::TOKEN_TYPE_LOGIN, 'expire' => time() - 60 * 60 * 24, 'secret' => 'secret2', + 'provider' => Auth::SESSION_PROVIDER_EMAIL, + 'providerUid' => 'test@example.com', ]), ]; $tokens2 = [ new Document([ // Correct secret and type time, wrong expire time '$id' => 'token1', - 'type' => Auth::TOKEN_TYPE_LOGIN, 'expire' => time() - 60 * 60 * 24, 'secret' => $hash, + 'provider' => Auth::SESSION_PROVIDER_EMAIL, + 'providerUid' => 'test@example.com', ]), new Document([ '$id' => 'token2', - 'type' => Auth::TOKEN_TYPE_LOGIN, 'expire' => time() - 60 * 60 * 24, 'secret' => 'secret2', + 'provider' => Auth::SESSION_PROVIDER_EMAIL, + 'providerUid' => 'test@example.com', ]), ]; - $tokens3 = [ // Correct secret and expire time, wrong type + $this->assertEquals(Auth::sessionVerify($tokens1, $secret), 'token1'); + $this->assertEquals(Auth::sessionVerify($tokens1, 'false-secret'), false); + $this->assertEquals(Auth::sessionVerify($tokens2, $secret), false); + $this->assertEquals(Auth::sessionVerify($tokens2, 'false-secret'), false); + } + + public function testTokenVerify() + { + $secret = 'secret1'; + $hash = Auth::hash($secret); + $tokens1 = [ new Document([ '$id' => 'token1', 'type' => Auth::TOKEN_TYPE_RECOVERY, @@ -105,20 +119,51 @@ class AuthTest extends TestCase ]), new Document([ '$id' => 'token2', - 'type' => Auth::TOKEN_TYPE_LOGIN, + 'type' => Auth::TOKEN_TYPE_RECOVERY, 'expire' => time() - 60 * 60 * 24, 'secret' => 'secret2', ]), ]; - $this->assertEquals(Auth::tokenVerify($tokens1, Auth::TOKEN_TYPE_LOGIN, $secret), 'token1'); - $this->assertEquals(Auth::tokenVerify($tokens1, Auth::TOKEN_TYPE_LOGIN, 'false-secret'), false); - $this->assertEquals(Auth::tokenVerify($tokens2, Auth::TOKEN_TYPE_LOGIN, $secret), false); - $this->assertEquals(Auth::tokenVerify($tokens2, Auth::TOKEN_TYPE_LOGIN, 'false-secret'), false); - $this->assertEquals(Auth::tokenVerify($tokens3, Auth::TOKEN_TYPE_LOGIN, $secret), false); - $this->assertEquals(Auth::tokenVerify($tokens3, Auth::TOKEN_TYPE_LOGIN, 'false-secret'), false); + $tokens2 = [ + new Document([ // Correct secret and type time, wrong expire time + '$id' => 'token1', + 'type' => Auth::TOKEN_TYPE_RECOVERY, + 'expire' => time() - 60 * 60 * 24, + 'secret' => $hash, + ]), + new Document([ + '$id' => 'token2', + 'type' => Auth::TOKEN_TYPE_RECOVERY, + 'expire' => time() - 60 * 60 * 24, + 'secret' => 'secret2', + ]), + ]; + + $tokens3 = [ // Correct secret and expire time, wrong type + new Document([ + '$id' => 'token1', + 'type' => Auth::TOKEN_TYPE_INVITE, + 'expire' => time() + 60 * 60 * 24, + 'secret' => $hash, + ]), + new Document([ + '$id' => 'token2', + 'type' => Auth::TOKEN_TYPE_RECOVERY, + 'expire' => time() - 60 * 60 * 24, + 'secret' => 'secret2', + ]), + ]; + + $this->assertEquals(Auth::tokenVerify($tokens1, Auth::TOKEN_TYPE_RECOVERY, $secret), 'token1'); + $this->assertEquals(Auth::tokenVerify($tokens1, Auth::TOKEN_TYPE_RECOVERY, 'false-secret'), false); + $this->assertEquals(Auth::tokenVerify($tokens2, Auth::TOKEN_TYPE_RECOVERY, $secret), false); + $this->assertEquals(Auth::tokenVerify($tokens2, Auth::TOKEN_TYPE_RECOVERY, 'false-secret'), false); + $this->assertEquals(Auth::tokenVerify($tokens3, Auth::TOKEN_TYPE_RECOVERY, $secret), false); + $this->assertEquals(Auth::tokenVerify($tokens3, Auth::TOKEN_TYPE_RECOVERY, 'false-secret'), false); } + public function testIsPreviliggedUser() { $this->assertEquals(false, Auth::isPreviliggedUser([])); From 8bc484dfca8d0721c668ec398e1021ad4dbddbf7 Mon Sep 17 00:00:00 2001 From: Torsten Dittmann Date: Fri, 19 Feb 2021 14:59:36 +0100 Subject: [PATCH 03/11] fix leftovers --- app/config/collections.php | 2 +- app/controllers/api/account.php | 22 +++++++++++-------- app/controllers/api/teams.php | 1 + app/controllers/api/users.php | 18 +++++++++------ app/workers/deletes.php | 10 ++++++++- .../Utopia/Response/Model/Session.php | 18 +++++++++++++++ 6 files changed, 53 insertions(+), 18 deletions(-) diff --git a/app/config/collections.php b/app/config/collections.php index 92e687cd17..d88bb849aa 100644 --- a/app/config/collections.php +++ b/app/config/collections.php @@ -307,7 +307,7 @@ $collections = [ '$collection' => Database::SYSTEM_COLLECTION_COLLECTIONS, '$id' => Database::SYSTEM_COLLECTION_SESSIONS, '$permissions' => ['read' => ['*']], - 'name' => 'Sessions', + 'name' => 'Session', 'structure' => true, 'rules' => [ [ diff --git a/app/controllers/api/account.php b/app/controllers/api/account.php index a81e38288a..d37e6f0476 100644 --- a/app/controllers/api/account.php +++ b/app/controllers/api/account.php @@ -1054,7 +1054,9 @@ App::delete('/v1/account/sessions/:sessionId') $sessions = $user->getAttribute('sessions', []); - foreach ($sessions as $session) { /** @var Document $session */ + foreach ($sessions as $session) { + /** @var Document $session */ + if (($sessionId == $session->getId())) { if (!$projectDB->deleteDocument($session->getId())) { throw new Exception('Failed to remove token from DB', 500); @@ -1121,10 +1123,12 @@ App::delete('/v1/account/sessions') /** @var Appwrite\Event\Event $events */ $protocol = $request->getProtocol(); - $tokens = $user->getAttribute('tokens', []); + $sessions = $user->getAttribute('sessions', []); - foreach ($tokens as $token) { /* @var $token Document */ - if (!$projectDB->deleteDocument($token->getId())) { + foreach ($sessions as $session) { + /** @var Document $session */ + + if (!$projectDB->deleteDocument($session->getId())) { throw new Exception('Failed to remove token from DB', 500); } @@ -1140,10 +1144,10 @@ App::delete('/v1/account/sessions') ; } - $token->setAttribute('current', false); + $session->setAttribute('current', false); - if ($token->getAttribute('secret') == Auth::hash(Auth::$secret)) { // If current session delete the cookies too - $token->setAttribute('current', true); + if ($session->getAttribute('secret') == Auth::hash(Auth::$secret)) { // If current session delete the cookies too + $session->setAttribute('current', true); $response ->addCookie(Auth::$cookieName.'_legacy', '', \time() - 3600, '/', Config::getParam('cookieDomain'), ('https' == $protocol), true, null) ->addCookie(Auth::$cookieName, '', \time() - 3600, '/', Config::getParam('cookieDomain'), ('https' == $protocol), true, Config::getParam('cookieSamesite')) @@ -1153,8 +1157,8 @@ App::delete('/v1/account/sessions') $events ->setParam('payload', $response->output(new Document([ - 'sum' => count($tokens), - 'sessions' => $tokens + 'sum' => count($sessions), + 'sessions' => $sessions ]), Response::MODEL_SESSION_LIST)) ; diff --git a/app/controllers/api/teams.php b/app/controllers/api/teams.php index 775d9b47a3..f75f072e76 100644 --- a/app/controllers/api/teams.php +++ b/app/controllers/api/teams.php @@ -327,6 +327,7 @@ App::post('/v1/teams/:teamId/memberships') 'registration' => \time(), 'reset' => false, 'name' => $name, + 'sessions' => [], 'tokens' => [], ], ['email' => $email]); } catch (Duplicate $th) { diff --git a/app/controllers/api/users.php b/app/controllers/api/users.php index b8e79ccb95..4766d0a5f9 100644 --- a/app/controllers/api/users.php +++ b/app/controllers/api/users.php @@ -430,11 +430,13 @@ App::delete('/v1/users/:userId/sessions/:sessionId') throw new Exception('User not found', 404); } - $tokens = $user->getAttribute('tokens', []); + $sessions = $user->getAttribute('sessions', []); - foreach ($tokens as $token) { /* @var $token Document */ - if ($sessionId == $token->getId()) { - if (!$projectDB->deleteDocument($token->getId())) { + foreach ($sessions as $session) { + /** @var Document $session */ + + if ($sessionId == $session->getId()) { + if (!$projectDB->deleteDocument($session->getId())) { throw new Exception('Failed to remove token from DB', 500); } @@ -474,10 +476,12 @@ App::delete('/v1/users/:userId/sessions') throw new Exception('User not found', 404); } - $tokens = $user->getAttribute('tokens', []); + $sessions = $user->getAttribute('sessions', []); - foreach ($tokens as $token) { /* @var $token Document */ - if (!$projectDB->deleteDocument($token->getId())) { + foreach ($sessions as $session) { + /** @var Document $session */ + + if (!$projectDB->deleteDocument($session->getId())) { throw new Exception('Failed to remove token from DB', 500); } } diff --git a/app/workers/deletes.php b/app/workers/deletes.php index 426dcf1ed6..cda60b78e5 100644 --- a/app/workers/deletes.php +++ b/app/workers/deletes.php @@ -112,13 +112,21 @@ class DeletesV1 protected function deleteUser(Document $document, $projectId) { $tokens = $document->getAttribute('tokens', []); - + foreach ($tokens as $token) { if (!$this->getProjectDB($projectId)->deleteDocument($token->getId())) { throw new Exception('Failed to remove token from DB'); } } + $sessions = $document->getAttribute('sessions', []); + + foreach ($sessions as $session) { + if (!$this->getProjectDB($projectId)->deleteDocument($session->getId())) { + throw new Exception('Failed to remove session from DB'); + } + } + // Delete Memberships $this->deleteByGroup([ '$collection='.Database::SYSTEM_COLLECTION_MEMBERSHIPS, diff --git a/src/Appwrite/Utopia/Response/Model/Session.php b/src/Appwrite/Utopia/Response/Model/Session.php index 4bc23ab79a..7db7fdee36 100644 --- a/src/Appwrite/Utopia/Response/Model/Session.php +++ b/src/Appwrite/Utopia/Response/Model/Session.php @@ -28,6 +28,24 @@ class Session extends Model 'default' => 0, 'example' => 1592981250, ]) + ->addRule('provider', [ + 'type' => self::TYPE_STRING, + 'description' => 'Session Provider.', + 'default' => 0, + 'example' => 1592981250, + ]) + ->addRule('providerUid', [ + 'type' => self::TYPE_STRING, + 'description' => 'Session Provider User ID.', + 'default' => 0, + 'example' => 1592981250, + ]) + ->addRule('providerToken', [ + 'type' => self::TYPE_STRING, + 'description' => 'Session Provider Token.', + 'default' => 0, + 'example' => 1592981250, + ]) ->addRule('ip', [ 'type' => self::TYPE_STRING, 'description' => 'IP in use when the session was created.', From 70666ddf0a0c65895057cda5fa7333ba61e5dc13 Mon Sep 17 00:00:00 2001 From: Torsten Dittmann Date: Fri, 19 Feb 2021 15:41:17 +0100 Subject: [PATCH 04/11] add current to sessions collection --- app/config/collections.php | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/app/config/collections.php b/app/config/collections.php index d88bb849aa..6abac72290 100644 --- a/app/config/collections.php +++ b/app/config/collections.php @@ -373,6 +373,15 @@ $collections = [ 'required' => true, 'array' => false, ], + [ + '$collection' => Database::SYSTEM_COLLECTION_RULES, + 'label' => 'Current', + 'key' => 'current', + 'type' => Database::SYSTEM_VAR_TYPE_BOOLEAN, + 'default' => false, + 'required' => true, + 'array' => false, + ], [ '$collection' => Database::SYSTEM_COLLECTION_RULES, 'label' => 'User Agent', From 19b85d7ae69bc3d597ce46fa9795f55e32999eda Mon Sep 17 00:00:00 2001 From: Torsten Dittmann Date: Fri, 19 Feb 2021 15:53:52 +0100 Subject: [PATCH 05/11] revert stupid change --- app/config/collections.php | 9 --------- 1 file changed, 9 deletions(-) diff --git a/app/config/collections.php b/app/config/collections.php index 6abac72290..d88bb849aa 100644 --- a/app/config/collections.php +++ b/app/config/collections.php @@ -373,15 +373,6 @@ $collections = [ 'required' => true, 'array' => false, ], - [ - '$collection' => Database::SYSTEM_COLLECTION_RULES, - 'label' => 'Current', - 'key' => 'current', - 'type' => Database::SYSTEM_VAR_TYPE_BOOLEAN, - 'default' => false, - 'required' => true, - 'array' => false, - ], [ '$collection' => Database::SYSTEM_COLLECTION_RULES, 'label' => 'User Agent', From 6dbc3966b2fd44cdb20aa73f1c1a1e647bb5060b Mon Sep 17 00:00:00 2001 From: Torsten Dittmann Date: Mon, 22 Feb 2021 12:27:31 +0100 Subject: [PATCH 06/11] adds migration and migration tests --- src/Appwrite/Migration/Version/V07.php | 70 +++++++++++++++++++++++ tests/unit/Migration/MigrationV07Test.php | 69 ++++++++++++++++++++++ 2 files changed, 139 insertions(+) create mode 100644 src/Appwrite/Migration/Version/V07.php create mode 100644 tests/unit/Migration/MigrationV07Test.php diff --git a/src/Appwrite/Migration/Version/V07.php b/src/Appwrite/Migration/Version/V07.php new file mode 100644 index 0000000000..0b97a83f80 --- /dev/null +++ b/src/Appwrite/Migration/Version/V07.php @@ -0,0 +1,70 @@ +db; + $project = $this->project; + Console::log('Migrating project: ' . $project->getAttribute('name') . ' (' . $project->getId() . ')'); + + $this->forEachDocument([$this, 'fixDocument']); + } + + protected function fixDocument(Document $document) + { + $providers = Config::getParam('providers'); + + switch ($document->getAttribute('$collection')) { + case Database::SYSTEM_COLLECTION_USERS: + foreach ($providers as $key => $provider) { + /** + * Remove deprecated OAuth2 properties in the Users Documents. + */ + if (!empty($document->getAttribute('oauth2' . \ucfirst($key)))) { + $document->removeAttribute('oauth2' . \ucfirst($key)); + } + + if (!empty($document->getAttribute('oauth2' . \ucfirst($key) . 'AccessToken'))) { + $document->removeAttribute('oauth2' . \ucfirst($key) . 'AccessToken'); + } + + /** + * Invalidate all Login Tokens, since they can't be migrated to the new structure. + * Reason for it is the missing distinction between E-Mail and OAuth2 tokens. + */ + $tokens = array_filter($document->getAttribute('tokens', []), function($token) { + return ($token->getAttribute('type') != Auth::TOKEN_TYPE_LOGIN); + }); + + $document->setAttribute('tokens', array_values($tokens)); + } + break; + } + + foreach ($document as &$attr) { // Handle child documents + if ($attr instanceof Document) { + $attr = $this->fixDocument($attr); + } + + if (\is_array($attr)) { + foreach ($attr as &$child) { + if ($child instanceof Document) { + $child = $this->fixDocument($child); + } + } + } + } + + return $document; + } +} diff --git a/tests/unit/Migration/MigrationV07Test.php b/tests/unit/Migration/MigrationV07Test.php new file mode 100644 index 0000000000..ca73c3229d --- /dev/null +++ b/tests/unit/Migration/MigrationV07Test.php @@ -0,0 +1,69 @@ +pdo = new \PDO('sqlite::memory:'); + $this->migration = new V07($this->pdo); + $reflector = new ReflectionClass('Appwrite\Migration\Version\V07'); + $this->method = $reflector->getMethod('fixDocument'); + $this->method->setAccessible(true); + } + + public function testMigration() + { + $document = $this->fixDocument(new Document([ + '$id' => 'unique', + '$collection' => Database::SYSTEM_COLLECTION_USERS, + 'oauth2Github' => 123, + 'oauth2GithubAccessToken' => 456, + 'tokens' => [ + new Document([ + '$collection' => Database::SYSTEM_COLLECTION_TOKENS, + 'userId' => 'unique', + 'type' => Auth::TOKEN_TYPE_LOGIN, + 'secret' => 'login', + ]), + new Document([ + '$collection' => Database::SYSTEM_COLLECTION_TOKENS, + 'userId' => 'unique', + 'type' => Auth::TOKEN_TYPE_INVITE, + 'secret' => 'invite', + ]), + new Document([ + '$collection' => Database::SYSTEM_COLLECTION_TOKENS, + 'userId' => 'unique', + 'type' => Auth::TOKEN_TYPE_RECOVERY, + 'secret' => 'recovery', + ]), + new Document([ + '$collection' => Database::SYSTEM_COLLECTION_TOKENS, + 'userId' => 'unique', + 'type' => Auth::TOKEN_TYPE_VERIFICATION, + 'secret' => 'verification', + ]), + ] + ])); + + $this->assertEquals($document->getAttribute('oauth2Github', null), null); + $this->assertEquals($document->getAttribute('oauth2GithubAccessToken', null), null); + + $this->assertCount(3, $document->getAttribute('tokens', [])); + $this->assertEquals(Auth::TOKEN_TYPE_INVITE, $document->getAttribute('tokens', [])[0]['type']); + $this->assertEquals(Auth::TOKEN_TYPE_RECOVERY, $document->getAttribute('tokens', [])[1]['type']); + $this->assertEquals(Auth::TOKEN_TYPE_VERIFICATION, $document->getAttribute('tokens', [])[2]['type']); + + } +} From 7aab693d66264b526751c419810d5ea47c06b7de Mon Sep 17 00:00:00 2001 From: Torsten Dittmann Date: Mon, 22 Feb 2021 13:03:34 +0100 Subject: [PATCH 07/11] remove duplicate secret prop from session collection --- app/config/collections.php | 9 --------- 1 file changed, 9 deletions(-) diff --git a/app/config/collections.php b/app/config/collections.php index d88bb849aa..130c57bd7c 100644 --- a/app/config/collections.php +++ b/app/config/collections.php @@ -319,15 +319,6 @@ $collections = [ 'required' => true, 'array' => false, ], - [ - '$collection' => Database::SYSTEM_COLLECTION_RULES, - 'label' => 'Secret', - 'key' => 'secret', - 'type' => Database::SYSTEM_VAR_TYPE_TEXT, - 'default' => '', - 'required' => true, - 'array' => false, - ], [ '$collection' => Database::SYSTEM_COLLECTION_RULES, 'label' => 'Provider', From e388cb462b069c2b8f40a6454aadb71f27ae87ab Mon Sep 17 00:00:00 2001 From: Torsten Dittmann Date: Mon, 22 Feb 2021 13:44:47 +0100 Subject: [PATCH 08/11] check duplicate collection rules --- tests/unit/General/CollectionsTest.php | 36 ++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) create mode 100644 tests/unit/General/CollectionsTest.php diff --git a/tests/unit/General/CollectionsTest.php b/tests/unit/General/CollectionsTest.php new file mode 100644 index 0000000000..bf7aea7c0c --- /dev/null +++ b/tests/unit/General/CollectionsTest.php @@ -0,0 +1,36 @@ +collections = require('app/config/collections.php'); + } + + public function tearDown(): void + { + } + + public function testDuplicateRules() + { + foreach ($this->collections as $collection) { + if ($collection['rules']) { + foreach ($collection['rules'] as $check) { + $occurences = 0; + foreach ($collection['rules'] as $rule) { + if ($rule['key'] == $check['key']) { + $occurences++; + } + } + $this->assertEquals(1, $occurences); + } + } + } + } +} From ceeb30fd4f444ed369950c32d1e2e6ab5eaf160d Mon Sep 17 00:00:00 2001 From: Torsten Dittmann Date: Mon, 29 Mar 2021 11:16:56 +0200 Subject: [PATCH 09/11] adapt to anon login --- app/config/collections.php | 2 +- app/controllers/api/account.php | 6 +++--- src/Appwrite/Utopia/Response/Model/Session.php | 12 ++++++------ 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/app/config/collections.php b/app/config/collections.php index 5d6c2d6491..d023cae514 100644 --- a/app/config/collections.php +++ b/app/config/collections.php @@ -334,7 +334,7 @@ $collections = [ 'key' => 'providerUid', 'type' => Database::SYSTEM_VAR_TYPE_TEXT, 'default' => '', - 'required' => true, + 'required' => false, 'array' => false, ], [ diff --git a/app/controllers/api/account.php b/app/controllers/api/account.php index 20043177b0..b2f382c895 100644 --- a/app/controllers/api/account.php +++ b/app/controllers/api/account.php @@ -650,10 +650,10 @@ App::post('/v1/account/sessions/anonymous') $expiry = \time() + Auth::TOKEN_EXPIRATION_LOGIN_LONG; $session = new Document(array_merge( [ - '$collection' => Database::SYSTEM_COLLECTION_TOKENS, + '$collection' => Database::SYSTEM_COLLECTION_SESSIONS, '$permissions' => ['read' => ['user:' . $user['$id']], 'write' => ['user:' . $user['$id']]], 'userId' => $user->getId(), - 'type' => Auth::TOKEN_TYPE_LOGIN, + 'provider' => Auth::SESSION_PROVIDER_ANONYMOUS, 'secret' => Auth::hash($secret), // One way hash encryption to protect DB leak 'expire' => $expiry, 'userAgent' => $request->getUserAgent('UNKNOWN'), @@ -665,7 +665,7 @@ App::post('/v1/account/sessions/anonymous') $detector->getDevice() )); - $user->setAttribute('tokens', $session, Document::SET_TYPE_APPEND); + $user->setAttribute('sessions', $session, Document::SET_TYPE_APPEND); Authorization::setRole('user:'.$user->getId()); diff --git a/src/Appwrite/Utopia/Response/Model/Session.php b/src/Appwrite/Utopia/Response/Model/Session.php index 7db7fdee36..d79d6cddc5 100644 --- a/src/Appwrite/Utopia/Response/Model/Session.php +++ b/src/Appwrite/Utopia/Response/Model/Session.php @@ -31,20 +31,20 @@ class Session extends Model ->addRule('provider', [ 'type' => self::TYPE_STRING, 'description' => 'Session Provider.', - 'default' => 0, - 'example' => 1592981250, + 'default' => '', + 'example' => 'email', ]) ->addRule('providerUid', [ 'type' => self::TYPE_STRING, 'description' => 'Session Provider User ID.', - 'default' => 0, - 'example' => 1592981250, + 'default' => '', + 'example' => 'user@example.com', ]) ->addRule('providerToken', [ 'type' => self::TYPE_STRING, 'description' => 'Session Provider Token.', - 'default' => 0, - 'example' => 1592981250, + 'default' => '', + 'example' => '1592981250', ]) ->addRule('ip', [ 'type' => self::TYPE_STRING, From f5fa640e68366ec21082a990d840e6956a385c80 Mon Sep 17 00:00:00 2001 From: Torsten Dittmann Date: Mon, 29 Mar 2021 12:29:18 +0200 Subject: [PATCH 10/11] remove providerUid on session verification for anon login --- src/Appwrite/Auth/Auth.php | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Appwrite/Auth/Auth.php b/src/Appwrite/Auth/Auth.php index 18a2837f5a..1e8dbc93d8 100644 --- a/src/Appwrite/Auth/Auth.php +++ b/src/Appwrite/Auth/Auth.php @@ -227,7 +227,6 @@ class Auth if ($session->isSet('secret') && $session->isSet('expire') && $session->isSet('provider') && - $session->isSet('providerUid') && $session->getAttribute('secret') === self::hash($secret) && $session->getAttribute('expire') >= \time()) { return (string)$session->getId(); From df69799ebb6dd2074ae26fe6395e638a0092ee38 Mon Sep 17 00:00:00 2001 From: Torsten Dittmann Date: Mon, 29 Mar 2021 13:22:50 +0200 Subject: [PATCH 11/11] adapt to review --- src/Appwrite/Utopia/Response/Model/Session.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Appwrite/Utopia/Response/Model/Session.php b/src/Appwrite/Utopia/Response/Model/Session.php index d79d6cddc5..f431f3f431 100644 --- a/src/Appwrite/Utopia/Response/Model/Session.php +++ b/src/Appwrite/Utopia/Response/Model/Session.php @@ -44,7 +44,7 @@ class Session extends Model 'type' => self::TYPE_STRING, 'description' => 'Session Provider Token.', 'default' => '', - 'example' => '1592981250', + 'example' => 'MTQ0NjJkZmQ5OTM2NDE1ZTZjNGZmZjI3', ]) ->addRule('ip', [ 'type' => self::TYPE_STRING,