forked from MirrorHub/synapse
Allow HS to send emails when adding an email to the HS (#6042)
This commit is contained in:
parent
7763dd3e95
commit
df3401a71d
12 changed files with 359 additions and 72 deletions
1
changelog.d/6042.feature
Normal file
1
changelog.d/6042.feature
Normal file
|
@ -0,0 +1 @@
|
|||
Allow homeserver to handle or delegate email validation when adding an email to a user's account.
|
|
@ -1261,6 +1261,12 @@ password_config:
|
|||
# #registration_template_html: registration.html
|
||||
# #registration_template_text: registration.txt
|
||||
#
|
||||
# # Templates for validation emails sent by the homeserver when adding an email to
|
||||
# # your user account
|
||||
# #
|
||||
# #add_threepid_template_html: add_threepid.html
|
||||
# #add_threepid_template_text: add_threepid.txt
|
||||
#
|
||||
# # Templates for password reset success and failure pages that a user
|
||||
# # will see after attempting to reset their password
|
||||
# #
|
||||
|
@ -1272,6 +1278,12 @@ password_config:
|
|||
# #
|
||||
# #registration_template_success_html: registration_success.html
|
||||
# #registration_template_failure_html: registration_failure.html
|
||||
#
|
||||
# # Templates for success and failure pages that a user will see after attempting
|
||||
# # to add an email or phone to their account
|
||||
# #
|
||||
# #add_threepid_success_html: add_threepid_success.html
|
||||
# #add_threepid_failure_html: add_threepid_failure.html
|
||||
|
||||
|
||||
#password_providers:
|
||||
|
|
|
@ -169,12 +169,22 @@ class EmailConfig(Config):
|
|||
self.email_registration_template_text = email_config.get(
|
||||
"registration_template_text", "registration.txt"
|
||||
)
|
||||
self.email_add_threepid_template_html = email_config.get(
|
||||
"add_threepid_template_html", "add_threepid.html"
|
||||
)
|
||||
self.email_add_threepid_template_text = email_config.get(
|
||||
"add_threepid_template_text", "add_threepid.txt"
|
||||
)
|
||||
|
||||
self.email_password_reset_template_failure_html = email_config.get(
|
||||
"password_reset_template_failure_html", "password_reset_failure.html"
|
||||
)
|
||||
self.email_registration_template_failure_html = email_config.get(
|
||||
"registration_template_failure_html", "registration_failure.html"
|
||||
)
|
||||
self.email_add_threepid_template_failure_html = email_config.get(
|
||||
"add_threepid_template_failure_html", "add_threepid_failure.html"
|
||||
)
|
||||
|
||||
# These templates do not support any placeholder variables, so we
|
||||
# will read them from disk once during setup
|
||||
|
@ -184,6 +194,9 @@ class EmailConfig(Config):
|
|||
email_registration_template_success_html = email_config.get(
|
||||
"registration_template_success_html", "registration_success.html"
|
||||
)
|
||||
email_add_threepid_template_success_html = email_config.get(
|
||||
"add_threepid_template_success_html", "add_threepid_success.html"
|
||||
)
|
||||
|
||||
# Check templates exist
|
||||
for f in [
|
||||
|
@ -191,9 +204,14 @@ class EmailConfig(Config):
|
|||
self.email_password_reset_template_text,
|
||||
self.email_registration_template_html,
|
||||
self.email_registration_template_text,
|
||||
self.email_add_threepid_template_html,
|
||||
self.email_add_threepid_template_text,
|
||||
self.email_password_reset_template_failure_html,
|
||||
self.email_registration_template_failure_html,
|
||||
self.email_add_threepid_template_failure_html,
|
||||
email_password_reset_template_success_html,
|
||||
email_registration_template_success_html,
|
||||
email_add_threepid_template_success_html,
|
||||
]:
|
||||
p = os.path.join(self.email_template_dir, f)
|
||||
if not os.path.isfile(p):
|
||||
|
@ -212,6 +230,12 @@ class EmailConfig(Config):
|
|||
self.email_registration_template_success_html_content = self.read_file(
|
||||
filepath, "email.registration_template_success_html"
|
||||
)
|
||||
filepath = os.path.join(
|
||||
self.email_template_dir, email_add_threepid_template_success_html
|
||||
)
|
||||
self.email_add_threepid_template_success_html_content = self.read_file(
|
||||
filepath, "email.add_threepid_template_success_html"
|
||||
)
|
||||
|
||||
if self.email_enable_notifs:
|
||||
required = [
|
||||
|
@ -328,6 +352,12 @@ class EmailConfig(Config):
|
|||
# #registration_template_html: registration.html
|
||||
# #registration_template_text: registration.txt
|
||||
#
|
||||
# # Templates for validation emails sent by the homeserver when adding an email to
|
||||
# # your user account
|
||||
# #
|
||||
# #add_threepid_template_html: add_threepid.html
|
||||
# #add_threepid_template_text: add_threepid.txt
|
||||
#
|
||||
# # Templates for password reset success and failure pages that a user
|
||||
# # will see after attempting to reset their password
|
||||
# #
|
||||
|
@ -339,6 +369,12 @@ class EmailConfig(Config):
|
|||
# #
|
||||
# #registration_template_success_html: registration_success.html
|
||||
# #registration_template_failure_html: registration_failure.html
|
||||
#
|
||||
# # Templates for success and failure pages that a user will see after attempting
|
||||
# # to add an email or phone to their account
|
||||
# #
|
||||
# #add_threepid_success_html: add_threepid_success.html
|
||||
# #add_threepid_failure_html: add_threepid_failure.html
|
||||
"""
|
||||
|
||||
|
||||
|
|
|
@ -81,11 +81,10 @@ class IdentityHandler(BaseHandler):
|
|||
given identity server
|
||||
|
||||
Args:
|
||||
id_server (str|None): The identity server to validate 3PIDs against. If None,
|
||||
we will attempt to extract id_server creds
|
||||
id_server (str): The identity server to validate 3PIDs against. Must be a
|
||||
complete URL including the protocol (http(s)://)
|
||||
|
||||
creds (dict[str, str]): Dictionary containing the following keys:
|
||||
* id_server|idServer: An optional domain name of an identity server
|
||||
* client_secret|clientSecret: A unique secret str provided by the client
|
||||
* sid: The ID of the validation session
|
||||
|
||||
|
@ -104,20 +103,10 @@ class IdentityHandler(BaseHandler):
|
|||
raise SynapseError(
|
||||
400, "Missing param session_id in creds", errcode=Codes.MISSING_PARAM
|
||||
)
|
||||
if not id_server:
|
||||
# Attempt to get the id_server from the creds dict
|
||||
id_server = creds.get("id_server") or creds.get("idServer")
|
||||
if not id_server:
|
||||
raise SynapseError(
|
||||
400, "Missing param id_server in creds", errcode=Codes.MISSING_PARAM
|
||||
)
|
||||
|
||||
query_params = {"sid": session_id, "client_secret": client_secret}
|
||||
|
||||
url = "https://%s%s" % (
|
||||
id_server,
|
||||
"/_matrix/identity/api/v1/3pid/getValidated3pid",
|
||||
)
|
||||
url = id_server + "/_matrix/identity/api/v1/3pid/getValidated3pid"
|
||||
|
||||
data = yield self.http_client.get_json(url, query_params)
|
||||
return data if "medium" in data else None
|
||||
|
|
|
@ -179,6 +179,35 @@ class Mailer(object):
|
|||
template_vars,
|
||||
)
|
||||
|
||||
@defer.inlineCallbacks
|
||||
def send_add_threepid_mail(self, email_address, token, client_secret, sid):
|
||||
"""Send an email with a validation link to a user for adding a 3pid to their account
|
||||
|
||||
Args:
|
||||
email_address (str): Email address we're sending the validation link to
|
||||
|
||||
token (str): Unique token generated by the server to verify the email was received
|
||||
|
||||
client_secret (str): Unique token generated by the client to group together
|
||||
multiple email sending attempts
|
||||
|
||||
sid (str): The generated session ID
|
||||
"""
|
||||
params = {"token": token, "client_secret": client_secret, "sid": sid}
|
||||
link = (
|
||||
self.hs.config.public_baseurl
|
||||
+ "_matrix/client/unstable/add_threepid/email/submit_token?%s"
|
||||
% urllib.parse.urlencode(params)
|
||||
)
|
||||
|
||||
template_vars = {"link": link}
|
||||
|
||||
yield self.send_email(
|
||||
email_address,
|
||||
"[%s] Validate Your Email" % self.hs.config.server_name,
|
||||
template_vars,
|
||||
)
|
||||
|
||||
@defer.inlineCallbacks
|
||||
def send_notification_mail(
|
||||
self, app_id, user_id, email_address, push_actions, reason
|
||||
|
|
9
synapse/res/templates/add_threepid.html
Normal file
9
synapse/res/templates/add_threepid.html
Normal file
|
@ -0,0 +1,9 @@
|
|||
<html>
|
||||
<body>
|
||||
<p>A request to add an email address to your Matrix account has been received. If this was you, please click the link below to confirm adding this email:</p>
|
||||
|
||||
<a href="{{ link }}">{{ link }}</a>
|
||||
|
||||
<p>If this was not you, you can safely ignore this email. Thank you.</p>
|
||||
</body>
|
||||
</html>
|
6
synapse/res/templates/add_threepid.txt
Normal file
6
synapse/res/templates/add_threepid.txt
Normal file
|
@ -0,0 +1,6 @@
|
|||
A request to add an email address to your Matrix account has been received. If this was you,
|
||||
please click the link below to confirm adding this email:
|
||||
|
||||
{{ link }}
|
||||
|
||||
If this was not you, you can safely ignore this email. Thank you.
|
8
synapse/res/templates/add_threepid_failure.html
Normal file
8
synapse/res/templates/add_threepid_failure.html
Normal file
|
@ -0,0 +1,8 @@
|
|||
<html>
|
||||
<head></head>
|
||||
<body>
|
||||
<p>The request failed for the following reason: {{ failure_reason }}.</p>
|
||||
|
||||
<p>No changes have been made to your account.</p>
|
||||
</body>
|
||||
</html>
|
6
synapse/res/templates/add_threepid_success.html
Normal file
6
synapse/res/templates/add_threepid_success.html
Normal file
|
@ -0,0 +1,6 @@
|
|||
<html>
|
||||
<head></head>
|
||||
<body>
|
||||
<p>Your email has now been validated, please return to your client. You may now close this window.</p>
|
||||
</body>
|
||||
</html>
|
|
@ -21,7 +21,12 @@ from six.moves import http_client
|
|||
from twisted.internet import defer
|
||||
|
||||
from synapse.api.constants import LoginType
|
||||
from synapse.api.errors import Codes, SynapseError, ThreepidValidationError
|
||||
from synapse.api.errors import (
|
||||
Codes,
|
||||
HttpResponseException,
|
||||
SynapseError,
|
||||
ThreepidValidationError,
|
||||
)
|
||||
from synapse.config.emailconfig import ThreepidBehaviour
|
||||
from synapse.http.server import finish_request
|
||||
from synapse.http.servlet import (
|
||||
|
@ -103,16 +108,9 @@ class EmailPasswordRequestTokenRestServlet(RestServlet):
|
|||
raise SynapseError(400, "Email not found", Codes.THREEPID_NOT_FOUND)
|
||||
|
||||
if self.config.threepid_behaviour_email == ThreepidBehaviour.REMOTE:
|
||||
# Have the configured identity server handle the request
|
||||
if not self.hs.config.account_threepid_delegate_email:
|
||||
logger.warn(
|
||||
"No upstream email account_threepid_delegate configured on the server to "
|
||||
"handle this request"
|
||||
)
|
||||
raise SynapseError(
|
||||
400, "Password reset by email is not supported on this homeserver"
|
||||
)
|
||||
assert self.hs.config.account_threepid_delegate_email
|
||||
|
||||
# Have the configured identity server handle the request
|
||||
ret = yield self.identity_handler.requestEmailToken(
|
||||
self.hs.config.account_threepid_delegate_email,
|
||||
email,
|
||||
|
@ -214,6 +212,11 @@ class PasswordResetSubmitTokenServlet(RestServlet):
|
|||
self.config = hs.config
|
||||
self.clock = hs.get_clock()
|
||||
self.store = hs.get_datastore()
|
||||
if self.config.threepid_behaviour_email == ThreepidBehaviour.LOCAL:
|
||||
self.failure_email_template, = load_jinja2_templates(
|
||||
self.config.email_template_dir,
|
||||
[self.config.email_password_reset_template_failure_html],
|
||||
)
|
||||
|
||||
@defer.inlineCallbacks
|
||||
def on_GET(self, request, medium):
|
||||
|
@ -261,13 +264,8 @@ class PasswordResetSubmitTokenServlet(RestServlet):
|
|||
request.setResponseCode(e.code)
|
||||
|
||||
# Show a failure page with a reason
|
||||
html_template, = load_jinja2_templates(
|
||||
self.config.email_template_dir,
|
||||
[self.config.email_password_reset_template_failure_html],
|
||||
)
|
||||
|
||||
template_vars = {"failure_reason": e.msg}
|
||||
html = html_template.render(**template_vars)
|
||||
html = self.failure_email_template.render(**template_vars)
|
||||
|
||||
request.write(html.encode("utf-8"))
|
||||
finish_request(request)
|
||||
|
@ -399,13 +397,35 @@ class EmailThreepidRequestTokenRestServlet(RestServlet):
|
|||
self.identity_handler = hs.get_handlers().identity_handler
|
||||
self.store = self.hs.get_datastore()
|
||||
|
||||
if self.config.threepid_behaviour_email == ThreepidBehaviour.LOCAL:
|
||||
template_html, template_text = load_jinja2_templates(
|
||||
self.config.email_template_dir,
|
||||
[
|
||||
self.config.email_add_threepid_template_html,
|
||||
self.config.email_add_threepid_template_text,
|
||||
],
|
||||
public_baseurl=self.config.public_baseurl,
|
||||
)
|
||||
self.mailer = Mailer(
|
||||
hs=self.hs,
|
||||
app_name=self.config.email_app_name,
|
||||
template_html=template_html,
|
||||
template_text=template_text,
|
||||
)
|
||||
|
||||
@defer.inlineCallbacks
|
||||
def on_POST(self, request):
|
||||
if self.config.threepid_behaviour_email == ThreepidBehaviour.OFF:
|
||||
if self.config.local_threepid_handling_disabled_due_to_email_config:
|
||||
logger.warn(
|
||||
"Adding emails have been disabled due to lack of an email config"
|
||||
)
|
||||
raise SynapseError(
|
||||
400, "Adding an email to your account is disabled on this server"
|
||||
)
|
||||
|
||||
body = parse_json_object_from_request(request)
|
||||
assert_params_in_dict(
|
||||
body, ["id_server", "client_secret", "email", "send_attempt"]
|
||||
)
|
||||
id_server = "https://" + body["id_server"] # Assume https
|
||||
assert_params_in_dict(body, ["client_secret", "email", "send_attempt"])
|
||||
client_secret = body["client_secret"]
|
||||
email = body["email"]
|
||||
send_attempt = body["send_attempt"]
|
||||
|
@ -425,9 +445,30 @@ class EmailThreepidRequestTokenRestServlet(RestServlet):
|
|||
if existing_user_id is not None:
|
||||
raise SynapseError(400, "Email is already in use", Codes.THREEPID_IN_USE)
|
||||
|
||||
ret = yield self.identity_handler.requestEmailToken(
|
||||
id_server, email, client_secret, send_attempt, next_link
|
||||
)
|
||||
if self.config.threepid_behaviour_email == ThreepidBehaviour.REMOTE:
|
||||
assert self.hs.config.account_threepid_delegate_email
|
||||
|
||||
# Have the configured identity server handle the request
|
||||
ret = yield self.identity_handler.requestEmailToken(
|
||||
self.hs.config.account_threepid_delegate_email,
|
||||
email,
|
||||
client_secret,
|
||||
send_attempt,
|
||||
next_link,
|
||||
)
|
||||
else:
|
||||
# Send threepid validation emails from Synapse
|
||||
sid = yield self.identity_handler.send_threepid_validation(
|
||||
email,
|
||||
client_secret,
|
||||
send_attempt,
|
||||
self.mailer.send_add_threepid_mail,
|
||||
next_link,
|
||||
)
|
||||
|
||||
# Wrap the session id in a JSON object
|
||||
ret = {"sid": sid}
|
||||
|
||||
return 200, ret
|
||||
|
||||
|
||||
|
@ -471,9 +512,86 @@ class MsisdnThreepidRequestTokenRestServlet(RestServlet):
|
|||
ret = yield self.identity_handler.requestMsisdnToken(
|
||||
id_server, country, phone_number, client_secret, send_attempt, next_link
|
||||
)
|
||||
|
||||
return 200, ret
|
||||
|
||||
|
||||
class AddThreepidSubmitTokenServlet(RestServlet):
|
||||
"""Handles 3PID validation token submission for adding an email to a user's account"""
|
||||
|
||||
PATTERNS = client_patterns(
|
||||
"/add_threepid/email/submit_token$", releases=(), unstable=True
|
||||
)
|
||||
|
||||
def __init__(self, hs):
|
||||
"""
|
||||
Args:
|
||||
hs (synapse.server.HomeServer): server
|
||||
"""
|
||||
super().__init__()
|
||||
self.config = hs.config
|
||||
self.clock = hs.get_clock()
|
||||
self.store = hs.get_datastore()
|
||||
if self.config.threepid_behaviour_email == ThreepidBehaviour.LOCAL:
|
||||
self.failure_email_template, = load_jinja2_templates(
|
||||
self.config.email_template_dir,
|
||||
[self.config.email_add_threepid_template_failure_html],
|
||||
)
|
||||
|
||||
@defer.inlineCallbacks
|
||||
def on_GET(self, request):
|
||||
if self.config.threepid_behaviour_email == ThreepidBehaviour.OFF:
|
||||
if self.config.local_threepid_handling_disabled_due_to_email_config:
|
||||
logger.warn(
|
||||
"Adding emails have been disabled due to lack of an email config"
|
||||
)
|
||||
raise SynapseError(
|
||||
400, "Adding an email to your account is disabled on this server"
|
||||
)
|
||||
elif self.config.threepid_behaviour_email == ThreepidBehaviour.REMOTE:
|
||||
raise SynapseError(
|
||||
400,
|
||||
"This homeserver is not validating threepids. Use an identity server "
|
||||
"instead.",
|
||||
)
|
||||
|
||||
sid = parse_string(request, "sid", required=True)
|
||||
client_secret = parse_string(request, "client_secret", required=True)
|
||||
token = parse_string(request, "token", required=True)
|
||||
|
||||
# Attempt to validate a 3PID session
|
||||
try:
|
||||
# Mark the session as valid
|
||||
next_link = yield self.store.validate_threepid_session(
|
||||
sid, client_secret, token, self.clock.time_msec()
|
||||
)
|
||||
|
||||
# Perform a 302 redirect if next_link is set
|
||||
if next_link:
|
||||
if next_link.startswith("file:///"):
|
||||
logger.warn(
|
||||
"Not redirecting to next_link as it is a local file: address"
|
||||
)
|
||||
else:
|
||||
request.setResponseCode(302)
|
||||
request.setHeader("Location", next_link)
|
||||
finish_request(request)
|
||||
return None
|
||||
|
||||
# Otherwise show the success template
|
||||
html = self.config.email_add_threepid_template_success_html_content
|
||||
request.setResponseCode(200)
|
||||
except ThreepidValidationError as e:
|
||||
request.setResponseCode(e.code)
|
||||
|
||||
# Show a failure page with a reason
|
||||
template_vars = {"failure_reason": e.msg}
|
||||
html = self.failure_email_template.render(**template_vars)
|
||||
|
||||
request.write(html.encode("utf-8"))
|
||||
finish_request(request)
|
||||
|
||||
|
||||
class ThreepidRestServlet(RestServlet):
|
||||
PATTERNS = client_patterns("/account/3pid$")
|
||||
|
||||
|
@ -495,6 +613,8 @@ class ThreepidRestServlet(RestServlet):
|
|||
|
||||
@defer.inlineCallbacks
|
||||
def on_POST(self, request):
|
||||
requester = yield self.auth.get_user_by_req(request)
|
||||
user_id = requester.user.to_string()
|
||||
body = parse_json_object_from_request(request)
|
||||
|
||||
threepid_creds = body.get("threePidCreds") or body.get("three_pid_creds")
|
||||
|
@ -502,26 +622,85 @@ class ThreepidRestServlet(RestServlet):
|
|||
raise SynapseError(
|
||||
400, "Missing param three_pid_creds", Codes.MISSING_PARAM
|
||||
)
|
||||
assert_params_in_dict(threepid_creds, ["client_secret", "sid"])
|
||||
|
||||
requester = yield self.auth.get_user_by_req(request)
|
||||
user_id = requester.user.to_string()
|
||||
client_secret = threepid_creds["client_secret"]
|
||||
sid = threepid_creds["sid"]
|
||||
|
||||
# Specify None as the identity server to retrieve it from the request body instead
|
||||
threepid = yield self.identity_handler.threepid_from_creds(None, threepid_creds)
|
||||
# We don't actually know which medium this 3PID is. Thus we first assume it's email,
|
||||
# and if validation fails we try msisdn
|
||||
validation_session = None
|
||||
|
||||
if not threepid:
|
||||
raise SynapseError(400, "Failed to auth 3pid", Codes.THREEPID_AUTH_FAILED)
|
||||
# Try to validate as email
|
||||
if self.hs.config.threepid_behaviour_email == ThreepidBehaviour.REMOTE:
|
||||
# Ask our delegated email identity server
|
||||
try:
|
||||
validation_session = yield self.identity_handler.threepid_from_creds(
|
||||
self.hs.config.account_threepid_delegate_email, threepid_creds
|
||||
)
|
||||
except HttpResponseException:
|
||||
logger.debug(
|
||||
"%s reported non-validated threepid: %s",
|
||||
self.hs.config.account_threepid_delegate_email,
|
||||
threepid_creds,
|
||||
)
|
||||
elif self.hs.config.threepid_behaviour_email == ThreepidBehaviour.LOCAL:
|
||||
# Get a validated session matching these details
|
||||
validation_session = yield self.datastore.get_threepid_validation_session(
|
||||
"email", client_secret, sid=sid, validated=True
|
||||
)
|
||||
|
||||
for reqd in ["medium", "address", "validated_at"]:
|
||||
if reqd not in threepid:
|
||||
logger.warn("Couldn't add 3pid: invalid response from ID server")
|
||||
raise SynapseError(500, "Invalid response from ID Server")
|
||||
# Old versions of Sydent return a 200 http code even on a failed validation check.
|
||||
# Thus, in addition to the HttpResponseException check above (which checks for
|
||||
# non-200 errors), we need to make sure validation_session isn't actually an error,
|
||||
# identified by containing an "error" key
|
||||
# See https://github.com/matrix-org/sydent/issues/215 for details
|
||||
if validation_session and "error" not in validation_session:
|
||||
yield self._add_threepid_to_account(user_id, validation_session)
|
||||
return 200, {}
|
||||
|
||||
yield self.auth_handler.add_threepid(
|
||||
user_id, threepid["medium"], threepid["address"], threepid["validated_at"]
|
||||
# Try to validate as msisdn
|
||||
if self.hs.config.account_threepid_delegate_msisdn:
|
||||
# Ask our delegated msisdn identity server
|
||||
try:
|
||||
validation_session = yield self.identity_handler.threepid_from_creds(
|
||||
self.hs.config.account_threepid_delegate_msisdn, threepid_creds
|
||||
)
|
||||
except HttpResponseException:
|
||||
logger.debug(
|
||||
"%s reported non-validated threepid: %s",
|
||||
self.hs.config.account_threepid_delegate_email,
|
||||
threepid_creds,
|
||||
)
|
||||
|
||||
# Check that validation_session isn't actually an error due to old Sydent instances
|
||||
# See explanatory comment above
|
||||
if validation_session and "error" not in validation_session:
|
||||
yield self._add_threepid_to_account(user_id, validation_session)
|
||||
return 200, {}
|
||||
|
||||
raise SynapseError(
|
||||
400, "No validated 3pid session found", Codes.THREEPID_AUTH_FAILED
|
||||
)
|
||||
|
||||
return 200, {}
|
||||
@defer.inlineCallbacks
|
||||
def _add_threepid_to_account(self, user_id, validation_session):
|
||||
"""Add a threepid wrapped in a validation_session dict to an account
|
||||
|
||||
Args:
|
||||
user_id (str): The mxid of the user to add this 3PID to
|
||||
|
||||
validation_session (dict): A dict containing the following:
|
||||
* medium - medium of the threepid
|
||||
* address - address of the threepid
|
||||
* validated_at - timestamp of when the validation occurred
|
||||
"""
|
||||
yield self.auth_handler.add_threepid(
|
||||
user_id,
|
||||
validation_session["medium"],
|
||||
validation_session["address"],
|
||||
validation_session["validated_at"],
|
||||
)
|
||||
|
||||
|
||||
class ThreepidUnbindRestServlet(RestServlet):
|
||||
|
@ -613,6 +792,7 @@ def register_servlets(hs, http_server):
|
|||
DeactivateAccountRestServlet(hs).register(http_server)
|
||||
EmailThreepidRequestTokenRestServlet(hs).register(http_server)
|
||||
MsisdnThreepidRequestTokenRestServlet(hs).register(http_server)
|
||||
AddThreepidSubmitTokenServlet(hs).register(http_server)
|
||||
ThreepidRestServlet(hs).register(http_server)
|
||||
ThreepidUnbindRestServlet(hs).register(http_server)
|
||||
ThreepidDeleteRestServlet(hs).register(http_server)
|
||||
|
|
|
@ -131,15 +131,9 @@ class EmailRegisterRequestTokenRestServlet(RestServlet):
|
|||
raise SynapseError(400, "Email is already in use", Codes.THREEPID_IN_USE)
|
||||
|
||||
if self.config.threepid_behaviour_email == ThreepidBehaviour.REMOTE:
|
||||
if not self.hs.config.account_threepid_delegate_email:
|
||||
logger.warn(
|
||||
"No upstream email account_threepid_delegate configured on the server to "
|
||||
"handle this request"
|
||||
)
|
||||
raise SynapseError(
|
||||
400, "Registration by email is not supported on this homeserver"
|
||||
)
|
||||
assert self.hs.config.account_threepid_delegate_email
|
||||
|
||||
# Have the configured identity server handle the request
|
||||
ret = yield self.identity_handler.requestEmailToken(
|
||||
self.hs.config.account_threepid_delegate_email,
|
||||
email,
|
||||
|
@ -246,6 +240,12 @@ class RegistrationSubmitTokenServlet(RestServlet):
|
|||
self.clock = hs.get_clock()
|
||||
self.store = hs.get_datastore()
|
||||
|
||||
if self.config.threepid_behaviour_email == ThreepidBehaviour.LOCAL:
|
||||
self.failure_email_template, = load_jinja2_templates(
|
||||
self.config.email_template_dir,
|
||||
[self.config.email_registration_template_failure_html],
|
||||
)
|
||||
|
||||
@defer.inlineCallbacks
|
||||
def on_GET(self, request, medium):
|
||||
if medium != "email":
|
||||
|
@ -289,17 +289,11 @@ class RegistrationSubmitTokenServlet(RestServlet):
|
|||
|
||||
request.setResponseCode(200)
|
||||
except ThreepidValidationError as e:
|
||||
# Show a failure page with a reason
|
||||
request.setResponseCode(e.code)
|
||||
|
||||
# Show a failure page with a reason
|
||||
html_template, = load_jinja2_templates(
|
||||
self.config.email_template_dir,
|
||||
[self.config.email_registration_template_failure_html],
|
||||
)
|
||||
|
||||
template_vars = {"failure_reason": e.msg}
|
||||
html = html_template.render(**template_vars)
|
||||
html = self.failure_email_template.render(**template_vars)
|
||||
|
||||
request.write(html.encode("utf-8"))
|
||||
finish_request(request)
|
||||
|
|
|
@ -24,7 +24,7 @@ from six.moves import range
|
|||
from twisted.internet import defer
|
||||
|
||||
from synapse.api.constants import UserTypes
|
||||
from synapse.api.errors import Codes, StoreError, ThreepidValidationError
|
||||
from synapse.api.errors import Codes, StoreError, SynapseError, ThreepidValidationError
|
||||
from synapse.metrics.background_process_metrics import run_as_background_process
|
||||
from synapse.storage import background_updates
|
||||
from synapse.storage._base import SQLBaseStore
|
||||
|
@ -661,18 +661,31 @@ class RegistrationWorkerStore(SQLBaseStore):
|
|||
medium (str|None): The medium of the 3PID
|
||||
address (str|None): The address of the 3PID
|
||||
sid (str|None): The ID of the validation session
|
||||
client_secret (str|None): A unique string provided by the client to
|
||||
help identify this validation attempt
|
||||
client_secret (str): A unique string provided by the client to help identify this
|
||||
validation attempt
|
||||
validated (bool|None): Whether sessions should be filtered by
|
||||
whether they have been validated already or not. None to
|
||||
perform no filtering
|
||||
|
||||
Returns:
|
||||
deferred {str, int}|None: A dict containing the
|
||||
latest session_id and send_attempt count for this 3PID.
|
||||
Otherwise None if there hasn't been a previous attempt
|
||||
Deferred[dict|None]: A dict containing the following:
|
||||
* address - address of the 3pid
|
||||
* medium - medium of the 3pid
|
||||
* client_secret - a secret provided by the client for this validation session
|
||||
* session_id - ID of the validation session
|
||||
* send_attempt - a number serving to dedupe send attempts for this session
|
||||
* validated_at - timestamp of when this session was validated if so
|
||||
|
||||
Otherwise None if a validation session is not found
|
||||
"""
|
||||
keyvalues = {"medium": medium, "client_secret": client_secret}
|
||||
if not client_secret:
|
||||
raise SynapseError(
|
||||
400, "Missing parameter: client_secret", errcode=Codes.MISSING_PARAM
|
||||
)
|
||||
|
||||
keyvalues = {"client_secret": client_secret}
|
||||
if medium:
|
||||
keyvalues["medium"] = medium
|
||||
if address:
|
||||
keyvalues["address"] = address
|
||||
if sid:
|
||||
|
@ -1209,6 +1222,10 @@ class RegistrationStore(
|
|||
current_ts (int): The current unix time in milliseconds. Used for
|
||||
checking token expiry status
|
||||
|
||||
Raises:
|
||||
ThreepidValidationError: if a matching validation token was not found or has
|
||||
expired
|
||||
|
||||
Returns:
|
||||
deferred str|None: A str representing a link to redirect the user
|
||||
to if there is one.
|
||||
|
|
Loading…
Reference in a new issue