Merge pull request #8315 from appwrite/feat-new-session-alert
Feat new session alert
This commit is contained in:
commit
1c0490aa91
11 changed files with 236 additions and 5 deletions
1
.env
1
.env
|
@ -4,6 +4,7 @@ _APP_LOCALE=en
|
||||||
_APP_WORKER_PER_CORE=6
|
_APP_WORKER_PER_CORE=6
|
||||||
_APP_CONSOLE_WHITELIST_ROOT=disabled
|
_APP_CONSOLE_WHITELIST_ROOT=disabled
|
||||||
_APP_CONSOLE_WHITELIST_EMAILS=
|
_APP_CONSOLE_WHITELIST_EMAILS=
|
||||||
|
_APP_CONSOLE_SESSION_ALERTS=enabled
|
||||||
_APP_CONSOLE_WHITELIST_IPS=
|
_APP_CONSOLE_WHITELIST_IPS=
|
||||||
_APP_CONSOLE_COUNTRIES_DENYLIST=AQ
|
_APP_CONSOLE_COUNTRIES_DENYLIST=AQ
|
||||||
_APP_CONSOLE_HOSTNAMES=localhost,appwrite.io,*.appwrite.io
|
_APP_CONSOLE_HOSTNAMES=localhost,appwrite.io,*.appwrite.io
|
||||||
|
|
14
app/config/locale/templates/email-session-alert.tpl
Normal file
14
app/config/locale/templates/email-session-alert.tpl
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
<p>{{hello}},</p>
|
||||||
|
|
||||||
|
<p>{{body}}</p>
|
||||||
|
|
||||||
|
<ol>
|
||||||
|
<li>{{listDevice}}</li>
|
||||||
|
<li>{{listIpAddress}}</li>
|
||||||
|
<li>{{listCountry}}</li>
|
||||||
|
</ol>
|
||||||
|
|
||||||
|
<p>{{footer}}</p>
|
||||||
|
|
||||||
|
<p style="margin-bottom: 0px;">{{thanks}}</p>
|
||||||
|
<p style="margin-top: 0px;">{{signature}}</p>
|
|
@ -18,6 +18,15 @@
|
||||||
"emails.magicSession.securityPhrase": "Security phrase for this email is {{b}}{{phrase}}{{/b}}. You can trust this email if this phrase matches the phrase shown during sign in.",
|
"emails.magicSession.securityPhrase": "Security phrase for this email is {{b}}{{phrase}}{{/b}}. You can trust this email if this phrase matches the phrase shown during sign in.",
|
||||||
"emails.magicSession.thanks": "Thanks,",
|
"emails.magicSession.thanks": "Thanks,",
|
||||||
"emails.magicSession.signature": "{{project}} team",
|
"emails.magicSession.signature": "{{project}} team",
|
||||||
|
"emails.sessionAlert.subject": "New session alert for {{project}}",
|
||||||
|
"emails.sessionAlert.hello":"Hello {{user}}",
|
||||||
|
"emails.sessionAlert.body": "We're writing to inform you that a new session has been initiated on your {{b}}{{project}}{{/b}} account, on {{b}}{{dateTime}}{{/b}}. \nHere are the details of the new session: ",
|
||||||
|
"emails.sessionAlert.listDevice": "Device: {{b}}{{device}}{{/b}}",
|
||||||
|
"emails.sessionAlert.listIpAddress": "IP Address: {{b}}{{ipAddress}}{{/b}}",
|
||||||
|
"emails.sessionAlert.listCountry": "Country: {{b}}{{country}}{{/b}}",
|
||||||
|
"emails.sessionAlert.footer": "If you didn't request the sign in, you can safely ignore this email. If you suspect unauthorized activity, please secure your account immediately.",
|
||||||
|
"emails.sessionAlert.thanks": "Thanks,",
|
||||||
|
"emails.sessionAlert.signature": "{{project}} team",
|
||||||
"emails.otpSession.subject": "OTP for {{project}} Login",
|
"emails.otpSession.subject": "OTP for {{project}} Login",
|
||||||
"emails.otpSession.hello": "Hello {{user}}",
|
"emails.otpSession.hello": "Hello {{user}}",
|
||||||
"emails.otpSession.description": "Enter the following verification code when prompted to securely sign in to your {{b}}{{project}}{{/b}} account. This code will expire in 15 minutes.",
|
"emails.otpSession.description": "Enter the following verification code when prompted to securely sign in to your {{b}}{{project}}{{/b}} account. This code will expire in 15 minutes.",
|
||||||
|
@ -34,7 +43,7 @@
|
||||||
"emails.recovery.subject": "Password Reset",
|
"emails.recovery.subject": "Password Reset",
|
||||||
"emails.recovery.hello": "Hello {{user}}",
|
"emails.recovery.hello": "Hello {{user}}",
|
||||||
"emails.recovery.body": "Follow this link to reset your {{b}}{{project}}{{/b}} password.",
|
"emails.recovery.body": "Follow this link to reset your {{b}}{{project}}{{/b}} password.",
|
||||||
"emails.recovery.footer": "If you didn’t ask to reset your password, you can ignore this message.",
|
"emails.recovery.footer": "If you didn't ask to reset your password, you can ignore this message.",
|
||||||
"emails.recovery.thanks": "Thanks",
|
"emails.recovery.thanks": "Thanks",
|
||||||
"emails.recovery.signature": "{{project}} team",
|
"emails.recovery.signature": "{{project}} team",
|
||||||
"emails.invitation.subject": "Invitation to %s Team at %s",
|
"emails.invitation.subject": "Invitation to %s Team at %s",
|
||||||
|
|
|
@ -250,6 +250,15 @@ return [
|
||||||
'question' => '',
|
'question' => '',
|
||||||
'filter' => ''
|
'filter' => ''
|
||||||
],
|
],
|
||||||
|
[
|
||||||
|
'name' => '_APP_CONSOLE_SESSION_ALERTS',
|
||||||
|
'description' => 'This option allows you configure if a new login in the Appwrite Console should send an alert email to the user. It\'s disabled by default with value "disabled", and to enable it, pass value "enabled".',
|
||||||
|
'introduction' => '1.6.0',
|
||||||
|
'default' => 'disabled',
|
||||||
|
'required' => false,
|
||||||
|
'question' => '',
|
||||||
|
'filter' => ''
|
||||||
|
],
|
||||||
],
|
],
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
|
|
|
@ -58,7 +58,92 @@ use Utopia\Validator\WhiteList;
|
||||||
$oauthDefaultSuccess = '/auth/oauth2/success';
|
$oauthDefaultSuccess = '/auth/oauth2/success';
|
||||||
$oauthDefaultFailure = '/auth/oauth2/failure';
|
$oauthDefaultFailure = '/auth/oauth2/failure';
|
||||||
|
|
||||||
$createSession = function (string $userId, string $secret, Request $request, Response $response, Document $user, Database $dbForProject, Document $project, Locale $locale, Reader $geodb, Event $queueForEvents) {
|
function sendSessionAlert(Locale $locale, Document $user, Document $project, Document $session, Mail $queueForMails)
|
||||||
|
{
|
||||||
|
$subject = $locale->getText("emails.sessionAlert.subject");
|
||||||
|
$customTemplate = $project->getAttribute('templates', [])['email.sessionAlert-' . $locale->default] ?? [];
|
||||||
|
|
||||||
|
$message = Template::fromFile(__DIR__ . '/../../config/locale/templates/email-session-alert.tpl');
|
||||||
|
$message
|
||||||
|
->setParam('{{hello}}', $locale->getText("emails.sessionAlert.hello"))
|
||||||
|
->setParam('{{body}}', $locale->getText("emails.sessionAlert.body"))
|
||||||
|
->setParam('{{listDevice}}', $locale->getText("emails.sessionAlert.listDevice"))
|
||||||
|
->setParam('{{listIpAddress}}', $locale->getText("emails.sessionAlert.listIpAddress"))
|
||||||
|
->setParam('{{listCountry}}', $locale->getText("emails.sessionAlert.listCountry"))
|
||||||
|
->setParam('{{footer}}', $locale->getText("emails.sessionAlert.footer"))
|
||||||
|
->setParam('{{thanks}}', $locale->getText("emails.sessionAlert.thanks"))
|
||||||
|
->setParam('{{signature}}', $locale->getText("emails.sessionAlert.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'),
|
||||||
|
'dateTime' => DateTime::format(new \DateTime(), 'Y-m-d H:i:s'),
|
||||||
|
'user' => $user->getAttribute('name'),
|
||||||
|
'project' => $project->getAttribute('name'),
|
||||||
|
'device' => $session->getAttribute('clientName'),
|
||||||
|
'ipAddress' => $session->getAttribute('ip'),
|
||||||
|
'country' => $locale->getText('countries.' . $session->getAttribute('countryCode'), $locale->getText('locale.country.unknown')),
|
||||||
|
];
|
||||||
|
|
||||||
|
$email = $user->getAttribute('email');
|
||||||
|
|
||||||
|
$queueForMails
|
||||||
|
->setSubject($subject)
|
||||||
|
->setBody($body)
|
||||||
|
->setVariables($emailVariables)
|
||||||
|
->setRecipient($email)
|
||||||
|
->trigger();
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
$createSession = function (string $userId, string $secret, Request $request, Response $response, Document $user, Database $dbForProject, Document $project, Locale $locale, Reader $geodb, Event $queueForEvents, Mail $queueForMails) {
|
||||||
$roles = Authorization::getRoles();
|
$roles = Authorization::getRoles();
|
||||||
$isPrivilegedUser = Auth::isPrivilegedUser($roles);
|
$isPrivilegedUser = Auth::isPrivilegedUser($roles);
|
||||||
$isAppUser = Auth::isAppUser($roles);
|
$isAppUser = Auth::isAppUser($roles);
|
||||||
|
@ -138,6 +223,10 @@ $createSession = function (string $userId, string $secret, Request $request, Res
|
||||||
throw new Exception(Exception::GENERAL_SERVER_ERROR, 'Failed saving user to DB');
|
throw new Exception(Exception::GENERAL_SERVER_ERROR, 'Failed saving user to DB');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ($project->getAttribute('auths', [])['sessionAlerts'] ?? false) {
|
||||||
|
sendSessionAlert($locale, $user, $project, $session, $queueForMails);
|
||||||
|
}
|
||||||
|
|
||||||
$queueForEvents
|
$queueForEvents
|
||||||
->setParam('userId', $user->getId())
|
->setParam('userId', $user->getId())
|
||||||
->setParam('sessionId', $session->getId());
|
->setParam('sessionId', $session->getId());
|
||||||
|
@ -719,8 +808,9 @@ App::post('/v1/account/sessions/email')
|
||||||
->inject('locale')
|
->inject('locale')
|
||||||
->inject('geodb')
|
->inject('geodb')
|
||||||
->inject('queueForEvents')
|
->inject('queueForEvents')
|
||||||
|
->inject('queueForMails')
|
||||||
->inject('hooks')
|
->inject('hooks')
|
||||||
->action(function (string $email, string $password, Request $request, Response $response, Document $user, Database $dbForProject, Document $project, Locale $locale, Reader $geodb, Event $queueForEvents, Hooks $hooks) {
|
->action(function (string $email, string $password, Request $request, Response $response, Document $user, Database $dbForProject, Document $project, Locale $locale, Reader $geodb, Event $queueForEvents, Mail $queueForMails, Hooks $hooks) {
|
||||||
$email = \strtolower($email);
|
$email = \strtolower($email);
|
||||||
$protocol = $request->getProtocol();
|
$protocol = $request->getProtocol();
|
||||||
|
|
||||||
|
@ -813,6 +903,10 @@ App::post('/v1/account/sessions/email')
|
||||||
->setParam('sessionId', $session->getId())
|
->setParam('sessionId', $session->getId())
|
||||||
;
|
;
|
||||||
|
|
||||||
|
if ($project->getAttribute('auths', [])['sessionAlerts'] ?? false) {
|
||||||
|
sendSessionAlert($locale, $user, $project, $session, $queueForMails);
|
||||||
|
}
|
||||||
|
|
||||||
$response->dynamic($session, Response::MODEL_SESSION);
|
$response->dynamic($session, Response::MODEL_SESSION);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -981,6 +1075,7 @@ App::post('/v1/account/sessions/token')
|
||||||
->inject('locale')
|
->inject('locale')
|
||||||
->inject('geodb')
|
->inject('geodb')
|
||||||
->inject('queueForEvents')
|
->inject('queueForEvents')
|
||||||
|
->inject('queueForMails')
|
||||||
->action($createSession);
|
->action($createSession);
|
||||||
|
|
||||||
App::get('/v1/account/sessions/oauth2/:provider')
|
App::get('/v1/account/sessions/oauth2/:provider')
|
||||||
|
@ -2142,6 +2237,7 @@ App::put('/v1/account/sessions/magic-url')
|
||||||
->inject('locale')
|
->inject('locale')
|
||||||
->inject('geodb')
|
->inject('geodb')
|
||||||
->inject('queueForEvents')
|
->inject('queueForEvents')
|
||||||
|
->inject('queueForMails')
|
||||||
->action($createSession);
|
->action($createSession);
|
||||||
|
|
||||||
App::put('/v1/account/sessions/phone')
|
App::put('/v1/account/sessions/phone')
|
||||||
|
@ -2172,6 +2268,7 @@ App::put('/v1/account/sessions/phone')
|
||||||
->inject('locale')
|
->inject('locale')
|
||||||
->inject('geodb')
|
->inject('geodb')
|
||||||
->inject('queueForEvents')
|
->inject('queueForEvents')
|
||||||
|
->inject('queueForMails')
|
||||||
->action($createSession);
|
->action($createSession);
|
||||||
|
|
||||||
App::post('/v1/account/tokens/phone')
|
App::post('/v1/account/tokens/phone')
|
||||||
|
|
|
@ -104,8 +104,10 @@ App::post('/v1/projects')
|
||||||
'passwordHistory' => 0,
|
'passwordHistory' => 0,
|
||||||
'passwordDictionary' => false,
|
'passwordDictionary' => false,
|
||||||
'duration' => Auth::TOKEN_EXPIRATION_LOGIN_LONG,
|
'duration' => Auth::TOKEN_EXPIRATION_LOGIN_LONG,
|
||||||
'personalDataCheck' => false
|
'personalDataCheck' => false,
|
||||||
|
'sessionAlerts' => false,
|
||||||
];
|
];
|
||||||
|
|
||||||
foreach ($auth as $method) {
|
foreach ($auth as $method) {
|
||||||
$auths[$method['key'] ?? ''] = true;
|
$auths[$method['key'] ?? ''] = true;
|
||||||
}
|
}
|
||||||
|
@ -362,7 +364,7 @@ App::patch('/v1/projects/:projectId')
|
||||||
});
|
});
|
||||||
|
|
||||||
App::patch('/v1/projects/:projectId/team')
|
App::patch('/v1/projects/:projectId/team')
|
||||||
->desc('Update Project Team')
|
->desc('Update project team')
|
||||||
->groups(['api', 'projects'])
|
->groups(['api', 'projects'])
|
||||||
->label('scope', 'projects.write')
|
->label('scope', 'projects.write')
|
||||||
->label('sdk.auth', [APP_AUTH_TYPE_ADMIN])
|
->label('sdk.auth', [APP_AUTH_TYPE_ADMIN])
|
||||||
|
@ -603,6 +605,37 @@ App::patch('/v1/projects/:projectId/oauth2')
|
||||||
$response->dynamic($project, Response::MODEL_PROJECT);
|
$response->dynamic($project, Response::MODEL_PROJECT);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
App::patch('/v1/projects/:projectId/auth/session-alerts')
|
||||||
|
->desc('Update project sessions emails')
|
||||||
|
->groups(['api', 'projects'])
|
||||||
|
->label('scope', 'projects.write')
|
||||||
|
->label('sdk.auth', [APP_AUTH_TYPE_ADMIN])
|
||||||
|
->label('sdk.namespace', 'projects')
|
||||||
|
->label('sdk.method', 'updateSessionAlerts')
|
||||||
|
->label('sdk.response.code', Response::STATUS_CODE_OK)
|
||||||
|
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
|
||||||
|
->label('sdk.response.model', Response::MODEL_PROJECT)
|
||||||
|
->param('projectId', '', new UID(), 'Project unique ID.')
|
||||||
|
->param('alerts', false, new Boolean(true), 'Set to true to enable session emails.')
|
||||||
|
->inject('response')
|
||||||
|
->inject('dbForConsole')
|
||||||
|
->action(function (string $projectId, bool $alerts, Response $response, Database $dbForConsole) {
|
||||||
|
|
||||||
|
$project = $dbForConsole->getDocument('projects', $projectId);
|
||||||
|
|
||||||
|
if ($project->isEmpty()) {
|
||||||
|
throw new Exception(Exception::PROJECT_NOT_FOUND);
|
||||||
|
}
|
||||||
|
|
||||||
|
$auths = $project->getAttribute('auths', []);
|
||||||
|
$auths['sessionAlerts'] = $alerts;
|
||||||
|
|
||||||
|
$dbForConsole->updateDocument('projects', $project->getId(), $project
|
||||||
|
->setAttribute('auths', $auths));
|
||||||
|
|
||||||
|
$response->dynamic($project, Response::MODEL_PROJECT);
|
||||||
|
});
|
||||||
|
|
||||||
App::patch('/v1/projects/:projectId/auth/limit')
|
App::patch('/v1/projects/:projectId/auth/limit')
|
||||||
->desc('Update project users limit')
|
->desc('Update project users limit')
|
||||||
->groups(['api', 'projects'])
|
->groups(['api', 'projects'])
|
||||||
|
|
|
@ -1323,6 +1323,7 @@ App::setResource('console', function () {
|
||||||
'invites' => System::getEnv('_APP_CONSOLE_INVITES', 'enabled') === 'enabled',
|
'invites' => System::getEnv('_APP_CONSOLE_INVITES', 'enabled') === 'enabled',
|
||||||
'limit' => (System::getEnv('_APP_CONSOLE_WHITELIST_ROOT', 'enabled') === 'enabled') ? 1 : 0, // limit signup to 1 user
|
'limit' => (System::getEnv('_APP_CONSOLE_WHITELIST_ROOT', 'enabled') === 'enabled') ? 1 : 0, // limit signup to 1 user
|
||||||
'duration' => Auth::TOKEN_EXPIRATION_LOGIN_LONG, // 1 Year in seconds
|
'duration' => Auth::TOKEN_EXPIRATION_LOGIN_LONG, // 1 Year in seconds
|
||||||
|
'sessionAlerts' => System::getEnv('_APP_CONSOLE_SESSION_ALERTS', 'disabled') === 'enabled'
|
||||||
],
|
],
|
||||||
'authWhitelistEmails' => (!empty(System::getEnv('_APP_CONSOLE_WHITELIST_EMAILS', null))) ? \explode(',', System::getEnv('_APP_CONSOLE_WHITELIST_EMAILS', null)) : [],
|
'authWhitelistEmails' => (!empty(System::getEnv('_APP_CONSOLE_WHITELIST_EMAILS', null))) ? \explode(',', System::getEnv('_APP_CONSOLE_WHITELIST_EMAILS', null)) : [],
|
||||||
'authWhitelistIPs' => (!empty(System::getEnv('_APP_CONSOLE_WHITELIST_IPS', null))) ? \explode(',', System::getEnv('_APP_CONSOLE_WHITELIST_IPS', null)) : [],
|
'authWhitelistIPs' => (!empty(System::getEnv('_APP_CONSOLE_WHITELIST_IPS', null))) ? \explode(',', System::getEnv('_APP_CONSOLE_WHITELIST_IPS', null)) : [],
|
||||||
|
|
|
@ -75,6 +75,7 @@ $image = $this->getParam('image', '');
|
||||||
- _APP_LOCALE
|
- _APP_LOCALE
|
||||||
- _APP_CONSOLE_WHITELIST_ROOT
|
- _APP_CONSOLE_WHITELIST_ROOT
|
||||||
- _APP_CONSOLE_WHITELIST_EMAILS
|
- _APP_CONSOLE_WHITELIST_EMAILS
|
||||||
|
- _APP_CONSOLE_SESSION_ALERTS
|
||||||
- _APP_CONSOLE_WHITELIST_IPS
|
- _APP_CONSOLE_WHITELIST_IPS
|
||||||
- _APP_CONSOLE_HOSTNAMES
|
- _APP_CONSOLE_HOSTNAMES
|
||||||
- _APP_SYSTEM_EMAIL_NAME
|
- _APP_SYSTEM_EMAIL_NAME
|
||||||
|
|
|
@ -98,6 +98,7 @@ services:
|
||||||
- _APP_LOCALE
|
- _APP_LOCALE
|
||||||
- _APP_CONSOLE_WHITELIST_ROOT
|
- _APP_CONSOLE_WHITELIST_ROOT
|
||||||
- _APP_CONSOLE_WHITELIST_EMAILS
|
- _APP_CONSOLE_WHITELIST_EMAILS
|
||||||
|
- _APP_CONSOLE_SESSION_ALERTS
|
||||||
- _APP_CONSOLE_WHITELIST_IPS
|
- _APP_CONSOLE_WHITELIST_IPS
|
||||||
- _APP_CONSOLE_HOSTNAMES
|
- _APP_CONSOLE_HOSTNAMES
|
||||||
- _APP_SYSTEM_EMAIL_NAME
|
- _APP_SYSTEM_EMAIL_NAME
|
||||||
|
|
|
@ -138,6 +138,12 @@ class Project extends Model
|
||||||
'default' => false,
|
'default' => false,
|
||||||
'example' => true,
|
'example' => true,
|
||||||
])
|
])
|
||||||
|
->addRule('authSessionAlerts', [
|
||||||
|
'type' => self::TYPE_BOOLEAN,
|
||||||
|
'description' => 'Whether or not to send session alert emails to users.',
|
||||||
|
'default' => false,
|
||||||
|
'example' => true,
|
||||||
|
])
|
||||||
->addRule('oAuthProviders', [
|
->addRule('oAuthProviders', [
|
||||||
'type' => Response::MODEL_AUTH_PROVIDER,
|
'type' => Response::MODEL_AUTH_PROVIDER,
|
||||||
'description' => 'List of Auth Providers.',
|
'description' => 'List of Auth Providers.',
|
||||||
|
@ -321,6 +327,7 @@ class Project extends Model
|
||||||
$document->setAttribute('authPasswordHistory', $authValues['passwordHistory'] ?? 0);
|
$document->setAttribute('authPasswordHistory', $authValues['passwordHistory'] ?? 0);
|
||||||
$document->setAttribute('authPasswordDictionary', $authValues['passwordDictionary'] ?? false);
|
$document->setAttribute('authPasswordDictionary', $authValues['passwordDictionary'] ?? false);
|
||||||
$document->setAttribute('authPersonalDataCheck', $authValues['personalDataCheck'] ?? false);
|
$document->setAttribute('authPersonalDataCheck', $authValues['personalDataCheck'] ?? false);
|
||||||
|
$document->setAttribute('authSessionAlerts', $authValues['sessionAlerts'] ?? false);
|
||||||
|
|
||||||
foreach ($auth as $index => $method) {
|
foreach ($auth as $index => $method) {
|
||||||
$key = $method['key'];
|
$key = $method['key'];
|
||||||
|
|
|
@ -1190,6 +1190,64 @@ class AccountCustomClientTest extends Scope
|
||||||
return $data;
|
return $data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @depends testCreateAccountSession
|
||||||
|
*/
|
||||||
|
public function testSessionAlert($data): void
|
||||||
|
{
|
||||||
|
$email = uniqid() . 'session-alert@appwrite.io';
|
||||||
|
$password = 'password123';
|
||||||
|
$name = 'Session Alert Tester';
|
||||||
|
|
||||||
|
// Enable session alerts
|
||||||
|
$response = $this->client->call(Client::METHOD_PATCH, '/projects/' . $this->getProject()['$id'] . '/auth/session-alerts', array_merge([
|
||||||
|
'origin' => 'http://localhost',
|
||||||
|
'content-type' => 'application/json',
|
||||||
|
'x-appwrite-project' => 'console',
|
||||||
|
'cookie' => 'a_session_console=' . $this->getRoot()['session'],
|
||||||
|
]), [
|
||||||
|
'alerts' => true,
|
||||||
|
]);
|
||||||
|
|
||||||
|
$this->assertEquals(200, $response['headers']['status-code']);
|
||||||
|
|
||||||
|
// Create a new account
|
||||||
|
$response = $this->client->call(Client::METHOD_POST, '/account', array_merge([
|
||||||
|
'origin' => 'http://localhost',
|
||||||
|
'content-type' => 'application/json',
|
||||||
|
'x-appwrite-project' => $this->getProject()['$id'],
|
||||||
|
]), [
|
||||||
|
'userId' => ID::unique(),
|
||||||
|
'email' => $email,
|
||||||
|
'password' => $password,
|
||||||
|
'name' => $name,
|
||||||
|
]);
|
||||||
|
|
||||||
|
$this->assertEquals(201, $response['headers']['status-code']);
|
||||||
|
|
||||||
|
// Create a session for the new account
|
||||||
|
$response = $this->client->call(Client::METHOD_POST, '/account/sessions/email', array_merge([
|
||||||
|
'origin' => 'http://localhost',
|
||||||
|
'content-type' => 'application/json',
|
||||||
|
'x-appwrite-project' => $this->getProject()['$id'],
|
||||||
|
'user-agent' => 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.0.0 Safari/537.36',
|
||||||
|
]), [
|
||||||
|
'email' => $email,
|
||||||
|
'password' => $password,
|
||||||
|
]);
|
||||||
|
|
||||||
|
$this->assertEquals(201, $response['headers']['status-code']);
|
||||||
|
|
||||||
|
// Check the alert email
|
||||||
|
$lastEmail = $this->getLastEmail();
|
||||||
|
|
||||||
|
$this->assertEquals($email, $lastEmail['to'][0]['address']);
|
||||||
|
$this->assertStringContainsString('New session alert', $lastEmail['subject']);
|
||||||
|
$this->assertStringContainsString($response['body']['ip'], $lastEmail['text']); // IP Address
|
||||||
|
$this->assertStringContainsString('Unknown', $lastEmail['text']); // Country
|
||||||
|
$this->assertStringContainsString($response['body']['clientName'], $lastEmail['text']); // Client name
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @depends testCreateAccountSession
|
* @depends testCreateAccountSession
|
||||||
*/
|
*/
|
||||||
|
|
Loading…
Reference in a new issue