summary refs log tree commit diff
diff options
context:
space:
mode:
authorDavid Baker <dave@matrix.org>2015-08-04 14:37:09 +0100
committerDavid Baker <dave@matrix.org>2015-08-04 14:37:09 +0100
commitc77048e12f032842cebbb0f1a0639bb62db88418 (patch)
tree9f9f29aa34f422d081ccef3fa177dd4362a45adb
parentDon't try & check the username if we don't have one (which we won't if it's b... (diff)
downloadsynapse-c77048e12f032842cebbb0f1a0639bb62db88418.tar.xz
Add endpoint that proxies ID server request token and errors if the given email is in use on this Home Server.
-rw-r--r--synapse/api/errors.py1
-rw-r--r--synapse/handlers/identity.py25
-rw-r--r--synapse/rest/client/v2_alpha/register.py27
-rw-r--r--synapse/storage/schema/delta/22/user_threepids_unique.sql19
4 files changed, 71 insertions, 1 deletions
diff --git a/synapse/api/errors.py b/synapse/api/errors.py
index 0b3320e62c..c3b4d971a8 100644
--- a/synapse/api/errors.py
+++ b/synapse/api/errors.py
@@ -40,6 +40,7 @@ class Codes(object):
     TOO_LARGE = "M_TOO_LARGE"
     EXCLUSIVE = "M_EXCLUSIVE"
     THREEPID_AUTH_FAILED = "M_THREEPID_AUTH_FAILED"
+    THREEPID_IN_USE = "THREEPID_IN_USE"
 
 
 class CodeMessageException(RuntimeError):
diff --git a/synapse/handlers/identity.py b/synapse/handlers/identity.py
index c1095708a0..2a99921d5f 100644
--- a/synapse/handlers/identity.py
+++ b/synapse/handlers/identity.py
@@ -117,3 +117,28 @@ class IdentityHandler(BaseHandler):
         except CodeMessageException as e:
             data = json.loads(e.msg)
         defer.returnValue(data)
+
+    @defer.inlineCallbacks
+    def requestEmailToken(self, id_server, email, client_secret, send_attempt, **kwargs):
+        yield run_on_reactor()
+        http_client = SimpleHttpClient(self.hs)
+
+        params = {
+            'email': email,
+            'client_secret': client_secret,
+            'send_attempt': send_attempt,
+        }
+        params.update(kwargs)
+
+        try:
+            data = yield http_client.post_urlencoded_get_json(
+                "https://%s%s" % (
+                    id_server,
+                    "/_matrix/identity/api/v1/validate/email/requestToken"
+                ),
+                params
+            )
+            defer.returnValue(data)
+        except CodeMessageException as e:
+            logger.info("Proxied requestToken failed: %r", e)
+            raise e
diff --git a/synapse/rest/client/v2_alpha/register.py b/synapse/rest/client/v2_alpha/register.py
index b5926f9ca6..7b97a73df6 100644
--- a/synapse/rest/client/v2_alpha/register.py
+++ b/synapse/rest/client/v2_alpha/register.py
@@ -41,7 +41,7 @@ logger = logging.getLogger(__name__)
 
 
 class RegisterRestServlet(RestServlet):
-    PATTERN = client_v2_pattern("/register")
+    PATTERN = client_v2_pattern("/register*")
 
     def __init__(self, hs):
         super(RegisterRestServlet, self).__init__()
@@ -55,6 +55,11 @@ class RegisterRestServlet(RestServlet):
     @defer.inlineCallbacks
     def on_POST(self, request):
         yield run_on_reactor()
+
+        if '/register/email/requestToken' in request.path:
+            ret = yield self.onEmailTokenRequest(request)
+            defer.returnValue(ret)
+
         body = parse_json_dict_from_request(request)
 
         # we do basic sanity checks here because the auth layer will store these
@@ -209,6 +214,26 @@ class RegisterRestServlet(RestServlet):
             "home_server": self.hs.hostname,
         }
 
+    @defer.inlineCallbacks
+    def onEmailTokenRequest(self, request):
+        body = parse_json_dict_from_request(request)
+
+        required = ['id_server', 'client_secret', 'email', 'send_attempt']
+        absent = []
+        for k in required:
+            if k not in body:
+                absent.append(k)
+
+        existingUid = self.hs.get_datastore().get_user_id_by_threepid('email', body['email'])
+        if existingUid is not None:
+            raise SynapseError(400, "Email is already in use", Codes.THREEPID_IN_USE)
+
+        if len(absent) > 0:
+            raise SynapseError(400, "Missing params: %r" % absent, Codes.MISSING_PARAM)
+
+        ret = yield self.identity_handler.requestEmailToken(**body)
+        defer.returnValue((200, ret))
+
 
 def register_servlets(hs, http_server):
     RegisterRestServlet(hs).register(http_server)
diff --git a/synapse/storage/schema/delta/22/user_threepids_unique.sql b/synapse/storage/schema/delta/22/user_threepids_unique.sql
new file mode 100644
index 0000000000..87edfa454c
--- /dev/null
+++ b/synapse/storage/schema/delta/22/user_threepids_unique.sql
@@ -0,0 +1,19 @@
+CREATE TABLE IF NOT EXISTS user_threepids2 (
+    user_id TEXT NOT NULL,
+    medium TEXT NOT NULL,
+    address TEXT NOT NULL,
+    validated_at BIGINT NOT NULL,
+    added_at BIGINT NOT NULL,
+    CONSTRAINT medium_address UNIQUE (medium, address)
+);
+
+INSERT INTO user_threepids2
+	SELECT * FROM user_threepids WHERE added_at IN (
+		SELECT max(added_at) FROM user_threepids GROUP BY medium, address
+	)
+;
+
+DROP TABLE user_threepids;
+ALTER TABLE user_threepids2 RENAME TO user_threepids;
+
+CREATE INDEX user_threepids_user_id ON user_threepids(user_id);