summary refs log tree commit diff
diff options
context:
space:
mode:
authorErik Johnston <erik@matrix.org>2014-10-17 19:37:41 +0100
committerErik Johnston <erik@matrix.org>2014-10-17 19:37:41 +0100
commitb3b19614962d78e7851299ff1f7b41706ced3d00 (patch)
treee5f361f10d133e68f478a0c622642d250d92750e
parentUse state groups to get current state. Make join dance actually work. (diff)
downloadsynapse-b3b19614962d78e7851299ff1f7b41706ced3d00.tar.xz
Fix bug where people could join private rooms
-rw-r--r--synapse/api/auth.py86
-rw-r--r--synapse/handlers/federation.py10
-rw-r--r--synapse/state.py12
3 files changed, 63 insertions, 45 deletions
diff --git a/synapse/api/auth.py b/synapse/api/auth.py
index 50ce7eb4cd..93a3533304 100644
--- a/synapse/api/auth.py
+++ b/synapse/api/auth.py
@@ -49,12 +49,12 @@ class Auth(object):
         """
         try:
             if hasattr(event, "room_id"):
-                if not event.old_state_events:
+                if event.old_state_events is None:
                     # Oh, we don't know what the state of the room was, so we
                     # are trusting that this is allowed (at least for now)
                     defer.returnValue(True)
 
-                if hasattr(event, "outlier") and event.outlier:
+                if hasattr(event, "outlier") and event.outlier is True:
                     # TODO (erikj): Auth for outliers is done differently.
                     defer.returnValue(True)
 
@@ -65,8 +65,12 @@ class Auth(object):
                     defer.returnValue(True)
 
                 if event.type == RoomMemberEvent.TYPE:
-                    yield self._can_replace_state(event)
-                    allowed = yield self.is_membership_change_allowed(event)
+                    self._can_replace_state(event)
+                    allowed = self.is_membership_change_allowed(event)
+                    if allowed:
+                        logger.debug("Allowing! %s", event)
+                    else:
+                        logger.debug("Denying! %s", event)
                     defer.returnValue(allowed)
                     return
 
@@ -77,24 +81,28 @@ class Auth(object):
                     # TODO (erikj): This really only should be called for *new*
                     # state
                     yield self._can_add_state(event)
-                    yield self._can_replace_state(event)
+                    self._can_replace_state(event)
                 else:
                     yield self._can_send_event(event)
 
                 if event.type == RoomPowerLevelsEvent.TYPE:
-                    yield self._check_power_levels(event)
+                    self._check_power_levels(event)
 
                 if event.type == RoomRedactionEvent.TYPE:
-                    yield self._check_redaction(event)
+                    self._check_redaction(event)
 
+
+                logger.debug("Allowing! %s", event)
                 defer.returnValue(True)
             else:
                 raise AuthError(500, "Unknown event: %s" % event)
         except AuthError as e:
             logger.info("Event auth check failed on event %s with msg: %s",
                         event, e.msg)
+            logger.info("Denying! %s", event)
             if raises:
                 raise e
+
         defer.returnValue(False)
 
     @defer.inlineCallbacks
@@ -126,7 +134,7 @@ class Auth(object):
                 user_id, room_id, repr(member)
             ))
 
-    @defer.inlineCallbacks
+    @log_function
     def is_membership_change_allowed(self, event):
         target_user_id = event.state_key
 
@@ -159,11 +167,23 @@ class Auth(object):
         )
 
         ban_level, kick_level, redact_level = (
-            yield self._get_ops_level_from_event_state(
+            self._get_ops_level_from_event_state(
                 event
             )
         )
 
+        logger.debug(
+            "is_membership_change_allowed: %s",
+            {
+                "caller_in_room": caller_in_room,
+                "target_in_room": target_in_room,
+                "membership": membership,
+                "join_rule": join_rule,
+                "target_user_id": target_user_id,
+                "event.user_id": event.user_id,
+            }
+        )
+
         if Membership.INVITE == membership:
             # TODO (erikj): We should probably handle this more intelligently
             # PRIVATE join rules.
@@ -183,10 +203,7 @@ class Auth(object):
             elif join_rule == JoinRules.PUBLIC:
                 pass
             elif join_rule == JoinRules.INVITE:
-                if (
-                    not caller or caller.membership not in
-                    [Membership.INVITE, Membership.JOIN]
-                ):
+                if not caller_in_room:
                     raise AuthError(403, "You are not invited to this room.")
             else:
                 # TODO (erikj): may_join list
@@ -218,7 +235,7 @@ class Auth(object):
         else:
             raise AuthError(500, "Unknown membership %s" % membership)
 
-        defer.returnValue(True)
+        return True
 
     def _get_power_level_from_event_state(self, event, user_id):
         key = (RoomPowerLevelsEvent.TYPE, "", )
@@ -359,17 +376,7 @@ class Auth(object):
 
         defer.returnValue(True)
 
-    @defer.inlineCallbacks
     def _can_replace_state(self, event):
-        current_state = yield self.store.get_current_state(
-            event.room_id,
-            event.type,
-            event.state_key,
-        )
-
-        if current_state:
-            current_state = current_state[0]
-
         user_level = self._get_power_level_from_event_state(
             event,
             event.user_id,
@@ -383,6 +390,10 @@ class Auth(object):
         logger.debug(
             "Checking power level for %s, %s", event.user_id, user_level
         )
+
+        key = (event.type, event.state_key, )
+        current_state = event.old_state_events.get(key)
+
         if current_state and hasattr(current_state, "required_power_level"):
             req = current_state.required_power_level
 
@@ -393,19 +404,20 @@ class Auth(object):
                     "You don't have permission to change that state"
                 )
 
-    @defer.inlineCallbacks
     def _check_redaction(self, event):
-        user_level = yield self.store.get_power_level(
-            event.room_id,
-            event.user_id,
-        )
-
         user_level = self._get_power_level_from_event_state(
             event,
             event.user_id,
         )
 
-        _, _, redact_level  = yield self.store.get_ops_levels(event.room_id)
+        if user_level:
+            user_level = int(user_level)
+        else:
+            user_level = 0
+
+        _, _, redact_level = self.store._get_ops_level_from_event_state(
+            event.room_id
+        )
 
         if not redact_level:
             redact_level = 50
@@ -416,7 +428,6 @@ class Auth(object):
                 "You don't have permission to redact events"
             )
 
-    @defer.inlineCallbacks
     def _check_power_levels(self, event):
         for k, v in event.content.items():
             if k == "default":
@@ -436,19 +447,16 @@ class Auth(object):
             except:
                 raise SynapseError(400, "Not a valid power level: %s" % (v,))
 
-        current_state = yield self.store.get_current_state(
-            event.room_id,
-            event.type,
-            event.state_key,
-        )
+        key = (event.type, event.state_key, )
+        current_state = event.old_state_events.get(key)
 
         if not current_state:
             return
         else:
             current_state = current_state[0]
 
-        user_level = yield self.store.get_power_level(
-            event.room_id,
+        user_level = self._get_power_level_from_event_state(
+            event,
             event.user_id,
         )
 
diff --git a/synapse/handlers/federation.py b/synapse/handlers/federation.py
index 70790aaa72..8c80a37164 100644
--- a/synapse/handlers/federation.py
+++ b/synapse/handlers/federation.py
@@ -269,12 +269,12 @@ class FederationHandler(BaseHandler):
         del self.room_queues[room_id]
 
         for p in room_queue:
-            p.outlier = True
             yield self.on_receive_pdu(p, backfilled=False)
 
         defer.returnValue(True)
 
     @defer.inlineCallbacks
+    @log_function
     def on_make_join_request(self, context, user_id):
         event = self.event_factory.create_event(
             etype=RoomMemberEvent.TYPE,
@@ -289,15 +289,21 @@ class FederationHandler(BaseHandler):
         )
         snapshot.fill_out_prev_events(event)
 
+        yield self.state_handler.annotate_state_groups(event)
+        yield self.auth.check(event, None, raises=True)
+
         pdu = self.pdu_codec.pdu_from_event(event)
 
         defer.returnValue(pdu)
 
     @defer.inlineCallbacks
+    @log_function
     def on_send_join_request(self, origin, pdu):
         event = self.pdu_codec.event_from_pdu(pdu)
 
-        is_new_state= yield self.state_handler.annotate_state_groups(event)
+        event.outlier = False
+
+        is_new_state = yield self.state_handler.annotate_state_groups(event)
         yield self.auth.check(event, None, raises=True)
 
         # FIXME (erikj):  All this is duplicated above :(
diff --git a/synapse/state.py b/synapse/state.py
index 24685c6fb4..c062cef757 100644
--- a/synapse/state.py
+++ b/synapse/state.py
@@ -22,6 +22,7 @@ from synapse.federation.pdu_codec import encode_event_id
 
 from collections import namedtuple
 
+import copy
 import logging
 import hashlib
 
@@ -143,13 +144,13 @@ class StateHandler(object):
         if hasattr(event, "outlier") and event.outlier:
             event.state_group = None
             event.old_state_events = None
-            event.state_events = None
+            event.state_events = {}
             defer.returnValue(False)
             return
 
         new_state = yield self.resolve_state_groups(event.prev_events)
 
-        event.old_state_events = new_state
+        event.old_state_events = copy.deepcopy(new_state)
 
         if hasattr(event, "state_key"):
             new_state[(event.type, event.state_key)] = event
@@ -164,9 +165,12 @@ class StateHandler(object):
         # FIXME: HACK!
         pdus = yield self.store.get_latest_pdus_in_context(room_id)
 
-        event_ids = [encode_event_id(p.pdu_id, p.origin) for p in pdus]
+        event_ids = [
+            encode_event_id(pdu_id, origin)
+            for pdu_id, origin, _ in pdus
+        ]
 
-        res = self.resolve_state_groups(event_ids)
+        res = yield self.resolve_state_groups(event_ids)
 
         if event_type:
             defer.returnValue(res.get((event_type, state_key)))