Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow enabling sliding sync per-user #17393

Merged
merged 3 commits into from
Jul 5, 2024
Merged
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/17393.misc
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Allow enabling sliding sync per-user.
1 change: 1 addition & 0 deletions docs/admin_api/experimental_features.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ This API allows a server administrator to enable or disable some experimental fe
basis. The currently supported features are:
- [MSC3881](https://github.com/matrix-org/matrix-spec-proposals/pull/3881): enable remotely toggling push notifications
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`
for a server admin: see [Admin API](../usage/administration/admin_api/).
Expand Down
18 changes: 17 additions & 1 deletion synapse/api/auth/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
# [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

Expand All @@ -28,6 +28,9 @@
from synapse.http.site import SynapseRequest
from synapse.types import Requester

if TYPE_CHECKING:
from synapse.rest.admin.experimental_features import ExperimentalFeature

# guests always get this device id.
GUEST_DEVICE_ID = "guest_device"

Expand Down Expand Up @@ -87,6 +90,19 @@ async def get_user_by_req(
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(
self, app_service: ApplicationService, user_id: str
) -> None:
Expand Down
29 changes: 29 additions & 0 deletions synapse/api/auth/internal.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
Codes,
InvalidClientTokenError,
MissingClientTokenError,
UnrecognizedRequestError,
)
from synapse.http.site import SynapseRequest
from synapse.logging.opentracing import active_span, force_tracing, start_active_span
Expand All @@ -38,8 +39,10 @@
from .base import BaseAuth

if TYPE_CHECKING:
from synapse.rest.admin.experimental_features import ExperimentalFeature
from synapse.server import HomeServer


logger = logging.getLogger(__name__)


Expand Down Expand Up @@ -106,6 +109,32 @@ async def get_user_by_req(
parent_span.set_tag("appservice_id", requester.app_service.id)
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
async def _wrapped_get_user_by_req(
self,
Expand Down
28 changes: 28 additions & 0 deletions synapse/api/auth/msc3861_delegated.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
OAuthInsufficientScopeError,
StoreError,
SynapseError,
UnrecognizedRequestError,
)
from synapse.http.site import SynapseRequest
from synapse.logging.context import make_deferred_yieldable
Expand All @@ -48,6 +49,7 @@
from synapse.util.caches.cached_call import RetryOnExceptionCachedCall

if TYPE_CHECKING:
from synapse.rest.admin.experimental_features import ExperimentalFeature
from synapse.server import HomeServer

logger = logging.getLogger(__name__)
Expand Down Expand Up @@ -245,6 +247,32 @@ async def get_user_by_req(

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(
self,
token: str,
Expand Down
3 changes: 3 additions & 0 deletions synapse/rest/admin/experimental_features.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,10 +42,13 @@ class ExperimentalFeature(str, Enum):
"""

MSC3881 = "msc3881"
MSC3575 = "msc3575"
Copy link
Member

Choose a reason for hiding this comment

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

We should update the Admin API docs to state that MSC3575 is now supported.


def is_globally_enabled(self, config: "HomeServerConfig") -> bool:
if self is ExperimentalFeature.MSC3881:
return config.experimental.msc3881_enabled
if self is ExperimentalFeature.MSC3575:
return config.experimental.msc3575_enabled

assert_never(self)

Expand Down
15 changes: 10 additions & 5 deletions synapse/rest/client/sync.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@
)
from synapse.http.site import SynapseRequest
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.rest.client import SlidingSyncBody
from synapse.util import json_decoder
Expand Down Expand Up @@ -673,7 +674,9 @@ def __init__(self, hs: "HomeServer"):
)

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
device_id = requester.device_id

Expand Down Expand Up @@ -873,7 +876,10 @@ def __init__(self, hs: "HomeServer"):
self.event_serializer = hs.get_event_client_serializer()

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
device_id = requester.device_id

Expand Down Expand Up @@ -1051,6 +1057,5 @@ async def encode_rooms(
def register_servlets(hs: "HomeServer", http_server: HttpServer) -> None:
SyncRestServlet(hs).register(http_server)

if hs.config.experimental.msc3575_enabled:
SlidingSyncRestServlet(hs).register(http_server)
SlidingSyncE2eeRestServlet(hs).register(http_server)
SlidingSyncRestServlet(hs).register(http_server)
SlidingSyncE2eeRestServlet(hs).register(http_server)
Loading