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 all 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
9 changes: 7 additions & 2 deletions synapse/events/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,13 @@ 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_out_of_band_membership(self):
"""Whether this is an out of band membership, like an invite or an invite
rejection. This is needed as those events are marked as outliers, but
they still need to be processed as if they're new events (e.g. updating
invite state in the database, relaying to clients, etc).
"""
return getattr(self, "out_of_band_membership", False)

def get_send_on_behalf_of(self):
"""Whether this server should send the event on behalf of another server.
Expand Down
24 changes: 20 additions & 4 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 @@ -522,6 +524,8 @@ def make_membership_event(self, destinations, room_id, user_id, membership,
Does so by asking one of the already participating servers to create an
event with proper context.

Returns a fully signed and hashed event.

Note that this does not append any events to any graphs.

Args:
Expand All @@ -536,8 +540,9 @@ def make_membership_event(self, destinations, room_id, user_id, membership,
params (dict[str, str|Iterable[str]]): Query parameters to include in the
request.
Return:
Deferred: resolves to a tuple of (origin (str), event (object))
where origin is the remote homeserver which generated the event.
Deferred[tuple[str, FrozenEvent]]: resolves to a tuple of `origin`
and event where origin is the remote homeserver which generated
the event.

Fails with a ``SynapseError`` if the chosen remote server
returns a 300/400 code.
Expand Down Expand Up @@ -571,7 +576,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
32 changes: 3 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,6 @@ def do_invite_join(self, target_hosts, room_id, joinee, content):
handled_events = set()

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

event.internal_metadata.outlier = True
event.internal_metadata.invite_from_remote = True
event.internal_metadata.out_of_band_membership = True

event.signatures.update(
compute_event_signature(
Expand All @@ -1313,7 +1308,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.out_of_band_membership = True

# Try the host that we succesfully called /make_leave/ on first for
# the /send_leave/ request.
Expand Down Expand Up @@ -1357,27 +1352,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 an "out of band membership",
# 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_out_of_band_membership()
)
is_mine = self.hs.is_mine_id(event.state_key)
if is_new_state and is_mine:
Expand Down