From 59bf16eddcb793705ee6bc243a2158824f7e05c8 Mon Sep 17 00:00:00 2001 From: David Baker Date: Mon, 30 Mar 2015 18:13:10 +0100 Subject: New registration for C/S API v2. Only ReCAPTCHA working currently. --- synapse/handlers/register.py | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) (limited to 'synapse/handlers/register.py') diff --git a/synapse/handlers/register.py b/synapse/handlers/register.py index c25e321099..542759a827 100644 --- a/synapse/handlers/register.py +++ b/synapse/handlers/register.py @@ -157,7 +157,11 @@ class RegistrationHandler(BaseHandler): @defer.inlineCallbacks def check_recaptcha(self, ip, private_key, challenge, response): - """Checks a recaptcha is correct.""" + """ + Checks a recaptcha is correct. + + Used only by c/s api v1 + """ captcha_response = yield self._validate_captcha( ip, @@ -282,6 +286,8 @@ class RegistrationHandler(BaseHandler): def _validate_captcha(self, ip_addr, private_key, challenge, response): """Validates the captcha provided. + Used only by c/s api v1 + Returns: dict: Containing 'valid'(bool) and 'error_url'(str) if invalid. @@ -299,6 +305,9 @@ class RegistrationHandler(BaseHandler): @defer.inlineCallbacks def _submit_captcha(self, ip_addr, private_key, challenge, response): + """ + Used only by c/s api v1 + """ # TODO: get this from the homeserver rather than creating a new one for # each request client = CaptchaServerHttpClient(self.hs) -- cgit 1.4.1 From a19b73990962ff3bfe8b2cae59446bbe7f93ec5c Mon Sep 17 00:00:00 2001 From: David Baker Date: Wed, 15 Apr 2015 15:50:38 +0100 Subject: Regstration with email in v2 --- synapse/handlers/__init__.py | 2 + synapse/handlers/auth.py | 64 +++++++++++++++++++++---------- synapse/handlers/identity.py | 66 ++++++++++++++++++++++++++++++++ synapse/handlers/register.py | 6 ++- synapse/rest/client/v2_alpha/password.py | 6 +-- synapse/rest/client/v2_alpha/register.py | 8 ++-- 6 files changed, 123 insertions(+), 29 deletions(-) create mode 100644 synapse/handlers/identity.py (limited to 'synapse/handlers/register.py') diff --git a/synapse/handlers/__init__.py b/synapse/handlers/__init__.py index 336ce15701..d1b0e032a3 100644 --- a/synapse/handlers/__init__.py +++ b/synapse/handlers/__init__.py @@ -30,6 +30,7 @@ from .admin import AdminHandler from .appservice import ApplicationServicesHandler from .sync import SyncHandler from .auth import AuthHandler +from .identity import IdentityHandler class Handlers(object): @@ -60,3 +61,4 @@ class Handlers(object): ) self.sync_handler = SyncHandler(hs) self.auth_handler = AuthHandler(hs) + self.identity_handler = IdentityHandler(hs) diff --git a/synapse/handlers/auth.py b/synapse/handlers/auth.py index 3d2461dd7d..2cc54707a2 100644 --- a/synapse/handlers/auth.py +++ b/synapse/handlers/auth.py @@ -20,6 +20,7 @@ from synapse.api.constants import LoginType from synapse.types import UserID from synapse.api.errors import LoginError, Codes from synapse.http.client import SimpleHttpClient +from synapse.util.async import run_on_reactor from twisted.web.client import PartialDownloadError @@ -40,6 +41,7 @@ class AuthHandler(BaseHandler): self.checkers = { LoginType.PASSWORD: self._check_password_auth, LoginType.RECAPTCHA: self._check_recaptcha, + LoginType.EMAIL_IDENTITY: self._check_email_identity, } self.sessions = {} @@ -54,24 +56,37 @@ class AuthHandler(BaseHandler): authdict: The dictionary from the client root level, not the 'auth' key: this method prompts for auth if none is sent. Returns: - A tuple of authed, dict where authed is true if the client - has successfully completed an auth flow. If it is true, the dict - contains the authenticated credentials of each stage. - If authed is false, the dictionary is the server response to the - login request and should be passed back to the client. + A tuple of authed, dict, dict where authed is true if the client + has successfully completed an auth flow. If it is true, the first + dict contains the authenticated credentials of each stage. + + If authed is false, the first dictionary is the server response to + the login request and should be passed back to the client. + + In either case, the second dict contains the parameters for this + request (which may have been given only in a previous call). """ - if not clientdict or 'auth' not in clientdict: - sess = self._get_session_info(None) + authdict = None + sid = None + if clientdict and 'auth' in clientdict: + authdict = clientdict['auth'] + del clientdict['auth'] + if 'session' in authdict: + sid = authdict['session'] + sess = self._get_session_info(sid) + + if len(clientdict) > 0: + sess['clientdict'] = clientdict + self._save_session(sess) + elif 'clientdict' in sess: + clientdict = sess['clientdict'] + + if not authdict: defer.returnValue( - (False, self._auth_dict_for_flows(flows, sess)) + (False, self._auth_dict_for_flows(flows, sess), clientdict) ) - authdict = clientdict['auth'] - - sess = self._get_session_info( - authdict['session'] if 'session' in authdict else None - ) if 'creds' not in sess: sess['creds'] = {} creds = sess['creds'] @@ -89,11 +104,11 @@ class AuthHandler(BaseHandler): if len(set(f) - set(creds.keys())) == 0: logger.info("Auth completed with creds: %r", creds) self._remove_session(sess) - defer.returnValue((True, creds)) + defer.returnValue((True, creds, clientdict)) ret = self._auth_dict_for_flows(flows, sess) ret['completed'] = creds.keys() - defer.returnValue((False, ret)) + defer.returnValue((False, ret, clientdict)) @defer.inlineCallbacks def add_oob_auth(self, stagetype, authdict, clientip): @@ -175,18 +190,25 @@ class AuthHandler(BaseHandler): defer.returnValue(True) raise LoginError(401, "", errcode=Codes.UNAUTHORIZED) + @defer.inlineCallbacks + def _check_email_identity(self, authdict, _): + yield run_on_reactor() + + threepidCreds = authdict['threepidCreds'] + identity_handler = self.hs.get_handlers().identity_handler + + logger.debug("Getting validated threepid. threepidcreds: %r" % (threepidCreds,)) + threepid = yield identity_handler.threepid_from_creds(threepidCreds) + + defer.returnValue(threepid) + def _get_params_recaptcha(self): return {"public_key": self.hs.config.recaptcha_public_key} def _auth_dict_for_flows(self, flows, session): public_flows = [] for f in flows: - hidden = False - for stagetype in f: - if stagetype in LoginType.HIDDEN_TYPES: - hidden = True - if not hidden: - public_flows.append(f) + public_flows.append(f) get_params = { LoginType.RECAPTCHA: self._get_params_recaptcha, diff --git a/synapse/handlers/identity.py b/synapse/handlers/identity.py new file mode 100644 index 0000000000..671d366e40 --- /dev/null +++ b/synapse/handlers/identity.py @@ -0,0 +1,66 @@ +# -*- coding: utf-8 -*- +# Copyright 2015 OpenMarket Ltd +# +# 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. + +"""Utilities for interacting with Identity Servers""" +from twisted.internet import defer + +from synapse.api.errors import ( + CodeMessageException +) +from ._base import BaseHandler +from synapse.http.client import SimpleHttpClient +from synapse.util.async import run_on_reactor + +import json +import logging + +logger = logging.getLogger(__name__) + + +class IdentityHandler(BaseHandler): + + def __init__(self, hs): + super(IdentityHandler, self).__init__(hs) + + @defer.inlineCallbacks + def threepid_from_creds(self, creds): + yield run_on_reactor() + + # TODO: get this from the homeserver rather than creating a new one for + # each request + http_client = SimpleHttpClient(self.hs) + # XXX: make this configurable! + #trustedIdServers = ['matrix.org', 'localhost:8090'] + trustedIdServers = ['matrix.org'] + if not creds['idServer'] in trustedIdServers: + logger.warn('%s is not a trusted ID server: rejecting 3pid ' + + 'credentials', creds['idServer']) + defer.returnValue(None) + + data = {} + try: + data = yield http_client.get_json( + "https://%s%s" % ( + creds['idServer'], + "/_matrix/identity/api/v1/3pid/getValidated3pid" + ), + {'sid': creds['sid'], 'clientSecret': creds['clientSecret']} + ) + except CodeMessageException as e: + data = json.loads(e.msg) + + if 'medium' in data: + defer.returnValue(data) + defer.returnValue(None) \ No newline at end of file diff --git a/synapse/handlers/register.py b/synapse/handlers/register.py index 542759a827..6759a8c582 100644 --- a/synapse/handlers/register.py +++ b/synapse/handlers/register.py @@ -180,7 +180,11 @@ class RegistrationHandler(BaseHandler): @defer.inlineCallbacks def register_email(self, threepidCreds): - """Registers emails with an identity server.""" + """ + Registers emails with an identity server. + + Used only by c/s api v1 + """ for c in threepidCreds: logger.info("validating theeepidcred sid %s on id server %s", diff --git a/synapse/rest/client/v2_alpha/password.py b/synapse/rest/client/v2_alpha/password.py index 85954c71cd..cb0c8cfb55 100644 --- a/synapse/rest/client/v2_alpha/password.py +++ b/synapse/rest/client/v2_alpha/password.py @@ -41,7 +41,7 @@ class PasswordRestServlet(RestServlet): def on_POST(self, request): body = parse_json_dict_from_request(request) - authed, result = yield self.auth_handler.check_auth([ + authed, result, params = yield self.auth_handler.check_auth([ [LoginType.PASSWORD] ], body) @@ -61,9 +61,9 @@ class PasswordRestServlet(RestServlet): user_id = auth_user.to_string() - if 'new_password' not in body: + if 'new_password' not in params: raise SynapseError(400, "", Codes.MISSING_PARAM) - new_password = body['new_password'] + new_password = params['new_password'] yield self.login_handler.set_password( user_id, new_password, client.token_id diff --git a/synapse/rest/client/v2_alpha/register.py b/synapse/rest/client/v2_alpha/register.py index 72319a3bb2..d7a20fc964 100644 --- a/synapse/rest/client/v2_alpha/register.py +++ b/synapse/rest/client/v2_alpha/register.py @@ -74,7 +74,7 @@ class RegisterRestServlet(RestServlet): ) is_using_shared_secret = True else: - authed, result = yield self.auth_handler.check_auth([ + authed, result, params = yield self.auth_handler.check_auth([ [LoginType.RECAPTCHA], [LoginType.EMAIL_IDENTITY, LoginType.RECAPTCHA], ], body, self.hs.get_ip_from_request(request)) @@ -90,10 +90,10 @@ class RegisterRestServlet(RestServlet): if not can_register: raise SynapseError(403, "Registration has been disabled") - if 'username' not in body or 'password' not in body: + if 'username' not in params or 'password' not in params: raise SynapseError(400, "", Codes.MISSING_PARAM) - desired_username = body['username'] - new_password = body['password'] + desired_username = params['username'] + new_password = params['password'] (user_id, token) = yield self.registration_handler.register( localpart=desired_username, -- cgit 1.4.1 From ea1776f556edaf6ca483bc5faed5e9d244aa1a15 Mon Sep 17 00:00:00 2001 From: David Baker Date: Thu, 16 Apr 2015 19:56:44 +0100 Subject: Return user ID in use error straight away --- synapse/handlers/auth.py | 2 + synapse/handlers/identity.py | 25 +++++++- synapse/handlers/register.py | 102 ++++++++++++------------------- synapse/rest/client/v2_alpha/register.py | 25 +++++++- 4 files changed, 88 insertions(+), 66 deletions(-) (limited to 'synapse/handlers/register.py') diff --git a/synapse/handlers/auth.py b/synapse/handlers/auth.py index 87866f298d..1f927e67ad 100644 --- a/synapse/handlers/auth.py +++ b/synapse/handlers/auth.py @@ -201,6 +201,8 @@ class AuthHandler(BaseHandler): logger.debug("Getting validated threepid. threepidcreds: %r" % (threepidCreds,)) threepid = yield identity_handler.threepid_from_creds(threepidCreds) + threepid['threepidCreds'] = authdict['threepidCreds'] + defer.returnValue(threepid) @defer.inlineCallbacks diff --git a/synapse/handlers/identity.py b/synapse/handlers/identity.py index 19896ce90d..cb5e1e80ac 100644 --- a/synapse/handlers/identity.py +++ b/synapse/handlers/identity.py @@ -63,4 +63,27 @@ class IdentityHandler(BaseHandler): if 'medium' in data: defer.returnValue(data) - defer.returnValue(None) \ No newline at end of file + defer.returnValue(None) + + @defer.inlineCallbacks + def bind_threepid(self, creds, mxid): + yield run_on_reactor() + logger.debug("binding threepid %r to %s", creds, mxid) + http_client = SimpleHttpClient(self.hs) + data = None + try: + data = yield http_client.post_urlencoded_get_json( + # XXX: Change when ID servers are all HTTPS + "http://%s%s" % ( + creds['idServer'], "/_matrix/identity/api/v1/3pid/bind" + ), + { + 'sid': creds['sid'], + 'clientSecret': creds['clientSecret'], + 'mxid': mxid, + } + ) + logger.debug("bound threepid %r to %s", creds, mxid) + except CodeMessageException as e: + data = json.loads(e.msg) + defer.returnValue(data) \ No newline at end of file diff --git a/synapse/handlers/register.py b/synapse/handlers/register.py index 6759a8c582..541b1019da 100644 --- a/synapse/handlers/register.py +++ b/synapse/handlers/register.py @@ -44,6 +44,36 @@ class RegistrationHandler(BaseHandler): self.distributor = hs.get_distributor() self.distributor.declare("registered_user") + @defer.inlineCallbacks + def check_username(self, localpart): + yield run_on_reactor() + + print "checking username %s" % (localpart) + + if urllib.quote(localpart) != localpart: + raise SynapseError( + 400, + "User ID must only contain characters which do not" + " require URL encoding." + ) + + user = UserID(localpart, self.hs.hostname) + user_id = user.to_string() + + yield self.check_user_id_is_valid(user_id) + + print "is valid" + + u = yield self.store.get_user_by_id(user_id) + print "user is: " + print u + if u: + raise SynapseError( + 400, + "User ID already taken.", + errcode=Codes.USER_IN_USE, + ) + @defer.inlineCallbacks def register(self, localpart=None, password=None): """Registers a new client on the server. @@ -64,18 +94,11 @@ class RegistrationHandler(BaseHandler): password_hash = bcrypt.hashpw(password, bcrypt.gensalt()) if localpart: - if localpart and urllib.quote(localpart) != localpart: - raise SynapseError( - 400, - "User ID must only contain characters which do not" - " require URL encoding." - ) + self.check_username(localpart) user = UserID(localpart, self.hs.hostname) user_id = user.to_string() - yield self.check_user_id_is_valid(user_id) - token = self._generate_token(user_id) yield self.store.register( user_id=user_id, @@ -190,7 +213,8 @@ class RegistrationHandler(BaseHandler): logger.info("validating theeepidcred sid %s on id server %s", c['sid'], c['idServer']) try: - threepid = yield self._threepid_from_creds(c) + identity_handler = self.hs.get_handlers().identity_handler + threepid = yield identity_handler.threepid_from_creds(c) except: logger.exception("Couldn't validate 3pid") raise RegistrationError(400, "Couldn't validate 3pid") @@ -202,12 +226,16 @@ class RegistrationHandler(BaseHandler): @defer.inlineCallbacks def bind_emails(self, user_id, threepidCreds): - """Links emails with a user ID and informs an identity server.""" + """Links emails with a user ID and informs an identity server. + + Used only by c/s api v1 + """ # Now we have a matrix ID, bind it to the threepids we were given for c in threepidCreds: + identity_handler = self.hs.get_handlers().identity_handler # XXX: This should be a deferred list, shouldn't it? - yield self._bind_threepid(c, user_id) + yield identity_handler.bind_threepid(c, user_id) @defer.inlineCallbacks def check_user_id_is_valid(self, user_id): @@ -234,58 +262,6 @@ class RegistrationHandler(BaseHandler): def _generate_user_id(self): return "-" + stringutils.random_string(18) - @defer.inlineCallbacks - def _threepid_from_creds(self, creds): - # TODO: get this from the homeserver rather than creating a new one for - # each request - http_client = SimpleHttpClient(self.hs) - # XXX: make this configurable! - trustedIdServers = ['matrix.org:8090', 'matrix.org'] - if not creds['idServer'] in trustedIdServers: - logger.warn('%s is not a trusted ID server: rejecting 3pid ' + - 'credentials', creds['idServer']) - defer.returnValue(None) - - data = {} - try: - data = yield http_client.get_json( - # XXX: This should be HTTPS - "http://%s%s" % ( - creds['idServer'], - "/_matrix/identity/api/v1/3pid/getValidated3pid" - ), - {'sid': creds['sid'], 'clientSecret': creds['clientSecret']} - ) - except CodeMessageException as e: - data = json.loads(e.msg) - - if 'medium' in data: - defer.returnValue(data) - defer.returnValue(None) - - @defer.inlineCallbacks - def _bind_threepid(self, creds, mxid): - yield - logger.debug("binding threepid") - http_client = SimpleHttpClient(self.hs) - data = None - try: - data = yield http_client.post_urlencoded_get_json( - # XXX: Change when ID servers are all HTTPS - "http://%s%s" % ( - creds['idServer'], "/_matrix/identity/api/v1/3pid/bind" - ), - { - 'sid': creds['sid'], - 'clientSecret': creds['clientSecret'], - 'mxid': mxid, - } - ) - logger.debug("bound threepid") - except CodeMessageException as e: - data = json.loads(e.msg) - defer.returnValue(data) - @defer.inlineCallbacks def _validate_captcha(self, ip_addr, private_key, challenge, response): """Validates the captcha provided. diff --git a/synapse/rest/client/v2_alpha/register.py b/synapse/rest/client/v2_alpha/register.py index ee99b74fd6..a5fec45dce 100644 --- a/synapse/rest/client/v2_alpha/register.py +++ b/synapse/rest/client/v2_alpha/register.py @@ -49,12 +49,20 @@ class RegisterRestServlet(RestServlet): self.auth = hs.get_auth() self.auth_handler = hs.get_handlers().auth_handler self.registration_handler = hs.get_handlers().registration_handler + self.identity_handler = hs.get_handlers().identity_handler @defer.inlineCallbacks def on_POST(self, request): yield run_on_reactor() body = parse_request_allow_empty(request) + if 'password' not in body: + raise SynapseError(400, "", Codes.MISSING_PARAM) + + if 'username' in body: + desired_username = body['username'] + print "username in body" + yield self.registration_handler.check_username(desired_username) is_using_shared_secret = False is_application_server = False @@ -100,15 +108,28 @@ class RegisterRestServlet(RestServlet): if not can_register: raise SynapseError(403, "Registration has been disabled") - if 'username' not in params or 'password' not in params: + if 'password' not in params: raise SynapseError(400, "", Codes.MISSING_PARAM) - desired_username = params['username'] + desired_username = params['username'] if 'username' in params else None new_password = params['password'] (user_id, token) = yield self.registration_handler.register( localpart=desired_username, password=new_password ) + + if 'bind_email' in params and params['bind_email']: + logger.info("bind_email specified: binding") + + emailThreepid = result[LoginType.EMAIL_IDENTITY] + threepidCreds = emailThreepid['threepidCreds'] + logger.debug("Binding emails %s to %s" % ( + emailThreepid, user_id + )) + yield self.identity_handler.bind_threepid(threepidCreds, user_id) + else: + logger.info("bind_email not specified: not binding email") + result = { "user_id": user_id, "access_token": token, -- cgit 1.4.1 From 4cd5fb13a31a4da1d7d8feb06d211a2f7842f5ad Mon Sep 17 00:00:00 2001 From: David Baker Date: Thu, 16 Apr 2015 20:03:13 +0100 Subject: Oops, left debugging in. --- synapse/handlers/register.py | 6 ------ 1 file changed, 6 deletions(-) (limited to 'synapse/handlers/register.py') diff --git a/synapse/handlers/register.py b/synapse/handlers/register.py index 541b1019da..25b1db62ea 100644 --- a/synapse/handlers/register.py +++ b/synapse/handlers/register.py @@ -48,8 +48,6 @@ class RegistrationHandler(BaseHandler): def check_username(self, localpart): yield run_on_reactor() - print "checking username %s" % (localpart) - if urllib.quote(localpart) != localpart: raise SynapseError( 400, @@ -62,11 +60,7 @@ class RegistrationHandler(BaseHandler): yield self.check_user_id_is_valid(user_id) - print "is valid" - u = yield self.store.get_user_by_id(user_id) - print "user is: " - print u if u: raise SynapseError( 400, -- cgit 1.4.1 From 83b554437ec9810dd09de992c728c2a2f01aa0e1 Mon Sep 17 00:00:00 2001 From: David Baker Date: Fri, 17 Apr 2015 12:57:25 +0100 Subject: Need to yield the username check, otherwise very very weird things happen. --- synapse/handlers/register.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'synapse/handlers/register.py') diff --git a/synapse/handlers/register.py b/synapse/handlers/register.py index 25b1db62ea..d4483c3a1d 100644 --- a/synapse/handlers/register.py +++ b/synapse/handlers/register.py @@ -88,7 +88,7 @@ class RegistrationHandler(BaseHandler): password_hash = bcrypt.hashpw(password, bcrypt.gensalt()) if localpart: - self.check_username(localpart) + yield self.check_username(localpart) user = UserID(localpart, self.hs.hostname) user_id = user.to_string() -- cgit 1.4.1 From 4eea5cf6c2a301938466828b02557d8500197bb3 Mon Sep 17 00:00:00 2001 From: David Baker Date: Fri, 17 Apr 2015 16:46:45 +0100 Subject: pep8 --- synapse/handlers/identity.py | 6 +++--- synapse/handlers/login.py | 2 +- synapse/handlers/register.py | 5 +---- synapse/storage/registration.py | 2 +- 4 files changed, 6 insertions(+), 9 deletions(-) (limited to 'synapse/handlers/register.py') diff --git a/synapse/handlers/identity.py b/synapse/handlers/identity.py index cb5e1e80ac..5c72635915 100644 --- a/synapse/handlers/identity.py +++ b/synapse/handlers/identity.py @@ -42,8 +42,8 @@ class IdentityHandler(BaseHandler): # each request http_client = SimpleHttpClient(self.hs) # XXX: make this configurable! - trustedIdServers = ['matrix.org', 'localhost:8090'] - #trustedIdServers = ['matrix.org'] + # trustedIdServers = ['matrix.org', 'localhost:8090'] + trustedIdServers = ['matrix.org'] if not creds['idServer'] in trustedIdServers: logger.warn('%s is not a trusted ID server: rejecting 3pid ' + 'credentials', creds['idServer']) @@ -86,4 +86,4 @@ class IdentityHandler(BaseHandler): logger.debug("bound threepid %r to %s", creds, mxid) except CodeMessageException as e: data = json.loads(e.msg) - defer.returnValue(data) \ No newline at end of file + defer.returnValue(data) diff --git a/synapse/handlers/login.py b/synapse/handlers/login.py index 5c39356d71..f7f3698340 100644 --- a/synapse/handlers/login.py +++ b/synapse/handlers/login.py @@ -80,4 +80,4 @@ class LoginHandler(BaseHandler): yield self.store.user_add_threepid( user_id, medium, address, validated_at, self.hs.get_clock().time_msec() - ) \ No newline at end of file + ) diff --git a/synapse/handlers/register.py b/synapse/handlers/register.py index d4483c3a1d..7b68585a17 100644 --- a/synapse/handlers/register.py +++ b/synapse/handlers/register.py @@ -18,18 +18,15 @@ from twisted.internet import defer from synapse.types import UserID from synapse.api.errors import ( - AuthError, Codes, SynapseError, RegistrationError, InvalidCaptchaError, - CodeMessageException + AuthError, Codes, SynapseError, RegistrationError, InvalidCaptchaError ) from ._base import BaseHandler import synapse.util.stringutils as stringutils from synapse.util.async import run_on_reactor -from synapse.http.client import SimpleHttpClient from synapse.http.client import CaptchaServerHttpClient import base64 import bcrypt -import json import logging import urllib diff --git a/synapse/storage/registration.py b/synapse/storage/registration.py index 4bc01f3cc2..8f62e5c6f2 100644 --- a/synapse/storage/registration.py +++ b/synapse/storage/registration.py @@ -185,4 +185,4 @@ class RegistrationStore(SQLBaseStore): }, { "validated_at": validated_at, "added_at": added_at, - }) \ No newline at end of file + }) -- cgit 1.4.1