mirror of
https://github.com/element-hq/synapse.git
synced 2026-08-21 21:10:47 +00:00
Stamp replaced knock into unsigned on an out-of-band denial
Outliers never gain replaces_state, so clients could not tell a denied knock (prev_content.membership == knock) from a plain kick. Reflect the replaced knock event in the denial's unsigned ourselves. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Uk8aPxHn3BHCe52L226jdG
This commit is contained in:
co-authored by
Claude Fable 5
parent
c464be40ac
commit
962148d404
@@ -323,6 +323,18 @@ class FederationEventHandler:
|
||||
pdu.state_key, pdu.room_id
|
||||
)
|
||||
if origin == via_server or origin == get_domain_from_id(pdu.sender):
|
||||
# As an outlier the event will never gain a
|
||||
# `replaces_state`, so reflect the replaced knock in
|
||||
# `unsigned` ourselves: clients use `prev_content` to
|
||||
# distinguish a denied knock from a plain kick.
|
||||
knock_event = await self._store.get_event(
|
||||
membership_event_id, allow_none=True
|
||||
)
|
||||
if knock_event is not None:
|
||||
pdu.unsigned["replaces_state"] = knock_event.event_id
|
||||
pdu.unsigned["prev_content"] = knock_event.content
|
||||
pdu.unsigned["prev_sender"] = knock_event.sender
|
||||
|
||||
# Handle the denial event
|
||||
pdu.internal_metadata.outlier = True
|
||||
pdu.internal_metadata.out_of_band_membership = True
|
||||
|
||||
@@ -405,9 +405,10 @@ class KnockViaServerTestCase(unittest.FederatingHomeserverTestCase):
|
||||
|
||||
# The knock should (eventually - the PDU is processed in the
|
||||
# background) be retracted.
|
||||
leave_event_id = None
|
||||
with test_timeout(3, "Denial of the knock was not processed"):
|
||||
while True:
|
||||
membership, _ = self.get_success(
|
||||
membership, leave_event_id = self.get_success(
|
||||
self.store.get_local_current_membership_for_user_in_room(
|
||||
knock_result.local_user1_id, knock_result.remote_room_id
|
||||
)
|
||||
@@ -416,6 +417,19 @@ class KnockViaServerTestCase(unittest.FederatingHomeserverTestCase):
|
||||
break
|
||||
time.sleep(0.1)
|
||||
|
||||
# The stored leave should carry the replaced knock in `unsigned`, so
|
||||
# that clients can tell a denied knock from a plain kick.
|
||||
assert leave_event_id is not None
|
||||
leave_event = self.get_success(self.store.get_event(leave_event_id))
|
||||
self.assertEqual(
|
||||
leave_event.unsigned.get("prev_content", {}).get("membership"),
|
||||
Membership.KNOCK,
|
||||
)
|
||||
self.assertEqual(
|
||||
leave_event.unsigned.get("replaces_state"),
|
||||
knock_result.knock_event_id,
|
||||
)
|
||||
|
||||
def test_denied_knock_ignored_without_knock_in_auth_events(self) -> None:
|
||||
"""A leave event for our knocked user which does not reference the
|
||||
knock in its auth events is ignored."""
|
||||
|
||||
Reference in New Issue
Block a user