mirror of
https://github.com/appwrite/appwrite
synced 2026-05-05 22:38:37 +00:00
changes
This commit is contained in:
parent
b91268b3cd
commit
b20c493fa6
13 changed files with 515 additions and 22 deletions
|
|
@ -1,6 +1,6 @@
|
|||
<?php
|
||||
|
||||
namespace Appwrite\Platform\Modules\Account\Http\Mfa\Authenticators;
|
||||
namespace Appwrite\Platform\Modules\Account\Http\Account\MFA\Authenticators;
|
||||
|
||||
use Appwrite\Auth\MFA\Type;
|
||||
use Appwrite\Auth\MFA\Type\TOTP;
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
<?php
|
||||
|
||||
namespace Appwrite\Platform\Modules\Account\Http\Mfa\Authenticators;
|
||||
namespace Appwrite\Platform\Modules\Account\Http\Account\MFA\Authenticators;
|
||||
|
||||
use Appwrite\Auth\MFA\Type;
|
||||
use Appwrite\Auth\MFA\Type\TOTP;
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
<?php
|
||||
|
||||
namespace Appwrite\Platform\Modules\Account\Http\Mfa\Authenticators;
|
||||
namespace Appwrite\Platform\Modules\Account\Http\Account\MFA\Authenticators;
|
||||
|
||||
use Appwrite\Auth\MFA\Challenge;
|
||||
use Appwrite\Auth\MFA\Type;
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
<?php
|
||||
|
||||
namespace Appwrite\Platform\Modules\Account\Http\Mfa\Challenge;
|
||||
namespace Appwrite\Platform\Modules\Account\Http\Mfa\Challenges;
|
||||
|
||||
use Appwrite\Auth\Auth;
|
||||
use Appwrite\Auth\MFA\Type;
|
||||
|
|
@ -44,7 +44,8 @@ class Create extends Action
|
|||
{
|
||||
$this
|
||||
->setHttpMethod(Action::HTTP_REQUEST_METHOD_POST)
|
||||
->setHttpPath('/v1/account/mfa/challenge')
|
||||
->setHttpPath('/v1/account/mfa/challenges')
|
||||
->httpAlias('/v1/account/mfa/challenge')
|
||||
->desc('Create MFA challenge')
|
||||
->groups(['api', 'account', 'mfa'])
|
||||
->label('scope', 'account')
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
<?php
|
||||
|
||||
namespace Appwrite\Platform\Modules\Account\Http\Mfa\Challenge;
|
||||
namespace Appwrite\Platform\Modules\Account\Http\Mfa\Challenges;
|
||||
|
||||
use Appwrite\Auth\MFA\Challenge;
|
||||
use Appwrite\Auth\MFA\Type;
|
||||
|
|
@ -32,7 +32,8 @@ class Update extends Action
|
|||
{
|
||||
$this
|
||||
->setHttpMethod(Action::HTTP_REQUEST_METHOD_PUT)
|
||||
->setHttpPath('/v1/account/mfa/challenge')
|
||||
->setHttpPath('/v1/account/mfa/challenges')
|
||||
->httpAlias('/v1/account/mfa/challenge')
|
||||
->desc('Update MFA challenge (confirmation)')
|
||||
->groups(['api', 'account', 'mfa'])
|
||||
->label('scope', 'account')
|
||||
|
|
@ -0,0 +1,330 @@
|
|||
<?php
|
||||
|
||||
namespace Appwrite\Platform\Modules\Account\Http\Account\MFA\Challenges;
|
||||
|
||||
use Appwrite\Auth\Auth;
|
||||
use Appwrite\Auth\MFA\Type;
|
||||
use Appwrite\Detector\Detector;
|
||||
use Appwrite\Event\Event;
|
||||
use Appwrite\Event\Mail;
|
||||
use Appwrite\Event\Messaging;
|
||||
use Appwrite\Event\StatsUsage;
|
||||
use Appwrite\Extend\Exception;
|
||||
use Appwrite\SDK\ContentType;
|
||||
use Appwrite\SDK\Deprecated;
|
||||
use Appwrite\SDK\Method;
|
||||
use Appwrite\SDK\Response as SDKResponse;
|
||||
use Appwrite\Template\Template;
|
||||
use Appwrite\Utopia\Request;
|
||||
use Appwrite\Utopia\Response;
|
||||
use libphonenumber\PhoneNumberUtil;
|
||||
use Utopia\Abuse\Abuse;
|
||||
use Utopia\Database\Database;
|
||||
use Utopia\Database\DateTime;
|
||||
use Utopia\Database\Document;
|
||||
use Utopia\Database\Helpers\Permission;
|
||||
use Utopia\Database\Helpers\Role;
|
||||
use Utopia\Locale\Locale;
|
||||
use Utopia\Platform\Action;
|
||||
use Utopia\Platform\Scope\HTTP;
|
||||
use Utopia\Storage\Validator\FileName;
|
||||
use Utopia\System\System;
|
||||
use Utopia\Validator\WhiteList;
|
||||
|
||||
class Create extends Action
|
||||
{
|
||||
use HTTP;
|
||||
|
||||
public static function getName(): string
|
||||
{
|
||||
return 'createMFAChallenge';
|
||||
}
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this
|
||||
->setHttpMethod(Action::HTTP_REQUEST_METHOD_POST)
|
||||
->setHttpPath('/v1/account/mfa/challenges')
|
||||
->httpAlias('/v1/account/mfa/challenge')
|
||||
->desc('Create MFA challenge')
|
||||
->groups(['api', 'account', 'mfa'])
|
||||
->label('scope', 'account')
|
||||
->label('event', 'users.[userId].challenges.[challengeId].create')
|
||||
->label('audits.event', 'challenge.create')
|
||||
->label('audits.resource', 'user/{response.userId}')
|
||||
->label('audits.userId', '{response.userId}')
|
||||
->label('sdk', [
|
||||
new Method(
|
||||
namespace: 'account',
|
||||
group: 'mfa',
|
||||
name: 'createMfaChallenge',
|
||||
description: '/docs/references/account/create-mfa-challenge.md',
|
||||
auth: [],
|
||||
responses: [
|
||||
new SDKResponse(
|
||||
code: Response::STATUS_CODE_CREATED,
|
||||
model: Response::MODEL_MFA_CHALLENGE,
|
||||
)
|
||||
],
|
||||
contentType: ContentType::JSON,
|
||||
deprecated: new Deprecated(
|
||||
since: '1.8.0',
|
||||
replaceWith: 'account.createMFAChallenge',
|
||||
),
|
||||
),
|
||||
new Method(
|
||||
namespace: 'account',
|
||||
group: 'mfa',
|
||||
name: 'createMFAChallenge',
|
||||
description: '/docs/references/account/create-mfa-challenge.md',
|
||||
auth: [],
|
||||
responses: [
|
||||
new SDKResponse(
|
||||
code: Response::STATUS_CODE_CREATED,
|
||||
model: Response::MODEL_MFA_CHALLENGE,
|
||||
)
|
||||
],
|
||||
contentType: ContentType::JSON
|
||||
)
|
||||
])
|
||||
->label('abuse-limit', 10)
|
||||
->label('abuse-key', 'url:{url},userId:{userId}')
|
||||
->param('factor', '', new WhiteList([Type::EMAIL, Type::PHONE, Type::TOTP, Type::RECOVERY_CODE]), 'Factor used for verification. Must be one of following: `' . Type::EMAIL . '`, `' . Type::PHONE . '`, `' . Type::TOTP . '`, `' . Type::RECOVERY_CODE . '`.')
|
||||
->inject('response')
|
||||
->inject('dbForProject')
|
||||
->inject('user')
|
||||
->inject('locale')
|
||||
->inject('project')
|
||||
->inject('request')
|
||||
->inject('queueForEvents')
|
||||
->inject('queueForMessaging')
|
||||
->inject('queueForMails')
|
||||
->inject('timelimit')
|
||||
->inject('queueForStatsUsage')
|
||||
->inject('plan')
|
||||
->callback($this->action(...));
|
||||
}
|
||||
|
||||
public function action(
|
||||
string $factor,
|
||||
Response $response,
|
||||
Database $dbForProject,
|
||||
Document $user,
|
||||
Locale $locale,
|
||||
Document $project,
|
||||
Request $request,
|
||||
Event $queueForEvents,
|
||||
Messaging $queueForMessaging,
|
||||
Mail $queueForMails,
|
||||
callable $timelimit,
|
||||
StatsUsage $queueForStatsUsage,
|
||||
array $plan
|
||||
): void {
|
||||
$expire = DateTime::formatTz(DateTime::addSeconds(new \DateTime(), Auth::TOKEN_EXPIRATION_CONFIRM));
|
||||
$code = Auth::codeGenerator();
|
||||
$challenge = new Document([
|
||||
'userId' => $user->getId(),
|
||||
'userInternalId' => $user->getSequence(),
|
||||
'type' => $factor,
|
||||
'token' => Auth::tokenGenerator(),
|
||||
'code' => $code,
|
||||
'expire' => $expire,
|
||||
'$permissions' => [
|
||||
Permission::read(Role::user($user->getId())),
|
||||
Permission::update(Role::user($user->getId())),
|
||||
Permission::delete(Role::user($user->getId())),
|
||||
],
|
||||
]);
|
||||
|
||||
$challenge = $dbForProject->createDocument('challenges', $challenge);
|
||||
|
||||
$templatesPath = \dirname(__DIR__, 7) . '/app/config/locale/templates';
|
||||
|
||||
switch ($factor) {
|
||||
case Type::PHONE:
|
||||
if (empty(System::getEnv('_APP_SMS_PROVIDER'))) {
|
||||
throw new Exception(Exception::GENERAL_PHONE_DISABLED, 'Phone provider not configured');
|
||||
}
|
||||
if (empty($user->getAttribute('phone'))) {
|
||||
throw new Exception(Exception::USER_PHONE_NOT_FOUND);
|
||||
}
|
||||
if (!$user->getAttribute('phoneVerification')) {
|
||||
throw new Exception(Exception::USER_PHONE_NOT_VERIFIED);
|
||||
}
|
||||
|
||||
$message = Template::fromFile($templatesPath . '/sms-base.tpl');
|
||||
|
||||
$customTemplate = $project->getAttribute('templates', [])['sms.mfaChallenge-' . $locale->default] ?? [];
|
||||
if (!empty($customTemplate)) {
|
||||
$message = $customTemplate['message'] ?? $message;
|
||||
}
|
||||
|
||||
$messageContent = Template::fromString($locale->getText("sms.verification.body"));
|
||||
$messageContent
|
||||
->setParam('{{project}}', $project->getAttribute('name'))
|
||||
->setParam('{{secret}}', $code);
|
||||
$messageContent = \strip_tags($messageContent->render());
|
||||
$message = $message->setParam('{{token}}', $messageContent);
|
||||
|
||||
$message = $message->render();
|
||||
|
||||
$phone = $user->getAttribute('phone');
|
||||
$queueForMessaging
|
||||
->setType(MESSAGE_SEND_TYPE_INTERNAL)
|
||||
->setMessage(new Document([
|
||||
'$id' => $challenge->getId(),
|
||||
'data' => [
|
||||
'content' => $code,
|
||||
],
|
||||
]))
|
||||
->setRecipients([$phone])
|
||||
->setProviderType(MESSAGE_TYPE_SMS);
|
||||
|
||||
if (isset($plan['authPhone'])) {
|
||||
$timelimit = $timelimit('organization:{organizationId}', $plan['authPhone'], 30 * 24 * 60 * 60); // 30 days
|
||||
$timelimit
|
||||
->setParam('{organizationId}', $project->getAttribute('teamId'));
|
||||
|
||||
$abuse = new Abuse($timelimit);
|
||||
if ($abuse->check() && System::getEnv('_APP_OPTIONS_ABUSE', 'enabled') === 'enabled') {
|
||||
$helper = PhoneNumberUtil::getInstance();
|
||||
$countryCode = $helper->parse($phone)->getCountryCode();
|
||||
|
||||
if (!empty($countryCode)) {
|
||||
$queueForStatsUsage
|
||||
->addMetric(str_replace('{countryCode}', $countryCode, METRIC_AUTH_METHOD_PHONE_COUNTRY_CODE), 1);
|
||||
}
|
||||
}
|
||||
$queueForStatsUsage
|
||||
->addMetric(METRIC_AUTH_METHOD_PHONE, 1)
|
||||
->setProject($project)
|
||||
->trigger();
|
||||
}
|
||||
break;
|
||||
case Type::EMAIL:
|
||||
if (empty(System::getEnv('_APP_SMTP_HOST'))) {
|
||||
throw new Exception(Exception::GENERAL_SMTP_DISABLED, 'SMTP disabled');
|
||||
}
|
||||
if (empty($user->getAttribute('email'))) {
|
||||
throw new Exception(Exception::USER_EMAIL_NOT_FOUND);
|
||||
}
|
||||
if (!$user->getAttribute('emailVerification')) {
|
||||
throw new Exception(Exception::USER_EMAIL_NOT_VERIFIED);
|
||||
}
|
||||
|
||||
$subject = $locale->getText("emails.mfaChallenge.subject");
|
||||
$preview = $locale->getText("emails.mfaChallenge.preview");
|
||||
$heading = $locale->getText("emails.mfaChallenge.heading");
|
||||
|
||||
$customTemplate = $project->getAttribute('templates', [])['email.mfaChallenge-' . $locale->default] ?? [];
|
||||
$smtpBaseTemplate = $project->getAttribute('smtpBaseTemplate', 'email-base');
|
||||
|
||||
$validator = new FileName();
|
||||
if (!$validator->isValid($smtpBaseTemplate)) {
|
||||
throw new Exception(Exception::GENERAL_BAD_REQUEST, 'Invalid template path');
|
||||
}
|
||||
|
||||
$bodyTemplate = $templatesPath . '/' . $smtpBaseTemplate . '.tpl';
|
||||
|
||||
$detector = new Detector($request->getUserAgent('UNKNOWN'));
|
||||
$agentOs = $detector->getOS();
|
||||
$agentClient = $detector->getClient();
|
||||
$agentDevice = $detector->getDevice();
|
||||
|
||||
$message = Template::fromFile($templatesPath . '/email-mfa-challenge.tpl');
|
||||
$message
|
||||
->setParam('{{hello}}', $locale->getText("emails.mfaChallenge.hello"))
|
||||
->setParam('{{description}}', $locale->getText("emails.mfaChallenge.description"))
|
||||
->setParam('{{clientInfo}}', $locale->getText("emails.mfaChallenge.clientInfo"))
|
||||
->setParam('{{thanks}}', $locale->getText("emails.mfaChallenge.thanks"))
|
||||
->setParam('{{signature}}', $locale->getText("emails.mfaChallenge.signature"));
|
||||
|
||||
$body = $message->render();
|
||||
|
||||
$smtp = $project->getAttribute('smtp', []);
|
||||
$smtpEnabled = $smtp['enabled'] ?? false;
|
||||
|
||||
$senderEmail = System::getEnv('_APP_SYSTEM_EMAIL_ADDRESS', APP_EMAIL_TEAM);
|
||||
$senderName = System::getEnv('_APP_SYSTEM_EMAIL_NAME', APP_NAME . ' Server');
|
||||
$replyTo = "";
|
||||
|
||||
if ($smtpEnabled) {
|
||||
if (!empty($smtp['senderEmail'])) {
|
||||
$senderEmail = $smtp['senderEmail'];
|
||||
}
|
||||
if (!empty($smtp['senderName'])) {
|
||||
$senderName = $smtp['senderName'];
|
||||
}
|
||||
if (!empty($smtp['replyTo'])) {
|
||||
$replyTo = $smtp['replyTo'];
|
||||
}
|
||||
|
||||
$queueForMails
|
||||
->setSmtpHost($smtp['host'] ?? '')
|
||||
->setSmtpPort($smtp['port'] ?? '')
|
||||
->setSmtpUsername($smtp['username'] ?? '')
|
||||
->setSmtpPassword($smtp['password'] ?? '')
|
||||
->setSmtpSecure($smtp['secure'] ?? '');
|
||||
|
||||
if (!empty($customTemplate)) {
|
||||
if (!empty($customTemplate['senderEmail'])) {
|
||||
$senderEmail = $customTemplate['senderEmail'];
|
||||
}
|
||||
if (!empty($customTemplate['senderName'])) {
|
||||
$senderName = $customTemplate['senderName'];
|
||||
}
|
||||
if (!empty($customTemplate['replyTo'])) {
|
||||
$replyTo = $customTemplate['replyTo'];
|
||||
}
|
||||
|
||||
$body = $customTemplate['message'] ?? '';
|
||||
$subject = $customTemplate['subject'] ?? $subject;
|
||||
}
|
||||
|
||||
$queueForMails
|
||||
->setSmtpReplyTo($replyTo)
|
||||
->setSmtpSenderEmail($senderEmail)
|
||||
->setSmtpSenderName($senderName);
|
||||
}
|
||||
|
||||
$emailVariables = [
|
||||
'heading' => $heading,
|
||||
'direction' => $locale->getText('settings.direction'),
|
||||
'user' => $user->getAttribute('name'),
|
||||
'project' => $project->getAttribute('name'),
|
||||
'otp' => $code,
|
||||
'agentDevice' => $agentDevice['deviceBrand'] ?? $agentDevice['deviceBrand'] ?? 'UNKNOWN',
|
||||
'agentClient' => $agentClient['clientName'] ?? 'UNKNOWN',
|
||||
'agentOs' => $agentOs['osName'] ?? 'UNKNOWN',
|
||||
];
|
||||
|
||||
if ($smtpBaseTemplate === APP_BRANDED_EMAIL_BASE_TEMPLATE) {
|
||||
$emailVariables = array_merge($emailVariables, [
|
||||
'accentColor' => APP_EMAIL_ACCENT_COLOR,
|
||||
'logoUrl' => APP_EMAIL_LOGO_URL,
|
||||
'twitterUrl' => APP_SOCIAL_TWITTER,
|
||||
'discordUrl' => APP_SOCIAL_DISCORD,
|
||||
'githubUrl' => APP_SOCIAL_GITHUB_APPWRITE,
|
||||
'termsUrl' => APP_EMAIL_TERMS_URL,
|
||||
'privacyUrl' => APP_EMAIL_PRIVACY_URL,
|
||||
]);
|
||||
}
|
||||
|
||||
$queueForMails
|
||||
->setSubject($subject)
|
||||
->setPreview($preview)
|
||||
->setBody($body)
|
||||
->setBodyTemplate($bodyTemplate)
|
||||
->setVariables($emailVariables)
|
||||
->setRecipient($user->getAttribute('email'))
|
||||
->trigger();
|
||||
break;
|
||||
}
|
||||
|
||||
$queueForEvents
|
||||
->setParam('userId', $user->getId())
|
||||
->setParam('challengeId', $challenge->getId());
|
||||
|
||||
$response->dynamic($challenge, Response::MODEL_MFA_CHALLENGE);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,161 @@
|
|||
<?php
|
||||
|
||||
namespace Appwrite\Platform\Modules\Account\Http\Account\MFA\Challenges;
|
||||
|
||||
use Appwrite\Auth\MFA\Challenge;
|
||||
use Appwrite\Auth\MFA\Type;
|
||||
use Appwrite\Event\Event;
|
||||
use Appwrite\Extend\Exception;
|
||||
use Appwrite\SDK\AuthType;
|
||||
use Appwrite\SDK\ContentType;
|
||||
use Appwrite\SDK\Deprecated;
|
||||
use Appwrite\SDK\Method;
|
||||
use Appwrite\SDK\Response as SDKResponse;
|
||||
use Appwrite\Utopia\Response;
|
||||
use Utopia\Database\Database;
|
||||
use Utopia\Database\DateTime;
|
||||
use Utopia\Database\Document;
|
||||
use Utopia\Platform\Action;
|
||||
use Utopia\Platform\Scope\HTTP;
|
||||
use Utopia\Validator\Text;
|
||||
|
||||
class Update extends Action
|
||||
{
|
||||
use HTTP;
|
||||
|
||||
public static function getName(): string
|
||||
{
|
||||
return 'updateMFAChallenge';
|
||||
}
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this
|
||||
->setHttpMethod(Action::HTTP_REQUEST_METHOD_PUT)
|
||||
->setHttpPath('/v1/account/mfa/challenges')
|
||||
->httpAlias('/v1/account/mfa/challenge')
|
||||
->desc('Update MFA challenge (confirmation)')
|
||||
->groups(['api', 'account', 'mfa'])
|
||||
->label('scope', 'account')
|
||||
->label('event', 'users.[userId].sessions.[sessionId].create')
|
||||
->label('audits.event', 'challenges.update')
|
||||
->label('audits.resource', 'user/{response.userId}')
|
||||
->label('audits.userId', '{response.userId}')
|
||||
->label('sdk', [
|
||||
new Method(
|
||||
namespace: 'account',
|
||||
group: 'mfa',
|
||||
name: 'updateMfaChallenge',
|
||||
description: '/docs/references/account/update-mfa-challenge.md',
|
||||
auth: [AuthType::SESSION, AuthType::JWT],
|
||||
responses: [
|
||||
new SDKResponse(
|
||||
code: Response::STATUS_CODE_OK,
|
||||
model: Response::MODEL_SESSION,
|
||||
)
|
||||
],
|
||||
contentType: ContentType::JSON,
|
||||
deprecated: new Deprecated(
|
||||
since: '1.8.0',
|
||||
replaceWith: 'account.updateMFAChallenge',
|
||||
),
|
||||
),
|
||||
new Method(
|
||||
namespace: 'account',
|
||||
group: 'mfa',
|
||||
name: 'updateMFAChallenge',
|
||||
description: '/docs/references/account/update-mfa-challenge.md',
|
||||
auth: [AuthType::SESSION, AuthType::JWT],
|
||||
responses: [
|
||||
new SDKResponse(
|
||||
code: Response::STATUS_CODE_OK,
|
||||
model: Response::MODEL_SESSION,
|
||||
)
|
||||
],
|
||||
contentType: ContentType::JSON
|
||||
)
|
||||
])
|
||||
->label('abuse-limit', 10)
|
||||
->label('abuse-key', 'url:{url},challengeId:{param-challengeId}')
|
||||
->param('challengeId', '', new Text(256), 'ID of the challenge.')
|
||||
->param('otp', '', new Text(256), 'Valid verification token.')
|
||||
->inject('project')
|
||||
->inject('response')
|
||||
->inject('user')
|
||||
->inject('session')
|
||||
->inject('dbForProject')
|
||||
->inject('queueForEvents')
|
||||
->callback($this->action(...));
|
||||
}
|
||||
|
||||
public function action(
|
||||
string $challengeId,
|
||||
string $otp,
|
||||
Document $project,
|
||||
Response $response,
|
||||
Document $user,
|
||||
Document $session,
|
||||
Database $dbForProject,
|
||||
Event $queueForEvents
|
||||
): void {
|
||||
$challenge = $dbForProject->getDocument('challenges', $challengeId);
|
||||
|
||||
if ($challenge->isEmpty()) {
|
||||
throw new Exception(Exception::USER_INVALID_TOKEN);
|
||||
}
|
||||
|
||||
$type = $challenge->getAttribute('type');
|
||||
|
||||
$recoveryCodeChallenge = function (Document $challenge, Document $user, string $otp) use ($dbForProject) {
|
||||
if (
|
||||
$challenge->isSet('type') &&
|
||||
$challenge->getAttribute('type') === \strtolower(Type::RECOVERY_CODE)
|
||||
) {
|
||||
$mfaRecoveryCodes = $user->getAttribute('mfaRecoveryCodes', []);
|
||||
if (\in_array($otp, $mfaRecoveryCodes)) {
|
||||
$mfaRecoveryCodes = \array_diff($mfaRecoveryCodes, [$otp]);
|
||||
$mfaRecoveryCodes = \array_values($mfaRecoveryCodes);
|
||||
$user->setAttribute('mfaRecoveryCodes', $mfaRecoveryCodes);
|
||||
$dbForProject->updateDocument('users', $user->getId(), $user);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return false;
|
||||
};
|
||||
|
||||
$success = (match ($type) {
|
||||
Type::TOTP => Challenge\TOTP::challenge($challenge, $user, $otp),
|
||||
Type::PHONE => Challenge\Phone::challenge($challenge, $user, $otp),
|
||||
Type::EMAIL => Challenge\Email::challenge($challenge, $user, $otp),
|
||||
\strtolower(Type::RECOVERY_CODE) => $recoveryCodeChallenge($challenge, $user, $otp),
|
||||
default => false
|
||||
});
|
||||
|
||||
if (!$success) {
|
||||
throw new Exception(Exception::USER_INVALID_TOKEN);
|
||||
}
|
||||
|
||||
$dbForProject->deleteDocument('challenges', $challengeId);
|
||||
$dbForProject->purgeCachedDocument('users', $user->getId());
|
||||
|
||||
$factors = $session->getAttribute('factors', []);
|
||||
$factors[] = $type;
|
||||
$factors = \array_values(\array_unique($factors));
|
||||
|
||||
$session
|
||||
->setAttribute('factors', $factors)
|
||||
->setAttribute('mfaUpdatedAt', DateTime::now());
|
||||
|
||||
$dbForProject->updateDocument('sessions', $session->getId(), $session);
|
||||
|
||||
$queueForEvents
|
||||
->setParam('userId', $user->getId())
|
||||
->setParam('sessionId', $session->getId());
|
||||
|
||||
$response->dynamic($session, Response::MODEL_SESSION);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
<?php
|
||||
|
||||
namespace Appwrite\Platform\Modules\Account\Http\Mfa\Factors;
|
||||
namespace Appwrite\Platform\Modules\Account\Http\Account\MFA\Factors;
|
||||
|
||||
use Appwrite\Auth\MFA\Type;
|
||||
use Appwrite\Auth\MFA\Type\TOTP;
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
<?php
|
||||
|
||||
namespace Appwrite\Platform\Modules\Account\Http\Mfa\RecoveryCodes;
|
||||
namespace Appwrite\Platform\Modules\Account\Http\Account\MFA\RecoveryCodes;
|
||||
|
||||
use Appwrite\Auth\MFA\Type;
|
||||
use Appwrite\Event\Event;
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
<?php
|
||||
|
||||
namespace Appwrite\Platform\Modules\Account\Http\Mfa\RecoveryCodes;
|
||||
namespace Appwrite\Platform\Modules\Account\Http\Account\MFA\RecoveryCodes;
|
||||
|
||||
use Appwrite\Extend\Exception;
|
||||
use Appwrite\SDK\AuthType;
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
<?php
|
||||
|
||||
namespace Appwrite\Platform\Modules\Account\Http\Mfa\RecoveryCodes;
|
||||
namespace Appwrite\Platform\Modules\Account\Http\Account\MFA\RecoveryCodes;
|
||||
|
||||
use Appwrite\Auth\MFA\Type;
|
||||
use Appwrite\Event\Event;
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
<?php
|
||||
|
||||
namespace Appwrite\Platform\Modules\Account\Http\Mfa;
|
||||
namespace Appwrite\Platform\Modules\Account\Http\Account\MFA;
|
||||
|
||||
use Appwrite\Auth\MFA\Type;
|
||||
use Appwrite\Auth\MFA\Type\TOTP;
|
||||
|
|
@ -2,16 +2,16 @@
|
|||
|
||||
namespace Appwrite\Platform\Modules\Account\Services;
|
||||
|
||||
use Appwrite\Platform\Modules\Account\Http\Mfa\Authenticators\Create as CreateAuthenticator;
|
||||
use Appwrite\Platform\Modules\Account\Http\Mfa\Authenticators\Delete as DeleteAuthenticator;
|
||||
use Appwrite\Platform\Modules\Account\Http\Mfa\Authenticators\Update as UpdateAuthenticator;
|
||||
use Appwrite\Platform\Modules\Account\Http\Mfa\Challenge\Create as CreateChallenge;
|
||||
use Appwrite\Platform\Modules\Account\Http\Mfa\Challenge\Update as UpdateChallenge;
|
||||
use Appwrite\Platform\Modules\Account\Http\Mfa\Factors\XList as ListFactors;
|
||||
use Appwrite\Platform\Modules\Account\Http\Mfa\RecoveryCodes\Create as CreateRecoveryCodes;
|
||||
use Appwrite\Platform\Modules\Account\Http\Mfa\RecoveryCodes\Get as GetRecoveryCodes;
|
||||
use Appwrite\Platform\Modules\Account\Http\Mfa\RecoveryCodes\Update as UpdateRecoveryCodes;
|
||||
use Appwrite\Platform\Modules\Account\Http\Mfa\Update as UpdateMfa;
|
||||
use Appwrite\Platform\Modules\Account\Http\Account\MFA\Authenticators\Create as CreateAuthenticator;
|
||||
use Appwrite\Platform\Modules\Account\Http\Account\MFA\Authenticators\Delete as DeleteAuthenticator;
|
||||
use Appwrite\Platform\Modules\Account\Http\Account\MFA\Authenticators\Update as UpdateAuthenticator;
|
||||
use Appwrite\Platform\Modules\Account\Http\Account\MFA\Challenges\Create as CreateChallenge;
|
||||
use Appwrite\Platform\Modules\Account\Http\Account\MFA\Challenges\Update as UpdateChallenge;
|
||||
use Appwrite\Platform\Modules\Account\Http\Account\MFA\Factors\XList as ListFactors;
|
||||
use Appwrite\Platform\Modules\Account\Http\Account\MFA\RecoveryCodes\Create as CreateRecoveryCodes;
|
||||
use Appwrite\Platform\Modules\Account\Http\Account\MFA\RecoveryCodes\Get as GetRecoveryCodes;
|
||||
use Appwrite\Platform\Modules\Account\Http\Account\MFA\RecoveryCodes\Update as UpdateRecoveryCodes;
|
||||
use Appwrite\Platform\Modules\Account\Http\Account\MFA\Update as UpdateMfa;
|
||||
use Utopia\Platform\Service;
|
||||
|
||||
class Http extends Service
|
||||
|
|
|
|||
Loading…
Reference in a new issue