diff --git a/app/config/locale/templates/email-mfa-challenge.tpl b/app/config/locale/templates/email-mfa-challenge.tpl
index cf09448ca5..e3cb6b444d 100644
--- a/app/config/locale/templates/email-mfa-challenge.tpl
+++ b/app/config/locale/templates/email-mfa-challenge.tpl
@@ -5,7 +5,7 @@
diff --git a/app/controllers/api/account.php b/app/controllers/api/account.php
index 90a35ede78..f379dd3023 100644
--- a/app/controllers/api/account.php
+++ b/app/controllers/api/account.php
@@ -1069,17 +1069,15 @@ App::get('/v1/account/sessions/oauth2/callback/:provider/:projectId')
$domain = $request->getHostname();
$protocol = $request->getProtocol();
+ $params = $request->getParams();
+ $params['project'] = $projectId;
+ unset($params['projectId']);
+
$response
->addHeader('Cache-Control', 'no-store, no-cache, must-revalidate, max-age=0')
->addHeader('Pragma', 'no-cache')
->redirect($protocol . '://' . $domain . '/v1/account/sessions/oauth2/' . $provider . '/redirect?'
- . \http_build_query([
- 'project' => $projectId,
- 'code' => $code,
- 'state' => $state,
- 'error' => $error,
- 'error_description' => $error_description
- ]));
+ . \http_build_query($params));
});
App::post('/v1/account/sessions/oauth2/callback/:provider/:projectId')
@@ -1102,17 +1100,15 @@ App::post('/v1/account/sessions/oauth2/callback/:provider/:projectId')
$domain = $request->getHostname();
$protocol = $request->getProtocol();
+ $params = $request->getParams();
+ $params['project'] = $projectId;
+ unset($params['projectId']);
+
$response
->addHeader('Cache-Control', 'no-store, no-cache, must-revalidate, max-age=0')
->addHeader('Pragma', 'no-cache')
->redirect($protocol . '://' . $domain . '/v1/account/sessions/oauth2/' . $provider . '/redirect?'
- . \http_build_query([
- 'project' => $projectId,
- 'code' => $code,
- 'state' => $state,
- 'error' => $error,
- 'error_description' => $error_description
- ]));
+ . \http_build_query($params));
});
App::get('/v1/account/sessions/oauth2/:provider/redirect')
@@ -1239,7 +1235,17 @@ App::get('/v1/account/sessions/oauth2/:provider/redirect')
$failureRedirect(Exception::USER_MISSING_ID);
}
- $name = $oauth2->getUserName($accessToken);
+ $name = '';
+ $nameOAuth = $oauth2->getUserName($accessToken);
+ $userParam = \json_decode($request->getParam('user'), true);
+ if (!empty($nameOAuth)) {
+ $name = $nameOAuth;
+ } elseif (is_array($userParam)) {
+ $nameParam = $userParam['name'];
+ if (is_array($nameParam) && isset($nameParam['firstName']) && isset($nameParam['lastName'])) {
+ $name = $nameParam['firstName'] . ' ' . $nameParam['lastName'];
+ }
+ }
$email = $oauth2->getUserEmail($accessToken);
// Check if this identity is connected to a different user
@@ -3495,14 +3501,33 @@ App::patch('/v1/account/mfa')
->inject('requestTimestamp')
->inject('response')
->inject('user')
+ ->inject('session')
->inject('dbForProject')
->inject('queueForEvents')
- ->action(function (bool $mfa, ?\DateTime $requestTimestamp, Response $response, Document $user, Database $dbForProject, Event $queueForEvents) {
+ ->action(function (bool $mfa, ?\DateTime $requestTimestamp, Response $response, Document $user, Document $session, Database $dbForProject, Event $queueForEvents) {
$user->setAttribute('mfa', $mfa);
$user = $dbForProject->withRequestTimestamp($requestTimestamp, fn () => $dbForProject->updateDocument('users', $user->getId(), $user));
+ if ($mfa) {
+ $factors = $session->getAttribute('factors', []);
+ $totp = TOTP::getAuthenticatorFromUser($user);
+ if ($totp !== null && $totp->getAttribute('verified', false)) {
+ $factors[] = Type::TOTP;
+ }
+ if ($user->getAttribute('email', false) && $user->getAttribute('emailVerification', false)) {
+ $factors[] = Type::EMAIL;
+ }
+ if ($user->getAttribute('phone', false) && $user->getAttribute('phoneVerification', false)) {
+ $factors[] = Type::PHONE;
+ }
+ $factors = \array_unique($factors);
+
+ $session->setAttribute('factors', $factors);
+ $dbForProject->updateDocument('sessions', $session->getId(), $session);
+ }
+
$queueForEvents->setParam('userId', $user->getId());
$response->dynamic($user, Response::MODEL_ACCOUNT);
@@ -3633,10 +3658,10 @@ App::put('/v1/account/mfa/authenticators/:type')
->param('otp', '', new Text(256), 'Valid verification token.')
->inject('response')
->inject('user')
- ->inject('project')
+ ->inject('session')
->inject('dbForProject')
->inject('queueForEvents')
- ->action(function (string $type, string $otp, Response $response, Document $user, Document $project, Database $dbForProject, Event $queueForEvents) {
+ ->action(function (string $type, string $otp, Response $response, Document $user, Document $session, Database $dbForProject, Event $queueForEvents) {
$authenticator = (match ($type) {
Type::TOTP => TOTP::getAuthenticatorFromUser($user),
@@ -3665,10 +3690,12 @@ App::put('/v1/account/mfa/authenticators/:type')
$dbForProject->updateDocument('authenticators', $authenticator->getId(), $authenticator);
$dbForProject->purgeCachedDocument('users', $user->getId());
- $authDuration = $project->getAttribute('auths', [])['duration'] ?? Auth::TOKEN_EXPIRATION_LOGIN_LONG;
- $sessionId = Auth::sessionVerify($user->getAttribute('sessions', []), Auth::$secret, $authDuration);
- $session = $dbForProject->getDocument('sessions', $sessionId);
- $dbForProject->updateDocument('sessions', $sessionId, $session->setAttribute('factors', $type, Document::SET_TYPE_APPEND));
+ $factors = $session->getAttribute('factors', []);
+ $factors[] = $type;
+ $factors = \array_unique($factors);
+
+ $session->setAttribute('factors', $factors);
+ $dbForProject->updateDocument('sessions', $session->getId(), $session);
$queueForEvents->setParam('userId', $user->getId());
@@ -4057,9 +4084,10 @@ App::put('/v1/account/mfa/challenge')
->inject('project')
->inject('response')
->inject('user')
+ ->inject('session')
->inject('dbForProject')
->inject('queueForEvents')
- ->action(function (string $challengeId, string $otp, Document $project, Response $response, Document $user, Database $dbForProject, Event $queueForEvents) {
+ ->action(function (string $challengeId, string $otp, Document $project, Response $response, Document $user, Document $session, Database $dbForProject, Event $queueForEvents) {
$challenge = $dbForProject->getDocument('challenges', $challengeId);
@@ -4105,15 +4133,15 @@ App::put('/v1/account/mfa/challenge')
$dbForProject->deleteDocument('challenges', $challengeId);
$dbForProject->purgeCachedDocument('users', $user->getId());
- $authDuration = $project->getAttribute('auths', [])['duration'] ?? Auth::TOKEN_EXPIRATION_LOGIN_LONG;
- $sessionId = Auth::sessionVerify($user->getAttribute('sessions', []), Auth::$secret, $authDuration);
- $session = $dbForProject->getDocument('sessions', $sessionId);
+ $factors = $session->getAttribute('factors', []);
+ $factors[] = $type;
+ $factors = \array_unique($factors);
- $session = $session
- ->setAttribute('factors', $type, Document::SET_TYPE_APPEND)
+ $session
+ ->setAttribute('factors', $factors)
->setAttribute('mfaUpdatedAt', DateTime::now());
- $dbForProject->updateDocument('sessions', $sessionId, $session);
+ $dbForProject->updateDocument('sessions', $session->getId(), $session);
$queueForEvents
->setParam('userId', $user->getId())
diff --git a/app/controllers/api/project.php b/app/controllers/api/project.php
index 208e288614..a3e07927d6 100644
--- a/app/controllers/api/project.php
+++ b/app/controllers/api/project.php
@@ -70,7 +70,7 @@ App::get('/v1/project/usage')
'1d' => 'Y-m-d\T00:00:00.000P',
};
- Authorization::skip(function () use ($dbForProject, $firstDay, $lastDay, $period, $metrics, &$total, &$stats) {
+ Authorization::skip(function () use ($dbForProject, $firstDay, $lastDay, $period, $metrics, $limit, &$total, &$stats) {
foreach ($metrics['total'] as $metric) {
$result = $dbForProject->findOne('stats', [
Query::equal('metric', [$metric]),
@@ -85,6 +85,7 @@ App::get('/v1/project/usage')
Query::equal('period', [$period]),
Query::greaterThanEqual('time', $firstDay),
Query::lessThan('time', $lastDay),
+ Query::limit($limit),
Query::orderDesc('time'),
]);
diff --git a/app/controllers/general.php b/app/controllers/general.php
index 85c76bd820..618f0b465c 100644
--- a/app/controllers/general.php
+++ b/app/controllers/general.php
@@ -750,12 +750,12 @@ App::error()
'file' => $file,
'line' => $line,
'trace' => \json_encode($trace, JSON_UNESCAPED_UNICODE) === false ? [] : $trace, // check for failing encode
- 'version' => $version,
+ 'version' => APP_VERSION_STABLE,
'type' => $type,
] : [
'message' => $message,
'code' => $code,
- 'version' => $version,
+ 'version' => APP_VERSION_STABLE,
'type' => $type,
];
diff --git a/app/init.php b/app/init.php
index 5165f64d7f..8bf5d682cd 100644
--- a/app/init.php
+++ b/app/init.php
@@ -1239,14 +1239,13 @@ App::setResource('project', function ($dbForConsole, $request, $console) {
return $project;
}, ['dbForConsole', 'request', 'console']);
-App::setResource('session', function (Document $user, Document $project) {
+App::setResource('session', function (Document $user) {
if ($user->isEmpty()) {
return;
}
$sessions = $user->getAttribute('sessions', []);
- $authDuration = $project->getAttribute('auths', [])['duration'] ?? Auth::TOKEN_EXPIRATION_LOGIN_LONG;
- $sessionId = Auth::sessionVerify($user->getAttribute('sessions'), Auth::$secret, $authDuration);
+ $sessionId = Auth::sessionVerify($user->getAttribute('sessions'), Auth::$secret);
if (!$sessionId) {
return;
@@ -1259,7 +1258,7 @@ App::setResource('session', function (Document $user, Document $project) {
}
return;
-}, ['user', 'project']);
+}, ['user']);
App::setResource('console', function () {
return new Document([
diff --git a/src/Appwrite/Auth/OAuth2/Apple.php b/src/Appwrite/Auth/OAuth2/Apple.php
index 2abf61c947..0b4ec50881 100644
--- a/src/Appwrite/Auth/OAuth2/Apple.php
+++ b/src/Appwrite/Auth/OAuth2/Apple.php
@@ -160,15 +160,6 @@ class Apple extends OAuth2
*/
public function getUserName(string $accessToken): string
{
- if (
- isset($this->claims['email']) &&
- !empty($this->claims['email']) &&
- isset($this->claims['email_verified']) &&
- $this->claims['email_verified'] === 'true'
- ) {
- return $this->claims['email'];
- }
-
return '';
}