mirror of
https://git.anonymousland.org/anonymousland/synapse.git
synced 2025-01-19 04:51:29 -05:00
Do not include rooms with an unknown room version in a sync response. (#10644)
A user will still see this room if it is in a local cache, but it will not reappear if clearing the cache and reloading.
This commit is contained in:
parent
b5fef6054a
commit
000aa89be6
1
changelog.d/10644.bugfix
Normal file
1
changelog.d/10644.bugfix
Normal file
@ -0,0 +1 @@
|
|||||||
|
Rooms with unsupported room versions are no longer returned via `/sync`.
|
1
mypy.ini
1
mypy.ini
@ -90,6 +90,7 @@ files =
|
|||||||
tests/test_utils,
|
tests/test_utils,
|
||||||
tests/handlers/test_password_providers.py,
|
tests/handlers/test_password_providers.py,
|
||||||
tests/handlers/test_room_summary.py,
|
tests/handlers/test_room_summary.py,
|
||||||
|
tests/handlers/test_sync.py,
|
||||||
tests/rest/client/v1/test_login.py,
|
tests/rest/client/v1/test_login.py,
|
||||||
tests/rest/client/v2_alpha/test_auth.py,
|
tests/rest/client/v2_alpha/test_auth.py,
|
||||||
tests/util/test_itertools.py,
|
tests/util/test_itertools.py,
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
# Copyright 2015, 2016 OpenMarket Ltd
|
# Copyright 2015-2021 The Matrix.org Foundation C.I.C.
|
||||||
# Copyright 2018, 2019 New Vector Ltd
|
|
||||||
#
|
#
|
||||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
# you may not use this file except in compliance with the License.
|
# you may not use this file except in compliance with the License.
|
||||||
@ -31,6 +30,7 @@ from prometheus_client import Counter
|
|||||||
|
|
||||||
from synapse.api.constants import AccountDataTypes, EventTypes, Membership
|
from synapse.api.constants import AccountDataTypes, EventTypes, Membership
|
||||||
from synapse.api.filtering import FilterCollection
|
from synapse.api.filtering import FilterCollection
|
||||||
|
from synapse.api.room_versions import KNOWN_ROOM_VERSIONS
|
||||||
from synapse.events import EventBase
|
from synapse.events import EventBase
|
||||||
from synapse.logging.context import current_context
|
from synapse.logging.context import current_context
|
||||||
from synapse.logging.opentracing import SynapseTags, log_kv, set_tag, start_active_span
|
from synapse.logging.opentracing import SynapseTags, log_kv, set_tag, start_active_span
|
||||||
@ -1843,6 +1843,9 @@ class SyncHandler:
|
|||||||
knocked = []
|
knocked = []
|
||||||
|
|
||||||
for event in room_list:
|
for event in room_list:
|
||||||
|
if event.room_version_id not in KNOWN_ROOM_VERSIONS:
|
||||||
|
continue
|
||||||
|
|
||||||
if event.membership == Membership.JOIN:
|
if event.membership == Membership.JOIN:
|
||||||
room_entries.append(
|
room_entries.append(
|
||||||
RoomSyncResultBuilder(
|
RoomSyncResultBuilder(
|
||||||
|
@ -386,9 +386,10 @@ class RoomMemberWorkerStore(EventsWorkerStore):
|
|||||||
)
|
)
|
||||||
|
|
||||||
sql = """
|
sql = """
|
||||||
SELECT room_id, e.sender, c.membership, event_id, e.stream_ordering
|
SELECT room_id, e.sender, c.membership, event_id, e.stream_ordering, r.room_version
|
||||||
FROM local_current_membership AS c
|
FROM local_current_membership AS c
|
||||||
INNER JOIN events AS e USING (room_id, event_id)
|
INNER JOIN events AS e USING (room_id, event_id)
|
||||||
|
INNER JOIN rooms AS r USING (room_id)
|
||||||
WHERE
|
WHERE
|
||||||
user_id = ?
|
user_id = ?
|
||||||
AND %s
|
AND %s
|
||||||
@ -397,7 +398,7 @@ class RoomMemberWorkerStore(EventsWorkerStore):
|
|||||||
)
|
)
|
||||||
|
|
||||||
txn.execute(sql, (user_id, *args))
|
txn.execute(sql, (user_id, *args))
|
||||||
results = [RoomsForUser(**r) for r in self.db_pool.cursor_to_dict(txn)]
|
results = [RoomsForUser(*r) for r in txn]
|
||||||
|
|
||||||
return results
|
return results
|
||||||
|
|
||||||
@ -447,7 +448,8 @@ class RoomMemberWorkerStore(EventsWorkerStore):
|
|||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
Returns the rooms the user is in currently, along with the stream
|
Returns the rooms the user is in currently, along with the stream
|
||||||
ordering of the most recent join for that user and room.
|
ordering of the most recent join for that user and room, along with
|
||||||
|
the room version of the room.
|
||||||
"""
|
"""
|
||||||
return await self.db_pool.runInteraction(
|
return await self.db_pool.runInteraction(
|
||||||
"get_rooms_for_user_with_stream_ordering",
|
"get_rooms_for_user_with_stream_ordering",
|
||||||
|
@ -30,6 +30,7 @@ class RoomsForUser:
|
|||||||
membership: str
|
membership: str
|
||||||
event_id: str
|
event_id: str
|
||||||
stream_ordering: int
|
stream_ordering: int
|
||||||
|
room_version_id: str
|
||||||
|
|
||||||
|
|
||||||
@attr.s(slots=True, frozen=True, weakref_slot=False, auto_attribs=True)
|
@attr.s(slots=True, frozen=True, weakref_slot=False, auto_attribs=True)
|
||||||
|
@ -12,9 +12,16 @@
|
|||||||
# See the License for the specific language governing permissions and
|
# See the License for the specific language governing permissions and
|
||||||
# limitations under the License.
|
# limitations under the License.
|
||||||
|
|
||||||
|
from typing import Optional
|
||||||
|
|
||||||
|
from synapse.api.constants import EventTypes, JoinRules
|
||||||
from synapse.api.errors import Codes, ResourceLimitError
|
from synapse.api.errors import Codes, ResourceLimitError
|
||||||
from synapse.api.filtering import DEFAULT_FILTER_COLLECTION
|
from synapse.api.filtering import DEFAULT_FILTER_COLLECTION
|
||||||
|
from synapse.api.room_versions import RoomVersions
|
||||||
from synapse.handlers.sync import SyncConfig
|
from synapse.handlers.sync import SyncConfig
|
||||||
|
from synapse.rest import admin
|
||||||
|
from synapse.rest.client import knock, login, room
|
||||||
|
from synapse.server import HomeServer
|
||||||
from synapse.types import UserID, create_requester
|
from synapse.types import UserID, create_requester
|
||||||
|
|
||||||
import tests.unittest
|
import tests.unittest
|
||||||
@ -24,8 +31,14 @@ import tests.utils
|
|||||||
class SyncTestCase(tests.unittest.HomeserverTestCase):
|
class SyncTestCase(tests.unittest.HomeserverTestCase):
|
||||||
"""Tests Sync Handler."""
|
"""Tests Sync Handler."""
|
||||||
|
|
||||||
def prepare(self, reactor, clock, hs):
|
servlets = [
|
||||||
self.hs = hs
|
admin.register_servlets,
|
||||||
|
knock.register_servlets,
|
||||||
|
login.register_servlets,
|
||||||
|
room.register_servlets,
|
||||||
|
]
|
||||||
|
|
||||||
|
def prepare(self, reactor, clock, hs: HomeServer):
|
||||||
self.sync_handler = self.hs.get_sync_handler()
|
self.sync_handler = self.hs.get_sync_handler()
|
||||||
self.store = self.hs.get_datastore()
|
self.store = self.hs.get_datastore()
|
||||||
|
|
||||||
@ -68,12 +81,124 @@ class SyncTestCase(tests.unittest.HomeserverTestCase):
|
|||||||
)
|
)
|
||||||
self.assertEquals(e.value.errcode, Codes.RESOURCE_LIMIT_EXCEEDED)
|
self.assertEquals(e.value.errcode, Codes.RESOURCE_LIMIT_EXCEEDED)
|
||||||
|
|
||||||
|
def test_unknown_room_version(self):
|
||||||
|
"""
|
||||||
|
A room with an unknown room version should not break sync (and should be excluded).
|
||||||
|
"""
|
||||||
|
inviter = self.register_user("creator", "pass", admin=True)
|
||||||
|
inviter_tok = self.login("@creator:test", "pass")
|
||||||
|
|
||||||
def generate_sync_config(user_id: str) -> SyncConfig:
|
user = self.register_user("user", "pass")
|
||||||
|
tok = self.login("user", "pass")
|
||||||
|
|
||||||
|
# Do an initial sync on a different device.
|
||||||
|
requester = create_requester(user)
|
||||||
|
initial_result = self.get_success(
|
||||||
|
self.sync_handler.wait_for_sync_for_user(
|
||||||
|
requester, sync_config=generate_sync_config(user, device_id="dev")
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
# Create a room as the user.
|
||||||
|
joined_room = self.helper.create_room_as(user, tok=tok)
|
||||||
|
|
||||||
|
# Invite the user to the room as someone else.
|
||||||
|
invite_room = self.helper.create_room_as(inviter, tok=inviter_tok)
|
||||||
|
self.helper.invite(invite_room, targ=user, tok=inviter_tok)
|
||||||
|
|
||||||
|
knock_room = self.helper.create_room_as(
|
||||||
|
inviter, room_version=RoomVersions.V7.identifier, tok=inviter_tok
|
||||||
|
)
|
||||||
|
self.helper.send_state(
|
||||||
|
knock_room,
|
||||||
|
EventTypes.JoinRules,
|
||||||
|
{"join_rule": JoinRules.KNOCK},
|
||||||
|
tok=inviter_tok,
|
||||||
|
)
|
||||||
|
channel = self.make_request(
|
||||||
|
"POST",
|
||||||
|
"/_matrix/client/r0/knock/%s" % (knock_room,),
|
||||||
|
b"{}",
|
||||||
|
tok,
|
||||||
|
)
|
||||||
|
self.assertEquals(200, channel.code, channel.result)
|
||||||
|
|
||||||
|
# The rooms should appear in the sync response.
|
||||||
|
result = self.get_success(
|
||||||
|
self.sync_handler.wait_for_sync_for_user(
|
||||||
|
requester, sync_config=generate_sync_config(user)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
self.assertIn(joined_room, [r.room_id for r in result.joined])
|
||||||
|
self.assertIn(invite_room, [r.room_id for r in result.invited])
|
||||||
|
self.assertIn(knock_room, [r.room_id for r in result.knocked])
|
||||||
|
|
||||||
|
# Test a incremental sync (by providing a since_token).
|
||||||
|
result = self.get_success(
|
||||||
|
self.sync_handler.wait_for_sync_for_user(
|
||||||
|
requester,
|
||||||
|
sync_config=generate_sync_config(user, device_id="dev"),
|
||||||
|
since_token=initial_result.next_batch,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
self.assertIn(joined_room, [r.room_id for r in result.joined])
|
||||||
|
self.assertIn(invite_room, [r.room_id for r in result.invited])
|
||||||
|
self.assertIn(knock_room, [r.room_id for r in result.knocked])
|
||||||
|
|
||||||
|
# Poke the database and update the room version to an unknown one.
|
||||||
|
for room_id in (joined_room, invite_room, knock_room):
|
||||||
|
self.get_success(
|
||||||
|
self.hs.get_datastores().main.db_pool.simple_update(
|
||||||
|
"rooms",
|
||||||
|
keyvalues={"room_id": room_id},
|
||||||
|
updatevalues={"room_version": "unknown-room-version"},
|
||||||
|
desc="updated-room-version",
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
# Blow away caches (supported room versions can only change due to a restart).
|
||||||
|
self.get_success(
|
||||||
|
self.store.get_rooms_for_user_with_stream_ordering.invalidate_all()
|
||||||
|
)
|
||||||
|
self.store._get_event_cache.clear()
|
||||||
|
|
||||||
|
# The rooms should be excluded from the sync response.
|
||||||
|
# Get a new request key.
|
||||||
|
result = self.get_success(
|
||||||
|
self.sync_handler.wait_for_sync_for_user(
|
||||||
|
requester, sync_config=generate_sync_config(user)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
self.assertNotIn(joined_room, [r.room_id for r in result.joined])
|
||||||
|
self.assertNotIn(invite_room, [r.room_id for r in result.invited])
|
||||||
|
self.assertNotIn(knock_room, [r.room_id for r in result.knocked])
|
||||||
|
|
||||||
|
# The rooms should also not be in an incremental sync.
|
||||||
|
result = self.get_success(
|
||||||
|
self.sync_handler.wait_for_sync_for_user(
|
||||||
|
requester,
|
||||||
|
sync_config=generate_sync_config(user, device_id="dev"),
|
||||||
|
since_token=initial_result.next_batch,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
self.assertNotIn(joined_room, [r.room_id for r in result.joined])
|
||||||
|
self.assertNotIn(invite_room, [r.room_id for r in result.invited])
|
||||||
|
self.assertNotIn(knock_room, [r.room_id for r in result.knocked])
|
||||||
|
|
||||||
|
|
||||||
|
_request_key = 0
|
||||||
|
|
||||||
|
|
||||||
|
def generate_sync_config(
|
||||||
|
user_id: str, device_id: Optional[str] = "device_id"
|
||||||
|
) -> SyncConfig:
|
||||||
|
"""Generate a sync config (with a unique request key)."""
|
||||||
|
global _request_key
|
||||||
|
_request_key += 1
|
||||||
return SyncConfig(
|
return SyncConfig(
|
||||||
user=UserID(user_id.split(":")[0][1:], user_id.split(":")[1]),
|
user=UserID.from_string(user_id),
|
||||||
filter_collection=DEFAULT_FILTER_COLLECTION,
|
filter_collection=DEFAULT_FILTER_COLLECTION,
|
||||||
is_guest=False,
|
is_guest=False,
|
||||||
request_key="request_key",
|
request_key=("request_key", _request_key),
|
||||||
device_id="device_id",
|
device_id=device_id,
|
||||||
)
|
)
|
||||||
|
@ -150,6 +150,7 @@ class SlavedEventStoreTestCase(BaseSlavedStoreTestCase):
|
|||||||
"invite",
|
"invite",
|
||||||
event.event_id,
|
event.event_id,
|
||||||
event.internal_metadata.stream_ordering,
|
event.internal_metadata.stream_ordering,
|
||||||
|
RoomVersions.V1.identifier,
|
||||||
)
|
)
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
Loading…
Reference in New Issue
Block a user