summary refs log tree commit diff
diff options
context:
space:
mode:
authorErik Johnston <erik@matrix.org>2014-11-27 16:02:26 +0000
committerErik Johnston <erik@matrix.org>2014-11-27 16:02:26 +0000
commit027542e2e5daa94c6517c0283be40834773fb475 (patch)
tree72cb0cef1a927355d14953dab42d0dfa55724490
parenton_receive_pdu takes more args (diff)
downloadsynapse-027542e2e5daa94c6517c0283be40834773fb475.tar.xz
Fix bugs when joining a remote room that has dodgy event graphs. This should also fix the number of times a HS will trigger a GET /event/
-rw-r--r--synapse/api/auth.py10
-rw-r--r--synapse/handlers/federation.py83
-rw-r--r--tests/handlers/test_federation.py6
3 files changed, 68 insertions, 31 deletions
diff --git a/synapse/api/auth.py b/synapse/api/auth.py
index fb911e51a6..2b0475543d 100644
--- a/synapse/api/auth.py
+++ b/synapse/api/auth.py
@@ -202,7 +202,10 @@ class Auth(object):
 
             # Invites are valid iff caller is in the room and target isn't.
             if not caller_in_room:  # caller isn't joined
-                raise AuthError(403, "You are not in room %s." % event.room_id)
+                raise AuthError(
+                    403,
+                    "%s not in room %s." % (event.user_id, event.room_id,)
+                )
             elif target_in_room:  # the target is already in the room.
                 raise AuthError(403, "%s is already in the room." %
                                      target_user_id)
@@ -225,7 +228,10 @@ class Auth(object):
             # TODO (erikj): Implement kicks.
 
             if not caller_in_room:  # trying to leave a room you aren't joined
-                raise AuthError(403, "You are not in room %s." % event.room_id)
+                raise AuthError(
+                    403,
+                    "%s not in room %s." % (target_user_id, event.room_id,)
+                )
             elif target_user_id != event.user_id:
                 if kick_level:
                     kick_level = int(kick_level)
diff --git a/synapse/handlers/federation.py b/synapse/handlers/federation.py
index 27ecd35b4b..925eb5376e 100644
--- a/synapse/handlers/federation.py
+++ b/synapse/handlers/federation.py
@@ -153,7 +153,7 @@ class FederationHandler(BaseHandler):
             event.room_id,
             self.server_name
         )
-        if not is_in_room:
+        if not is_in_room and not event.outlier:
             logger.debug("Got event for room we're not in.")
 
             replication_layer = self.replication_layer
@@ -163,28 +163,30 @@ class FederationHandler(BaseHandler):
                 event_id=event.event_id,
             )
 
-            current_state = yield replication_layer.get_state_for_context(
-                origin,
-                context=event.room_id,
-                event_id=event.event_id,
-            )
-
             for e in auth_chain:
                 e.outlier = True
                 try:
-                    yield self._handle_new_event(e)
-                    yield self.notifier.on_new_room_event(e)
+                    yield self._handle_new_event(e, fetch_missing=False)
                 except:
                     logger.exception(
                         "Failed to parse auth event %s",
                         e.event_id,
                     )
 
-            for e in current_state:
+            if not state:
+                state = yield replication_layer.get_state_for_context(
+                    origin,
+                    context=event.room_id,
+                    event_id=event.event_id,
+                )
+
+            current_state = state
+
+        if state:
+            for e in state:
                 e.outlier = True
                 try:
                     yield self._handle_new_event(e)
-                    yield self.notifier.on_new_room_event(e)
                 except:
                     logger.exception(
                         "Failed to parse state event %s",
@@ -284,6 +286,16 @@ class FederationHandler(BaseHandler):
     @defer.inlineCallbacks
     def on_event_auth(self, event_id):
         auth = yield self.store.get_auth_chain(event_id)
+
+        for event in auth:
+            event.signatures.update(
+                compute_event_signature(
+                    event,
+                    self.hs.hostname,
+                    self.hs.config.signing_key[0]
+                )
+            )
+
         defer.returnValue([e for e in auth])
 
     @log_function
@@ -343,6 +355,7 @@ class FederationHandler(BaseHandler):
 
             state = ret["state"]
             auth_chain = ret["auth_chain"]
+            auth_chain.sort(key=lambda e: e.depth)
 
             logger.debug("do_invite_join auth_chain: %s", auth_chain)
             logger.debug("do_invite_join state: %s", state)
@@ -362,10 +375,7 @@ class FederationHandler(BaseHandler):
             for e in auth_chain:
                 e.outlier = True
                 try:
-                    yield self._handle_new_event(e)
-                    yield self.notifier.on_new_room_event(
-                        e, extra_users=[joinee]
-                    )
+                    yield self._handle_new_event(e, fetch_missing=False)
                 except:
                     logger.exception(
                         "Failed to parse auth event %s",
@@ -376,9 +386,9 @@ class FederationHandler(BaseHandler):
                 # FIXME: Auth these.
                 e.outlier = True
                 try:
-                    yield self._handle_new_event(e)
-                    yield self.notifier.on_new_room_event(
-                        e, extra_users=[joinee]
+                    yield self._handle_new_event(
+                        e,
+                        fetch_missing=True
                     )
                 except:
                     logger.exception(
@@ -389,7 +399,7 @@ class FederationHandler(BaseHandler):
             yield self._handle_new_event(
                 event,
                 state=state,
-                current_state=state
+                current_state=state,
             )
 
             yield self.notifier.on_new_room_event(
@@ -552,7 +562,17 @@ class FederationHandler(BaseHandler):
                 else:
                     del results[(event.type, event.state_key)]
 
-            defer.returnValue(results.values())
+            res = results.values()
+            for event in res:
+                event.signatures.update(
+                    compute_event_signature(
+                        event,
+                        self.hs.hostname,
+                        self.hs.config.signing_key[0]
+                    )
+                )
+
+            defer.returnValue(res)
         else:
             defer.returnValue([])
 
@@ -623,11 +643,7 @@ class FederationHandler(BaseHandler):
 
     @defer.inlineCallbacks
     def _handle_new_event(self, event, state=None, backfilled=False,
-                          current_state=None):
-        if state:
-            for s in state:
-                yield self._handle_new_event(s)
-
+                          current_state=None, fetch_missing=True):
         is_new_state = yield self.state_handler.annotate_event_with_state(
             event,
             old_state=state
@@ -667,11 +683,22 @@ class FederationHandler(BaseHandler):
                 )
 
                 if not e:
-                    raise AuthError(
-                        403,
-                        "Can't find auth event %s." % (e_id, )
+                    e = yield self.replication_layer.get_pdu(
+                        event.origin, e_id, outlier=True
                     )
 
+                    if e and fetch_missing:
+                        try:
+                            yield self.on_receive_pdu(event.origin, e, False)
+                        except:
+                            logger.exception(
+                                "Failed to parse auth event %s",
+                                e_id,
+                            )
+
+                if not e:
+                    logger.warn("Can't find auth event %s.", e_id)
+
                 auth_events[(e.type, e.state_key)] = e
 
             if event.type == RoomMemberEvent.TYPE and not event.auth_events:
diff --git a/tests/handlers/test_federation.py b/tests/handlers/test_federation.py
index 98cfbe50b3..33016c16ef 100644
--- a/tests/handlers/test_federation.py
+++ b/tests/handlers/test_federation.py
@@ -42,6 +42,7 @@ class FederationTestCase(unittest.TestCase):
 
         self.auth = NonCallableMock(spec_set=[
             "check",
+            "check_host_in_room",
         ])
 
         self.hostname = "test"
@@ -89,13 +90,16 @@ class FederationTestCase(unittest.TestCase):
 
         self.datastore.persist_event.return_value = defer.succeed(None)
         self.datastore.get_room.return_value = defer.succeed(True)
+        self.auth.check_host_in_room.return_value = defer.succeed(True)
 
         def annotate(ev, old_state=None):
             ev.old_state_events = []
             return defer.succeed(False)
         self.state_handler.annotate_event_with_state.side_effect = annotate
 
-        yield self.handlers.federation_handler.on_receive_pdu(pdu, False)
+        yield self.handlers.federation_handler.on_receive_pdu(
+            "fo", pdu, False
+        )
 
         self.datastore.persist_event.assert_called_once_with(
             ANY, is_new_state=False, backfilled=False, current_state=None