From 5f30a69a9e617028c39ea3851b9a5de43d42a299 Mon Sep 17 00:00:00 2001 From: Kegan Dougal Date: Tue, 16 Sep 2014 11:22:40 +0100 Subject: [PATCH] Added PasswordResetRestServlet. Hit the IS to confirm the email/user. Need to send email. --- synapse/handlers/login.py | 29 ++++++++++++++++++++++++++++- synapse/rest/login.py | 22 ++++++++++++++++++++++ 2 files changed, 50 insertions(+), 1 deletion(-) diff --git a/synapse/handlers/login.py b/synapse/handlers/login.py index 6ee7ce5a2..101b9a81a 100644 --- a/synapse/handlers/login.py +++ b/synapse/handlers/login.py @@ -17,9 +17,11 @@ from twisted.internet import defer from ._base import BaseHandler from synapse.api.errors import LoginError, Codes +from synapse.http.client import PlainHttpClient import bcrypt import logging +import urllib logger = logging.getLogger(__name__) @@ -62,4 +64,29 @@ class LoginHandler(BaseHandler): defer.returnValue(token) else: logger.warn("Failed password login for user %s", user) - raise LoginError(403, "", errcode=Codes.FORBIDDEN) \ No newline at end of file + raise LoginError(403, "", errcode=Codes.FORBIDDEN) + + @defer.inlineCallbacks + def reset_password(self, user_id, email): + is_valid = yield self._check_valid_association(user_id, email) + logger.info("reset_password user=%s email=%s valid=%s", user_id, email, + is_valid) + + @defer.inlineCallbacks + def _check_valid_association(self, user_id, email): + identity = yield self._query_email(email) + if identity and "mxid" in identity: + if identity["mxid"] == user_id: + defer.returnValue(True) + return + defer.returnValue(False) + + @defer.inlineCallbacks + def _query_email(self, email): + httpCli = PlainHttpClient(self.hs) + data = yield httpCli.get_json( + 'matrix.org:8090', # TODO FIXME This should be configurable. + "/_matrix/identity/api/v1/lookup?medium=email&address=" + + "%s" % urllib.quote(email) + ) + defer.returnValue(data) \ No newline at end of file diff --git a/synapse/rest/login.py b/synapse/rest/login.py index ba49afcaa..7ab9cb51e 100644 --- a/synapse/rest/login.py +++ b/synapse/rest/login.py @@ -73,6 +73,27 @@ class LoginFallbackRestServlet(RestServlet): return (200, {}) +class PasswordResetRestServlet(RestServlet): + PATTERN = client_path_pattern("/login/reset") + + @defer.inlineCallbacks + def on_POST(self, request): + reset_info = _parse_json(request) + try: + email = reset_info["email"] + user_id = reset_info["user_id"] + handler = self.handlers.login_handler + yield handler.reset_password(user_id, email) + # purposefully give no feedback to avoid people hammering different + # combinations. + defer.returnValue((200, {})) + except KeyError: + raise SynapseError( + 400, + "Missing keys. Requires 'email' and 'user_id'." + ) + + def _parse_json(request): try: content = json.loads(request.content.read()) @@ -85,3 +106,4 @@ def _parse_json(request): def register_servlets(hs, http_server): LoginRestServlet(hs).register(http_server) + PasswordResetRestServlet(hs).register(http_server)