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

Allow upgrading a room only once #5045

Closed
wants to merge 2 commits into from
Closed
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/5045.bugfix
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Prevent the abiltiy to upgrade the same room more than once.
14 changes: 13 additions & 1 deletion synapse/handlers/room.py
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,9 @@ def __init__(self, hs):

@defer.inlineCallbacks
def upgrade_room(self, requester, old_room_id, new_version):
"""Replace a room with a new room with a different version
"""Replace a room with a new room with a different version. Will
raise an exception if the room has already been upgraded, or in
currently in the process of being upgraded.

Args:
requester (synapse.types.Requester): the user requesting the upgrade
Expand All @@ -85,12 +87,22 @@ def upgrade_room(self, requester, old_room_id, new_version):

Returns:
Deferred[unicode]: the new room id

Raises:
NotFoundError if the room is unknown
SynapseError if this room has already been upgraded
"""
yield self.ratelimit(requester)

user_id = requester.user.to_string()

with (yield self._upgrade_linearizer.queue(old_room_id)):
# Check that this room has not already been upgraded
tombstone = yield self.store.get_room_tombstone(old_room_id)

if tombstone is not None:
raise SynapseError(400, "This room has already been upgraded")

# start by allocating a new room id
r = yield self.store.get_room(old_room_id)
if r is None:
Expand Down
30 changes: 29 additions & 1 deletion synapse/storage/state.py
Original file line number Diff line number Diff line change
Expand Up @@ -433,7 +433,8 @@ def get_room_predecessor(self, room_id):
room_id (str)

Returns:
Deferred[unicode|None]: predecessor room id
Deferred[unicode|None]: predecessor room id, or None if a
predecessor is not found

Raises:
NotFoundError if the room is unknown
Expand All @@ -444,6 +445,33 @@ def get_room_predecessor(self, room_id):
# Return predecessor if present
defer.returnValue(create_event.content.get("predecessor", None))

@defer.inlineCallbacks
def get_room_tombstone(self, room_id):
"""Get the tombstone event of an upgraded room if one exists.
Otherwise return None.

Args:
room_id (str)

Returns:
Deferred[FrozenEvent|None]: the tombstone event, or None if a
tombstone event was not found

Raises:
NotFoundError if the room is unknown
"""
# Retrieve the room's tombstone event if it exists
state_ids = yield self.get_current_state_ids(room_id)
tombstone_id = state_ids.get((EventTypes.Tombstone, ""))

# If we can't find the tombstone, assume we've hit a dead end
if not tombstone_id:
defer.returnValue(None)

# Retrieve the room's tombstone event and return
tombstone_event = yield self.get_event(tombstone_id)
Copy link
Member

Choose a reason for hiding this comment

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

This will raise an exception if the event has been redacted. We probably want to allow an upgrade if the tombstone is redacted? idk

defer.returnValue(tombstone_event)

@defer.inlineCallbacks
def get_create_event_for_room(self, room_id):
"""Get the create state event for a room.
Expand Down