summary refs log tree commit diff
path: root/synapse/handlers/federation.py
diff options
context:
space:
mode:
Diffstat (limited to 'synapse/handlers/federation.py')
-rw-r--r--synapse/handlers/federation.py146
1 files changed, 85 insertions, 61 deletions
diff --git a/synapse/handlers/federation.py b/synapse/handlers/federation.py
index aba266c2bc..b13b7c7701 100644
--- a/synapse/handlers/federation.py
+++ b/synapse/handlers/federation.py
@@ -130,7 +130,9 @@ class FederationHandler(BaseHandler):
         if auth_chain:
             event_ids |= {e.event_id for e in auth_chain}
 
-        seen_ids = (yield self.store.have_events(event_ids)).keys()
+        seen_ids = set(
+            (yield self.store.have_events(event_ids)).keys()
+        )
 
         if state and auth_chain is not None:
             # If we have any state or auth_chain given to us by the replication
@@ -332,8 +334,11 @@ class FederationHandler(BaseHandler):
 
             # Try the host we successfully got a response to /make_join/
             # request first.
-            target_hosts.remove(origin)
-            target_hosts.insert(0, origin)
+            try:
+                target_hosts.remove(origin)
+                target_hosts.insert(0, origin)
+            except ValueError:
+                pass
 
             ret = yield self.replication_layer.send_join(
                 target_hosts,
@@ -521,7 +526,7 @@ class FederationHandler(BaseHandler):
                     "Failed to get destination from event %s", s.event_id
                 )
 
-        destinations.remove(origin)
+        destinations.discard(origin)
 
         logger.debug(
             "on_send_join_request: Sending event: %s, signatures: %s",
@@ -786,12 +791,12 @@ class FederationHandler(BaseHandler):
     @log_function
     def do_auth(self, origin, event, context, auth_events):
         # Check if we have all the auth events.
-        res = yield self.store.have_events(
+        have_events = yield self.store.have_events(
             [e_id for e_id, _ in event.auth_events]
         )
 
         event_auth_events = set(e_id for e_id, _ in event.auth_events)
-        seen_events = set(res.keys())
+        seen_events = set(have_events.keys())
 
         missing_auth = event_auth_events - seen_events
 
@@ -834,6 +839,11 @@ class FederationHandler(BaseHandler):
                             auth_events[(e.type, e.state_key)] = e
                     except AuthError:
                         pass
+
+                have_events = yield self.store.have_events(
+                    [e_id for e_id, _ in event.auth_events]
+                )
+                seen_events = set(have_events.keys())
             except:
                 # FIXME:
                 logger.exception("Failed to get auth chain")
@@ -847,64 +857,75 @@ class FederationHandler(BaseHandler):
             # Do auth conflict res.
             logger.debug("Different auth: %s", different_auth)
 
-            # 1. Get what we think is the auth chain.
-            auth_ids = self.auth.compute_auth_events(
-                event, context.current_state
-            )
-            local_auth_chain = yield self.store.get_auth_chain(auth_ids)
-
-            try:
-                # 2. Get remote difference.
-                result = yield self.replication_layer.query_auth(
-                    origin,
-                    event.room_id,
-                    event.event_id,
-                    local_auth_chain,
+            # Only do auth resolution if we have something new to say.
+            # We can't rove an auth failure.
+            do_resolution = False
+            for e_id in different_auth:
+                if e_id in have_events:
+                    if have_events[e_id] != RejectedReason.AUTH_ERROR:
+                        do_resolution = True
+                        break
+
+            if do_resolution:
+                # 1. Get what we think is the auth chain.
+                auth_ids = self.auth.compute_auth_events(
+                    event, context.current_state
                 )
+                local_auth_chain = yield self.store.get_auth_chain(auth_ids)
 
-                seen_remotes = yield self.store.have_events(
-                    [e.event_id for e in result["auth_chain"]]
-                )
-
-                # 3. Process any remote auth chain events we haven't seen.
-                for ev in result["auth_chain"]:
-                    if ev.event_id in seen_remotes.keys():
-                        continue
-
-                    if ev.event_id == event.event_id:
-                        continue
-
-                    try:
-                        auth_ids = [e_id for e_id, _ in ev.auth_events]
-                        auth = {
-                            (e.type, e.state_key): e for e in result["auth_chain"]
-                            if e.event_id in auth_ids
-                        }
-                        ev.internal_metadata.outlier = True
-
-                        logger.debug(
-                            "do_auth %s different_auth: %s",
-                            event.event_id, e.event_id
-                        )
+                try:
+                    # 2. Get remote difference.
+                    result = yield self.replication_layer.query_auth(
+                        origin,
+                        event.room_id,
+                        event.event_id,
+                        local_auth_chain,
+                    )
 
-                        yield self._handle_new_event(
-                            origin, ev, auth_events=auth
-                        )
+                    seen_remotes = yield self.store.have_events(
+                        [e.event_id for e in result["auth_chain"]]
+                    )
 
-                        if ev.event_id in event_auth_events:
-                            auth_events[(ev.type, ev.state_key)] = ev
-                    except AuthError:
-                        pass
+                    # 3. Process any remote auth chain events we haven't seen.
+                    for ev in result["auth_chain"]:
+                        if ev.event_id in seen_remotes.keys():
+                            continue
+
+                        if ev.event_id == event.event_id:
+                            continue
+
+                        try:
+                            auth_ids = [e_id for e_id, _ in ev.auth_events]
+                            auth = {
+                                (e.type, e.state_key): e
+                                for e in result["auth_chain"]
+                                if e.event_id in auth_ids
+                            }
+                            ev.internal_metadata.outlier = True
+
+                            logger.debug(
+                                "do_auth %s different_auth: %s",
+                                event.event_id, e.event_id
+                            )
+
+                            yield self._handle_new_event(
+                                origin, ev, auth_events=auth
+                            )
+
+                            if ev.event_id in event_auth_events:
+                                auth_events[(ev.type, ev.state_key)] = ev
+                        except AuthError:
+                            pass
 
-            except:
-                # FIXME:
-                logger.exception("Failed to query auth chain")
+                except:
+                    # FIXME:
+                    logger.exception("Failed to query auth chain")
 
-            # 4. Look at rejects and their proofs.
-            # TODO.
+                # 4. Look at rejects and their proofs.
+                # TODO.
 
-            context.current_state.update(auth_events)
-            context.state_group = None
+                context.current_state.update(auth_events)
+                context.state_group = None
 
         try:
             self.auth.check(event, auth_events=auth_events)
@@ -1013,16 +1034,19 @@ class FederationHandler(BaseHandler):
         for e in missing_remotes:
             for e_id, _ in e.auth_events:
                 if e_id in missing_remote_ids:
-                    base_remote_rejected.remove(e)
+                    try:
+                        base_remote_rejected.remove(e)
+                    except ValueError:
+                        pass
 
         reason_map = {}
 
         for e in base_remote_rejected:
             reason = yield self.store.get_rejection_reason(e.event_id)
             if reason is None:
-                # FIXME: ERRR?!
-                logger.warn("Could not find reason for %s", e.event_id)
-                raise RuntimeError("Could not find reason for %s" % e.event_id)
+                # TODO: e is not in the current state, so we should
+                # construct some proof of that.
+                continue
 
             reason_map[e.event_id] = reason