diff --git a/synapse/rest/client/v2_alpha/account.py b/synapse/rest/client/v2_alpha/account.py
index 1139bb156c..b8c48dc8f1 100644
--- a/synapse/rest/client/v2_alpha/account.py
+++ b/synapse/rest/client/v2_alpha/account.py
@@ -21,12 +21,7 @@ from six.moves import http_client
from twisted.internet import defer
from synapse.api.constants import LoginType
-from synapse.api.errors import (
- Codes,
- HttpResponseException,
- SynapseError,
- ThreepidValidationError,
-)
+from synapse.api.errors import Codes, SynapseError, ThreepidValidationError
from synapse.config.emailconfig import ThreepidBehaviour
from synapse.http.server import finish_request
from synapse.http.servlet import (
@@ -485,10 +480,8 @@ class MsisdnThreepidRequestTokenRestServlet(RestServlet):
def on_POST(self, request):
body = parse_json_object_from_request(request)
assert_params_in_dict(
- body,
- ["id_server", "client_secret", "country", "phone_number", "send_attempt"],
+ body, ["client_secret", "country", "phone_number", "send_attempt"]
)
- id_server = "https://" + body["id_server"] # Assume https
client_secret = body["client_secret"]
country = body["country"]
phone_number = body["phone_number"]
@@ -509,8 +502,23 @@ class MsisdnThreepidRequestTokenRestServlet(RestServlet):
if existing_user_id is not None:
raise SynapseError(400, "MSISDN is already in use", Codes.THREEPID_IN_USE)
+ if not self.hs.config.account_threepid_delegate_msisdn:
+ logger.warn(
+ "No upstream msisdn account_threepid_delegate configured on the server to "
+ "handle this request"
+ )
+ raise SynapseError(
+ 400,
+ "Adding phone numbers to user account is not supported by this homeserver",
+ )
+
ret = yield self.identity_handler.requestMsisdnToken(
- id_server, country, phone_number, client_secret, send_attempt, next_link
+ self.hs.config.account_threepid_delegate_msisdn,
+ country,
+ phone_number,
+ client_secret,
+ send_attempt,
+ next_link,
)
return 200, ret
@@ -627,81 +635,88 @@ class ThreepidRestServlet(RestServlet):
client_secret = threepid_creds["client_secret"]
sid = threepid_creds["sid"]
- # 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
-
- # 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
- )
-
- # 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)
+ validation_session = yield self.identity_handler.validate_threepid_session(
+ client_secret, sid
+ )
+ if validation_session:
+ yield self.auth_handler.add_threepid(
+ user_id,
+ validation_session["medium"],
+ validation_session["address"],
+ validation_session["validated_at"],
+ )
return 200, {}
- # 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,
- )
+ raise SynapseError(
+ 400, "No validated 3pid session found", Codes.THREEPID_AUTH_FAILED
+ )
+
- # 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, {}
+class ThreepidAddRestServlet(RestServlet):
+ PATTERNS = client_patterns("/account/3pid/add$", releases=(), unstable=True)
+
+ def __init__(self, hs):
+ super(ThreepidAddRestServlet, self).__init__()
+ self.hs = hs
+ self.identity_handler = hs.get_handlers().identity_handler
+ self.auth = hs.get_auth()
+ self.auth_handler = hs.get_auth_handler()
+
+ @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)
+
+ assert_params_in_dict(body, ["client_secret", "sid"])
+ client_secret = body["client_secret"]
+ sid = body["sid"]
+
+ validation_session = yield self.identity_handler.validate_threepid_session(
+ client_secret, sid
+ )
+ if validation_session:
+ yield self.auth_handler.add_threepid(
+ user_id,
+ validation_session["medium"],
+ validation_session["address"],
+ validation_session["validated_at"],
+ )
+ return 200, {}
raise SynapseError(
400, "No validated 3pid session found", Codes.THREEPID_AUTH_FAILED
)
+
+class ThreepidBindRestServlet(RestServlet):
+ PATTERNS = client_patterns("/account/3pid/bind$", releases=(), unstable=True)
+
+ def __init__(self, hs):
+ super(ThreepidBindRestServlet, self).__init__()
+ self.hs = hs
+ self.identity_handler = hs.get_handlers().identity_handler
+ self.auth = hs.get_auth()
+
@defer.inlineCallbacks
- def _add_threepid_to_account(self, user_id, validation_session):
- """Add a threepid wrapped in a validation_session dict to an account
+ def on_POST(self, request):
+ body = parse_json_object_from_request(request)
- Args:
- user_id (str): The mxid of the user to add this 3PID to
+ assert_params_in_dict(body, ["id_server", "sid", "client_secret"])
+ id_server = body["id_server"]
+ sid = body["sid"]
+ client_secret = body["client_secret"]
+ id_access_token = body.get("id_access_token") # optional
- 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"],
+ requester = yield self.auth.get_user_by_req(request)
+ user_id = requester.user.to_string()
+
+ yield self.identity_handler.bind_threepid(
+ client_secret, sid, user_id, id_server, id_access_token
)
+ return 200, {}
+
class ThreepidUnbindRestServlet(RestServlet):
PATTERNS = client_patterns("/account/3pid/unbind$", releases=(), unstable=True)
@@ -794,6 +809,8 @@ def register_servlets(hs, http_server):
MsisdnThreepidRequestTokenRestServlet(hs).register(http_server)
AddThreepidSubmitTokenServlet(hs).register(http_server)
ThreepidRestServlet(hs).register(http_server)
+ ThreepidAddRestServlet(hs).register(http_server)
+ ThreepidBindRestServlet(hs).register(http_server)
ThreepidUnbindRestServlet(hs).register(http_server)
ThreepidDeleteRestServlet(hs).register(http_server)
WhoamiRestServlet(hs).register(http_server)
diff --git a/synapse/rest/client/v2_alpha/register.py b/synapse/rest/client/v2_alpha/register.py
index e99b1f5c45..135a70808f 100644
--- a/synapse/rest/client/v2_alpha/register.py
+++ b/synapse/rest/client/v2_alpha/register.py
@@ -246,6 +246,12 @@ class RegistrationSubmitTokenServlet(RestServlet):
[self.config.email_registration_template_failure_html],
)
+ 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":
|