mirror of
https://github.com/element-hq/synapse.git
synced 2026-08-15 09:10:32 +00:00
Gate the paginated sync endpoint per user, disabled by default
Add MSC4525 to the per-user ExperimentalFeature registry: the servlet is always registered but 404s unless the feature is enabled globally (msc4525_enabled) or for the requesting user via the admin experimental-features API.
This commit is contained in:
@@ -122,7 +122,8 @@ class ExperimentalConfig(Config):
|
||||
# MSC4525: Paginated Sync, a simplified dialect of Simplified Sliding
|
||||
# Sync (MSC4186) without lists/ranges/subscriptions, where the server
|
||||
# pages the client through changed rooms (most recently active first)
|
||||
# with bounded response sizes.
|
||||
# with bounded response sizes. Disabled by default; can also be enabled
|
||||
# for individual users via the admin experimental-features API.
|
||||
self.msc4525_enabled: bool = experimental.get("msc4525_enabled", False)
|
||||
|
||||
# MSC3773: Thread notifications
|
||||
|
||||
@@ -44,6 +44,7 @@ class ExperimentalFeature(str, Enum):
|
||||
MSC3881 = "msc3881"
|
||||
MSC3575 = "msc3575"
|
||||
MSC4222 = "msc4222"
|
||||
MSC4525 = "msc4525"
|
||||
|
||||
def is_globally_enabled(self, config: "HomeServerConfig") -> bool:
|
||||
if self is ExperimentalFeature.MSC3881:
|
||||
@@ -52,6 +53,8 @@ class ExperimentalFeature(str, Enum):
|
||||
return config.experimental.msc3575_enabled
|
||||
if self is ExperimentalFeature.MSC4222:
|
||||
return config.experimental.msc4222_enabled
|
||||
if self is ExperimentalFeature.MSC4525:
|
||||
return config.experimental.msc4525_enabled
|
||||
|
||||
assert_never(self)
|
||||
|
||||
|
||||
@@ -31,6 +31,7 @@ from synapse.http.servlet import (
|
||||
)
|
||||
from synapse.http.site import SynapseRequest
|
||||
from synapse.logging.opentracing import log_kv, set_tag
|
||||
from synapse.rest.admin.experimental_features import ExperimentalFeature
|
||||
from synapse.rest.client._base import client_patterns
|
||||
from synapse.rest.client.sync import SlidingSyncRestServlet
|
||||
from synapse.types import JsonDict, Requester, SlidingSyncStreamToken
|
||||
@@ -67,7 +68,11 @@ class PaginatedSyncRestServlet(SlidingSyncRestServlet):
|
||||
self.paginated_sync_handler = hs.get_paginated_sync_handler()
|
||||
|
||||
async def on_POST(self, request: SynapseRequest) -> tuple[int, JsonDict]:
|
||||
requester = await self.auth.get_user_by_req(request, allow_guest=True)
|
||||
# Disabled by default; enabled either globally (`msc4525_enabled`) or
|
||||
# per user via the admin experimental-features API. 404s otherwise.
|
||||
requester = await self.auth.get_user_by_req_experimental_feature(
|
||||
request, allow_guest=True, feature=ExperimentalFeature.MSC4525
|
||||
)
|
||||
user = requester.user
|
||||
|
||||
timeout = parse_integer(request, "timeout", default=0)
|
||||
@@ -156,5 +161,6 @@ class PaginatedSyncRestServlet(SlidingSyncRestServlet):
|
||||
|
||||
|
||||
def register_servlets(hs: "HomeServer", http_server: HttpServer) -> None:
|
||||
if hs.config.experimental.msc4525_enabled:
|
||||
PaginatedSyncRestServlet(hs).register(http_server)
|
||||
# Always registered; access is gated per user (or globally) via
|
||||
# `ExperimentalFeature.MSC4525` in `on_POST`.
|
||||
PaginatedSyncRestServlet(hs).register(http_server)
|
||||
|
||||
@@ -408,3 +408,53 @@ class PaginatedSyncTestCase(unittest.HomeserverTestCase):
|
||||
response = self._sync(body, pos=pos)
|
||||
account_data_response = response["extensions"]["account_data"]["rooms"]
|
||||
self.assertIn(room_id, account_data_response, response)
|
||||
|
||||
|
||||
class PaginatedSyncPerUserEnablementTestCase(unittest.HomeserverTestCase):
|
||||
"""The endpoint is disabled by default and enablable per user via the
|
||||
admin experimental-features API (`ExperimentalFeature.MSC4525`)."""
|
||||
|
||||
servlets = [
|
||||
synapse.rest.admin.register_servlets,
|
||||
login.register_servlets,
|
||||
room.register_servlets,
|
||||
paginated_sync.register_servlets,
|
||||
]
|
||||
|
||||
sync_endpoint = "/_matrix/client/unstable/org.matrix.msc4525/sync?timeout=0"
|
||||
|
||||
def prepare(self, reactor: MemoryReactor, clock: Clock, hs: HomeServer) -> None:
|
||||
self.user = self.register_user("alice", "password")
|
||||
self.tok = self.login("alice", "password")
|
||||
self.admin_tok = self.login(
|
||||
self.register_user("admin", "password", admin=True), "password"
|
||||
)
|
||||
|
||||
def test_disabled_by_default_and_enablable_per_user(self) -> None:
|
||||
body = {"page_size": 10, "limit": 5}
|
||||
|
||||
channel = self.make_request(
|
||||
"POST", self.sync_endpoint, body, access_token=self.tok
|
||||
)
|
||||
self.assertEqual(channel.code, 404, channel.json_body)
|
||||
|
||||
# Enable the feature for alice only.
|
||||
channel = self.make_request(
|
||||
"PUT",
|
||||
f"/_synapse/admin/v1/experimental_features/{self.user}",
|
||||
{"features": {"msc4525": True}},
|
||||
access_token=self.admin_tok,
|
||||
)
|
||||
self.assertEqual(channel.code, 200, channel.json_body)
|
||||
|
||||
channel = self.make_request(
|
||||
"POST", self.sync_endpoint, body, access_token=self.tok
|
||||
)
|
||||
self.assertEqual(channel.code, 200, channel.json_body)
|
||||
|
||||
# Other users remain gated.
|
||||
bob_tok = self.login(self.register_user("bob", "password"), "password")
|
||||
channel = self.make_request(
|
||||
"POST", self.sync_endpoint, body, access_token=bob_tok
|
||||
)
|
||||
self.assertEqual(channel.code, 404, channel.json_body)
|
||||
|
||||
Reference in New Issue
Block a user