mirror of
https://github.com/element-hq/synapse.git
synced 2024-12-14 11:57:44 +00:00
Merge branch 'release-v1.121' into matrix-org-hotfixes
This commit is contained in:
commit
0fb2633a27
32 changed files with 418 additions and 56 deletions
12
.github/workflows/release-artifacts.yml
vendored
12
.github/workflows/release-artifacts.yml
vendored
|
@ -5,7 +5,7 @@ name: Build release artifacts
|
|||
on:
|
||||
# we build on PRs and develop to (hopefully) get early warning
|
||||
# of things breaking (but only build one set of debs). PRs skip
|
||||
# building wheels on ARM.
|
||||
# building wheels on macOS & ARM.
|
||||
pull_request:
|
||||
push:
|
||||
branches: ["develop", "release-*"]
|
||||
|
@ -111,7 +111,7 @@ jobs:
|
|||
runs-on: ${{ matrix.os }}
|
||||
strategy:
|
||||
matrix:
|
||||
os: [ubuntu-22.04]
|
||||
os: [ubuntu-22.04, macos-13]
|
||||
arch: [x86_64, aarch64]
|
||||
# is_pr is a flag used to exclude certain jobs from the matrix on PRs.
|
||||
# It is not read by the rest of the workflow.
|
||||
|
@ -119,6 +119,12 @@ jobs:
|
|||
- ${{ startsWith(github.ref, 'refs/pull/') }}
|
||||
|
||||
exclude:
|
||||
# Don't build macos wheels on PR CI.
|
||||
- is_pr: true
|
||||
os: "macos-13"
|
||||
# Don't build aarch64 wheels on mac.
|
||||
- os: "macos-13"
|
||||
arch: aarch64
|
||||
# Don't build aarch64 wheels on PR CI.
|
||||
- is_pr: true
|
||||
arch: aarch64
|
||||
|
@ -207,7 +213,7 @@ jobs:
|
|||
tar -cvJf debs.tar.xz debs
|
||||
- name: Attach to release
|
||||
# Pinned to work around https://github.com/softprops/action-gh-release/issues/445
|
||||
uses: softprops/action-gh-release@v2.0.5
|
||||
uses: softprops/action-gh-release@v0.1.15
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
with:
|
||||
|
|
47
CHANGES.md
47
CHANGES.md
|
@ -1,3 +1,50 @@
|
|||
# Synapse 1.121.0rc1 (2024-12-04)
|
||||
|
||||
This release candidate contains the security fixes from [v1.120.2](https://github.com/element-hq/synapse/releases/tag/v1.120.2).
|
||||
|
||||
New changes listed below.
|
||||
|
||||
### Features
|
||||
|
||||
- Support for [MSC4190](https://github.com/matrix-org/matrix-spec-proposals/pull/4190): device management for Application Services. ([\#17705](https://github.com/element-hq/synapse/issues/17705))
|
||||
- Update [MSC4186](https://github.com/matrix-org/matrix-spec-proposals/pull/4186) Sliding Sync to include invite, ban, kick, targets when `$LAZY`-loading room members. ([\#17947](https://github.com/element-hq/synapse/issues/17947))
|
||||
- Use stable `M_USER_LOCKED` error code for locked accounts, as per [Matrix 1.12](https://spec.matrix.org/v1.12/client-server-api/#account-locking). ([\#17965](https://github.com/element-hq/synapse/issues/17965))
|
||||
- [MSC4076](https://github.com/matrix-org/matrix-spec-proposals/pull/4076): Add `disable_badge_count` to pusher configuration. ([\#17975](https://github.com/element-hq/synapse/issues/17975))
|
||||
|
||||
### Bugfixes
|
||||
|
||||
- Fix long-standing bug where read receipts could get overly delayed being sent over federation. ([\#17933](https://github.com/element-hq/synapse/issues/17933))
|
||||
|
||||
### Improved Documentation
|
||||
|
||||
- Add OIDC example configuration for Forgejo (fork of Gitea). ([\#17872](https://github.com/element-hq/synapse/issues/17872))
|
||||
- Link to element-docker-demo from contrib/docker*. ([\#17953](https://github.com/element-hq/synapse/issues/17953))
|
||||
|
||||
### Internal Changes
|
||||
|
||||
- [MSC4108](https://github.com/matrix-org/matrix-spec-proposals/pull/4108): Add a `Content-Type` header on the `PUT` response to work around a faulty behavior in some caching reverse proxies. ([\#17253](https://github.com/element-hq/synapse/issues/17253))
|
||||
- Fix incorrect comment in new schema delta. ([\#17936](https://github.com/element-hq/synapse/issues/17936))
|
||||
- Raise setuptools_rust version cap to 1.10.2. ([\#17944](https://github.com/element-hq/synapse/issues/17944))
|
||||
- Enable encrypted appservice related experimental features in the complement docker image. ([\#17945](https://github.com/element-hq/synapse/issues/17945))
|
||||
- Return whether the user is suspended when querying the user account in the Admin API. ([\#17952](https://github.com/element-hq/synapse/issues/17952))
|
||||
- Fix new scheduled tasks jumping the queue. ([\#17962](https://github.com/element-hq/synapse/issues/17962))
|
||||
- Bump pyo3 and dependencies to v0.23.2. ([\#17966](https://github.com/element-hq/synapse/issues/17966))
|
||||
- Update setuptools-rust and fix building abi3 wheels in latest version. ([\#17969](https://github.com/element-hq/synapse/issues/17969))
|
||||
- Consolidate SSO redirects through `/_matrix/client/v3/login/sso/redirect(/{idpId})`. ([\#17972](https://github.com/element-hq/synapse/issues/17972))
|
||||
- Fix Docker and Complement config to be able to use `public_baseurl`. ([\#17986](https://github.com/element-hq/synapse/issues/17986))
|
||||
- Fix building wheels for MacOS which was temporarily disabled in Synapse 1.120.2. ([\#17993](https://github.com/element-hq/synapse/issues/17993))
|
||||
- Fix release process to not create duplicate releases. ([\#17970](https://github.com/element-hq/synapse/issues/17970), [\#17995](https://github.com/element-hq/synapse/issues/17995))
|
||||
|
||||
|
||||
### Updates to locked dependencies
|
||||
|
||||
* Bump bytes from 1.8.0 to 1.9.0. ([\#17982](https://github.com/element-hq/synapse/issues/17982))
|
||||
* Bump pysaml2 from 7.3.1 to 7.5.0. ([\#17978](https://github.com/element-hq/synapse/issues/17978))
|
||||
* Bump serde_json from 1.0.132 to 1.0.133. ([\#17939](https://github.com/element-hq/synapse/issues/17939))
|
||||
* Bump tomli from 2.0.2 to 2.1.0. ([\#17959](https://github.com/element-hq/synapse/issues/17959))
|
||||
* Bump tomli from 2.1.0 to 2.2.1. ([\#17979](https://github.com/element-hq/synapse/issues/17979))
|
||||
* Bump tornado from 6.4.1 to 6.4.2. ([\#17955](https://github.com/element-hq/synapse/issues/17955))
|
||||
|
||||
# Synapse 1.120.2 (2024-12-03)
|
||||
|
||||
This version has building of wheels for macOS disabled.
|
||||
|
|
|
@ -1 +0,0 @@
|
|||
[MSC4108](https://github.com/matrix-org/matrix-spec-proposals/pull/4108): Add a `Content-Type` header on the `PUT` response to work around a faulty behavior in some caching reverse proxies.
|
|
@ -1 +0,0 @@
|
|||
Add OIDC example configuration for Forgejo (fork of Gitea).
|
|
@ -1 +0,0 @@
|
|||
Fix long-standing bug where read receipts could get overly delayed being sent over federation.
|
|
@ -1 +0,0 @@
|
|||
Fix incorrect comment in new schema delta.
|
|
@ -1 +0,0 @@
|
|||
Raise setuptools_rust version cap to 1.10.2.
|
|
@ -1 +0,0 @@
|
|||
Enable encrypted appservice related experimental features in the complement docker image.
|
|
@ -1 +0,0 @@
|
|||
Update [MSC4186](https://github.com/matrix-org/matrix-spec-proposals/pull/4186) Sliding Sync to include invite, ban, kick, targets when `$LAZY`-loading room members.
|
|
@ -1 +0,0 @@
|
|||
Return whether the user is suspended when querying the user account in the Admin API.
|
|
@ -1 +0,0 @@
|
|||
Link to element-docker-demo from contrib/docker*.
|
|
@ -1 +0,0 @@
|
|||
Fix new scheduled tasks jumping the queue.
|
|
@ -1 +0,0 @@
|
|||
Use stable `M_USER_LOCKED` error code for locked accounts, as per [Matrix 1.12](https://spec.matrix.org/v1.12/client-server-api/#account-locking).
|
|
@ -1 +0,0 @@
|
|||
Bump pyo3 and dependencies to v0.23.2.
|
|
@ -1 +0,0 @@
|
|||
Update setuptools-rust and fix building abi3 wheels in latest version.
|
|
@ -1 +0,0 @@
|
|||
Fix release process to not create duplicate releases.
|
|
@ -1 +0,0 @@
|
|||
Consolidate SSO redirects through `/_matrix/client/v3/login/sso/redirect(/{idpId})`.
|
|
@ -1 +0,0 @@
|
|||
[MSC4076](https://github.com/matrix-org/matrix-spec-proposals/pull/4076): Add `disable_badge_count` to pusher configuration.
|
|
@ -1 +0,0 @@
|
|||
Fix Docker and Complement config to be able to use `public_baseurl`.
|
6
debian/changelog
vendored
6
debian/changelog
vendored
|
@ -1,3 +1,9 @@
|
|||
matrix-synapse-py3 (1.121.0~rc1) stable; urgency=medium
|
||||
|
||||
* New Synapse release 1.121.0rc1.
|
||||
|
||||
-- Synapse Packaging team <packages@matrix.org> Wed, 04 Dec 2024 14:47:23 +0000
|
||||
|
||||
matrix-synapse-py3 (1.120.2) stable; urgency=medium
|
||||
|
||||
* New synapse release 1.120.2.
|
||||
|
|
|
@ -97,7 +97,7 @@ module-name = "synapse.synapse_rust"
|
|||
|
||||
[tool.poetry]
|
||||
name = "matrix-synapse"
|
||||
version = "1.120.2"
|
||||
version = "1.121.0rc1"
|
||||
description = "Homeserver for the Matrix decentralised comms protocol"
|
||||
authors = ["Matrix.org Team and Contributors <packages@matrix.org>"]
|
||||
license = "AGPL-3.0-or-later"
|
||||
|
@ -386,8 +386,11 @@ build-backend = "poetry.core.masonry.api"
|
|||
# c.f. https://github.com/matrix-org/synapse/pull/14259
|
||||
skip = "cp36* cp37* cp38* pp37* pp38* *-musllinux_i686 pp*aarch64 *-musllinux_aarch64"
|
||||
|
||||
# We need a rust compiler
|
||||
before-all = "curl https://sh.rustup.rs -sSf | sh -s -- --default-toolchain stable -y --profile minimal"
|
||||
# We need a rust compiler.
|
||||
#
|
||||
# We temporarily pin Rust to 1.82.0 to work around
|
||||
# https://github.com/element-hq/synapse/issues/17988
|
||||
before-all = "curl https://sh.rustup.rs -sSf | sh -s -- --default-toolchain 1.82.0 -y --profile minimal"
|
||||
environment= { PATH = "$PATH:$HOME/.cargo/bin" }
|
||||
|
||||
# For some reason if we don't manually clean the build directory we
|
||||
|
|
|
@ -87,6 +87,7 @@ class ApplicationService:
|
|||
ip_range_whitelist: Optional[IPSet] = None,
|
||||
supports_ephemeral: bool = False,
|
||||
msc3202_transaction_extensions: bool = False,
|
||||
msc4190_device_management: bool = False,
|
||||
):
|
||||
self.token = token
|
||||
self.url = (
|
||||
|
@ -100,6 +101,7 @@ class ApplicationService:
|
|||
self.ip_range_whitelist = ip_range_whitelist
|
||||
self.supports_ephemeral = supports_ephemeral
|
||||
self.msc3202_transaction_extensions = msc3202_transaction_extensions
|
||||
self.msc4190_device_management = msc4190_device_management
|
||||
|
||||
if "|" in self.id:
|
||||
raise Exception("application service ID cannot contain '|' character")
|
||||
|
|
|
@ -183,6 +183,18 @@ def _load_appservice(
|
|||
"The `org.matrix.msc3202` option should be true or false if specified."
|
||||
)
|
||||
|
||||
# Opt-in flag for the MSC4190 behaviours.
|
||||
# When enabled, the following C-S API endpoints change for appservices:
|
||||
# - POST /register does not return an access token
|
||||
# - PUT /devices/{device_id} creates a new device if one does not exist
|
||||
# - DELETE /devices/{device_id} no longer requires UIA
|
||||
# - POST /delete_devices/{device_id} no longer requires UIA
|
||||
msc4190_enabled = as_info.get("io.element.msc4190", False)
|
||||
if not isinstance(msc4190_enabled, bool):
|
||||
raise ValueError(
|
||||
"The `io.element.msc4190` option should be true or false if specified."
|
||||
)
|
||||
|
||||
return ApplicationService(
|
||||
token=as_info["as_token"],
|
||||
url=as_info["url"],
|
||||
|
@ -195,4 +207,5 @@ def _load_appservice(
|
|||
ip_range_whitelist=ip_range_whitelist,
|
||||
supports_ephemeral=supports_ephemeral,
|
||||
msc3202_transaction_extensions=msc3202_transaction_extensions,
|
||||
msc4190_device_management=msc4190_enabled,
|
||||
)
|
||||
|
|
|
@ -729,6 +729,40 @@ class DeviceHandler(DeviceWorkerHandler):
|
|||
|
||||
await self.notify_device_update(user_id, device_ids)
|
||||
|
||||
async def upsert_device(
|
||||
self, user_id: str, device_id: str, display_name: Optional[str] = None
|
||||
) -> bool:
|
||||
"""Create or update a device
|
||||
|
||||
Args:
|
||||
user_id: The user to update devices of.
|
||||
device_id: The device to update.
|
||||
display_name: The new display name for this device.
|
||||
|
||||
Returns:
|
||||
True if the device was created, False if it was updated.
|
||||
|
||||
"""
|
||||
|
||||
# Reject a new displayname which is too long.
|
||||
self._check_device_name_length(display_name)
|
||||
|
||||
created = await self.store.store_device(
|
||||
user_id,
|
||||
device_id,
|
||||
initial_device_display_name=display_name,
|
||||
)
|
||||
|
||||
if not created:
|
||||
await self.store.update_device(
|
||||
user_id,
|
||||
device_id,
|
||||
new_display_name=display_name,
|
||||
)
|
||||
|
||||
await self.notify_device_update(user_id, [device_id])
|
||||
return created
|
||||
|
||||
async def update_device(self, user_id: str, device_id: str, content: dict) -> None:
|
||||
"""Update the given device
|
||||
|
||||
|
|
|
@ -630,7 +630,9 @@ class RegistrationHandler:
|
|||
"""
|
||||
await self._auto_join_rooms(user_id)
|
||||
|
||||
async def appservice_register(self, user_localpart: str, as_token: str) -> str:
|
||||
async def appservice_register(
|
||||
self, user_localpart: str, as_token: str
|
||||
) -> Tuple[str, ApplicationService]:
|
||||
user = UserID(user_localpart, self.hs.hostname)
|
||||
user_id = user.to_string()
|
||||
service = self.store.get_app_service_by_token(as_token)
|
||||
|
@ -653,7 +655,7 @@ class RegistrationHandler:
|
|||
appservice_id=service_id,
|
||||
create_profile_with_displayname=user.localpart,
|
||||
)
|
||||
return user_id
|
||||
return (user_id, service)
|
||||
|
||||
def check_user_id_not_appservice_exclusive(
|
||||
self, user_id: str, allowed_appservice: Optional[ApplicationService] = None
|
||||
|
|
|
@ -114,6 +114,10 @@ class DeleteDevicesRestServlet(RestServlet):
|
|||
else:
|
||||
raise e
|
||||
|
||||
if requester.app_service and requester.app_service.msc4190_device_management:
|
||||
# MSC4190 can skip UIA for this endpoint
|
||||
pass
|
||||
else:
|
||||
await self.auth_handler.validate_user_via_ui_auth(
|
||||
requester,
|
||||
request,
|
||||
|
@ -175,9 +179,6 @@ class DeviceRestServlet(RestServlet):
|
|||
async def on_DELETE(
|
||||
self, request: SynapseRequest, device_id: str
|
||||
) -> Tuple[int, JsonDict]:
|
||||
if self._msc3861_oauth_delegation_enabled:
|
||||
raise UnrecognizedRequestError(code=404)
|
||||
|
||||
requester = await self.auth.get_user_by_req(request)
|
||||
|
||||
try:
|
||||
|
@ -192,6 +193,15 @@ class DeviceRestServlet(RestServlet):
|
|||
else:
|
||||
raise
|
||||
|
||||
if requester.app_service and requester.app_service.msc4190_device_management:
|
||||
# MSC4190 allows appservices to delete devices through this endpoint without UIA
|
||||
# It's also allowed with MSC3861 enabled
|
||||
pass
|
||||
|
||||
else:
|
||||
if self._msc3861_oauth_delegation_enabled:
|
||||
raise UnrecognizedRequestError(code=404)
|
||||
|
||||
await self.auth_handler.validate_user_via_ui_auth(
|
||||
requester,
|
||||
request,
|
||||
|
@ -216,6 +226,16 @@ class DeviceRestServlet(RestServlet):
|
|||
requester = await self.auth.get_user_by_req(request, allow_guest=True)
|
||||
|
||||
body = parse_and_validate_json_object_from_request(request, self.PutBody)
|
||||
|
||||
# MSC4190 allows appservices to create devices through this endpoint
|
||||
if requester.app_service and requester.app_service.msc4190_device_management:
|
||||
created = await self.device_handler.upsert_device(
|
||||
user_id=requester.user.to_string(),
|
||||
device_id=device_id,
|
||||
display_name=body.display_name,
|
||||
)
|
||||
return 201 if created else 200, {}
|
||||
|
||||
await self.device_handler.update_device(
|
||||
requester.user.to_string(), device_id, body.dict()
|
||||
)
|
||||
|
|
|
@ -771,9 +771,12 @@ class RegisterRestServlet(RestServlet):
|
|||
body: JsonDict,
|
||||
should_issue_refresh_token: bool = False,
|
||||
) -> JsonDict:
|
||||
user_id = await self.registration_handler.appservice_register(
|
||||
user_id, appservice = await self.registration_handler.appservice_register(
|
||||
username, as_token
|
||||
)
|
||||
if appservice.msc4190_device_management:
|
||||
body["inhibit_login"] = True
|
||||
|
||||
return await self._create_registration_details(
|
||||
user_id,
|
||||
body,
|
||||
|
@ -937,7 +940,7 @@ class RegisterAppServiceOnlyRestServlet(RestServlet):
|
|||
|
||||
as_token = self.auth.get_access_token_from_request(request)
|
||||
|
||||
user_id = await self.registration_handler.appservice_register(
|
||||
user_id, _ = await self.registration_handler.appservice_register(
|
||||
desired_username, as_token
|
||||
)
|
||||
return 200, {"user_id": user_id}
|
||||
|
|
|
@ -1165,12 +1165,23 @@ class ApplicationServicesHandlerOtkCountsTestCase(unittest.HomeserverTestCase):
|
|||
self.hs.get_datastores().main.services_cache = [self._service]
|
||||
|
||||
# Register some appservice users
|
||||
self._sender_user, self._sender_device = self.register_appservice_user(
|
||||
user_id, device_id = self.register_appservice_user(
|
||||
"as.sender", self._service_token
|
||||
)
|
||||
self._namespaced_user, self._namespaced_device = self.register_appservice_user(
|
||||
# With MSC4190 enabled, there will not be a device created
|
||||
# during AS registration. However MSC4190 is not enabled
|
||||
# in this test. It may become the default behaviour in the
|
||||
# future, in which case this test will need to be updated.
|
||||
assert device_id is not None
|
||||
self._sender_user = user_id
|
||||
self._sender_device = device_id
|
||||
|
||||
user_id, device_id = self.register_appservice_user(
|
||||
"_as_user1", self._service_token
|
||||
)
|
||||
assert device_id is not None
|
||||
self._namespaced_user = user_id
|
||||
self._namespaced_device = device_id
|
||||
|
||||
# Register a real user as well.
|
||||
self._real_user = self.register_user("real.user", "meow")
|
||||
|
|
|
@ -560,9 +560,15 @@ class MSC3861OAuthDelegation(HomeserverTestCase):
|
|||
self.assertEqual(channel.code, 401, channel.json_body)
|
||||
|
||||
def expect_unrecognized(
|
||||
self, method: str, path: str, content: Union[bytes, str, JsonDict] = ""
|
||||
self,
|
||||
method: str,
|
||||
path: str,
|
||||
content: Union[bytes, str, JsonDict] = "",
|
||||
auth: bool = False,
|
||||
) -> None:
|
||||
channel = self.make_request(method, path, content)
|
||||
channel = self.make_request(
|
||||
method, path, content, access_token="token" if auth else None
|
||||
)
|
||||
|
||||
self.assertEqual(channel.code, 404, channel.json_body)
|
||||
self.assertEqual(
|
||||
|
@ -648,8 +654,25 @@ class MSC3861OAuthDelegation(HomeserverTestCase):
|
|||
|
||||
def test_device_management_endpoints_removed(self) -> None:
|
||||
"""Test that device management endpoints that were removed in MSC2964 are no longer available."""
|
||||
self.expect_unrecognized("POST", "/_matrix/client/v3/delete_devices")
|
||||
self.expect_unrecognized("DELETE", "/_matrix/client/v3/devices/{DEVICE}")
|
||||
|
||||
# Because we still support those endpoints with ASes, it checks the
|
||||
# access token before returning 404
|
||||
self.http_client.request = AsyncMock(
|
||||
return_value=FakeResponse.json(
|
||||
code=200,
|
||||
payload={
|
||||
"active": True,
|
||||
"sub": SUBJECT,
|
||||
"scope": " ".join([MATRIX_USER_SCOPE, MATRIX_DEVICE_SCOPE]),
|
||||
"username": USERNAME,
|
||||
},
|
||||
)
|
||||
)
|
||||
|
||||
self.expect_unrecognized("POST", "/_matrix/client/v3/delete_devices", auth=True)
|
||||
self.expect_unrecognized(
|
||||
"DELETE", "/_matrix/client/v3/devices/{DEVICE}", auth=True
|
||||
)
|
||||
|
||||
def test_openid_endpoints_removed(self) -> None:
|
||||
"""Test that OpenID id_token endpoints that were removed in MSC2964 are no longer available."""
|
||||
|
|
|
@ -24,6 +24,7 @@ from twisted.internet.defer import ensureDeferred
|
|||
from twisted.test.proto_helpers import MemoryReactor
|
||||
|
||||
from synapse.api.errors import NotFoundError
|
||||
from synapse.appservice import ApplicationService
|
||||
from synapse.rest import admin, devices, sync
|
||||
from synapse.rest.client import keys, login, register
|
||||
from synapse.server import HomeServer
|
||||
|
@ -455,3 +456,183 @@ class DehydratedDeviceTestCase(unittest.HomeserverTestCase):
|
|||
token,
|
||||
)
|
||||
self.assertEqual(channel.json_body["device_keys"], {"@mikey:test": {}})
|
||||
|
||||
|
||||
class MSC4190AppserviceDevicesTestCase(unittest.HomeserverTestCase):
|
||||
servlets = [
|
||||
register.register_servlets,
|
||||
devices.register_servlets,
|
||||
]
|
||||
|
||||
def make_homeserver(self, reactor: MemoryReactor, clock: Clock) -> HomeServer:
|
||||
self.hs = self.setup_test_homeserver()
|
||||
|
||||
# This application service uses the new MSC4190 behaviours
|
||||
self.msc4190_service = ApplicationService(
|
||||
id="msc4190",
|
||||
token="some_token",
|
||||
hs_token="some_token",
|
||||
sender="@as:example.com",
|
||||
namespaces={
|
||||
ApplicationService.NS_USERS: [{"regex": "@.*", "exclusive": False}]
|
||||
},
|
||||
msc4190_device_management=True,
|
||||
)
|
||||
# This application service doesn't use the new MSC4190 behaviours
|
||||
self.pre_msc_service = ApplicationService(
|
||||
id="regular",
|
||||
token="other_token",
|
||||
hs_token="other_token",
|
||||
sender="@as2:example.com",
|
||||
namespaces={
|
||||
ApplicationService.NS_USERS: [{"regex": "@.*", "exclusive": False}]
|
||||
},
|
||||
msc4190_device_management=False,
|
||||
)
|
||||
self.hs.get_datastores().main.services_cache.append(self.msc4190_service)
|
||||
self.hs.get_datastores().main.services_cache.append(self.pre_msc_service)
|
||||
return self.hs
|
||||
|
||||
def test_PUT_device(self) -> None:
|
||||
self.register_appservice_user("alice", self.msc4190_service.token)
|
||||
self.register_appservice_user("bob", self.pre_msc_service.token)
|
||||
|
||||
channel = self.make_request(
|
||||
"GET",
|
||||
"/_matrix/client/v3/devices?user_id=@alice:test",
|
||||
access_token=self.msc4190_service.token,
|
||||
)
|
||||
self.assertEqual(channel.code, 200, channel.json_body)
|
||||
self.assertEqual(channel.json_body, {"devices": []})
|
||||
|
||||
channel = self.make_request(
|
||||
"PUT",
|
||||
"/_matrix/client/v3/devices/AABBCCDD?user_id=@alice:test",
|
||||
content={"display_name": "Alice's device"},
|
||||
access_token=self.msc4190_service.token,
|
||||
)
|
||||
self.assertEqual(channel.code, 201, channel.json_body)
|
||||
|
||||
channel = self.make_request(
|
||||
"GET",
|
||||
"/_matrix/client/v3/devices?user_id=@alice:test",
|
||||
access_token=self.msc4190_service.token,
|
||||
)
|
||||
self.assertEqual(channel.code, 200, channel.json_body)
|
||||
self.assertEqual(len(channel.json_body["devices"]), 1)
|
||||
self.assertEqual(channel.json_body["devices"][0]["device_id"], "AABBCCDD")
|
||||
|
||||
# Doing a second time should return a 200 instead of a 201
|
||||
channel = self.make_request(
|
||||
"PUT",
|
||||
"/_matrix/client/v3/devices/AABBCCDD?user_id=@alice:test",
|
||||
content={"display_name": "Alice's device"},
|
||||
access_token=self.msc4190_service.token,
|
||||
)
|
||||
self.assertEqual(channel.code, 200, channel.json_body)
|
||||
|
||||
# On the regular service, that API should not allow for the
|
||||
# creation of new devices.
|
||||
channel = self.make_request(
|
||||
"PUT",
|
||||
"/_matrix/client/v3/devices/AABBCCDD?user_id=@bob:test",
|
||||
content={"display_name": "Bob's device"},
|
||||
access_token=self.pre_msc_service.token,
|
||||
)
|
||||
self.assertEqual(channel.code, 404, channel.json_body)
|
||||
|
||||
def test_DELETE_device(self) -> None:
|
||||
self.register_appservice_user("alice", self.msc4190_service.token)
|
||||
|
||||
# There should be no device
|
||||
channel = self.make_request(
|
||||
"GET",
|
||||
"/_matrix/client/v3/devices?user_id=@alice:test",
|
||||
access_token=self.msc4190_service.token,
|
||||
)
|
||||
self.assertEqual(channel.code, 200, channel.json_body)
|
||||
self.assertEqual(channel.json_body, {"devices": []})
|
||||
|
||||
# Create a device
|
||||
channel = self.make_request(
|
||||
"PUT",
|
||||
"/_matrix/client/v3/devices/AABBCCDD?user_id=@alice:test",
|
||||
content={},
|
||||
access_token=self.msc4190_service.token,
|
||||
)
|
||||
self.assertEqual(channel.code, 201, channel.json_body)
|
||||
|
||||
# There should be one device
|
||||
channel = self.make_request(
|
||||
"GET",
|
||||
"/_matrix/client/v3/devices?user_id=@alice:test",
|
||||
access_token=self.msc4190_service.token,
|
||||
)
|
||||
self.assertEqual(channel.code, 200, channel.json_body)
|
||||
self.assertEqual(len(channel.json_body["devices"]), 1)
|
||||
|
||||
# Delete the device. UIA should not be required.
|
||||
channel = self.make_request(
|
||||
"DELETE",
|
||||
"/_matrix/client/v3/devices/AABBCCDD?user_id=@alice:test",
|
||||
access_token=self.msc4190_service.token,
|
||||
)
|
||||
self.assertEqual(channel.code, 200, channel.json_body)
|
||||
|
||||
# There should be no device again
|
||||
channel = self.make_request(
|
||||
"GET",
|
||||
"/_matrix/client/v3/devices?user_id=@alice:test",
|
||||
access_token=self.msc4190_service.token,
|
||||
)
|
||||
self.assertEqual(channel.code, 200, channel.json_body)
|
||||
self.assertEqual(channel.json_body, {"devices": []})
|
||||
|
||||
def test_POST_delete_devices(self) -> None:
|
||||
self.register_appservice_user("alice", self.msc4190_service.token)
|
||||
|
||||
# There should be no device
|
||||
channel = self.make_request(
|
||||
"GET",
|
||||
"/_matrix/client/v3/devices?user_id=@alice:test",
|
||||
access_token=self.msc4190_service.token,
|
||||
)
|
||||
self.assertEqual(channel.code, 200, channel.json_body)
|
||||
self.assertEqual(channel.json_body, {"devices": []})
|
||||
|
||||
# Create a device
|
||||
channel = self.make_request(
|
||||
"PUT",
|
||||
"/_matrix/client/v3/devices/AABBCCDD?user_id=@alice:test",
|
||||
content={},
|
||||
access_token=self.msc4190_service.token,
|
||||
)
|
||||
self.assertEqual(channel.code, 201, channel.json_body)
|
||||
|
||||
# There should be one device
|
||||
channel = self.make_request(
|
||||
"GET",
|
||||
"/_matrix/client/v3/devices?user_id=@alice:test",
|
||||
access_token=self.msc4190_service.token,
|
||||
)
|
||||
self.assertEqual(channel.code, 200, channel.json_body)
|
||||
self.assertEqual(len(channel.json_body["devices"]), 1)
|
||||
|
||||
# Delete the device with delete_devices
|
||||
# UIA should not be required.
|
||||
channel = self.make_request(
|
||||
"POST",
|
||||
"/_matrix/client/v3/delete_devices?user_id=@alice:test",
|
||||
content={"devices": ["AABBCCDD"]},
|
||||
access_token=self.msc4190_service.token,
|
||||
)
|
||||
self.assertEqual(channel.code, 200, channel.json_body)
|
||||
|
||||
# There should be no device again
|
||||
channel = self.make_request(
|
||||
"GET",
|
||||
"/_matrix/client/v3/devices?user_id=@alice:test",
|
||||
access_token=self.msc4190_service.token,
|
||||
)
|
||||
self.assertEqual(channel.code, 200, channel.json_body)
|
||||
self.assertEqual(channel.json_body, {"devices": []})
|
||||
|
|
|
@ -120,6 +120,34 @@ class RegisterRestServletTestCase(unittest.HomeserverTestCase):
|
|||
|
||||
self.assertEqual(channel.code, 401, msg=channel.result)
|
||||
|
||||
def test_POST_appservice_msc4190_enabled(self) -> None:
|
||||
# With MSC4190 enabled, the registration should *not* return an access token
|
||||
user_id = "@as_user_kermit:test"
|
||||
as_token = "i_am_an_app_service"
|
||||
|
||||
appservice = ApplicationService(
|
||||
as_token,
|
||||
id="1234",
|
||||
namespaces={"users": [{"regex": r"@as_user.*", "exclusive": True}]},
|
||||
sender="@as:test",
|
||||
msc4190_device_management=True,
|
||||
)
|
||||
|
||||
self.hs.get_datastores().main.services_cache.append(appservice)
|
||||
request_data = {
|
||||
"username": "as_user_kermit",
|
||||
"type": APP_SERVICE_REGISTRATION_TYPE,
|
||||
}
|
||||
|
||||
channel = self.make_request(
|
||||
b"POST", self.url + b"?access_token=i_am_an_app_service", request_data
|
||||
)
|
||||
|
||||
self.assertEqual(channel.code, 200, msg=channel.result)
|
||||
det_data = {"user_id": user_id, "home_server": self.hs.hostname}
|
||||
self.assertLessEqual(det_data.items(), channel.json_body.items())
|
||||
self.assertNotIn("access_token", channel.json_body)
|
||||
|
||||
def test_POST_bad_password(self) -> None:
|
||||
request_data = {"username": "kermit", "password": 666}
|
||||
channel = self.make_request(b"POST", self.url, request_data)
|
||||
|
|
|
@ -781,7 +781,7 @@ class HomeserverTestCase(TestCase):
|
|||
self,
|
||||
username: str,
|
||||
appservice_token: str,
|
||||
) -> Tuple[str, str]:
|
||||
) -> Tuple[str, Optional[str]]:
|
||||
"""Register an appservice user as an application service.
|
||||
Requires the client-facing registration API be registered.
|
||||
|
||||
|
@ -805,7 +805,7 @@ class HomeserverTestCase(TestCase):
|
|||
access_token=appservice_token,
|
||||
)
|
||||
self.assertEqual(channel.code, 200, channel.json_body)
|
||||
return channel.json_body["user_id"], channel.json_body["device_id"]
|
||||
return channel.json_body["user_id"], channel.json_body.get("device_id")
|
||||
|
||||
def login(
|
||||
self,
|
||||
|
|
Loading…
Reference in a new issue