summary refs log tree commit diff
path: root/synapse/handlers/register.py
diff options
context:
space:
mode:
Diffstat (limited to 'synapse/handlers/register.py')
-rw-r--r--synapse/handlers/register.py100
1 files changed, 100 insertions, 0 deletions
diff --git a/synapse/handlers/register.py b/synapse/handlers/register.py
new file mode 100644
index 0000000000..246c1f6530
--- /dev/null
+++ b/synapse/handlers/register.py
@@ -0,0 +1,100 @@
+# -*- coding: utf-8 -*-
+# Copyright 2014 matrix.org
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+"""Contains functions for registering clients."""
+from twisted.internet import defer
+
+from synapse.types import UserID
+from synapse.api.errors import SynapseError, RegistrationError
+from ._base import BaseHandler
+import synapse.util.stringutils as stringutils
+
+import base64
+import bcrypt
+
+
+class RegistrationHandler(BaseHandler):
+
+    def __init__(self, hs):
+        super(RegistrationHandler, self).__init__(hs)
+
+        self.distributor = hs.get_distributor()
+        self.distributor.declare("registered_user")
+
+    @defer.inlineCallbacks
+    def register(self, localpart=None, password=None):
+        """Registers a new client on the server.
+
+        Args:
+            localpart : The local part of the user ID to register. If None,
+              one will be randomly generated.
+            password (str) : The password to assign to this user so they can
+            login again.
+        Returns:
+            A tuple of (user_id, access_token).
+        Raises:
+            RegistrationError if there was a problem registering.
+        """
+        password_hash = None
+        if password:
+            password_hash = bcrypt.hashpw(password, bcrypt.gensalt())
+
+        if localpart:
+            user = UserID(localpart, self.hs.hostname, True)
+            user_id = user.to_string()
+
+            token = self._generate_token(user_id)
+            yield self.store.register(user_id=user_id,
+                token=token,
+                password_hash=password_hash)
+
+            self.distributor.fire("registered_user", user)
+            defer.returnValue((user_id, token))
+        else:
+            # autogen a random user ID
+            attempts = 0
+            user_id = None
+            token = None
+            while not user_id and not token:
+                try:
+                    localpart = self._generate_user_id()
+                    user = UserID(localpart, self.hs.hostname, True)
+                    user_id = user.to_string()
+
+                    token = self._generate_token(user_id)
+                    yield self.store.register(
+                        user_id=user_id,
+                        token=token,
+                        password_hash=password_hash)
+
+                    self.distributor.fire("registered_user", user)
+                    defer.returnValue((user_id, token))
+                except SynapseError:
+                    # if user id is taken, just generate another
+                    user_id = None
+                    token = None
+                    attempts += 1
+                    if attempts > 5:
+                        raise RegistrationError(
+                            500, "Cannot generate user ID.")
+
+    def _generate_token(self, user_id):
+        # urlsafe variant uses _ and - so use . as the separator and replace
+        # all =s with .s so http clients don't quote =s when it is used as
+        # query params.
+        return (base64.urlsafe_b64encode(user_id).replace('=', '.') + '.' +
+                stringutils.random_string(18))
+
+    def _generate_user_id(self):
+        return "-" + stringutils.random_string(18)