Allow enabling sliding sync per-user (#17393)

Based on #17392
This commit is contained in:
Erik Johnston 2024-07-05 13:04:27 +01:00 committed by GitHub
parent 57538eb4d9
commit 8e9e6f1a0a
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 89 additions and 6 deletions

1
changelog.d/17393.misc Normal file
View File

@ -0,0 +1 @@
Allow enabling sliding sync per-user.

View File

@ -4,6 +4,7 @@ This API allows a server administrator to enable or disable some experimental fe
basis. The currently supported features are: basis. The currently supported features are:
- [MSC3881](https://github.com/matrix-org/matrix-spec-proposals/pull/3881): enable remotely toggling push notifications - [MSC3881](https://github.com/matrix-org/matrix-spec-proposals/pull/3881): enable remotely toggling push notifications
for another client for another client
- [MSC3575](https://github.com/matrix-org/matrix-spec-proposals/pull/3575): enable experimental sliding sync support
To use it, you will need to authenticate by providing an `access_token` To use it, you will need to authenticate by providing an `access_token`
for a server admin: see [Admin API](../usage/administration/admin_api/). for a server admin: see [Admin API](../usage/administration/admin_api/).

View File

@ -18,7 +18,7 @@
# [This file includes modifications made by New Vector Limited] # [This file includes modifications made by New Vector Limited]
# #
# #
from typing import Optional, Tuple from typing import TYPE_CHECKING, Optional, Tuple
from typing_extensions import Protocol from typing_extensions import Protocol
@ -28,6 +28,9 @@ from synapse.appservice import ApplicationService
from synapse.http.site import SynapseRequest from synapse.http.site import SynapseRequest
from synapse.types import Requester from synapse.types import Requester
if TYPE_CHECKING:
from synapse.rest.admin.experimental_features import ExperimentalFeature
# guests always get this device id. # guests always get this device id.
GUEST_DEVICE_ID = "guest_device" GUEST_DEVICE_ID = "guest_device"
@ -87,6 +90,19 @@ class Auth(Protocol):
AuthError if access is denied for the user in the access token AuthError if access is denied for the user in the access token
""" """
async def get_user_by_req_experimental_feature(
self,
request: SynapseRequest,
feature: "ExperimentalFeature",
allow_guest: bool = False,
allow_expired: bool = False,
allow_locked: bool = False,
) -> Requester:
"""Like `get_user_by_req`, except also checks if the user has access to
the experimental feature. If they don't returns a 404 unrecognized
request.
"""
async def validate_appservice_can_control_user_id( async def validate_appservice_can_control_user_id(
self, app_service: ApplicationService, user_id: str self, app_service: ApplicationService, user_id: str
) -> None: ) -> None:

View File

@ -28,6 +28,7 @@ from synapse.api.errors import (
Codes, Codes,
InvalidClientTokenError, InvalidClientTokenError,
MissingClientTokenError, MissingClientTokenError,
UnrecognizedRequestError,
) )
from synapse.http.site import SynapseRequest from synapse.http.site import SynapseRequest
from synapse.logging.opentracing import active_span, force_tracing, start_active_span from synapse.logging.opentracing import active_span, force_tracing, start_active_span
@ -38,8 +39,10 @@ from . import GUEST_DEVICE_ID
from .base import BaseAuth from .base import BaseAuth
if TYPE_CHECKING: if TYPE_CHECKING:
from synapse.rest.admin.experimental_features import ExperimentalFeature
from synapse.server import HomeServer from synapse.server import HomeServer
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
@ -106,6 +109,32 @@ class InternalAuth(BaseAuth):
parent_span.set_tag("appservice_id", requester.app_service.id) parent_span.set_tag("appservice_id", requester.app_service.id)
return requester return requester
async def get_user_by_req_experimental_feature(
self,
request: SynapseRequest,
feature: "ExperimentalFeature",
allow_guest: bool = False,
allow_expired: bool = False,
allow_locked: bool = False,
) -> Requester:
try:
requester = await self.get_user_by_req(
request,
allow_guest=allow_guest,
allow_expired=allow_expired,
allow_locked=allow_locked,
)
if await self.store.is_feature_enabled(requester.user.to_string(), feature):
return requester
raise UnrecognizedRequestError(code=404)
except (AuthError, InvalidClientTokenError):
if feature.is_globally_enabled(self.hs.config):
# If its globally enabled then return the auth error
raise
raise UnrecognizedRequestError(code=404)
@cancellable @cancellable
async def _wrapped_get_user_by_req( async def _wrapped_get_user_by_req(
self, self,

View File

@ -40,6 +40,7 @@ from synapse.api.errors import (
OAuthInsufficientScopeError, OAuthInsufficientScopeError,
StoreError, StoreError,
SynapseError, SynapseError,
UnrecognizedRequestError,
) )
from synapse.http.site import SynapseRequest from synapse.http.site import SynapseRequest
from synapse.logging.context import make_deferred_yieldable from synapse.logging.context import make_deferred_yieldable
@ -48,6 +49,7 @@ from synapse.util import json_decoder
from synapse.util.caches.cached_call import RetryOnExceptionCachedCall from synapse.util.caches.cached_call import RetryOnExceptionCachedCall
if TYPE_CHECKING: if TYPE_CHECKING:
from synapse.rest.admin.experimental_features import ExperimentalFeature
from synapse.server import HomeServer from synapse.server import HomeServer
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
@ -245,6 +247,32 @@ class MSC3861DelegatedAuth(BaseAuth):
return requester return requester
async def get_user_by_req_experimental_feature(
self,
request: SynapseRequest,
feature: "ExperimentalFeature",
allow_guest: bool = False,
allow_expired: bool = False,
allow_locked: bool = False,
) -> Requester:
try:
requester = await self.get_user_by_req(
request,
allow_guest=allow_guest,
allow_expired=allow_expired,
allow_locked=allow_locked,
)
if await self.store.is_feature_enabled(requester.user.to_string(), feature):
return requester
raise UnrecognizedRequestError(code=404)
except (AuthError, InvalidClientTokenError):
if feature.is_globally_enabled(self.hs.config):
# If its globally enabled then return the auth error
raise
raise UnrecognizedRequestError(code=404)
async def get_user_by_access_token( async def get_user_by_access_token(
self, self,
token: str, token: str,

View File

@ -42,10 +42,13 @@ class ExperimentalFeature(str, Enum):
""" """
MSC3881 = "msc3881" MSC3881 = "msc3881"
MSC3575 = "msc3575"
def is_globally_enabled(self, config: "HomeServerConfig") -> bool: def is_globally_enabled(self, config: "HomeServerConfig") -> bool:
if self is ExperimentalFeature.MSC3881: if self is ExperimentalFeature.MSC3881:
return config.experimental.msc3881_enabled return config.experimental.msc3881_enabled
if self is ExperimentalFeature.MSC3575:
return config.experimental.msc3575_enabled
assert_never(self) assert_never(self)

View File

@ -53,6 +53,7 @@ from synapse.http.servlet import (
) )
from synapse.http.site import SynapseRequest from synapse.http.site import SynapseRequest
from synapse.logging.opentracing import trace_with_opname from synapse.logging.opentracing import trace_with_opname
from synapse.rest.admin.experimental_features import ExperimentalFeature
from synapse.types import JsonDict, Requester, StreamToken from synapse.types import JsonDict, Requester, StreamToken
from synapse.types.rest.client import SlidingSyncBody from synapse.types.rest.client import SlidingSyncBody
from synapse.util import json_decoder from synapse.util import json_decoder
@ -673,7 +674,9 @@ class SlidingSyncE2eeRestServlet(RestServlet):
) )
async def on_GET(self, request: SynapseRequest) -> Tuple[int, JsonDict]: async def on_GET(self, request: SynapseRequest) -> Tuple[int, JsonDict]:
requester = await self.auth.get_user_by_req(request, allow_guest=True) requester = await self.auth.get_user_by_req_experimental_feature(
request, allow_guest=True, feature=ExperimentalFeature.MSC3575
)
user = requester.user user = requester.user
device_id = requester.device_id device_id = requester.device_id
@ -873,7 +876,10 @@ class SlidingSyncRestServlet(RestServlet):
self.event_serializer = hs.get_event_client_serializer() self.event_serializer = hs.get_event_client_serializer()
async def on_POST(self, request: SynapseRequest) -> Tuple[int, JsonDict]: async def on_POST(self, request: SynapseRequest) -> Tuple[int, JsonDict]:
requester = await self.auth.get_user_by_req(request, allow_guest=True) requester = await self.auth.get_user_by_req_experimental_feature(
request, allow_guest=True, feature=ExperimentalFeature.MSC3575
)
user = requester.user user = requester.user
device_id = requester.device_id device_id = requester.device_id
@ -1051,6 +1057,5 @@ class SlidingSyncRestServlet(RestServlet):
def register_servlets(hs: "HomeServer", http_server: HttpServer) -> None: def register_servlets(hs: "HomeServer", http_server: HttpServer) -> None:
SyncRestServlet(hs).register(http_server) SyncRestServlet(hs).register(http_server)
if hs.config.experimental.msc3575_enabled:
SlidingSyncRestServlet(hs).register(http_server) SlidingSyncRestServlet(hs).register(http_server)
SlidingSyncE2eeRestServlet(hs).register(http_server) SlidingSyncE2eeRestServlet(hs).register(http_server)