Skip to content

Commit 4777323

Browse files
authored
Redact membership events if the user requested erasure upon deactivating (#17076)
Fixes #15355 by redacting all membership events before leaving rooms.
1 parent 2e92b71 commit 4777323

File tree

4 files changed

+72
-1
lines changed

4 files changed

+72
-1
lines changed

changelog.d/17076.bugfix

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Redact membership events if the user requested erasure upon deactivating.

synapse/handlers/deactivate_account.py

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -261,11 +261,22 @@ async def _part_user(self, user_id: str) -> None:
261261
user = UserID.from_string(user_id)
262262

263263
rooms_for_user = await self.store.get_rooms_for_user(user_id)
264+
requester = create_requester(user, authenticated_entity=self._server_name)
265+
should_erase = await self.store.is_user_erased(user_id)
266+
264267
for room_id in rooms_for_user:
265268
logger.info("User parter parting %r from %r", user_id, room_id)
266269
try:
270+
# Before parting the user, redact all membership events if requested
271+
if should_erase:
272+
event_ids = await self.store.get_membership_event_ids_for_user(
273+
user_id, room_id
274+
)
275+
for event_id in event_ids:
276+
await self.store.expire_event(event_id)
277+
267278
await self._room_member_handler.update_membership(
268-
create_requester(user, authenticated_entity=self._server_name),
279+
requester,
269280
user,
270281
room_id,
271282
"leave",

synapse/storage/databases/main/roommember.py

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1234,6 +1234,28 @@ async def get_rooms_user_has_been_in(self, user_id: str) -> Set[str]:
12341234

12351235
return set(room_ids)
12361236

1237+
async def get_membership_event_ids_for_user(
1238+
self, user_id: str, room_id: str
1239+
) -> Set[str]:
1240+
"""Get all event_ids for the given user and room.
1241+
1242+
Args:
1243+
user_id: The user ID to get the event IDs for.
1244+
room_id: The room ID to look up events for.
1245+
1246+
Returns:
1247+
Set of event IDs
1248+
"""
1249+
1250+
event_ids = await self.db_pool.simple_select_onecol(
1251+
table="room_memberships",
1252+
keyvalues={"user_id": user_id, "room_id": room_id},
1253+
retcol="event_id",
1254+
desc="get_membership_event_ids_for_user",
1255+
)
1256+
1257+
return set(event_ids)
1258+
12371259
@cached(max_entries=5000)
12381260
async def _get_membership_from_event_id(
12391261
self, member_event_id: str

tests/handlers/test_deactivate_account.py

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -424,3 +424,40 @@ def test_deactivate_account_rejects_knocks(self) -> None:
424424
self._store.get_knocked_at_rooms_for_local_user(self.user)
425425
)
426426
self.assertEqual(len(after_deactivate_knocks), 0)
427+
428+
def test_membership_is_redacted_upon_deactivation(self) -> None:
429+
"""
430+
Tests that room membership events are redacted if erasure is requested.
431+
"""
432+
# Create a room
433+
room_id = self.helper.create_room_as(
434+
self.user,
435+
is_public=True,
436+
tok=self.token,
437+
)
438+
439+
# Change the displayname
440+
membership_event, _ = self.get_success(
441+
self.handler.update_membership(
442+
requester=create_requester(self.user),
443+
target=UserID.from_string(self.user),
444+
room_id=room_id,
445+
action=Membership.JOIN,
446+
content={"displayname": "Hello World!"},
447+
)
448+
)
449+
450+
# Deactivate the account
451+
self._deactivate_my_account()
452+
453+
# Get the all membership event IDs
454+
membership_event_ids = self.get_success(
455+
self._store.get_membership_event_ids_for_user(self.user, room_id=room_id)
456+
)
457+
458+
# Get the events incl. JSON
459+
events = self.get_success(self._store.get_events_as_list(membership_event_ids))
460+
461+
# Validate that there is no displayname in any of the events
462+
for event in events:
463+
self.assertTrue("displayname" not in event.content)

0 commit comments

Comments
 (0)