diff --git a/synapse/handlers/login.py b/synapse/handlers/login.py
index 6ee7ce5a2d..101b9a81ad 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 ba49afcaa7..7ab9cb51e8 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)
|