mirror of
https://github.com/appwrite/appwrite.git
synced 2026-05-26 13:51:13 +00:00
Compare commits
19
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4c5451febe | ||
|
|
8533b1d3ce | ||
|
|
4df94de1d9 | ||
|
|
5eb83b5de3 | ||
|
|
3468b25a52 | ||
|
|
f3e6b18b9f | ||
|
|
01fc574d36 | ||
|
|
3cfbe07744 | ||
|
|
4100e4f019 | ||
|
|
96d39e1421 | ||
|
|
14e248f321 | ||
|
|
db74bed93e | ||
|
|
6487b5f980 | ||
|
|
f20e7d4beb | ||
|
|
e7dc727102 | ||
|
|
f7e591eeaa | ||
|
|
7f45078ff5 | ||
|
|
dcb19c3f80 | ||
|
|
f7a115cff1 |
@@ -7,6 +7,8 @@ return [
|
||||
'recovery',
|
||||
'invitation',
|
||||
'mfaChallenge',
|
||||
'mfaEnabled',
|
||||
'mfaDisabled',
|
||||
'sessionAlert',
|
||||
'otpSession'
|
||||
],
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
<p>{{hello}},</p>
|
||||
<p>{{body}}</p>
|
||||
<p>{{footer}}</p>
|
||||
<p style="margin-bottom: 32px">
|
||||
{{thanks}},
|
||||
<br/>
|
||||
{{signature}}
|
||||
</p>
|
||||
@@ -0,0 +1,11 @@
|
||||
{{body}}
|
||||
|
||||
<br/><br/>
|
||||
|
||||
<table border="0" cellspacing="0" cellpadding="0" style="padding-top: 10px; padding-bottom: 10px; display: inline-block;">
|
||||
<tr>
|
||||
<td align="center" style="border-radius: 8px; background-color: #FD366E;">
|
||||
<a rel="noopener" target="_blank" href="{{redirect}}" style="font-size: 14px; font-family: Inter; color: #ffffff; text-decoration: none; border-radius: 8px; padding: 9px 14px; border: 1px solid #FD366E; display: inline-block;">{{buttonText}}</a>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"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 can’t 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.buttonText": "Visit your account",
|
||||
"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.buttonText": "Visit your account"
|
||||
}
|
||||
@@ -40,6 +40,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.mfaEnabled.subject": "Two-factor authentication is enabled for your {{project}} account",
|
||||
"emails.mfaEnabled.hello": "Hello {{user}}",
|
||||
"emails.mfaEnabled.body": "Two-factor authentication has been successfully enabled for your {{project}} account.",
|
||||
"emails.mfaEnabled.footer": "If you didn’t 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 for 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 didn’t 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.",
|
||||
|
||||
@@ -3648,13 +3648,17 @@ 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) {
|
||||
$mfaAltered = $user->getAttribute('mfa') !== $mfa;
|
||||
$user->setAttribute('mfa', $mfa);
|
||||
|
||||
$user = $dbForProject->withRequestTimestamp($requestTimestamp, fn () => $dbForProject->updateDocument('users', $user->getId(), $user));
|
||||
@@ -3679,6 +3683,110 @@ App::patch('/v1/account/mfa')
|
||||
|
||||
$queueForEvents->setParam('userId', $user->getId());
|
||||
|
||||
// If MFA Changes then we need to send a email
|
||||
if ($mfaAltered && !empty($user->getAttribute('email'))) {
|
||||
$domain = $request->getHostname();
|
||||
$protocol = $request->getProtocol();
|
||||
|
||||
$redirect = $protocol . '://' . $domain . '/console/account';
|
||||
$type = $mfa ? 'mfaEnabled' : 'mfaDisabled';
|
||||
|
||||
$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-console.tpl');
|
||||
|
||||
$consoleLocale = clone $locale;
|
||||
$consoleLocale->default = 'console-' . $locale->default;
|
||||
|
||||
$buttonText = $consoleLocale->getText("emails.{$type}.buttonText", null) ?? $locale->getText("emails.{$type}.buttonText");
|
||||
$bodyText = $consoleLocale->getText("emails.{$type}.body", null) ?? $locale->getText("emails.{$type}.body");
|
||||
|
||||
$body
|
||||
->setParam('{{buttonText}}', $buttonText)
|
||||
->setParam('{{redirect}}', $redirect)
|
||||
->setParam('{{body}}', $bodyText, escapeHtml: false);
|
||||
|
||||
$message->setParam('{{body}}', $body->render(), escapeHtml: false);
|
||||
} else {
|
||||
$message = Template::fromFile(__DIR__ . '/../../config/locale/templates/email-mfa-altered-client.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 = [
|
||||
'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()
|
||||
;
|
||||
}
|
||||
|
||||
$response->dynamic($user, Response::MODEL_ACCOUNT);
|
||||
});
|
||||
|
||||
@@ -3811,7 +3919,6 @@ App::put('/v1/account/mfa/authenticators/:type')
|
||||
->inject('dbForProject')
|
||||
->inject('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),
|
||||
default => null
|
||||
@@ -3984,7 +4091,6 @@ App::delete('/v1/account/mfa/authenticators/:type')
|
||||
->inject('dbForProject')
|
||||
->inject('queueForEvents')
|
||||
->action(function (string $type, Response $response, Document $user, Database $dbForProject, Event $queueForEvents) {
|
||||
|
||||
$authenticator = (match ($type) {
|
||||
Type::TOTP => TOTP::getAuthenticatorFromUser($user),
|
||||
default => null
|
||||
|
||||
@@ -1068,6 +1068,11 @@ foreach ($locales as $locale) {
|
||||
}
|
||||
}
|
||||
|
||||
$consolePath = __DIR__ . '/config/locale/translations/console/' . \substr($code, 0, 2) . '.json';
|
||||
if (file_exists($consolePath)) {
|
||||
Locale::setLanguageFromJSON('console-'.$code, $consolePath);
|
||||
}
|
||||
|
||||
Locale::setLanguageFromJSON($code, $path);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user