summary refs log tree commit diff
path: root/synapse
diff options
context:
space:
mode:
Diffstat (limited to 'synapse')
-rw-r--r--synapse/api/auth.py4
-rw-r--r--synapse/config/captcha.py7
-rw-r--r--synapse/handlers/federation.py10
-rw-r--r--synapse/handlers/message.py16
-rw-r--r--synapse/handlers/room.py11
-rw-r--r--synapse/rest/register.py53
-rw-r--r--synapse/rest/room.py13
7 files changed, 88 insertions, 26 deletions
diff --git a/synapse/api/auth.py b/synapse/api/auth.py
index 8f32191b57..5321864d51 100644
--- a/synapse/api/auth.py
+++ b/synapse/api/auth.py
@@ -372,11 +372,11 @@ class Auth(object):
         }
 
         removed = set(old_people.keys()) - set(new_people.keys())
-        added = set(old_people.keys()) - set(new_people.keys())
+        added = set(new_people.keys()) - set(old_people.keys())
         same = set(old_people.keys()) & set(new_people.keys())
 
         for r in removed:
-            if int(old_list.content[r]) > user_level:
+            if int(old_list[r]) > user_level:
                 raise AuthError(
                     403,
                     "You don't have permission to remove user: %s" % (r, )
diff --git a/synapse/config/captcha.py b/synapse/config/captcha.py
index 8ebcfc3623..4ed9070b9e 100644
--- a/synapse/config/captcha.py
+++ b/synapse/config/captcha.py
@@ -24,6 +24,7 @@ class CaptchaConfig(Config):
         self.captcha_ip_origin_is_x_forwarded = (
             args.captcha_ip_origin_is_x_forwarded
         )
+        self.captcha_bypass_secret = args.captcha_bypass_secret
 
     @classmethod
     def add_arguments(cls, parser):
@@ -43,4 +44,8 @@ class CaptchaConfig(Config):
             "--captcha_ip_origin_is_x_forwarded", type=bool, default=False,
             help="When checking captchas, use the X-Forwarded-For (XFF) header"
             + " as the client IP and not the actual client IP."
-        )
\ No newline at end of file
+        )
+        group.add_argument(
+            "--captcha_bypass_secret", type=str,
+            help="A secret key used to bypass the captcha test entirely."
+        )
diff --git a/synapse/handlers/federation.py b/synapse/handlers/federation.py
index 001c6c110c..f52591d2a3 100644
--- a/synapse/handlers/federation.py
+++ b/synapse/handlers/federation.py
@@ -169,7 +169,15 @@ class FederationHandler(BaseHandler):
                     )
 
             if not backfilled:
-                yield self.notifier.on_new_room_event(event)
+                extra_users = []
+                if event.type == RoomMemberEvent.TYPE:
+                    target_user_id = event.state_key
+                    target_user = self.hs.parse_userid(target_user_id)
+                    extra_users.append(target_user)
+
+                yield self.notifier.on_new_room_event(
+                    event, extra_users=extra_users
+                )
 
         if event.type == RoomMemberEvent.TYPE:
             if event.membership == Membership.JOIN:
diff --git a/synapse/handlers/message.py b/synapse/handlers/message.py
index 14fae689f2..317ef2c80c 100644
--- a/synapse/handlers/message.py
+++ b/synapse/handlers/message.py
@@ -233,6 +233,22 @@ class MessageHandler(BaseHandler):
         yield self._on_new_room_event(event, snapshot)
 
     @defer.inlineCallbacks
+    def get_state_events(self, user_id, room_id):
+        """Retrieve all state events for a given room.
+
+        Args:
+            user_id(str): The user requesting state events.
+            room_id(str): The room ID to get all state events from.
+        Returns:
+            A list of dicts representing state events. [{}, {}, {}]
+        """
+        yield self.auth.check_joined_room(room_id, user_id)
+
+        # TODO: This is duplicating logic from snapshot_all_rooms
+        current_state = yield self.store.get_current_state(room_id)
+        defer.returnValue([self.hs.serialize_event(c) for c in current_state])
+
+    @defer.inlineCallbacks
     def snapshot_all_rooms(self, user_id=None, pagin_config=None,
                            feedback=False):
         """Retrieve a snapshot of all rooms the user is invited or has joined.
diff --git a/synapse/handlers/room.py b/synapse/handlers/room.py
index 5bc1280432..4d8727e8af 100644
--- a/synapse/handlers/room.py
+++ b/synapse/handlers/room.py
@@ -146,17 +146,6 @@ class RoomCreationHandler(BaseHandler):
             )
 
             yield handle_event(name_event)
-        elif room_alias:
-            name = room_alias.to_string()
-            name_event = self.event_factory.create_event(
-                etype=RoomNameEvent.TYPE,
-                room_id=room_id,
-                user_id=user_id,
-                required_power_level=50,
-                content={"name": name},
-            )
-
-            yield handle_event(name_event)
 
         if "topic" in config:
             topic = config["topic"]
diff --git a/synapse/rest/register.py b/synapse/rest/register.py
index af528a44f6..4935e323d9 100644
--- a/synapse/rest/register.py
+++ b/synapse/rest/register.py
@@ -21,6 +21,8 @@ from synapse.api.constants import LoginType
 from base import RestServlet, client_path_pattern
 import synapse.util.stringutils as stringutils
 
+from hashlib import sha1
+import hmac
 import json
 import logging
 import urllib
@@ -28,6 +30,16 @@ import urllib
 logger = logging.getLogger(__name__)
 
 
+# We ought to be using hmac.compare_digest() but on older pythons it doesn't
+# exist. It's a _really minor_ security flaw to use plain string comparison
+# because the timing attack is so obscured by all the other code here it's
+# unlikely to make much difference
+if hasattr(hmac, "compare_digest"):
+    compare_digest = hmac.compare_digest
+else:
+    compare_digest = lambda a, b: a == b
+
+
 class RegisterRestServlet(RestServlet):
     """Handles registration with the home server.
 
@@ -142,6 +154,38 @@ class RegisterRestServlet(RestServlet):
         if not self.hs.config.enable_registration_captcha:
             raise SynapseError(400, "Captcha not required.")
 
+        yield self._check_recaptcha(request, register_json, session)
+
+        session[LoginType.RECAPTCHA] = True  # mark captcha as done
+        self._save_session(session)
+        defer.returnValue({
+            "next": [LoginType.PASSWORD, LoginType.EMAIL_IDENTITY]
+        })
+
+    @defer.inlineCallbacks
+    def _check_recaptcha(self, request, register_json, session):
+        if ("captcha_bypass_hmac" in register_json and
+                self.hs.config.captcha_bypass_secret):
+            if "user" not in register_json:
+                raise SynapseError(400, "Captcha bypass needs 'user'")
+
+            want = hmac.new(
+                key=self.hs.config.captcha_bypass_secret,
+                msg=register_json["user"],
+                digestmod=sha1,
+            ).hexdigest()
+
+            # str() because otherwise hmac complains that 'unicode' does not
+            # have the buffer interface
+            got = str(register_json["captcha_bypass_hmac"])
+
+            if compare_digest(want, got):
+                session["user"] = register_json["user"]
+                defer.returnValue(None)
+            else:
+                raise SynapseError(400, "Captcha bypass HMAC incorrect",
+                    errcode=Codes.CAPTCHA_NEEDED)
+
         challenge = None
         user_response = None
         try:
@@ -166,11 +210,6 @@ class RegisterRestServlet(RestServlet):
             challenge,
             user_response
         )
-        session[LoginType.RECAPTCHA] = True  # mark captcha as done
-        self._save_session(session)
-        defer.returnValue({
-            "next": [LoginType.PASSWORD, LoginType.EMAIL_IDENTITY]
-        })
 
     @defer.inlineCallbacks
     def _do_email_identity(self, request, register_json, session):
@@ -195,6 +234,10 @@ class RegisterRestServlet(RestServlet):
             # captcha should've been done by this stage!
             raise SynapseError(400, "Captcha is required.")
 
+        if ("user" in session and "user" in register_json and
+                session["user"] != register_json["user"]):
+            raise SynapseError(400, "Cannot change user ID during registration")
+
         password = register_json["password"].encode("utf-8")
         desired_user_id = (register_json["user"].encode("utf-8") if "user"
                           in register_json else None)
diff --git a/synapse/rest/room.py b/synapse/rest/room.py
index ecb1e346d9..cf2e7af2e4 100644
--- a/synapse/rest/room.py
+++ b/synapse/rest/room.py
@@ -329,12 +329,13 @@ class RoomStateRestServlet(RestServlet):
     @defer.inlineCallbacks
     def on_GET(self, request, room_id):
         user = yield self.auth.get_user_by_req(request)
-        # TODO: Get all the current state for this room and return in the same
-        # format as initial sync, that is:
-        # [
-        #   { state event }, { state event }
-        # ]
-        defer.returnValue((200, []))
+        handler = self.handlers.message_handler
+        # Get all the current state for this room
+        events = yield handler.get_state_events(
+            room_id=urllib.unquote(room_id),
+            user_id=user.to_string(),
+        )
+        defer.returnValue((200, events))
 
 
 # TODO: Needs unit testing