Skip to content
This repository has been archived by the owner on Apr 26, 2024. It is now read-only.

[1/2] Allow homeservers to send registration emails | Sending the email #5835

Merged
merged 37 commits into from
Aug 30, 2019
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
eacd505
Allow homeservers to send registration emails
anoadragon453 Aug 8, 2019
959c051
Add changelog
anoadragon453 Aug 8, 2019
0197954
lint
anoadragon453 Aug 8, 2019
c7a2317
update
anoadragon453 Aug 8, 2019
053638d
account_threepid_delegate defaults to empty string. fix bug
anoadragon453 Aug 9, 2019
176dd5d
fix config
anoadragon453 Aug 14, 2019
73df394
lint
anoadragon453 Aug 14, 2019
c092a35
Fix lack of self.config
anoadragon453 Aug 14, 2019
616ee20
Standardize on self.store/self.config
anoadragon453 Aug 14, 2019
994c51f
Merge branch 'develop' into anoa/reg_email_sending_email
anoadragon453 Aug 14, 2019
cc5983d
Warn users with deprecated config option to update their config
anoadragon453 Aug 15, 2019
4f035bd
Fix registration email subject
anoadragon453 Aug 15, 2019
c8ba612
Actually send registration emails when registering
anoadragon453 Aug 15, 2019
7f402b1
Descope adding an email to your account
anoadragon453 Aug 15, 2019
858414f
Don't allow multiple path_regexes in client_patterns
anoadragon453 Aug 16, 2019
7e983f9
break up password reset and registration submit_token servlets
anoadragon453 Aug 16, 2019
7cd1133
lint
anoadragon453 Aug 16, 2019
6b053d3
Send emails through the configured identity server
anoadragon453 Aug 16, 2019
a6e22d7
Merge branch 'anoa/reg_email' into anoa/reg_email_sending_email
anoadragon453 Aug 19, 2019
a03cc2a
Split functionality off into other PRs
anoadragon453 Aug 19, 2019
075541a
Merge 'anoa/reg_email' into 'anoa/reg_email_sending_email'
anoadragon453 Aug 28, 2019
9e1e774
Merge branch 'anoa/reg_email' into anoa/reg_email_sending_email
anoadragon453 Aug 28, 2019
798e72b
lint
anoadragon453 Aug 28, 2019
1bc713d
Apply suggestions from code review
anoadragon453 Aug 28, 2019
70127b8
fixes from suggestions
anoadragon453 Aug 28, 2019
03d3789
Merge branch 'anoa/reg_email_sending_email' of github.com:matrix-org/…
anoadragon453 Aug 28, 2019
75b279e
Add v1.4.0 upgrade notes to UPGRADE.rst
anoadragon453 Aug 28, 2019
53c5432
Add email template information
anoadragon453 Aug 28, 2019
f14b097
lint
anoadragon453 Aug 28, 2019
6706844
Make things work again
anoadragon453 Aug 28, 2019
b29c62b
Update UPGRADE.rst to talk more about email reg
anoadragon453 Aug 29, 2019
9b1a340
Update UPGRADE.rst with reg success and fail templates
anoadragon453 Aug 29, 2019
ace8fa5
Address review comments
anoadragon453 Aug 29, 2019
5113d9e
Add password reset template information to UPGRADE.rst for Synapse v1
anoadragon453 Aug 29, 2019
06815e8
Tokens -> messages
anoadragon453 Aug 29, 2019
4dd5b97
Merge branch 'anoa/reg_email' into anoa/reg_email_sending_email
anoadragon453 Aug 29, 2019
80abdf2
Merge branch 'anoa/reg_email' into anoa/reg_email_sending_email
anoadragon453 Aug 30, 2019
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
36 changes: 36 additions & 0 deletions UPGRADE.rst
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,42 @@ returned by the Client-Server API:
# configured on port 443.
curl -kv https://<host.name>/_matrix/client/versions 2>&1 | grep "Server:"

Upgrading to v1.4.0
anoadragon453 marked this conversation as resolved.
Show resolved Hide resolved
===================

Config options
--------------

Synapse v1.4.0 deprecates the ``email.trust_identity_server_for_password_resets`` option and
replaces it with ``account_threepid_delegate``. These options define whether the homeserver
should use an external server (typically an `identity server
<https://matrix.org/docs/spec/identity_service/r0.2.1>`_) to handle sending password reset
tokens and (as of this Synapse release) registration via a third-party address (email or phone
number).

If ``email.trust_identity_server_for_password_resets`` was changed from its default to
``true``, and ``account_threepid_delegate`` is not set to an identity server domain, then the
server handling password resets and registration via third-party address will be set to the
first entry in your config's ``trusted_third_party_id_servers`` entry. If no domains are
configured, Synapse will throw an error on startup.

If ``email.trust_identity_server_for_password_resets`` is not set to ``true`` and
``account_threepid_delegate`` is not set to a domain, then Synapse will attempt to send
password reset and registration tokens itself. Currently Synapse only supports sending emails,
and does not have support for phone-based password reset or account registration. If Synapse is
configured to handle these on its own, the ``email`` block of the config must be configured. If
not, then password resets and registration via third-party IDs will be disabled.

Email templates
---------------

If you have configured a custom email template directory with the ``email.template_dir``
anoadragon453 marked this conversation as resolved.
Show resolved Hide resolved
option, be aware that templates ``registration.html`` and ``registration.txt`` have been
anoadragon453 marked this conversation as resolved.
Show resolved Hide resolved
added, and Synapse will expect them to exist inside the configured template directory.

To view the default email templates, see `synapse/res/templates
anoadragon453 marked this conversation as resolved.
Show resolved Hide resolved
<https://github.com/matrix-org/synapse/tree/master/synapse/res/templates>`_.

Upgrading to v1.2.0
===================

Expand Down
2 changes: 1 addition & 1 deletion changelog.d/5835.feature
Original file line number Diff line number Diff line change
@@ -1 +1 @@
Ability to send registration emails from the homeserver.
Add the ability to send registration emails from the homeserver rather than delegating to an Identity Server.
5 changes: 5 additions & 0 deletions docs/sample_config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -1208,6 +1208,11 @@ password_config:
# #password_reset_template_html: password_reset.html
# #password_reset_template_text: password_reset.txt
#
# # Templates for registration emails sent by the homeserver
# #
# #registration_template_html: registration.html
# #registration_template_text: registration.txt
#
# # Templates for password reset success and failure pages that a user
# # will see after attempting to reset their password
# #
Expand Down
16 changes: 12 additions & 4 deletions synapse/config/emailconfig.py
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,10 @@ def read_config(self, config, **kwargs):
# if they have this set and tell them to use the updated option, while using a default
# identity server in the process.
self.using_identity_server_from_trusted_list = False
if config.get("trust_identity_server_for_password_resets", False) is True:
if (
not self.account_threepid_delegate
and config.get("trust_identity_server_for_password_resets", False) is True
):
# Use the first entry in self.trusted_third_party_id_servers instead
if self.trusted_third_party_id_servers:
self.account_threepid_delegate = self.trusted_third_party_id_servers[0]
anoadragon453 marked this conversation as resolved.
Show resolved Hide resolved
Expand All @@ -98,11 +101,11 @@ def read_config(self, config, **kwargs):
'"trusted_third_party_id_servers" but it is empty.'
)

self.local_threepid_emails_disabled_due_to_config = False
self.local_threepid_handling_disabled_due_to_email_config = False
if self.threepid_behaviour == ThreepidBehaviour.LOCAL and email_config == {}:
# We cannot warn the user this has happened here
# Instead do so when a user attempts to reset their password
self.local_threepid_emails_disabled_due_to_config = True
self.local_threepid_handling_disabled_due_to_email_config = True

self.threepid_behaviour = ThreepidBehaviour.OFF

Expand Down Expand Up @@ -197,7 +200,7 @@ def read_config(self, config, **kwargs):
filepath = os.path.join(
self.email_template_dir, email_registration_template_success_html
)
self.email_registration_template_success_html = self.read_file(
self.email_registration_template_success_html_content = self.read_file(
filepath, "email.registration_template_success_html"
)

Expand Down Expand Up @@ -311,6 +314,11 @@ def generate_config_section(self, config_dir_path, server_name, **kwargs):
# #password_reset_template_html: password_reset.html
# #password_reset_template_text: password_reset.txt
#
# # Templates for registration emails sent by the homeserver
# #
# #registration_template_html: registration.html
# #registration_template_text: registration.txt
#
# # Templates for password reset success and failure pages that a user
# # will see after attempting to reset their password
# #
Expand Down
79 changes: 79 additions & 0 deletions synapse/handlers/identity.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
from twisted.internet import defer

from synapse.api.errors import CodeMessageException, HttpResponseException, SynapseError
from synapse.util.stringutils import random_string

from ._base import BaseHandler

Expand Down Expand Up @@ -196,6 +197,84 @@ def try_unbind_threepid_with_id_server(self, mxid, threepid, id_server):

return changed

@defer.inlineCallbacks
def send_threepid_validation(
self,
email_address,
client_secret,
send_attempt,
send_email_func,
next_link=None,
):
"""Send a threepid validation email for password reset or
registration purposes

Args:
email_address (str): The user's email address
client_secret (str): The provided client secret
send_attempt (int): Which send attempt this is
send_email_func (func): A function that takes an email address, token,
client_secret and session_id, sends an email
and returns a Deferred.
next_link (str|None): The URL to redirect the user to after validation

Returns:
The new session_id upon success

Raises:
SynapseError is an error occurred when sending the email
"""
# Check that this email/client_secret/send_attempt combo is new or
# greater than what we've seen previously
session = yield self.store.get_threepid_validation_session(
"email", client_secret, address=email_address, validated=False
)

# Check to see if a session already exists and that it is not yet
# marked as validated
if session and session.get("validated_at") is None:
session_id = session["session_id"]
last_send_attempt = session["last_send_attempt"]

# Check that the send_attempt is higher than previous attempts
if send_attempt <= last_send_attempt:
# If not, just return a success without sending an email
return session_id
else:
# An non-validated session does not exist yet.
# Generate a session id
session_id = random_string(16)

# Generate a new validation token
token = random_string(32)

# Send the mail with the link containing the token, client_secret
# and session_id
try:
yield send_email_func(email_address, token, client_secret, session_id)
except Exception:
logger.exception(
"Error sending threepid validation email to %s", email_address
)
raise SynapseError(500, "An error was encountered when sending the email")

token_expires = (
self.hs.clock.time_msec() + self.hs.config.email_validation_token_lifetime
)

yield self.store.start_or_continue_validation_session(
"email",
email_address,
session_id,
client_secret,
send_attempt,
next_link,
token,
token_expires,
)

return session_id

@defer.inlineCallbacks
def requestEmailToken(
self, id_server, email, client_secret, send_attempt, next_link=None
Expand Down
81 changes: 1 addition & 80 deletions synapse/push/mailer.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
from twisted.internet import defer

from synapse.api.constants import EventTypes
from synapse.api.errors import StoreError, SynapseError
from synapse.api.errors import StoreError
from synapse.logging.context import make_deferred_yieldable
from synapse.push.presentable_names import (
calculate_room_name,
Expand All @@ -37,7 +37,6 @@
)
from synapse.types import UserID
from synapse.util.async_helpers import concurrently_execute
from synapse.util.stringutils import random_string
from synapse.visibility import filter_events_for_client

logger = logging.getLogger(__name__)
Expand Down Expand Up @@ -124,84 +123,6 @@ def __init__(self, hs, app_name, template_html, template_text):

logger.info("Created Mailer for app_name %s" % app_name)

@defer.inlineCallbacks
def send_threepid_validation(
self,
email_address,
client_secret,
send_attempt,
send_email_func,
next_link=None,
):
"""Send a threepid validation email for password reset or
registration purposes

Args:
email_address (str): The user's email address
client_secret (str): The provided client secret
send_attempt (int): Which send attempt this is
send_email_func (func): A function that takes an email address, token,
client_secret and session_id, sends an email
and returns a Deferred.
next_link (str|None): The URL to redirect the user to after validation

Returns:
The new session_id upon success

Raises:
SynapseError is an error occurred when sending the email
"""
# Check that this email/client_secret/send_attempt combo is new or
# greater than what we've seen previously
session = yield self.store.get_threepid_validation_session(
"email", client_secret, address=email_address, validated=False
)

# Check to see if a session already exists and that it is not yet
# marked as validated
if session and session.get("validated_at") is None:
session_id = session["session_id"]
last_send_attempt = session["last_send_attempt"]

# Check that the send_attempt is higher than previous attempts
if send_attempt <= last_send_attempt:
# If not, just return a success without sending an email
return session_id
else:
# An non-validated session does not exist yet.
# Generate a session id
session_id = random_string(16)

# Generate a new validation token
token = random_string(32)

# Send the mail with the link containing the token, client_secret
# and session_id
try:
yield send_email_func(email_address, token, client_secret, session_id)
except Exception:
logger.exception(
"Error sending threepid validation email to %s", email_address
)
raise SynapseError(500, "An error was encountered when sending the email")

token_expires = (
self.hs.clock.time_msec() + self.hs.config.email_validation_token_lifetime
)

yield self.store.start_or_continue_validation_session(
"email",
email_address,
session_id,
client_secret,
send_attempt,
next_link,
token,
token_expires,
)

return session_id

@defer.inlineCallbacks
def send_password_reset_mail(self, email_address, token, client_secret, sid):
"""Send an email with a password reset link to a user
Expand Down
Loading