Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Merged
merged 5 commits into from
Apr 23, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions changelog.d/16819.feature
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Send an email if the address is already bound to an user account.
12 changes: 12 additions & 0 deletions synapse/config/emailconfig.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@
"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",
"email_validation": "[%(server_name)s] Validate your email",
"email_already_in_use": "[%(server_name)s] Email already in use",
}

LEGACY_TEMPLATE_DIR_WARNING = """
Expand All @@ -76,6 +77,7 @@ class EmailSubjectConfig:
invite_from_person_to_space: str
password_reset: str
email_validation: str
email_already_in_use: str


class EmailConfig(Config):
Expand Down Expand Up @@ -180,6 +182,12 @@ def read_config(self, config: JsonDict, **kwargs: Any) -> None:
registration_template_text = email_config.get(
"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", "add_threepid.html"
)
Expand Down Expand Up @@ -215,6 +223,8 @@ def read_config(self, config: JsonDict, **kwargs: Any) -> None:
self.email_password_reset_template_text,
self.email_registration_template_html,
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_text,
self.email_password_reset_template_confirmation_html,
Expand All @@ -230,6 +240,8 @@ def read_config(self, config: JsonDict, **kwargs: Any) -> None:
password_reset_template_text,
registration_template_html,
registration_template_text,
already_in_use_template_html,
already_in_use_template_text,
add_threepid_template_html,
add_threepid_template_text,
"password_reset_confirmation.html",
Expand Down
16 changes: 16 additions & 0 deletions synapse/push/mailer.py
Original file line number Diff line number Diff line change
Expand Up @@ -205,6 +205,22 @@ async def send_registration_mail(
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")

async def send_add_threepid_mail(
Expand Down
12 changes: 12 additions & 0 deletions synapse/res/templates/already_in_use.html
Original file line number Diff line number Diff line change
@@ -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 %}
10 changes: 10 additions & 0 deletions synapse/res/templates/already_in_use.txt
Original file line number Diff line number Diff line change
@@ -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.
12 changes: 10 additions & 2 deletions synapse/rest/client/register.py
Original file line number Diff line number Diff line change
Expand Up @@ -86,12 +86,18 @@ def __init__(self, hs: "HomeServer"):
self.config = hs.config

if self.hs.config.email.can_verify_email:
self.mailer = Mailer(
self.registration_mailer = Mailer(
hs=self.hs,
app_name=self.config.email.email_app_name,
template_html=self.config.email.email_registration_template_html,
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]:
if not self.hs.config.email.can_verify_email:
Expand Down Expand Up @@ -139,8 +145,10 @@ async def on_POST(self, request: SynapseRequest) -> Tuple[int, JsonDict]:
if self.hs.config.server.request_token_inhibit_3pid_errors:
# Make the client think the operation succeeded. See the rationale in the
# 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
# 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)
return 200, {"sid": random_string(16)}

Expand All @@ -151,7 +159,7 @@ async def on_POST(self, request: SynapseRequest) -> Tuple[int, JsonDict]:
email,
client_secret,
send_attempt,
self.mailer.send_registration_mail,
self.registration_mailer.send_registration_mail,
next_link,
)

Expand Down
9 changes: 9 additions & 0 deletions tests/rest/client/test_register.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
import datetime
import os
from typing import Any, Dict, List, Tuple
from unittest.mock import AsyncMock

import pkg_resources

Expand All @@ -42,6 +43,7 @@
from synapse.util import Clock

from tests import unittest
from tests.server import ThreadedMemoryReactorClock
from tests.unittest import override_config


Expand All @@ -58,6 +60,13 @@ def default_config(self) -> Dict[str, Any]:
config["allow_guest_access"] = True
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:
user_id = "@as_user_kermit:test"
as_token = "i_am_an_app_service"
Expand Down
Loading