diff options
Diffstat (limited to 'synapse/handlers/register.py')
-rw-r--r-- | synapse/handlers/register.py | 100 |
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) |