Skip to content

Commit

Permalink
Redact membership events if the user requested erasure upon deactivat…
Browse files Browse the repository at this point in the history
…ing (#17076)

Fixes #15355 by redacting all membership events before leaving rooms.
  • Loading branch information
S7evinK authored Apr 25, 2024
1 parent 2e92b71 commit 4777323
Show file tree
Hide file tree
Showing 4 changed files with 72 additions and 1 deletion.
1 change: 1 addition & 0 deletions changelog.d/17076.bugfix
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Redact membership events if the user requested erasure upon deactivating.
13 changes: 12 additions & 1 deletion synapse/handlers/deactivate_account.py
Original file line number Diff line number Diff line change
Expand Up @@ -261,11 +261,22 @@ async def _part_user(self, user_id: str) -> None:
user = UserID.from_string(user_id)

rooms_for_user = await self.store.get_rooms_for_user(user_id)
requester = create_requester(user, authenticated_entity=self._server_name)
should_erase = await self.store.is_user_erased(user_id)

for room_id in rooms_for_user:
logger.info("User parter parting %r from %r", user_id, room_id)
try:
# Before parting the user, redact all membership events if requested
if should_erase:
event_ids = await self.store.get_membership_event_ids_for_user(
user_id, room_id
)
for event_id in event_ids:
await self.store.expire_event(event_id)

await self._room_member_handler.update_membership(
create_requester(user, authenticated_entity=self._server_name),
requester,
user,
room_id,
"leave",
Expand Down
22 changes: 22 additions & 0 deletions synapse/storage/databases/main/roommember.py
Original file line number Diff line number Diff line change
Expand Up @@ -1234,6 +1234,28 @@ async def get_rooms_user_has_been_in(self, user_id: str) -> Set[str]:

return set(room_ids)

async def get_membership_event_ids_for_user(
self, user_id: str, room_id: str
) -> Set[str]:
"""Get all event_ids for the given user and room.
Args:
user_id: The user ID to get the event IDs for.
room_id: The room ID to look up events for.
Returns:
Set of event IDs
"""

event_ids = await self.db_pool.simple_select_onecol(
table="room_memberships",
keyvalues={"user_id": user_id, "room_id": room_id},
retcol="event_id",
desc="get_membership_event_ids_for_user",
)

return set(event_ids)

@cached(max_entries=5000)
async def _get_membership_from_event_id(
self, member_event_id: str
Expand Down
37 changes: 37 additions & 0 deletions tests/handlers/test_deactivate_account.py
Original file line number Diff line number Diff line change
Expand Up @@ -424,3 +424,40 @@ def test_deactivate_account_rejects_knocks(self) -> None:
self._store.get_knocked_at_rooms_for_local_user(self.user)
)
self.assertEqual(len(after_deactivate_knocks), 0)

def test_membership_is_redacted_upon_deactivation(self) -> None:
"""
Tests that room membership events are redacted if erasure is requested.
"""
# Create a room
room_id = self.helper.create_room_as(
self.user,
is_public=True,
tok=self.token,
)

# Change the displayname
membership_event, _ = self.get_success(
self.handler.update_membership(
requester=create_requester(self.user),
target=UserID.from_string(self.user),
room_id=room_id,
action=Membership.JOIN,
content={"displayname": "Hello World!"},
)
)

# Deactivate the account
self._deactivate_my_account()

# Get the all membership event IDs
membership_event_ids = self.get_success(
self._store.get_membership_event_ids_for_user(self.user, room_id=room_id)
)

# Get the events incl. JSON
events = self.get_success(self._store.get_events_as_list(membership_event_ids))

# Validate that there is no displayname in any of the events
for event in events:
self.assertTrue("displayname" not in event.content)

0 comments on commit 4777323

Please sign in to comment.