Skip to content
This repository has been archived by the owner on Apr 26, 2024. It is now read-only.

Commit

Permalink
Store rejected remote invite events as outliers
Browse files Browse the repository at this point in the history
Currently they're stored as non-outliers even though the server isn't in
the room, which can be problematic in places where the code assumes it
has the state for all non outlier events.

In particular, there is an edge case where persisting the leave event
triggers a state resolution, which requires looking up the room version
from state. Since the server doesn't have the state, this causes an
exception to be thrown.
  • Loading branch information
erikjohnston committed Jan 23, 2019
1 parent 6b90ae6 commit 886e5ac
Show file tree
Hide file tree
Showing 3 changed files with 21 additions and 38 deletions.
10 changes: 8 additions & 2 deletions synapse/federation/federation_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,6 @@
HttpResponseException,
SynapseError,
)
from synapse.events import builder
from synapse.federation.federation_base import FederationBase, event_from_pdu_json
from synapse.util import logcontext, unwrapFirstError
from synapse.util.caches.expiringcache import ExpiringCache
Expand Down Expand Up @@ -66,6 +65,8 @@ def __init__(self, hs):
self.state = hs.get_state_handler()
self.transport_layer = hs.get_federation_transport_client()

self.event_builder_factory = hs.get_event_builder_factory()

self._get_pdu_cache = ExpiringCache(
cache_name="get_pdu_cache",
clock=self._clock,
Expand Down Expand Up @@ -571,7 +572,12 @@ def send_request(destination):
if "prev_state" not in pdu_dict:
pdu_dict["prev_state"] = []

ev = builder.EventBuilder(pdu_dict)
# Strip off the fields that we want to clobber.
pdu_dict.pop("origin", None)
pdu_dict.pop("origin_server_ts", None)
pdu_dict.pop("unsigned", None)

ev = self.event_builder_factory.new(pdu_dict)

defer.returnValue(
(destination, ev)
Expand Down
44 changes: 12 additions & 32 deletions synapse/handlers/federation.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,10 +43,7 @@
StoreError,
SynapseError,
)
from synapse.crypto.event_signing import (
add_hashes_and_signatures,
compute_event_signature,
)
from synapse.crypto.event_signing import compute_event_signature
from synapse.events.validator import EventValidator
from synapse.replication.http.federation import (
ReplicationCleanRoomRestServlet,
Expand All @@ -58,7 +55,6 @@
from synapse.util import logcontext, unwrapFirstError
from synapse.util.async_helpers import Linearizer
from synapse.util.distributor import user_joined_room
from synapse.util.frozenutils import unfreeze
from synapse.util.logutils import log_function
from synapse.util.retryutils import NotRetryingDestination
from synapse.visibility import filter_events_for_server
Expand Down Expand Up @@ -1083,7 +1079,9 @@ def do_invite_join(self, target_hosts, room_id, joinee, content):
handled_events = set()

try:
event = self._sign_event(event)
self._sign_event(event)
event.internal_metadata.outlier = False

# Try the host we successfully got a response to /make_join/
# request first.
try:
Expand Down Expand Up @@ -1289,13 +1287,7 @@ def on_invite_request(self, origin, pdu):
event.internal_metadata.outlier = True
event.internal_metadata.invite_from_remote = True

event.signatures.update(
compute_event_signature(
event,
self.hs.hostname,
self.hs.config.signing_key[0]
)
)
self._sign_event(event)

context = yield self.state_handler.compute_event_context(event)
yield self.persist_events_and_notify([(event, context)])
Expand All @@ -1313,7 +1305,7 @@ def do_remotely_reject_invite(self, target_hosts, room_id, user_id):
# Mark as outlier as we don't have any state for this event; we're not
# even in the room.
event.internal_metadata.outlier = True
event = self._sign_event(event)
self._sign_event(event)

# Try the host that we succesfully called /make_leave/ on first for
# the /send_leave/ request.
Expand Down Expand Up @@ -1358,26 +1350,14 @@ def _make_and_verify_event(self, target_hosts, room_id, user_id, membership,
defer.returnValue((origin, event))

def _sign_event(self, event):
event.internal_metadata.outlier = False

builder = self.event_builder_factory.new(
unfreeze(event.get_pdu_json())
)

builder.event_id = self.event_builder_factory.create_event_id()
builder.origin = self.hs.hostname

if not hasattr(event, "signatures"):
builder.signatures = {}

add_hashes_and_signatures(
builder,
self.hs.hostname,
self.hs.config.signing_key[0],
event.signatures.update(
compute_event_signature(
event,
self.hs.hostname,
self.hs.config.signing_key[0]
)
)

return builder.build()

@defer.inlineCallbacks
@log_function
def on_make_leave_request(self, room_id, user_id):
Expand Down
5 changes: 1 addition & 4 deletions synapse/storage/roommember.py
Original file line number Diff line number Diff line change
Expand Up @@ -591,10 +591,7 @@ def _store_room_members_txn(self, txn, events, backfilled):
# i.e., its something that has just happened.
# The only current event that can also be an outlier is if its an
# invite that has come in across federation.
is_new_state = not backfilled and (
not event.internal_metadata.is_outlier()
or event.internal_metadata.is_invite_from_remote()
)
is_new_state = not backfilled
is_mine = self.hs.is_mine_id(event.state_key)
if is_new_state and is_mine:
if event.membership == Membership.INVITE:
Expand Down

0 comments on commit 886e5ac

Please sign in to comment.