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

Store rejected remote invite events as outliers #4405

Merged
merged 7 commits into from
Jan 24, 2019
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions changelog.d/4405.bugfix
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Fix bug when rejecting remote invites
8 changes: 6 additions & 2 deletions synapse/events/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,12 @@ def get_dict(self):
def is_outlier(self):
return getattr(self, "outlier", False)

def is_invite_from_remote(self):
return getattr(self, "invite_from_remote", False)
def is_new_remote_event(self):
"""Whether this is a new remote event, like an invite or an invite
rejection. This is needed as those events are marked as outliers, but
they still need to be processed.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

could you define "processed" a bit better?

"""
return getattr(self, "new_remote_event", False)
erikjohnston marked this conversation as resolved.
Show resolved Hide resolved

def get_send_on_behalf_of(self):
"""Whether this server should send the event on behalf of another server.
Expand Down
17 changes: 15 additions & 2 deletions synapse/federation/federation_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@
HttpResponseException,
SynapseError,
)
from synapse.events import builder
from synapse.crypto.event_signing import add_hashes_and_signatures
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 +66,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 +573,18 @@ 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.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

could you add something to the docstring to say that we will do the hashing/signing magic?

pdu_dict.pop("origin", None)
pdu_dict.pop("origin_server_ts", None)
pdu_dict.pop("unsigned", None)

builder = self.event_builder_factory.new(pdu_dict)
add_hashes_and_signatures(
builder,
self.hs.hostname,
self.hs.config.signing_key[0]
)
ev = builder.build()

defer.returnValue(
(destination, ev)
Expand Down
34 changes: 5 additions & 29 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,8 @@ def do_invite_join(self, target_hosts, room_id, joinee, content):
handled_events = set()

try:
event = self._sign_event(event)
event.internal_metadata.outlier = False
erikjohnston marked this conversation as resolved.
Show resolved Hide resolved

# Try the host we successfully got a response to /make_join/
# request first.
try:
Expand Down Expand Up @@ -1287,7 +1284,7 @@ def on_invite_request(self, origin, pdu):
)

event.internal_metadata.outlier = True
event.internal_metadata.invite_from_remote = True
event.internal_metadata.new_remote_event = True

event.signatures.update(
compute_event_signature(
Expand All @@ -1313,7 +1310,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)
event.internal_metadata.new_remote_event = True

# Try the host that we succesfully called /make_leave/ on first for
# the /send_leave/ request.
Expand Down Expand Up @@ -1357,27 +1354,6 @@ def _make_and_verify_event(self, target_hosts, room_id, user_id, membership,
assert(event.room_id == room_id)
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],
)

return builder.build()

@defer.inlineCallbacks
@log_function
def on_make_leave_request(self, room_id, user_id):
Expand Down
8 changes: 4 additions & 4 deletions synapse/storage/roommember.py
Original file line number Diff line number Diff line change
Expand Up @@ -588,12 +588,12 @@ def _store_room_members_txn(self, txn, events, backfilled):
)

# We update the local_invites table only if the event is "current",
# 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.
# i.e., its something that has just happened. If the event is an
# outlier it is only current if its a "new remote event", like a
# remote invite or a rejection of a remote invite.
is_new_state = not backfilled and (
not event.internal_metadata.is_outlier()
or event.internal_metadata.is_invite_from_remote()
or event.internal_metadata.is_new_remote_event()
)
is_mine = self.hs.is_mine_id(event.state_key)
if is_new_state and is_mine:
Expand Down