Clean up code and switch to mfaEnabled/Disabled

This commit is contained in:
Bradley Schofield
2024-08-12 13:07:30 +09:00
parent dcb19c3f80
commit 7f45078ff5
3 changed files with 127 additions and 213 deletions
+2 -2
View File
@@ -7,8 +7,8 @@ return [
'recovery',
'invitation',
'mfaChallenge',
'mfaCreated',
'mfaRemoved',
'mfaEnabled',
'mfaDisabled',
],
'sms' => [
'verification',
+14 -14
View File
@@ -31,20 +31,20 @@
"emails.mfaChallenge.clientInfo": "This verification code was requested using {{b}}{{agentClient}}{{/b}} on {{b}}{{agentDevice}}{{/b}} {{b}}{{agentOs}}{{/b}}. If you didn't request the verification code, you can safely ignore this email.",
"emails.mfaChallenge.thanks": "Thanks,",
"emails.mfaChallenge.signature": "{{project}} team",
"emails.mfaCreated.subject": "Two-factor authentication is enabled in your {{project}} account",
"emails.mfaCreated.hello": "Hello {{user}}",
"emails.mfaCreated.body": "Two-factor authentication has been successfully enabled for your {{project}} account.<br/><br/>Please make sure to store your security codes safely, so you can use them if you lose or cant access your mobile device. Each recovery code can only be used once, but you can re-generate a new set of 6 codes at any time.",
"emails.mfaCreated.footer": "If you didnt enable two-factor authentication, please contact us immediately.",
"emails.mfaCreated.thanks": "Thanks,",
"emails.mfaCreated.signature": "{{project}} team",
"emails.mfaCreated.buttonText": "Visit your account",
"emails.mfaRemoved.subject": "Two-factor authentication is disabled in your {{project}} account",
"emails.mfaRemoved.hello": "Hello {{user}}",
"emails.mfaRemoved.body": "You've recently disabled two-factor authentication for your {{project}} account. You can always enable it again through your {{project}} account.",
"emails.mfaRemoved.footer": "If you didnt disable two-factor authentication, please contact us immediately.",
"emails.mfaRemoved.thanks": "Thanks,",
"emails.mfaRemoved.signature": "{{project}} team",
"emails.mfaRemoved.buttonText": "Visit your account",
"emails.mfaEnabled.subject": "Two-factor authentication is enabled in your {{project}} account",
"emails.mfaEnabled.hello": "Hello {{user}}",
"emails.mfaEnabled.body": "Two-factor authentication has been successfully enabled for your {{project}} account.<br/><br/>Please make sure to store your security codes safely, so you can use them if you lose or cant access your mobile device. Each recovery code can only be used once, but you can re-generate a new set of 6 codes at any time.",
"emails.mfaEnabled.footer": "If you didnt enable two-factor authentication, please contact us immediately.",
"emails.mfaEnabled.thanks": "Thanks",
"emails.mfaEnabled.signature": "{{project}} team",
"emails.mfaEnabled.buttonText": "Visit your account",
"emails.mfaDisabled.subject": "Two-factor authentication is disabled in your {{project}} account",
"emails.mfaDisabled.hello": "Hello {{user}}",
"emails.mfaDisabled.body": "You've disabled two-factor authentication for your {{project}} account. You can always enable it again through your {{project}} account.",
"emails.mfaDisabled.footer": "If you didnt disable two-factor authentication, please contact us immediately.",
"emails.mfaDisabled.thanks": "Thanks",
"emails.mfaDisabled.signature": "{{project}} team",
"emails.mfaDisabled.buttonText": "Visit your account",
"emails.recovery.subject": "Password Reset",
"emails.recovery.hello": "Hello {{user}}",
"emails.recovery.body": "Follow this link to reset your {{b}}{{project}}{{/b}} password.",
+111 -197
View File
@@ -166,6 +166,101 @@ $createSession = function (string $userId, string $secret, Request $request, Res
$response->dynamic($session, Response::MODEL_SESSION);
};
$sendMFAAlert = function (Document $project, Document $user, Locale $locale, Mail $queueForMails, string $type, string $redirect) {
$subject = $locale->getText("emails.{$type}.subject");
$customTemplate = $project->getAttribute('templates', [])["email.{$type}-" . $locale->default] ?? [];
// Appwrite Theming for Console
if ($project->getInternalId() === 'console') {
$message = Template::fromFile(__DIR__ . '/../../config/locale/templates/email-base-styled.tpl');
$body = Template::fromFile(__DIR__ . '/../../config/locale/templates/email-mfa-altered.tpl');
$body
->setParam('{{buttonText}}', $locale->getText("emails.{$type}.buttonText"))
->setParam('{{redirect}}', 'http://' . App::getEnv('_APP_DOMAIN') . '/console/account')
->setParam('{{body}}', $locale->getText("emails.{$type}.body"), escapeHtml: false)
->setParam('{{project}}', $project->getAttribute('name'))
->setParam('{{user}}', $user->getAttribute('name'));
$message->setParam('{{body}}', $body->render(), escapeHtml: false);
} else {
$message = Template::fromFile(__DIR__ . '/../../config/locale/templates/email-inner-base.tpl');
$message->setParam('{{body}}', $locale->getText("emails.{$type}.body"), escapeHtml: false);
}
$message
->setParam('{{hello}}', $locale->getText("emails.{$type}.hello"))
->setParam('{{footer}}', $locale->getText("emails.{$type}.footer"))
->setParam('{{thanks}}', $locale->getText("emails.{$type}.thanks"))
->setParam('{{signature}}', $locale->getText("emails.{$type}.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 = [
'owner' => $user->getAttribute('name'),
'direction' => $locale->getText('settings.direction'),
'user' => $user->getAttribute('name'),
'project' => $project->getAttribute('name'),
'redirect' => $redirect
];
$queueForMails
->setSubject($subject)
->setBody($body)
->setRecipient($user->getAttribute('email'))
->setName($user->getAttribute('name'))
->setVariables($emailVariables)
->trigger()
;
};
App::post('/v1/account')
->desc('Create account')
->groups(['api', 'account', 'auth'])
@@ -3505,12 +3600,25 @@ App::patch('/v1/account/mfa')
->label('sdk.offline.key', 'current')
->param('mfa', null, new Boolean(), 'Enable or disable MFA.')
->inject('requestTimestamp')
->inject('request')
->inject('response')
->inject('user')
->inject('project')
->inject('session')
->inject('locale')
->inject('dbForProject')
->inject('queueForEvents')
->action(function (bool $mfa, ?\DateTime $requestTimestamp, Response $response, Document $user, Document $session, Database $dbForProject, Event $queueForEvents) {
->inject('queueForMails')
->action(function (bool $mfa, ?\DateTime $requestTimestamp, Request $request, Response $response, Document $user, Document $project, Document $session, Locale $locale, Database $dbForProject, Event $queueForEvents, Mail $queueForMails) use ($sendMFAAlert) {
// If MFA Changes then we need to send a email
if ($mfa !== $user->getAttribute('mfa')) {
$domain = $request->getHostname();
$protocol = $request->getProtocol();
$redirect = $protocol . '://' . $domain . '/console/account';
$sendMFAAlert($project, $user, $locale, $queueForMails, $mfa ? 'mfaEnabled' : 'mfaDisabled', $redirect);
}
$user->setAttribute('mfa', $mfa);
@@ -3667,11 +3775,7 @@ App::put('/v1/account/mfa/authenticators/:type')
->inject('session')
->inject('dbForProject')
->inject('queueForEvents')
->inject('project')
->inject('locale')
->inject('queueForMails')
->action(function (string $type, string $otp, Response $response, Document $user, Document $session, Database $dbForProject, Event $queueForEvents, Document $project, Locale $locale, Mail $queueForMails) {
->action(function (string $type, string $otp, Response $response, Document $user, Document $session, Database $dbForProject, Event $queueForEvents) {
$authenticator = (match ($type) {
Type::TOTP => TOTP::getAuthenticatorFromUser($user),
default => null
@@ -3706,99 +3810,6 @@ App::put('/v1/account/mfa/authenticators/:type')
$session->setAttribute('factors', $factors);
$dbForProject->updateDocument('sessions', $session->getId(), $session);
// Send email to user informing that MFA is enabled
$subject = $locale->getText("emails.mfaCreated.subject");
$customTemplate = $project->getAttribute('templates', [])['email.mfaCreated-' . $locale->default] ?? [];
// Appwrite theming for console
if ($project->getInternalId() === 'console') {
$message = Template::fromFile(__DIR__ . '/../../config/locale/templates/email-base-styled.tpl');
$body = Template::fromFile(__DIR__ . '/../../config/locale/templates/email-mfa-altered.tpl');
$body
->setParam('{{buttonText}}', $locale->getText("emails.mfaCreated.buttonText"))
->setParam('{{redirect}}', 'http://' . App::getEnv('_APP_DOMAIN') . '/console/account')
->setParam('{{body}}', $locale->getText("emails.mfaCreated.body"), escapeHtml: false)
->setParam('{{project}}', $project->getAttribute('name'))
->setParam('{{user}}', $user->getAttribute('name'));
$message->setParam('{{body}}', $body->render(), escapeHtml: false);
} else {
$message = Template::fromFile(__DIR__ . '/../../config/locale/templates/email-inner-base.tpl');
$message->setParam('{{body}}', $locale->getText("emails.mfaCreated.body"), escapeHtml: false);
}
$message
->setParam('{{hello}}', $locale->getText("emails.mfaCreated.hello"))
->setParam('{{footer}}', $locale->getText("emails.mfaCreated.footer"))
->setParam('{{thanks}}', $locale->getText("emails.mfaCreated.thanks"))
->setParam('{{signature}}', $locale->getText("emails.mfaCreated.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 = [
'owner' => $user->getAttribute('name'),
'direction' => $locale->getText('settings.direction'),
'user' => $user->getAttribute('name'),
'project' => $project->getAttribute('name')
];
$queueForMails
->setSubject($subject)
->setBody($body)
->setRecipient($user->getAttribute('email'))
->setName($user->getAttribute('name'))
->setVariables($emailVariables)
->trigger()
;
$queueForEvents->setParam('userId', $user->getId());
$response->dynamic($user, Response::MODEL_ACCOUNT);
@@ -3937,11 +3948,7 @@ App::delete('/v1/account/mfa/authenticators/:type')
->inject('user')
->inject('dbForProject')
->inject('queueForEvents')
->inject('project')
->inject('locale')
->inject('queueForMails')
->action(function (string $type, string $otp, Response $response, Document $user, Database $dbForProject, Event $queueForEvents, Document $project, Locale $locale, Mail $queueForMails) {
->action(function (string $type, string $otp, Response $response, Document $user, Database $dbForProject, Event $queueForEvents) {
$authenticator = (match ($type) {
Type::TOTP => TOTP::getAuthenticatorFromUser($user),
default => null
@@ -3975,99 +3982,6 @@ App::delete('/v1/account/mfa/authenticators/:type')
$dbForProject->deleteDocument('authenticators', $authenticator->getId());
$dbForProject->purgeCachedDocument('users', $user->getId());
// Send email to user informing that MFA is disabled
$subject = $locale->getText("emails.mfaRemoved.subject");
$customTemplate = $project->getAttribute('templates', [])['email.mfaRemoved-' . $locale->default] ?? [];
// Appwrite theming for console
if ($project->getInternalId() === 'console') {
$message = Template::fromFile(__DIR__ . '/../../config/locale/templates/email-base-styled.tpl');
$body = Template::fromFile(__DIR__ . '/../../config/locale/templates/email-mfa-altered.tpl');
$body
->setParam('{{buttonText}}', $locale->getText("emails.mfaRemoved.buttonText"))
->setParam('{{redirect}}', 'http://' . App::getEnv('_APP_DOMAIN') . '/console/account')
->setParam('{{body}}', $locale->getText("emails.mfaRemoved.body"), escapeHtml: false)
->setParam('{{project}}', $project->getAttribute('name'))
->setParam('{{user}}', $user->getAttribute('name'));
$message->setParam('{{body}}', $body->render(), escapeHtml: false);
} else {
$message = Template::fromFile(__DIR__ . '/../../config/locale/templates/email-inner-base.tpl');
$message->setParam('{{body}}', $locale->getText("emails.mfaRemoved.body"), escapeHtml: false);
}
$message
->setParam('{{hello}}', $locale->getText("emails.mfaRemoved.hello"))
->setParam('{{footer}}', $locale->getText("emails.mfaRemoved.footer"))
->setParam('{{thanks}}', $locale->getText("emails.mfaRemoved.thanks"))
->setParam('{{signature}}', $locale->getText("emails.mfaRemoved.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 = [
'owner' => $user->getAttribute('name'),
'direction' => $locale->getText('settings.direction'),
'user' => $user->getAttribute('name'),
'project' => $project->getAttribute('name')
];
$queueForMails
->setSubject($subject)
->setBody($body)
->setRecipient($user->getAttribute('email'))
->setName($user->getAttribute('name'))
->setVariables($emailVariables)
->trigger()
;
$queueForEvents->setParam('userId', $user->getId());
$response->noContent();