Send an email if the address is already bound to an user account (#16819)

Co-authored-by: Mathieu Velten <mathieu.velten@beta.gouv.fr>
Co-authored-by: Olivier D <odelcroi@gmail.com>
This commit is contained in:
mcalinghee 2024-04-23 17:45:24 +02:00 committed by GitHub
parent 074ef4d75f
commit ae181233aa
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 70 additions and 2 deletions

View File

@ -0,0 +1 @@
Send an email if the address is already bound to an user account.

View File

@ -52,6 +52,7 @@ DEFAULT_SUBJECTS = {
"invite_from_person_to_space": "[%(app)s] %(person)s has invited you to join the %(space)s space on %(app)s...", "invite_from_person_to_space": "[%(app)s] %(person)s has invited you to join the %(space)s space on %(app)s...",
"password_reset": "[%(server_name)s] Password reset", "password_reset": "[%(server_name)s] Password reset",
"email_validation": "[%(server_name)s] Validate your email", "email_validation": "[%(server_name)s] Validate your email",
"email_already_in_use": "[%(server_name)s] Email already in use",
} }
LEGACY_TEMPLATE_DIR_WARNING = """ LEGACY_TEMPLATE_DIR_WARNING = """
@ -76,6 +77,7 @@ class EmailSubjectConfig:
invite_from_person_to_space: str invite_from_person_to_space: str
password_reset: str password_reset: str
email_validation: str email_validation: str
email_already_in_use: str
class EmailConfig(Config): class EmailConfig(Config):
@ -180,6 +182,12 @@ class EmailConfig(Config):
registration_template_text = email_config.get( registration_template_text = email_config.get(
"registration_template_text", "registration.txt" "registration_template_text", "registration.txt"
) )
already_in_use_template_html = email_config.get(
"already_in_use_template_html", "already_in_use.html"
)
already_in_use_template_text = email_config.get(
"already_in_use_template_html", "already_in_use.txt"
)
add_threepid_template_html = email_config.get( add_threepid_template_html = email_config.get(
"add_threepid_template_html", "add_threepid.html" "add_threepid_template_html", "add_threepid.html"
) )
@ -215,6 +223,8 @@ class EmailConfig(Config):
self.email_password_reset_template_text, self.email_password_reset_template_text,
self.email_registration_template_html, self.email_registration_template_html,
self.email_registration_template_text, self.email_registration_template_text,
self.email_already_in_use_template_html,
self.email_already_in_use_template_text,
self.email_add_threepid_template_html, self.email_add_threepid_template_html,
self.email_add_threepid_template_text, self.email_add_threepid_template_text,
self.email_password_reset_template_confirmation_html, self.email_password_reset_template_confirmation_html,
@ -230,6 +240,8 @@ class EmailConfig(Config):
password_reset_template_text, password_reset_template_text,
registration_template_html, registration_template_html,
registration_template_text, registration_template_text,
already_in_use_template_html,
already_in_use_template_text,
add_threepid_template_html, add_threepid_template_html,
add_threepid_template_text, add_threepid_template_text,
"password_reset_confirmation.html", "password_reset_confirmation.html",

View File

@ -205,6 +205,22 @@ class Mailer:
template_vars, template_vars,
) )
emails_sent_counter.labels("already_in_use")
async def send_already_in_use_mail(self, email_address: str) -> None:
"""Send an email if the address is already bound to an user account
Args:
email_address: Email address we're sending to the "already in use" mail
"""
await self.send_email(
email_address,
self.email_subjects.email_already_in_use
% {"server_name": self.hs.config.server.server_name, "app": self.app_name},
{},
)
emails_sent_counter.labels("add_threepid") emails_sent_counter.labels("add_threepid")
async def send_add_threepid_mail( async def send_add_threepid_mail(

View File

@ -0,0 +1,12 @@
{% extends "_base.html" %}
{% block title %}Email already in use{% endblock %}
{% block body %}
<p>You have asked us to register this email with a new Matrix account, but this email is already registered with an existing account.</p>
<p>Please reset your password if needed.</p>
<p>If this was not you, you can safely disregard this email.</p>
<p>Thank you.</p>
{% endblock %}

View File

@ -0,0 +1,10 @@
Hello there,
You have asked us to register this email with a new Matrix account,
but this email is already registered with an existing account.
Please reset your password if needed.
If this was not you, you can safely disregard this email.
Thank you.

View File

@ -86,12 +86,18 @@ class EmailRegisterRequestTokenRestServlet(RestServlet):
self.config = hs.config self.config = hs.config
if self.hs.config.email.can_verify_email: if self.hs.config.email.can_verify_email:
self.mailer = Mailer( self.registration_mailer = Mailer(
hs=self.hs, hs=self.hs,
app_name=self.config.email.email_app_name, app_name=self.config.email.email_app_name,
template_html=self.config.email.email_registration_template_html, template_html=self.config.email.email_registration_template_html,
template_text=self.config.email.email_registration_template_text, template_text=self.config.email.email_registration_template_text,
) )
self.already_in_use_mailer = Mailer(
hs=self.hs,
app_name=self.config.email.email_app_name,
template_html=self.config.email.email_already_in_use_template_html,
template_text=self.config.email.email_already_in_use_template_text,
)
async def on_POST(self, request: SynapseRequest) -> Tuple[int, JsonDict]: async def on_POST(self, request: SynapseRequest) -> Tuple[int, JsonDict]:
if not self.hs.config.email.can_verify_email: if not self.hs.config.email.can_verify_email:
@ -139,8 +145,10 @@ class EmailRegisterRequestTokenRestServlet(RestServlet):
if self.hs.config.server.request_token_inhibit_3pid_errors: if self.hs.config.server.request_token_inhibit_3pid_errors:
# Make the client think the operation succeeded. See the rationale in the # Make the client think the operation succeeded. See the rationale in the
# comments for request_token_inhibit_3pid_errors. # comments for request_token_inhibit_3pid_errors.
# Still send an email to warn the user that an account already exists.
# Also wait for some random amount of time between 100ms and 1s to make it # Also wait for some random amount of time between 100ms and 1s to make it
# look like we did something. # look like we did something.
await self.already_in_use_mailer.send_already_in_use_mail(email)
await self.hs.get_clock().sleep(random.randint(1, 10) / 10) await self.hs.get_clock().sleep(random.randint(1, 10) / 10)
return 200, {"sid": random_string(16)} return 200, {"sid": random_string(16)}
@ -151,7 +159,7 @@ class EmailRegisterRequestTokenRestServlet(RestServlet):
email, email,
client_secret, client_secret,
send_attempt, send_attempt,
self.mailer.send_registration_mail, self.registration_mailer.send_registration_mail,
next_link, next_link,
) )

View File

@ -22,6 +22,7 @@
import datetime import datetime
import os import os
from typing import Any, Dict, List, Tuple from typing import Any, Dict, List, Tuple
from unittest.mock import AsyncMock
import pkg_resources import pkg_resources
@ -42,6 +43,7 @@ from synapse.types import JsonDict
from synapse.util import Clock from synapse.util import Clock
from tests import unittest from tests import unittest
from tests.server import ThreadedMemoryReactorClock
from tests.unittest import override_config from tests.unittest import override_config
@ -58,6 +60,13 @@ class RegisterRestServletTestCase(unittest.HomeserverTestCase):
config["allow_guest_access"] = True config["allow_guest_access"] = True
return config return config
def make_homeserver(
self, reactor: ThreadedMemoryReactorClock, clock: Clock
) -> HomeServer:
hs = super().make_homeserver(reactor, clock)
hs.get_send_email_handler()._sendmail = AsyncMock()
return hs
def test_POST_appservice_registration_valid(self) -> None: def test_POST_appservice_registration_valid(self) -> None:
user_id = "@as_user_kermit:test" user_id = "@as_user_kermit:test"
as_token = "i_am_an_app_service" as_token = "i_am_an_app_service"