From 137d81be9ebe4233a678f1d4ebf545b378cb8077 Mon Sep 17 00:00:00 2001 From: loks0n <22452787+loks0n@users.noreply.github.com> Date: Tue, 16 Jul 2024 12:49:30 +0100 Subject: [PATCH 1/7] feat: add to templates --- app/config/locale/templates.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/config/locale/templates.php b/app/config/locale/templates.php index ac5a2acf1d..e013c3ccc9 100644 --- a/app/config/locale/templates.php +++ b/app/config/locale/templates.php @@ -6,7 +6,8 @@ return [ 'magicSession', 'recovery', 'invitation', - 'mfaChallenge' + 'mfaChallenge', + 'sessionAlert' ], 'sms' => [ 'verification', From 612aa1421bc1086f91b7aef62166a33bc33c20d1 Mon Sep 17 00:00:00 2001 From: loks0n <22452787+loks0n@users.noreply.github.com> Date: Tue, 16 Jul 2024 12:56:52 +0100 Subject: [PATCH 2/7] feat: improve copy --- app/config/locale/translations/en.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/app/config/locale/translations/en.json b/app/config/locale/translations/en.json index 3a4a199e38..b16b50196f 100644 --- a/app/config/locale/translations/en.json +++ b/app/config/locale/translations/en.json @@ -18,13 +18,13 @@ "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.signature": "{{project}} team", - "emails.sessionAlert.subject": "New session alert for {{project}}", + "emails.sessionAlert.subject": "Security alert: new session on your {{project}} account", "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.body": "A new session has been created 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.footer": "If this was you, there's nothing more you need to do.\nIf you didn't initiate this session or suspect any unauthorized activity, please secure your account.", "emails.sessionAlert.thanks": "Thanks,", "emails.sessionAlert.signature": "{{project}} team", "emails.otpSession.subject": "OTP for {{project}} Login", From 67ec4b49ed19d95079b355b34ff12e55134b9ee7 Mon Sep 17 00:00:00 2001 From: loks0n <22452787+loks0n@users.noreply.github.com> Date: Tue, 16 Jul 2024 13:01:23 +0100 Subject: [PATCH 3/7] feat: only send after first session --- app/controllers/api/account.php | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/app/controllers/api/account.php b/app/controllers/api/account.php index 37627d79fc..d99776e560 100644 --- a/app/controllers/api/account.php +++ b/app/controllers/api/account.php @@ -223,7 +223,12 @@ $createSession = function (string $userId, string $secret, Request $request, Res throw new Exception(Exception::GENERAL_SERVER_ERROR, 'Failed saving user to DB'); } - if ($project->getAttribute('auths', [])['sessionAlerts'] ?? false) { + $sessionAlertsEnabled = $project->getAttribute('auths', [])['sessionAlerts'] ?? false; + $isFirstSession = $dbForProject->count('sessions', [ + Query::equal('userId', [$user->getId()]), + ]) === 1; + + if ($sessionAlertsEnabled && !$isFirstSession) { sendSessionAlert($locale, $user, $project, $session, $queueForMails); } @@ -903,10 +908,16 @@ App::post('/v1/account/sessions/email') ->setParam('sessionId', $session->getId()) ; - if ($project->getAttribute('auths', [])['sessionAlerts'] ?? false) { + $sessionAlertsEnabled = $project->getAttribute('auths', [])['sessionAlerts'] ?? false; + $isFirstSession = $dbForProject->count('sessions', [ + Query::equal('userId', [$user->getId()]), + ]) === 1; + + if ($sessionAlertsEnabled && !$isFirstSession) { sendSessionAlert($locale, $user, $project, $session, $queueForMails); } + $response->dynamic($session, Response::MODEL_SESSION); }); From 20e77a1e9ee879d1830ff6285c68bb43e41bca6d Mon Sep 17 00:00:00 2001 From: loks0n <22452787+loks0n@users.noreply.github.com> Date: Tue, 16 Jul 2024 13:03:26 +0100 Subject: [PATCH 4/7] feat: optimise --- app/controllers/api/account.php | 27 ++++++++++++--------------- 1 file changed, 12 insertions(+), 15 deletions(-) diff --git a/app/controllers/api/account.php b/app/controllers/api/account.php index d99776e560..b4973da931 100644 --- a/app/controllers/api/account.php +++ b/app/controllers/api/account.php @@ -223,13 +223,12 @@ $createSession = function (string $userId, string $secret, Request $request, Res throw new Exception(Exception::GENERAL_SERVER_ERROR, 'Failed saving user to DB'); } - $sessionAlertsEnabled = $project->getAttribute('auths', [])['sessionAlerts'] ?? false; - $isFirstSession = $dbForProject->count('sessions', [ - Query::equal('userId', [$user->getId()]), - ]) === 1; - - if ($sessionAlertsEnabled && !$isFirstSession) { - sendSessionAlert($locale, $user, $project, $session, $queueForMails); + if ($$project->getAttribute('auths', [])['sessionAlerts'] ?? false) { + if ($dbForProject->count('sessions', [ + Query::equal('userId', [$user->getId()]), + ]) !== 1) { + sendSessionAlert($locale, $user, $project, $session, $queueForMails); + } } $queueForEvents @@ -908,16 +907,14 @@ App::post('/v1/account/sessions/email') ->setParam('sessionId', $session->getId()) ; - $sessionAlertsEnabled = $project->getAttribute('auths', [])['sessionAlerts'] ?? false; - $isFirstSession = $dbForProject->count('sessions', [ - Query::equal('userId', [$user->getId()]), - ]) === 1; - - if ($sessionAlertsEnabled && !$isFirstSession) { - sendSessionAlert($locale, $user, $project, $session, $queueForMails); + if ($$project->getAttribute('auths', [])['sessionAlerts'] ?? false) { + if ($dbForProject->count('sessions', [ + Query::equal('userId', [$user->getId()]), + ]) !== 1) { + sendSessionAlert($locale, $user, $project, $session, $queueForMails); + } } - $response->dynamic($session, Response::MODEL_SESSION); }); From 46fa5dbb74f09c843431627a63ec3134b9e0586d Mon Sep 17 00:00:00 2001 From: loks0n <22452787+loks0n@users.noreply.github.com> Date: Tue, 16 Jul 2024 13:31:32 +0100 Subject: [PATCH 5/7] test: update session alert tests --- .../Services/Account/AccountCustomClientTest.php | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/tests/e2e/Services/Account/AccountCustomClientTest.php b/tests/e2e/Services/Account/AccountCustomClientTest.php index 321b1110fd..7f465a8260 100644 --- a/tests/e2e/Services/Account/AccountCustomClientTest.php +++ b/tests/e2e/Services/Account/AccountCustomClientTest.php @@ -1225,7 +1225,7 @@ class AccountCustomClientTest extends Scope $this->assertEquals(201, $response['headers']['status-code']); - // Create a session for the new account + // Create first session for the new account $response = $this->client->call(Client::METHOD_POST, '/account/sessions/email', array_merge([ 'origin' => 'http://localhost', 'content-type' => 'application/json', @@ -1238,11 +1238,23 @@ class AccountCustomClientTest extends Scope $this->assertEquals(201, $response['headers']['status-code']); + // Create second 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, + ]); + + // Check the alert email $lastEmail = $this->getLastEmail(); $this->assertEquals($email, $lastEmail['to'][0]['address']); - $this->assertStringContainsString('New session alert', $lastEmail['subject']); + $this->assertStringContainsString('Security alert: new session', $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 From d765c7657637f84b7943f47b84a6f1656ec692e8 Mon Sep 17 00:00:00 2001 From: loks0n <22452787+loks0n@users.noreply.github.com> Date: Tue, 16 Jul 2024 14:42:46 +0100 Subject: [PATCH 6/7] fix: typo --- app/controllers/api/account.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/controllers/api/account.php b/app/controllers/api/account.php index b4973da931..9c00d5804d 100644 --- a/app/controllers/api/account.php +++ b/app/controllers/api/account.php @@ -223,7 +223,7 @@ $createSession = function (string $userId, string $secret, Request $request, Res throw new Exception(Exception::GENERAL_SERVER_ERROR, 'Failed saving user to DB'); } - if ($$project->getAttribute('auths', [])['sessionAlerts'] ?? false) { + if ($project->getAttribute('auths', [])['sessionAlerts'] ?? false) { if ($dbForProject->count('sessions', [ Query::equal('userId', [$user->getId()]), ]) !== 1) { @@ -907,7 +907,7 @@ App::post('/v1/account/sessions/email') ->setParam('sessionId', $session->getId()) ; - if ($$project->getAttribute('auths', [])['sessionAlerts'] ?? false) { + if ($project->getAttribute('auths', [])['sessionAlerts'] ?? false) { if ($dbForProject->count('sessions', [ Query::equal('userId', [$user->getId()]), ]) !== 1) { From 2060b23379732c32ba5e9d7c42daae893959d256 Mon Sep 17 00:00:00 2001 From: loks0n <22452787+loks0n@users.noreply.github.com> Date: Fri, 19 Jul 2024 22:19:52 +0100 Subject: [PATCH 7/7] feat: improve date --- app/config/locale/templates/email-session-alert.tpl | 2 +- app/controllers/api/account.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app/config/locale/templates/email-session-alert.tpl b/app/config/locale/templates/email-session-alert.tpl index 9855175b6f..20cecf212d 100644 --- a/app/config/locale/templates/email-session-alert.tpl +++ b/app/config/locale/templates/email-session-alert.tpl @@ -11,4 +11,4 @@
{{footer}}
{{thanks}}
-{{signature}}
+{{signature}}
\ No newline at end of file diff --git a/app/controllers/api/account.php b/app/controllers/api/account.php index 9c00d5804d..af4e60364e 100644 --- a/app/controllers/api/account.php +++ b/app/controllers/api/account.php @@ -124,7 +124,7 @@ function sendSessionAlert(Locale $locale, Document $user, Document $project, Doc $emailVariables = [ 'direction' => $locale->getText('settings.direction'), - 'dateTime' => DateTime::format(new \DateTime(), 'Y-m-d H:i:s'), + 'dateTime' => DateTime::format(new \DateTime(), 'h:ia MMMM dS'), 'user' => $user->getAttribute('name'), 'project' => $project->getAttribute('name'), 'device' => $session->getAttribute('clientName'),