Merge branch 'release-v1.66' into matrix-org-hotfixes

pull/13598/head
David Robertson 2022-08-23 10:21:42 +01:00
commit 04b00974e5
No known key found for this signature in database
GPG Key ID: 903ECE108A39DEDD
74 changed files with 366 additions and 257 deletions

View File

@ -1,3 +1,72 @@
Synapse 1.66.0rc1 (2022-08-23)
==============================
Features
--------
- Improve validation of request bodies for the following client-server API endpoints: [`/account/password`](https://spec.matrix.org/v1.3/client-server-api/#post_matrixclientv3accountpassword), [`/account/password/email/requestToken`](https://spec.matrix.org/v1.3/client-server-api/#post_matrixclientv3accountpasswordemailrequesttoken), [`/account/deactivate`](https://spec.matrix.org/v1.3/client-server-api/#post_matrixclientv3accountdeactivate) and [`/account/3pid/email/requestToken`](https://spec.matrix.org/v1.3/client-server-api/#post_matrixclientv3account3pidemailrequesttoken). ([\#13188](https://github.com/matrix-org/synapse/issues/13188), [\#13563](https://github.com/matrix-org/synapse/issues/13563))
- Add forgotten status to [Room Details Admin API](https://matrix-org.github.io/synapse/latest/admin_api/rooms.html#room-details-api). ([\#13503](https://github.com/matrix-org/synapse/issues/13503))
- Add an experimental implementation for [MSC3852 (Expose user agents on `Device`)](https://github.com/matrix-org/matrix-spec-proposals/pull/3852). ([\#13549](https://github.com/matrix-org/synapse/issues/13549))
- Add `org.matrix.msc2716v4` experimental room version with updated content fields. Part of [MSC2716 (Importing history)](https://github.com/matrix-org/matrix-spec-proposals/pull/2716). ([\#13551](https://github.com/matrix-org/synapse/issues/13551))
- Add support for compression to federation responses. ([\#13537](https://github.com/matrix-org/synapse/issues/13537))
- Improve performance of sending messages in rooms with thousands of local users. ([\#13522](https://github.com/matrix-org/synapse/issues/13522), [\#13547](https://github.com/matrix-org/synapse/issues/13547))
Bugfixes
--------
- Faster room joins: make `/joined_members` block whilst the room is partial stated. ([\#13514](https://github.com/matrix-org/synapse/issues/13514))
- Fix a bug introduced in Synapse 1.21 where the [`/event_reports` Admin API](https://matrix-org.github.io/synapse/develop/admin_api/event_reports.html) could return a total count which was larger than the number of results you can actually query for. ([\#13525](https://github.com/matrix-org/synapse/issues/13525))
- Fix a bug introduced in Synapse 1.52.0 where sending server notices fails if `max_avatar_size` or `allowed_avatar_mimetypes` is set and not `system_mxid_avatar_url`. ([\#13566](https://github.com/matrix-org/synapse/issues/13566))
- Fix a bug where the `opentracing.force_tracing_for_users` config option not applying to [`/sendToDevice`](https://spec.matrix.org/v1.3/client-server-api/#put_matrixclientv3sendtodeviceeventtypetxnid) and [`/keys/upload`](https://spec.matrix.org/v1.3/client-server-api/#post_matrixclientv3keysupload) requests. ([\#13574](https://github.com/matrix-org/synapse/issues/13574))
Improved Documentation
----------------------
- Add `openssl` example for generating registration HMAC digest. ([\#13472](https://github.com/matrix-org/synapse/issues/13472))
- Tidy up Synapse's README. ([\#13491](https://github.com/matrix-org/synapse/issues/13491))
- Document that event purging related to the `redaction_retention_period` config option is executed only every 5 minutes. ([\#13492](https://github.com/matrix-org/synapse/issues/13492))
- Add a warning to retention documentation regarding the possibility of database corruption. ([\#13497](https://github.com/matrix-org/synapse/issues/13497))
- Document that the `DOCKER_BUILDKIT=1` flag is needed to build the docker image. ([\#13515](https://github.com/matrix-org/synapse/issues/13515))
- Add missing links in `user_consent` section of configuration manual. ([\#13536](https://github.com/matrix-org/synapse/issues/13536))
- Fix the doc and some warnings that were referring to the nonexistent `custom_templates_directory` setting (instead of `custom_template_directory`). ([\#13538](https://github.com/matrix-org/synapse/issues/13538))
Internal Changes
----------------
### Faster room joins
- Faster room joins: update the rejected state of events during de-partial-stating. ([\#13459](https://github.com/matrix-org/synapse/issues/13459))
- Faster room joins: Avoid blocking lazy-loading `/sync`s during partial joins due to remote memberships. Pull remote memberships from auth events instead of the room state. ([\#13477](https://github.com/matrix-org/synapse/issues/13477))
- Faster room joins: Refuse to start when faster joins is enabled on a deployment with workers, since worker configurations are not currently supported. ([\#13531](https://github.com/matrix-org/synapse/issues/13531))
### Metrics and tracing
- Allow use of both `@trace` and `@tag_args` stacked on the same function. ([\#13453](https://github.com/matrix-org/synapse/issues/13453))
- Instrument the federation/backfill part of `/messages` for understandable traces in Jaeger. ([\#13489](https://github.com/matrix-org/synapse/issues/13489))
- Instrument `FederationStateIdsServlet` (`/state_ids`) for understandable traces in Jaeger. ([\#13499](https://github.com/matrix-org/synapse/issues/13499), [\#13554](https://github.com/matrix-org/synapse/issues/13554))
- Track HTTP response times over 10 seconds from `/messages` (`synapse_room_message_list_rest_servlet_response_time_seconds`). ([\#13533](https://github.com/matrix-org/synapse/issues/13533))
- Add metrics to track how the rate limiter is affecting requests (sleep/reject). ([\#13534](https://github.com/matrix-org/synapse/issues/13534), [\#13541](https://github.com/matrix-org/synapse/issues/13541))
- Add metrics to time how long it takes us to do backfill processing (`synapse_federation_backfill_processing_before_time_seconds`, `synapse_federation_backfill_processing_after_time_seconds`). ([\#13535](https://github.com/matrix-org/synapse/issues/13535), [\#13584](https://github.com/matrix-org/synapse/issues/13584))
- Add metrics to track rate limiter queue timing (`synapse_rate_limit_queue_wait_time_seconds`). ([\#13544](https://github.com/matrix-org/synapse/issues/13544))
- Update metrics to track `/messages` response time by room size. ([\#13545](https://github.com/matrix-org/synapse/issues/13545))
### Everything else
- Refactor methods in `synapse.api.auth.Auth` to use `Requester` objects everywhere instead of user IDs. ([\#13024](https://github.com/matrix-org/synapse/issues/13024))
- Clean-up tests for notifications. ([\#13471](https://github.com/matrix-org/synapse/issues/13471))
- Add some miscellaneous comments to document sync, especially around `compute_state_delta`. ([\#13474](https://github.com/matrix-org/synapse/issues/13474))
- Use literals in place of `HTTPStatus` constants in tests. ([\#13479](https://github.com/matrix-org/synapse/issues/13479), [\#13488](https://github.com/matrix-org/synapse/issues/13488))
- Add comments about how event push actions are rotated. ([\#13485](https://github.com/matrix-org/synapse/issues/13485))
- Modify HTML template content to better support mobile devices' screen sizes. ([\#13493](https://github.com/matrix-org/synapse/issues/13493))
- Add a linter script which will reject non-strict types in Pydantic models. ([\#13502](https://github.com/matrix-org/synapse/issues/13502))
- Reduce the number of tests using legacy TCP replication. ([\#13543](https://github.com/matrix-org/synapse/issues/13543))
- Allow specifying additional request fields when using the `HomeServerTestCase.login` helper method. ([\#13549](https://github.com/matrix-org/synapse/issues/13549))
- Make `HomeServerTestCase` load any configured homeserver modules automatically. ([\#13558](https://github.com/matrix-org/synapse/issues/13558))
Synapse 1.65.0 (2022-08-16) Synapse 1.65.0 (2022-08-16)
=========================== ===========================

View File

@ -1 +0,0 @@
Improve validation of request bodies for the following client-server API endpoints: [`/account/password`](https://spec.matrix.org/v1.3/client-server-api/#post_matrixclientv3accountpassword), [`/account/password/email/requestToken`](https://spec.matrix.org/v1.3/client-server-api/#post_matrixclientv3accountpasswordemailrequesttoken), [`/account/deactivate`](https://spec.matrix.org/v1.3/client-server-api/#post_matrixclientv3accountdeactivate) and [`/account/3pid/email/requestToken`](https://spec.matrix.org/v1.3/client-server-api/#post_matrixclientv3account3pidemailrequesttoken).

View File

@ -1 +0,0 @@
Allow use of both `@trace` and `@tag_args` stacked on the same function (tracing).

View File

@ -1 +0,0 @@
Faster joins: update the rejected state of events during de-partial-stating.

View File

@ -1 +0,0 @@
Clean-up tests for notifications.

View File

@ -1 +0,0 @@
Add `openssl` example for generating registration HMAC digest.

View File

@ -1 +0,0 @@
Add some miscellaneous comments to document sync, especially around `compute_state_delta`.

View File

@ -1 +0,0 @@
Faster room joins: Avoid blocking lazy-loading `/sync`s during partial joins due to remote memberships. Pull remote memberships from auth events instead of the room state.

View File

@ -1 +0,0 @@
Use literals in place of `HTTPStatus` constants in tests.

View File

@ -1 +0,0 @@
Add comments about how event push actions are rotated.

View File

@ -1 +0,0 @@
Use literals in place of `HTTPStatus` constants in tests.

View File

@ -1 +0,0 @@
Instrument the federation/backfill part of `/messages` for understandable traces in Jaeger.

View File

@ -1 +0,0 @@
Tidy up Synapse's README.

View File

@ -1 +0,0 @@
Document that event purging related to the `redaction_retention_period` config option is executed only every 5 minutes.

View File

@ -1 +0,0 @@
Modify HTML template content to better support mobile devices' screen sizes.

View File

@ -1,2 +0,0 @@
Add a warning to retention documentation regarding the possibility of database corruption.

View File

@ -1 +0,0 @@
Instrument `FederationStateIdsServlet` (`/state_ids`) for understandable traces in Jaeger.

View File

@ -1 +0,0 @@
Add a linter script which will reject non-strict types in Pydantic models.

View File

@ -1 +0,0 @@
Add forgotten status to Room Details API.

View File

@ -1 +0,0 @@
Faster room joins: make `/joined_members` block whilst the room is partial stated.

View File

@ -1 +0,0 @@
Document that the `DOCKER_BUILDKIT=1` flag is needed to build the docker image.

View File

@ -1 +0,0 @@
Improve performance of sending messages in rooms with thousands of local users.

View File

@ -1 +0,0 @@
Fix a bug in the `/event_reports` Admin API which meant that the total count could be larger than the number of results you can actually query for.

View File

@ -1 +0,0 @@
Faster room joins: Refuse to start when faster joins is enabled on a deployment with workers, since worker configurations are not currently supported.

View File

@ -1 +0,0 @@
Track HTTP response times over 10 seconds from `/messages` (`synapse_room_message_list_rest_servlet_response_time_seconds`).

View File

@ -1 +0,0 @@
Add metrics to track how the rate limiter is affecting requests (sleep/reject).

View File

@ -1 +0,0 @@
Add metrics to time how long it takes us to do backfill processing (`synapse_federation_backfill_processing_before_time_seconds`, `synapse_federation_backfill_processing_after_time_seconds`).

View File

@ -1 +0,0 @@
Add missing links in `user_consent` section of configuration manual.

View File

@ -1 +0,0 @@
Add support for compression to federation responses.

View File

@ -1 +0,0 @@
Fix the doc and some warnings that were referring to the nonexistent `custom_templates_directory` setting (instead of `custom_template_directory`).

View File

@ -1 +0,0 @@
Add metrics to track how the rate limiter is affecting requests (sleep/reject).

View File

@ -1 +0,0 @@
Reduce the number of tests using legacy TCP replication.

View File

@ -1 +0,0 @@
Add metrics to track rate limiter queue timing (`synapse_rate_limit_queue_wait_time_seconds`).

View File

@ -1 +0,0 @@
Update metrics to track `/messages` response time by room size.

View File

@ -1 +0,0 @@
Improve performance of sending messages in rooms with thousands of local users.

View File

@ -1 +0,0 @@
Add an experimental implementation for [MSC3852](https://github.com/matrix-org/matrix-spec-proposals/pull/3852).

View File

@ -1 +0,0 @@
Allow specifying additional request fields when using the `HomeServerTestCase.login` helper method.

View File

@ -1 +0,0 @@
Add `org.matrix.msc2716v4` experimental room version with updated content fields.

View File

@ -1 +0,0 @@
Instrument `FederationStateIdsServlet` (`/state_ids`) for understandable traces in Jaeger.

View File

@ -1 +0,0 @@
Make `HomeServerTestCase` load any configured homeserver modules automatically.

View File

@ -1 +0,0 @@
Improve validation of request bodies for the following client-server API endpoints: [`/account/password`](https://spec.matrix.org/v1.3/client-server-api/#post_matrixclientv3accountpassword), [`/account/password/email/requestToken`](https://spec.matrix.org/v1.3/client-server-api/#post_matrixclientv3accountpasswordemailrequesttoken), [`/account/deactivate`](https://spec.matrix.org/v1.3/client-server-api/#post_matrixclientv3accountdeactivate) and [`/account/3pid/email/requestToken`](https://spec.matrix.org/v1.3/client-server-api/#post_matrixclientv3account3pidemailrequesttoken).

View File

@ -1 +0,0 @@
Fix the `opentracing.force_tracing_for_users` config option not applying to [`/sendToDevice`](https://spec.matrix.org/v1.3/client-server-api/#put_matrixclientv3sendtodeviceeventtypetxnid) and [`/keys/upload`](https://spec.matrix.org/v1.3/client-server-api/#post_matrixclientv3keysupload) requests.

6
debian/changelog vendored
View File

@ -1,3 +1,9 @@
matrix-synapse-py3 (1.66.0~rc1) stable; urgency=medium
* New Synapse release 1.66.0rc1.
-- Synapse Packaging team <packages@matrix.org> Tue, 23 Aug 2022 09:48:55 +0100
matrix-synapse-py3 (1.65.0) stable; urgency=medium matrix-synapse-py3 (1.65.0) stable; urgency=medium
* New Synapse release 1.65.0. * New Synapse release 1.65.0.

View File

@ -337,6 +337,8 @@ A response body like the following is returned:
} }
``` ```
_Changed in Synapse 1.66:_ Added the `forgotten` key to the response body.
# Room Members API # Room Members API
The Room Members admin API allows server admins to get a list of all members of a room. The Room Members admin API allows server admins to get a list of all members of a room.

View File

@ -54,7 +54,7 @@ skip_gitignore = true
[tool.poetry] [tool.poetry]
name = "matrix-synapse" name = "matrix-synapse"
version = "1.65.0" version = "1.66.0rc1"
description = "Homeserver for the Matrix decentralised comms protocol" description = "Homeserver for the Matrix decentralised comms protocol"
authors = ["Matrix.org Team and Contributors <packages@matrix.org>"] authors = ["Matrix.org Team and Contributors <packages@matrix.org>"]
license = "Apache-2.0" license = "Apache-2.0"

View File

@ -37,8 +37,7 @@ from synapse.logging.opentracing import (
start_active_span, start_active_span,
trace, trace,
) )
from synapse.storage.databases.main.registration import TokenLookupResult from synapse.types import Requester, create_requester
from synapse.types import Requester, UserID, create_requester
if TYPE_CHECKING: if TYPE_CHECKING:
from synapse.server import HomeServer from synapse.server import HomeServer
@ -70,14 +69,14 @@ class Auth:
async def check_user_in_room( async def check_user_in_room(
self, self,
room_id: str, room_id: str,
user_id: str, requester: Requester,
allow_departed_users: bool = False, allow_departed_users: bool = False,
) -> Tuple[str, Optional[str]]: ) -> Tuple[str, Optional[str]]:
"""Check if the user is in the room, or was at some point. """Check if the user is in the room, or was at some point.
Args: Args:
room_id: The room to check. room_id: The room to check.
user_id: The user to check. requester: The user making the request, according to the access token.
current_state: Optional map of the current state of the room. current_state: Optional map of the current state of the room.
If provided then that map is used to check whether they are a If provided then that map is used to check whether they are a
@ -94,6 +93,7 @@ class Auth:
membership event ID of the user. membership event ID of the user.
""" """
user_id = requester.user.to_string()
( (
membership, membership,
member_event_id, member_event_id,
@ -182,96 +182,69 @@ class Auth:
access_token = self.get_access_token_from_request(request) access_token = self.get_access_token_from_request(request)
( # First check if it could be a request from an appservice
user_id, requester = await self._get_appservice_user(request)
device_id, if not requester:
app_service, # If not, it should be from a regular user
) = await self._get_appservice_user_id_and_device_id(request) requester = await self.get_user_by_access_token(
if user_id and app_service: access_token, allow_expired=allow_expired
if ip_addr and self._track_appservice_user_ips:
await self.store.insert_client_ip(
user_id=user_id,
access_token=access_token,
ip=ip_addr,
user_agent=user_agent,
device_id="dummy-device"
if device_id is None
else device_id, # stubbed
)
requester = create_requester(
user_id, app_service=app_service, device_id=device_id
) )
request.requester = user_id # Deny the request if the user account has expired.
return requester # This check is only done for regular users, not appservice ones.
if not allow_expired:
if await self._account_validity_handler.is_user_expired(
requester.user.to_string()
):
# Raise the error if either an account validity module has determined
# the account has expired, or the legacy account validity
# implementation is enabled and determined the account has expired
raise AuthError(
403,
"User account has expired",
errcode=Codes.EXPIRED_ACCOUNT,
)
user_info = await self.get_user_by_access_token( if ip_addr and (
access_token, allow_expired=allow_expired not requester.app_service or self._track_appservice_user_ips
) ):
token_id = user_info.token_id # XXX(quenting): I'm 95% confident that we could skip setting the
is_guest = user_info.is_guest # device_id to "dummy-device" for appservices, and that the only impact
shadow_banned = user_info.shadow_banned # would be some rows which whould not deduplicate in the 'user_ips'
# table during the transition
# Deny the request if the user account has expired. recorded_device_id = (
if not allow_expired: "dummy-device"
if await self._account_validity_handler.is_user_expired( if requester.device_id is None and requester.app_service is not None
user_info.user_id else requester.device_id
): )
# Raise the error if either an account validity module has determined
# the account has expired, or the legacy account validity
# implementation is enabled and determined the account has expired
raise AuthError(
403,
"User account has expired",
errcode=Codes.EXPIRED_ACCOUNT,
)
device_id = user_info.device_id
if access_token and ip_addr:
await self.store.insert_client_ip( await self.store.insert_client_ip(
user_id=user_info.token_owner, user_id=requester.authenticated_entity,
access_token=access_token, access_token=access_token,
ip=ip_addr, ip=ip_addr,
user_agent=user_agent, user_agent=user_agent,
device_id=device_id, device_id=recorded_device_id,
) )
# Track also the puppeted user client IP if enabled and the user is puppeting # Track also the puppeted user client IP if enabled and the user is puppeting
if ( if (
user_info.user_id != user_info.token_owner requester.user.to_string() != requester.authenticated_entity
and self._track_puppeted_user_ips and self._track_puppeted_user_ips
): ):
await self.store.insert_client_ip( await self.store.insert_client_ip(
user_id=user_info.user_id, user_id=requester.user.to_string(),
access_token=access_token, access_token=access_token,
ip=ip_addr, ip=ip_addr,
user_agent=user_agent, user_agent=user_agent,
device_id=device_id, device_id=requester.device_id,
) )
if is_guest and not allow_guest: if requester.is_guest and not allow_guest:
raise AuthError( raise AuthError(
403, 403,
"Guest access not allowed", "Guest access not allowed",
errcode=Codes.GUEST_ACCESS_FORBIDDEN, errcode=Codes.GUEST_ACCESS_FORBIDDEN,
) )
# Mark the token as used. This is used to invalidate old refresh
# tokens after some time.
if not user_info.token_used and token_id is not None:
await self.store.mark_access_token_as_used(token_id)
requester = create_requester(
user_info.user_id,
token_id,
is_guest,
shadow_banned,
device_id,
app_service=app_service,
authenticated_entity=user_info.token_owner,
)
request.requester = requester request.requester = requester
return requester return requester
except KeyError: except KeyError:
@ -308,9 +281,7 @@ class Auth:
403, "Application service has not registered this user (%s)" % user_id 403, "Application service has not registered this user (%s)" % user_id
) )
async def _get_appservice_user_id_and_device_id( async def _get_appservice_user(self, request: Request) -> Optional[Requester]:
self, request: Request
) -> Tuple[Optional[str], Optional[str], Optional[ApplicationService]]:
""" """
Given a request, reads the request parameters to determine: Given a request, reads the request parameters to determine:
- whether it's an application service that's making this request - whether it's an application service that's making this request
@ -325,15 +296,13 @@ class Auth:
Must use `org.matrix.msc3202.device_id` in place of `device_id` for now. Must use `org.matrix.msc3202.device_id` in place of `device_id` for now.
Returns: Returns:
3-tuple of the application service `Requester` of that request
(user ID?, device ID?, application service?)
Postconditions: Postconditions:
- If an application service is returned, so is a user ID - The `app_service` field in the returned `Requester` is set
- A user ID is never returned without an application service - The `user_id` field in the returned `Requester` is either the application
- A device ID is never returned without a user ID or an application service service sender or the controlled user set by the `user_id` URI parameter
- The returned application service, if present, is permitted to control the - The returned application service is permitted to control the returned user ID.
returned user ID.
- The returned device ID, if present, has been checked to be a valid device ID - The returned device ID, if present, has been checked to be a valid device ID
for the returned user ID. for the returned user ID.
""" """
@ -343,12 +312,12 @@ class Auth:
self.get_access_token_from_request(request) self.get_access_token_from_request(request)
) )
if app_service is None: if app_service is None:
return None, None, None return None
if app_service.ip_range_whitelist: if app_service.ip_range_whitelist:
ip_address = IPAddress(request.getClientAddress().host) ip_address = IPAddress(request.getClientAddress().host)
if ip_address not in app_service.ip_range_whitelist: if ip_address not in app_service.ip_range_whitelist:
return None, None, None return None
# This will always be set by the time Twisted calls us. # This will always be set by the time Twisted calls us.
assert request.args is not None assert request.args is not None
@ -382,13 +351,15 @@ class Auth:
Codes.EXCLUSIVE, Codes.EXCLUSIVE,
) )
return effective_user_id, effective_device_id, app_service return create_requester(
effective_user_id, app_service=app_service, device_id=effective_device_id
)
async def get_user_by_access_token( async def get_user_by_access_token(
self, self,
token: str, token: str,
allow_expired: bool = False, allow_expired: bool = False,
) -> TokenLookupResult: ) -> Requester:
"""Validate access token and get user_id from it """Validate access token and get user_id from it
Args: Args:
@ -405,9 +376,9 @@ class Auth:
# First look in the database to see if the access token is present # First look in the database to see if the access token is present
# as an opaque token. # as an opaque token.
r = await self.store.get_user_by_access_token(token) user_info = await self.store.get_user_by_access_token(token)
if r: if user_info:
valid_until_ms = r.valid_until_ms valid_until_ms = user_info.valid_until_ms
if ( if (
not allow_expired not allow_expired
and valid_until_ms is not None and valid_until_ms is not None
@ -419,7 +390,20 @@ class Auth:
msg="Access token has expired", soft_logout=True msg="Access token has expired", soft_logout=True
) )
return r # Mark the token as used. This is used to invalidate old refresh
# tokens after some time.
await self.store.mark_access_token_as_used(user_info.token_id)
requester = create_requester(
user_id=user_info.user_id,
access_token_id=user_info.token_id,
is_guest=user_info.is_guest,
shadow_banned=user_info.shadow_banned,
device_id=user_info.device_id,
authenticated_entity=user_info.token_owner,
)
return requester
# If the token isn't found in the database, then it could still be a # If the token isn't found in the database, then it could still be a
# macaroon for a guest, so we check that here. # macaroon for a guest, so we check that here.
@ -445,11 +429,12 @@ class Auth:
"Guest access token used for regular user" "Guest access token used for regular user"
) )
return TokenLookupResult( return create_requester(
user_id=user_id, user_id=user_id,
is_guest=True, is_guest=True,
# all guests get the same device id # all guests get the same device id
device_id=GUEST_DEVICE_ID, device_id=GUEST_DEVICE_ID,
authenticated_entity=user_id,
) )
except ( except (
pymacaroons.exceptions.MacaroonException, pymacaroons.exceptions.MacaroonException,
@ -472,32 +457,33 @@ class Auth:
request.requester = create_requester(service.sender, app_service=service) request.requester = create_requester(service.sender, app_service=service)
return service return service
async def is_server_admin(self, user: UserID) -> bool: async def is_server_admin(self, requester: Requester) -> bool:
"""Check if the given user is a local server admin. """Check if the given user is a local server admin.
Args: Args:
user: user to check requester: The user making the request, according to the access token.
Returns: Returns:
True if the user is an admin True if the user is an admin
""" """
return await self.store.is_server_admin(user) return await self.store.is_server_admin(requester.user)
async def check_can_change_room_list(self, room_id: str, user: UserID) -> bool: async def check_can_change_room_list(
self, room_id: str, requester: Requester
) -> bool:
"""Determine whether the user is allowed to edit the room's entry in the """Determine whether the user is allowed to edit the room's entry in the
published room list. published room list.
Args: Args:
room_id room_id: The room to check.
user requester: The user making the request, according to the access token.
""" """
is_admin = await self.is_server_admin(user) is_admin = await self.is_server_admin(requester)
if is_admin: if is_admin:
return True return True
user_id = user.to_string() await self.check_user_in_room(room_id, requester)
await self.check_user_in_room(room_id, user_id)
# We currently require the user is a "moderator" in the room. We do this # We currently require the user is a "moderator" in the room. We do this
# by checking if they would (theoretically) be able to change the # by checking if they would (theoretically) be able to change the
@ -516,7 +502,9 @@ class Auth:
send_level = event_auth.get_send_level( send_level = event_auth.get_send_level(
EventTypes.CanonicalAlias, "", power_level_event EventTypes.CanonicalAlias, "", power_level_event
) )
user_level = event_auth.get_user_power_level(user_id, auth_events) user_level = event_auth.get_user_power_level(
requester.user.to_string(), auth_events
)
return user_level >= send_level return user_level >= send_level
@ -574,16 +562,16 @@ class Auth:
@trace @trace
async def check_user_in_room_or_world_readable( async def check_user_in_room_or_world_readable(
self, room_id: str, user_id: str, allow_departed_users: bool = False self, room_id: str, requester: Requester, allow_departed_users: bool = False
) -> Tuple[str, Optional[str]]: ) -> Tuple[str, Optional[str]]:
"""Checks that the user is or was in the room or the room is world """Checks that the user is or was in the room or the room is world
readable. If it isn't then an exception is raised. readable. If it isn't then an exception is raised.
Args: Args:
room_id: room to check room_id: The room to check.
user_id: user to check requester: The user making the request, according to the access token.
allow_departed_users: if True, accept users that were previously allow_departed_users: If True, accept users that were previously
members but have now departed members but have now departed.
Returns: Returns:
Resolves to the current membership of the user in the room and the Resolves to the current membership of the user in the room and the
@ -598,7 +586,7 @@ class Auth:
# * The user is a guest user, and has joined the room # * The user is a guest user, and has joined the room
# else it will throw. # else it will throw.
return await self.check_user_in_room( return await self.check_user_in_room(
room_id, user_id, allow_departed_users=allow_departed_users room_id, requester, allow_departed_users=allow_departed_users
) )
except AuthError: except AuthError:
visibility = await self._storage_controllers.state.get_current_state_event( visibility = await self._storage_controllers.state.get_current_state_event(
@ -613,6 +601,6 @@ class Auth:
raise UnstableSpecAuthError( raise UnstableSpecAuthError(
403, 403,
"User %s not in room %s, and room previews are disabled" "User %s not in room %s, and room previews are disabled"
% (user_id, room_id), % (requester.user, room_id),
errcode=Codes.NOT_JOINED, errcode=Codes.NOT_JOINED,
) )

View File

@ -280,7 +280,7 @@ class AuthHandler:
that it isn't stolen by re-authenticating them. that it isn't stolen by re-authenticating them.
Args: Args:
requester: The user, as given by the access token requester: The user making the request, according to the access token.
request: The request sent by the client. request: The request sent by the client.
@ -1435,20 +1435,25 @@ class AuthHandler:
access_token: access token to be deleted access_token: access token to be deleted
""" """
user_info = await self.auth.get_user_by_access_token(access_token) token = await self.store.get_user_by_access_token(access_token)
if not token:
# At this point, the token should already have been fetched once by
# the caller, so this should not happen, unless of a race condition
# between two delete requests
raise SynapseError(HTTPStatus.UNAUTHORIZED, "Unrecognised access token")
await self.store.delete_access_token(access_token) await self.store.delete_access_token(access_token)
# see if any modules want to know about this # see if any modules want to know about this
await self.password_auth_provider.on_logged_out( await self.password_auth_provider.on_logged_out(
user_id=user_info.user_id, user_id=token.user_id,
device_id=user_info.device_id, device_id=token.device_id,
access_token=access_token, access_token=access_token,
) )
# delete pushers associated with this access token # delete pushers associated with this access token
if user_info.token_id is not None: if token.token_id is not None:
await self.hs.get_pusherpool().remove_pushers_by_access_token( await self.hs.get_pusherpool().remove_pushers_by_access_token(
user_info.user_id, (user_info.token_id,) token.user_id, (token.token_id,)
) )
async def delete_access_tokens_for_user( async def delete_access_tokens_for_user(

View File

@ -30,7 +30,7 @@ from synapse.api.errors import (
from synapse.appservice import ApplicationService from synapse.appservice import ApplicationService
from synapse.module_api import NOT_SPAM from synapse.module_api import NOT_SPAM
from synapse.storage.databases.main.directory import RoomAliasMapping from synapse.storage.databases.main.directory import RoomAliasMapping
from synapse.types import JsonDict, Requester, RoomAlias, UserID, get_domain_from_id from synapse.types import JsonDict, Requester, RoomAlias, get_domain_from_id
if TYPE_CHECKING: if TYPE_CHECKING:
from synapse.server import HomeServer from synapse.server import HomeServer
@ -133,7 +133,7 @@ class DirectoryHandler:
else: else:
# Server admins are not subject to the same constraints as normal # Server admins are not subject to the same constraints as normal
# users when creating an alias (e.g. being in the room). # users when creating an alias (e.g. being in the room).
is_admin = await self.auth.is_server_admin(requester.user) is_admin = await self.auth.is_server_admin(requester)
if (self.require_membership and check_membership) and not is_admin: if (self.require_membership and check_membership) and not is_admin:
rooms_for_user = await self.store.get_rooms_for_user(user_id) rooms_for_user = await self.store.get_rooms_for_user(user_id)
@ -197,7 +197,7 @@ class DirectoryHandler:
user_id = requester.user.to_string() user_id = requester.user.to_string()
try: try:
can_delete = await self._user_can_delete_alias(room_alias, user_id) can_delete = await self._user_can_delete_alias(room_alias, requester)
except StoreError as e: except StoreError as e:
if e.code == 404: if e.code == 404:
raise NotFoundError("Unknown room alias") raise NotFoundError("Unknown room alias")
@ -400,7 +400,9 @@ class DirectoryHandler:
# either no interested services, or no service with an exclusive lock # either no interested services, or no service with an exclusive lock
return True return True
async def _user_can_delete_alias(self, alias: RoomAlias, user_id: str) -> bool: async def _user_can_delete_alias(
self, alias: RoomAlias, requester: Requester
) -> bool:
"""Determine whether a user can delete an alias. """Determine whether a user can delete an alias.
One of the following must be true: One of the following must be true:
@ -413,7 +415,7 @@ class DirectoryHandler:
""" """
creator = await self.store.get_room_alias_creator(alias.to_string()) creator = await self.store.get_room_alias_creator(alias.to_string())
if creator == user_id: if creator == requester.user.to_string():
return True return True
# Resolve the alias to the corresponding room. # Resolve the alias to the corresponding room.
@ -422,9 +424,7 @@ class DirectoryHandler:
if not room_id: if not room_id:
return False return False
return await self.auth.check_can_change_room_list( return await self.auth.check_can_change_room_list(room_id, requester)
room_id, UserID.from_string(user_id)
)
async def edit_published_room_list( async def edit_published_room_list(
self, requester: Requester, room_id: str, visibility: str self, requester: Requester, room_id: str, visibility: str
@ -463,7 +463,7 @@ class DirectoryHandler:
raise SynapseError(400, "Unknown room") raise SynapseError(400, "Unknown room")
can_change_room_list = await self.auth.check_can_change_room_list( can_change_room_list = await self.auth.check_can_change_room_list(
room_id, requester.user room_id, requester
) )
if not can_change_room_list: if not can_change_room_list:
raise AuthError( raise AuthError(
@ -528,10 +528,8 @@ class DirectoryHandler:
Get a list of the aliases that currently point to this room on this server Get a list of the aliases that currently point to this room on this server
""" """
# allow access to server admins and current members of the room # allow access to server admins and current members of the room
is_admin = await self.auth.is_server_admin(requester.user) is_admin = await self.auth.is_server_admin(requester)
if not is_admin: if not is_admin:
await self.auth.check_user_in_room_or_world_readable( await self.auth.check_user_in_room_or_world_readable(room_id, requester)
room_id, requester.user.to_string()
)
return await self.store.get_aliases_for_room(room_id) return await self.store.get_aliases_for_room(room_id)

View File

@ -86,9 +86,14 @@ backfill_processing_before_timer = Histogram(
"sec", "sec",
[], [],
buckets=( buckets=(
0.1,
0.5,
1.0, 1.0,
2.5,
5.0, 5.0,
7.5,
10.0, 10.0,
15.0,
20.0, 20.0,
30.0, 30.0,
40.0, 40.0,
@ -482,7 +487,7 @@ class FederationHandler:
processing_end_time = self.clock.time_msec() processing_end_time = self.clock.time_msec()
backfill_processing_before_timer.observe( backfill_processing_before_timer.observe(
(processing_start_time - processing_end_time) / 1000 (processing_end_time - processing_start_time) / 1000
) )
success = await try_backfill(likely_domains) success = await try_backfill(likely_domains)

View File

@ -104,15 +104,25 @@ backfill_processing_after_timer = Histogram(
"sec", "sec",
[], [],
buckets=( buckets=(
0.1,
0.25,
0.5,
1.0, 1.0,
2.5,
5.0, 5.0,
7.5,
10.0, 10.0,
15.0,
20.0, 20.0,
25.0,
30.0, 30.0,
40.0, 40.0,
50.0,
60.0, 60.0,
80.0, 80.0,
100.0,
120.0, 120.0,
150.0,
180.0, 180.0,
"+Inf", "+Inf",
), ),

View File

@ -309,18 +309,18 @@ class InitialSyncHandler:
if blocked: if blocked:
raise SynapseError(403, "This room has been blocked on this server") raise SynapseError(403, "This room has been blocked on this server")
user_id = requester.user.to_string()
( (
membership, membership,
member_event_id, member_event_id,
) = await self.auth.check_user_in_room_or_world_readable( ) = await self.auth.check_user_in_room_or_world_readable(
room_id, room_id,
user_id, requester,
allow_departed_users=True, allow_departed_users=True,
) )
is_peeking = member_event_id is None is_peeking = member_event_id is None
user_id = requester.user.to_string()
if membership == Membership.JOIN: if membership == Membership.JOIN:
result = await self._room_initial_sync_joined( result = await self._room_initial_sync_joined(
user_id, room_id, pagin_config, membership, is_peeking user_id, room_id, pagin_config, membership, is_peeking

View File

@ -104,7 +104,7 @@ class MessageHandler:
async def get_room_data( async def get_room_data(
self, self,
user_id: str, requester: Requester,
room_id: str, room_id: str,
event_type: str, event_type: str,
state_key: str, state_key: str,
@ -112,7 +112,7 @@ class MessageHandler:
"""Get data from a room. """Get data from a room.
Args: Args:
user_id requester: The user who did the request.
room_id room_id
event_type event_type
state_key state_key
@ -125,7 +125,7 @@ class MessageHandler:
membership, membership,
membership_event_id, membership_event_id,
) = await self.auth.check_user_in_room_or_world_readable( ) = await self.auth.check_user_in_room_or_world_readable(
room_id, user_id, allow_departed_users=True room_id, requester, allow_departed_users=True
) )
if membership == Membership.JOIN: if membership == Membership.JOIN:
@ -161,11 +161,10 @@ class MessageHandler:
async def get_state_events( async def get_state_events(
self, self,
user_id: str, requester: Requester,
room_id: str, room_id: str,
state_filter: Optional[StateFilter] = None, state_filter: Optional[StateFilter] = None,
at_token: Optional[StreamToken] = None, at_token: Optional[StreamToken] = None,
is_guest: bool = False,
) -> List[dict]: ) -> List[dict]:
"""Retrieve all state events for a given room. If the user is """Retrieve all state events for a given room. If the user is
joined to the room then return the current state. If the user has joined to the room then return the current state. If the user has
@ -174,14 +173,13 @@ class MessageHandler:
visible. visible.
Args: Args:
user_id: The user requesting state events. requester: The user requesting state events.
room_id: The room ID to get all state events from. room_id: The room ID to get all state events from.
state_filter: The state filter used to fetch state from the database. state_filter: The state filter used to fetch state from the database.
at_token: the stream token of the at which we are requesting at_token: the stream token of the at which we are requesting
the stats. If the user is not allowed to view the state as of that the stats. If the user is not allowed to view the state as of that
stream token, we raise a 403 SynapseError. If None, returns the current stream token, we raise a 403 SynapseError. If None, returns the current
state based on the current_state_events table. state based on the current_state_events table.
is_guest: whether this user is a guest
Returns: Returns:
A list of dicts representing state events. [{}, {}, {}] A list of dicts representing state events. [{}, {}, {}]
Raises: Raises:
@ -191,6 +189,7 @@ class MessageHandler:
members of this room. members of this room.
""" """
state_filter = state_filter or StateFilter.all() state_filter = state_filter or StateFilter.all()
user_id = requester.user.to_string()
if at_token: if at_token:
last_event_id = ( last_event_id = (
@ -223,7 +222,7 @@ class MessageHandler:
membership, membership,
membership_event_id, membership_event_id,
) = await self.auth.check_user_in_room_or_world_readable( ) = await self.auth.check_user_in_room_or_world_readable(
room_id, user_id, allow_departed_users=True room_id, requester, allow_departed_users=True
) )
if membership == Membership.JOIN: if membership == Membership.JOIN:
@ -317,12 +316,11 @@ class MessageHandler:
Returns: Returns:
A dict of user_id to profile info A dict of user_id to profile info
""" """
user_id = requester.user.to_string()
if not requester.app_service: if not requester.app_service:
# We check AS auth after fetching the room membership, as it # We check AS auth after fetching the room membership, as it
# requires us to pull out all joined members anyway. # requires us to pull out all joined members anyway.
membership, _ = await self.auth.check_user_in_room_or_world_readable( membership, _ = await self.auth.check_user_in_room_or_world_readable(
room_id, user_id, allow_departed_users=True room_id, requester, allow_departed_users=True
) )
if membership != Membership.JOIN: if membership != Membership.JOIN:
raise SynapseError( raise SynapseError(
@ -340,8 +338,13 @@ class MessageHandler:
# If this is an AS, double check that they are allowed to see the members. # If this is an AS, double check that they are allowed to see the members.
# This can either be because the AS user is in the room or because there # This can either be because the AS user is in the room or because there
# is a user in the room that the AS is "interested in" # is a user in the room that the AS is "interested in"
if False and requester.app_service and user_id not in users_with_profile: # type: ignore[unreachable] if (
for uid in users_with_profile: # type: ignore[unreachable] False # See https://github.com/matrix-org/matrix-appservice-irc/issues/506
# and https://github.com/matrix-org/synapse/issues/4826#issuecomment-1028105662
and requester.app_service
and requester.user.to_string() not in users_with_profile
):
for uid in users_with_profile:
if requester.app_service.is_interested_in_user(uid): if requester.app_service.is_interested_in_user(uid):
break break
else: else:

View File

@ -464,7 +464,7 @@ class PaginationHandler:
membership, membership,
member_event_id, member_event_id,
) = await self.auth.check_user_in_room_or_world_readable( ) = await self.auth.check_user_in_room_or_world_readable(
room_id, user_id, allow_departed_users=True room_id, requester, allow_departed_users=True
) )
if pagin_config.direction == "b": if pagin_config.direction == "b":

View File

@ -29,7 +29,13 @@ from synapse.api.constants import (
JoinRules, JoinRules,
LoginType, LoginType,
) )
from synapse.api.errors import AuthError, Codes, ConsentNotGivenError, SynapseError from synapse.api.errors import (
AuthError,
Codes,
ConsentNotGivenError,
InvalidClientTokenError,
SynapseError,
)
from synapse.appservice import ApplicationService from synapse.appservice import ApplicationService
from synapse.config.server import is_threepid_reserved from synapse.config.server import is_threepid_reserved
from synapse.http.servlet import assert_params_in_dict from synapse.http.servlet import assert_params_in_dict
@ -180,10 +186,7 @@ class RegistrationHandler:
) )
if guest_access_token: if guest_access_token:
user_data = await self.auth.get_user_by_access_token(guest_access_token) user_data = await self.auth.get_user_by_access_token(guest_access_token)
if ( if not user_data.is_guest or user_data.user.localpart != localpart:
not user_data.is_guest
or UserID.from_string(user_data.user_id).localpart != localpart
):
raise AuthError( raise AuthError(
403, 403,
"Cannot register taken user ID without valid guest " "Cannot register taken user ID without valid guest "
@ -618,7 +621,7 @@ class RegistrationHandler:
user_id = user.to_string() user_id = user.to_string()
service = self.store.get_app_service_by_token(as_token) service = self.store.get_app_service_by_token(as_token)
if not service: if not service:
raise AuthError(403, "Invalid application service token.") raise InvalidClientTokenError()
if not service.is_interested_in_user(user_id): if not service.is_interested_in_user(user_id):
raise SynapseError( raise SynapseError(
400, 400,

View File

@ -103,7 +103,7 @@ class RelationsHandler:
# TODO Properly handle a user leaving a room. # TODO Properly handle a user leaving a room.
(_, member_event_id) = await self._auth.check_user_in_room_or_world_readable( (_, member_event_id) = await self._auth.check_user_in_room_or_world_readable(
room_id, user_id, allow_departed_users=True room_id, requester, allow_departed_users=True
) )
# This gets the original event and checks that a) the event exists and # This gets the original event and checks that a) the event exists and

View File

@ -721,7 +721,7 @@ class RoomCreationHandler:
# allow the server notices mxid to create rooms # allow the server notices mxid to create rooms
is_requester_admin = True is_requester_admin = True
else: else:
is_requester_admin = await self.auth.is_server_admin(requester.user) is_requester_admin = await self.auth.is_server_admin(requester)
# Let the third party rules modify the room creation config if needed, or abort # Let the third party rules modify the room creation config if needed, or abort
# the room creation entirely with an exception. # the room creation entirely with an exception.
@ -1279,7 +1279,7 @@ class RoomContextHandler:
""" """
user = requester.user user = requester.user
if use_admin_priviledge: if use_admin_priviledge:
await assert_user_is_admin(self.auth, requester.user) await assert_user_is_admin(self.auth, requester)
before_limit = math.floor(limit / 2.0) before_limit = math.floor(limit / 2.0)
after_limit = limit - before_limit after_limit = limit - before_limit

View File

@ -179,7 +179,7 @@ class RoomMemberHandler(metaclass=abc.ABCMeta):
"""Try and join a room that this server is not in """Try and join a room that this server is not in
Args: Args:
requester requester: The user making the request, according to the access token.
remote_room_hosts: List of servers that can be used to join via. remote_room_hosts: List of servers that can be used to join via.
room_id: Room that we are trying to join room_id: Room that we are trying to join
user: User who is trying to join user: User who is trying to join
@ -703,7 +703,7 @@ class RoomMemberHandler(metaclass=abc.ABCMeta):
errcode=Codes.BAD_JSON, errcode=Codes.BAD_JSON,
) )
if "avatar_url" in content: if "avatar_url" in content and content.get("avatar_url") is not None:
if not await self.profile_handler.check_avatar_size_and_mime_type( if not await self.profile_handler.check_avatar_size_and_mime_type(
content["avatar_url"], content["avatar_url"],
): ):
@ -758,7 +758,7 @@ class RoomMemberHandler(metaclass=abc.ABCMeta):
is_requester_admin = True is_requester_admin = True
else: else:
is_requester_admin = await self.auth.is_server_admin(requester.user) is_requester_admin = await self.auth.is_server_admin(requester)
if not is_requester_admin: if not is_requester_admin:
if self.config.server.block_non_admin_invites: if self.config.server.block_non_admin_invites:
@ -882,7 +882,7 @@ class RoomMemberHandler(metaclass=abc.ABCMeta):
bypass_spam_checker = True bypass_spam_checker = True
else: else:
bypass_spam_checker = await self.auth.is_server_admin(requester.user) bypass_spam_checker = await self.auth.is_server_admin(requester)
inviter = await self._get_inviter(target.to_string(), room_id) inviter = await self._get_inviter(target.to_string(), room_id)
if ( if (
@ -1424,7 +1424,7 @@ class RoomMemberHandler(metaclass=abc.ABCMeta):
ShadowBanError if the requester has been shadow-banned. ShadowBanError if the requester has been shadow-banned.
""" """
if self.config.server.block_non_admin_invites: if self.config.server.block_non_admin_invites:
is_requester_admin = await self.auth.is_server_admin(requester.user) is_requester_admin = await self.auth.is_server_admin(requester)
if not is_requester_admin: if not is_requester_admin:
raise SynapseError( raise SynapseError(
403, "Invites have been disabled on this server", Codes.FORBIDDEN 403, "Invites have been disabled on this server", Codes.FORBIDDEN
@ -1707,7 +1707,7 @@ class RoomMemberMasterHandler(RoomMemberHandler):
check_complexity check_complexity
and self.hs.config.server.limit_remote_rooms.admins_can_join and self.hs.config.server.limit_remote_rooms.admins_can_join
): ):
check_complexity = not await self.auth.is_server_admin(user) check_complexity = not await self.store.is_server_admin(user)
if check_complexity: if check_complexity:
# Fetch the room complexity # Fetch the room complexity

View File

@ -253,12 +253,11 @@ class TypingWriterHandler(FollowerTypingHandler):
self, target_user: UserID, requester: Requester, room_id: str, timeout: int self, target_user: UserID, requester: Requester, room_id: str, timeout: int
) -> None: ) -> None:
target_user_id = target_user.to_string() target_user_id = target_user.to_string()
auth_user_id = requester.user.to_string()
if not self.is_mine_id(target_user_id): if not self.is_mine_id(target_user_id):
raise SynapseError(400, "User is not hosted on this homeserver") raise SynapseError(400, "User is not hosted on this homeserver")
if target_user_id != auth_user_id: if target_user != requester.user:
raise AuthError(400, "Cannot set another user's typing state") raise AuthError(400, "Cannot set another user's typing state")
if requester.shadow_banned: if requester.shadow_banned:
@ -266,7 +265,7 @@ class TypingWriterHandler(FollowerTypingHandler):
await self.clock.sleep(random.randint(1, 10)) await self.clock.sleep(random.randint(1, 10))
raise ShadowBanError() raise ShadowBanError()
await self.auth.check_user_in_room(room_id, target_user_id) await self.auth.check_user_in_room(room_id, requester)
logger.debug("%s has started typing in %s", target_user_id, room_id) logger.debug("%s has started typing in %s", target_user_id, room_id)
@ -289,12 +288,11 @@ class TypingWriterHandler(FollowerTypingHandler):
self, target_user: UserID, requester: Requester, room_id: str self, target_user: UserID, requester: Requester, room_id: str
) -> None: ) -> None:
target_user_id = target_user.to_string() target_user_id = target_user.to_string()
auth_user_id = requester.user.to_string()
if not self.is_mine_id(target_user_id): if not self.is_mine_id(target_user_id):
raise SynapseError(400, "User is not hosted on this homeserver") raise SynapseError(400, "User is not hosted on this homeserver")
if target_user_id != auth_user_id: if target_user != requester.user:
raise AuthError(400, "Cannot set another user's typing state") raise AuthError(400, "Cannot set another user's typing state")
if requester.shadow_banned: if requester.shadow_banned:
@ -302,7 +300,7 @@ class TypingWriterHandler(FollowerTypingHandler):
await self.clock.sleep(random.randint(1, 10)) await self.clock.sleep(random.randint(1, 10))
raise ShadowBanError() raise ShadowBanError()
await self.auth.check_user_in_room(room_id, target_user_id) await self.auth.check_user_in_room(room_id, requester)
logger.debug("%s has stopped typing in %s", target_user_id, room_id) logger.debug("%s has stopped typing in %s", target_user_id, room_id)

View File

@ -226,7 +226,7 @@ class SynapseRequest(Request):
# If this is a request where the target user doesn't match the user who # If this is a request where the target user doesn't match the user who
# authenticated (e.g. and admin is puppetting a user) then we return both. # authenticated (e.g. and admin is puppetting a user) then we return both.
if self._requester.user.to_string() != authenticated_entity: if requester != authenticated_entity:
return requester, authenticated_entity return requester, authenticated_entity
return requester, None return requester, None

View File

@ -19,7 +19,7 @@ from typing import Iterable, Pattern
from synapse.api.auth import Auth from synapse.api.auth import Auth
from synapse.api.errors import AuthError from synapse.api.errors import AuthError
from synapse.http.site import SynapseRequest from synapse.http.site import SynapseRequest
from synapse.types import UserID from synapse.types import Requester
def admin_patterns(path_regex: str, version: str = "v1") -> Iterable[Pattern]: def admin_patterns(path_regex: str, version: str = "v1") -> Iterable[Pattern]:
@ -48,19 +48,19 @@ async def assert_requester_is_admin(auth: Auth, request: SynapseRequest) -> None
AuthError if the requester is not a server admin AuthError if the requester is not a server admin
""" """
requester = await auth.get_user_by_req(request) requester = await auth.get_user_by_req(request)
await assert_user_is_admin(auth, requester.user) await assert_user_is_admin(auth, requester)
async def assert_user_is_admin(auth: Auth, user_id: UserID) -> None: async def assert_user_is_admin(auth: Auth, requester: Requester) -> None:
"""Verify that the given user is an admin user """Verify that the given user is an admin user
Args: Args:
auth: Auth singleton auth: Auth singleton
user_id: user to check requester: The user making the request, according to the access token.
Raises: Raises:
AuthError if the user is not a server admin AuthError if the user is not a server admin
""" """
is_admin = await auth.is_server_admin(user_id) is_admin = await auth.is_server_admin(requester)
if not is_admin: if not is_admin:
raise AuthError(HTTPStatus.FORBIDDEN, "You are not a server admin") raise AuthError(HTTPStatus.FORBIDDEN, "You are not a server admin")

View File

@ -54,7 +54,7 @@ class QuarantineMediaInRoom(RestServlet):
self, request: SynapseRequest, room_id: str self, request: SynapseRequest, room_id: str
) -> Tuple[int, JsonDict]: ) -> Tuple[int, JsonDict]:
requester = await self.auth.get_user_by_req(request) requester = await self.auth.get_user_by_req(request)
await assert_user_is_admin(self.auth, requester.user) await assert_user_is_admin(self.auth, requester)
logging.info("Quarantining room: %s", room_id) logging.info("Quarantining room: %s", room_id)
@ -81,7 +81,7 @@ class QuarantineMediaByUser(RestServlet):
self, request: SynapseRequest, user_id: str self, request: SynapseRequest, user_id: str
) -> Tuple[int, JsonDict]: ) -> Tuple[int, JsonDict]:
requester = await self.auth.get_user_by_req(request) requester = await self.auth.get_user_by_req(request)
await assert_user_is_admin(self.auth, requester.user) await assert_user_is_admin(self.auth, requester)
logging.info("Quarantining media by user: %s", user_id) logging.info("Quarantining media by user: %s", user_id)
@ -110,7 +110,7 @@ class QuarantineMediaByID(RestServlet):
self, request: SynapseRequest, server_name: str, media_id: str self, request: SynapseRequest, server_name: str, media_id: str
) -> Tuple[int, JsonDict]: ) -> Tuple[int, JsonDict]:
requester = await self.auth.get_user_by_req(request) requester = await self.auth.get_user_by_req(request)
await assert_user_is_admin(self.auth, requester.user) await assert_user_is_admin(self.auth, requester)
logging.info("Quarantining media by ID: %s/%s", server_name, media_id) logging.info("Quarantining media by ID: %s/%s", server_name, media_id)

View File

@ -75,7 +75,7 @@ class RoomRestV2Servlet(RestServlet):
) -> Tuple[int, JsonDict]: ) -> Tuple[int, JsonDict]:
requester = await self._auth.get_user_by_req(request) requester = await self._auth.get_user_by_req(request)
await assert_user_is_admin(self._auth, requester.user) await assert_user_is_admin(self._auth, requester)
content = parse_json_object_from_request(request) content = parse_json_object_from_request(request)
@ -327,7 +327,7 @@ class RoomRestServlet(RestServlet):
pagination_handler: "PaginationHandler", pagination_handler: "PaginationHandler",
) -> Tuple[int, JsonDict]: ) -> Tuple[int, JsonDict]:
requester = await auth.get_user_by_req(request) requester = await auth.get_user_by_req(request)
await assert_user_is_admin(auth, requester.user) await assert_user_is_admin(auth, requester)
content = parse_json_object_from_request(request) content = parse_json_object_from_request(request)
@ -461,7 +461,7 @@ class JoinRoomAliasServlet(ResolveRoomIdMixin, RestServlet):
assert request.args is not None assert request.args is not None
requester = await self.auth.get_user_by_req(request) requester = await self.auth.get_user_by_req(request)
await assert_user_is_admin(self.auth, requester.user) await assert_user_is_admin(self.auth, requester)
content = parse_json_object_from_request(request) content = parse_json_object_from_request(request)
@ -551,7 +551,7 @@ class MakeRoomAdminRestServlet(ResolveRoomIdMixin, RestServlet):
self, request: SynapseRequest, room_identifier: str self, request: SynapseRequest, room_identifier: str
) -> Tuple[int, JsonDict]: ) -> Tuple[int, JsonDict]:
requester = await self.auth.get_user_by_req(request) requester = await self.auth.get_user_by_req(request)
await assert_user_is_admin(self.auth, requester.user) await assert_user_is_admin(self.auth, requester)
content = parse_json_object_from_request(request, allow_empty_body=True) content = parse_json_object_from_request(request, allow_empty_body=True)
room_id, _ = await self.resolve_room_id(room_identifier) room_id, _ = await self.resolve_room_id(room_identifier)
@ -742,7 +742,7 @@ class RoomEventContextServlet(RestServlet):
self, request: SynapseRequest, room_id: str, event_id: str self, request: SynapseRequest, room_id: str, event_id: str
) -> Tuple[int, JsonDict]: ) -> Tuple[int, JsonDict]:
requester = await self.auth.get_user_by_req(request, allow_guest=False) requester = await self.auth.get_user_by_req(request, allow_guest=False)
await assert_user_is_admin(self.auth, requester.user) await assert_user_is_admin(self.auth, requester)
limit = parse_integer(request, "limit", default=10) limit = parse_integer(request, "limit", default=10)
@ -834,7 +834,7 @@ class BlockRoomRestServlet(RestServlet):
self, request: SynapseRequest, room_id: str self, request: SynapseRequest, room_id: str
) -> Tuple[int, JsonDict]: ) -> Tuple[int, JsonDict]:
requester = await self._auth.get_user_by_req(request) requester = await self._auth.get_user_by_req(request)
await assert_user_is_admin(self._auth, requester.user) await assert_user_is_admin(self._auth, requester)
content = parse_json_object_from_request(request) content = parse_json_object_from_request(request)

View File

@ -183,7 +183,7 @@ class UserRestServletV2(RestServlet):
self, request: SynapseRequest, user_id: str self, request: SynapseRequest, user_id: str
) -> Tuple[int, JsonDict]: ) -> Tuple[int, JsonDict]:
requester = await self.auth.get_user_by_req(request) requester = await self.auth.get_user_by_req(request)
await assert_user_is_admin(self.auth, requester.user) await assert_user_is_admin(self.auth, requester)
target_user = UserID.from_string(user_id) target_user = UserID.from_string(user_id)
body = parse_json_object_from_request(request) body = parse_json_object_from_request(request)
@ -575,10 +575,9 @@ class WhoisRestServlet(RestServlet):
) -> Tuple[int, JsonDict]: ) -> Tuple[int, JsonDict]:
target_user = UserID.from_string(user_id) target_user = UserID.from_string(user_id)
requester = await self.auth.get_user_by_req(request) requester = await self.auth.get_user_by_req(request)
auth_user = requester.user
if target_user != auth_user: if target_user != requester.user:
await assert_user_is_admin(self.auth, auth_user) await assert_user_is_admin(self.auth, requester)
if not self.is_mine(target_user): if not self.is_mine(target_user):
raise SynapseError(HTTPStatus.BAD_REQUEST, "Can only whois a local user") raise SynapseError(HTTPStatus.BAD_REQUEST, "Can only whois a local user")
@ -601,7 +600,7 @@ class DeactivateAccountRestServlet(RestServlet):
self, request: SynapseRequest, target_user_id: str self, request: SynapseRequest, target_user_id: str
) -> Tuple[int, JsonDict]: ) -> Tuple[int, JsonDict]:
requester = await self.auth.get_user_by_req(request) requester = await self.auth.get_user_by_req(request)
await assert_user_is_admin(self.auth, requester.user) await assert_user_is_admin(self.auth, requester)
if not self.is_mine(UserID.from_string(target_user_id)): if not self.is_mine(UserID.from_string(target_user_id)):
raise SynapseError( raise SynapseError(
@ -693,7 +692,7 @@ class ResetPasswordRestServlet(RestServlet):
This needs user to have administrator access in Synapse. This needs user to have administrator access in Synapse.
""" """
requester = await self.auth.get_user_by_req(request) requester = await self.auth.get_user_by_req(request)
await assert_user_is_admin(self.auth, requester.user) await assert_user_is_admin(self.auth, requester)
UserID.from_string(target_user_id) UserID.from_string(target_user_id)
@ -807,7 +806,7 @@ class UserAdminServlet(RestServlet):
self, request: SynapseRequest, user_id: str self, request: SynapseRequest, user_id: str
) -> Tuple[int, JsonDict]: ) -> Tuple[int, JsonDict]:
requester = await self.auth.get_user_by_req(request) requester = await self.auth.get_user_by_req(request)
await assert_user_is_admin(self.auth, requester.user) await assert_user_is_admin(self.auth, requester)
auth_user = requester.user auth_user = requester.user
target_user = UserID.from_string(user_id) target_user = UserID.from_string(user_id)
@ -921,7 +920,7 @@ class UserTokenRestServlet(RestServlet):
self, request: SynapseRequest, user_id: str self, request: SynapseRequest, user_id: str
) -> Tuple[int, JsonDict]: ) -> Tuple[int, JsonDict]:
requester = await self.auth.get_user_by_req(request) requester = await self.auth.get_user_by_req(request)
await assert_user_is_admin(self.auth, requester.user) await assert_user_is_admin(self.auth, requester)
auth_user = requester.user auth_user = requester.user
if not self.is_mine_id(user_id): if not self.is_mine_id(user_id):

View File

@ -66,7 +66,7 @@ class ProfileDisplaynameRestServlet(RestServlet):
) -> Tuple[int, JsonDict]: ) -> Tuple[int, JsonDict]:
requester = await self.auth.get_user_by_req(request, allow_guest=True) requester = await self.auth.get_user_by_req(request, allow_guest=True)
user = UserID.from_string(user_id) user = UserID.from_string(user_id)
is_admin = await self.auth.is_server_admin(requester.user) is_admin = await self.auth.is_server_admin(requester)
content = parse_json_object_from_request(request) content = parse_json_object_from_request(request)
@ -123,7 +123,7 @@ class ProfileAvatarURLRestServlet(RestServlet):
) -> Tuple[int, JsonDict]: ) -> Tuple[int, JsonDict]:
requester = await self.auth.get_user_by_req(request) requester = await self.auth.get_user_by_req(request)
user = UserID.from_string(user_id) user = UserID.from_string(user_id)
is_admin = await self.auth.is_server_admin(requester.user) is_admin = await self.auth.is_server_admin(requester)
content = parse_json_object_from_request(request) content = parse_json_object_from_request(request)
try: try:

View File

@ -484,9 +484,6 @@ class RegisterRestServlet(RestServlet):
"Appservice token must be provided when using a type of m.login.application_service", "Appservice token must be provided when using a type of m.login.application_service",
) )
# Verify the AS
self.auth.get_appservice_by_req(request)
# Set the desired user according to the AS API (which uses the # Set the desired user according to the AS API (which uses the
# 'user' key not 'username'). Since this is a new addition, we'll # 'user' key not 'username'). Since this is a new addition, we'll
# fallback to 'username' if they gave one. # fallback to 'username' if they gave one.

View File

@ -116,9 +116,13 @@ messsages_response_timer = Histogram(
2.5, 2.5,
5.0, 5.0,
10.0, 10.0,
20.0,
30.0, 30.0,
60.0, 60.0,
80.0,
100.0,
120.0, 120.0,
150.0,
180.0, 180.0,
"+Inf", "+Inf",
), ),
@ -229,7 +233,7 @@ class RoomStateEventRestServlet(TransactionRestServlet):
msg_handler = self.message_handler msg_handler = self.message_handler
data = await msg_handler.get_room_data( data = await msg_handler.get_room_data(
user_id=requester.user.to_string(), requester=requester,
room_id=room_id, room_id=room_id,
event_type=event_type, event_type=event_type,
state_key=state_key, state_key=state_key,
@ -574,7 +578,7 @@ class RoomMemberListRestServlet(RestServlet):
events = await handler.get_state_events( events = await handler.get_state_events(
room_id=room_id, room_id=room_id,
user_id=requester.user.to_string(), requester=requester,
at_token=at_token, at_token=at_token,
state_filter=StateFilter.from_types([(EventTypes.Member, None)]), state_filter=StateFilter.from_types([(EventTypes.Member, None)]),
) )
@ -674,7 +678,7 @@ class RoomMessageListRestServlet(RestServlet):
room_member_count = await make_deferred_yieldable(room_member_count_deferred) room_member_count = await make_deferred_yieldable(room_member_count_deferred)
messsages_response_timer.labels( messsages_response_timer.labels(
room_size=_RoomSize.from_member_count(room_member_count) room_size=_RoomSize.from_member_count(room_member_count)
).observe((processing_start_time - processing_end_time) / 1000) ).observe((processing_end_time - processing_start_time) / 1000)
return 200, msgs return 200, msgs
@ -696,8 +700,7 @@ class RoomStateRestServlet(RestServlet):
# Get all the current state for this room # Get all the current state for this room
events = await self.message_handler.get_state_events( events = await self.message_handler.get_state_events(
room_id=room_id, room_id=room_id,
user_id=requester.user.to_string(), requester=requester,
is_guest=requester.is_guest,
) )
return 200, events return 200, events
@ -755,7 +758,7 @@ class RoomEventServlet(RestServlet):
== "true" == "true"
) )
if include_unredacted_content and not await self.auth.is_server_admin( if include_unredacted_content and not await self.auth.is_server_admin(
requester.user requester
): ):
power_level_event = ( power_level_event = (
await self._storage_controllers.state.get_current_state_event( await self._storage_controllers.state.get_current_state_event(
@ -1260,9 +1263,7 @@ class TimestampLookupRestServlet(RestServlet):
self, request: SynapseRequest, room_id: str self, request: SynapseRequest, room_id: str
) -> Tuple[int, JsonDict]: ) -> Tuple[int, JsonDict]:
requester = await self._auth.get_user_by_req(request) requester = await self._auth.get_user_by_req(request)
await self._auth.check_user_in_room_or_world_readable( await self._auth.check_user_in_room_or_world_readable(room_id, requester)
room_id, requester.user.to_string()
)
timestamp = parse_integer(request, "ts", required=True) timestamp = parse_integer(request, "ts", required=True)
direction = parse_string(request, "dir", default="f", allowed_values=["f", "b"]) direction = parse_string(request, "dir", default="f", allowed_values=["f", "b"])

View File

@ -244,7 +244,7 @@ class ServerNoticesManager:
assert self.server_notices_mxid is not None assert self.server_notices_mxid is not None
notice_user_data_in_room = await self._message_handler.get_room_data( notice_user_data_in_room = await self._message_handler.get_room_data(
self.server_notices_mxid, create_requester(self.server_notices_mxid),
room_id, room_id,
EventTypes.Member, EventTypes.Member,
self.server_notices_mxid, self.server_notices_mxid,

View File

@ -69,9 +69,9 @@ class TokenLookupResult:
""" """
user_id: str user_id: str
token_id: int
is_guest: bool = False is_guest: bool = False
shadow_banned: bool = False shadow_banned: bool = False
token_id: Optional[int] = None
device_id: Optional[str] = None device_id: Optional[str] = None
valid_until_ms: Optional[int] = None valid_until_ms: Optional[int] = None
token_owner: str = attr.ib() token_owner: str = attr.ib()

View File

@ -284,10 +284,13 @@ class AuthTestCase(unittest.HomeserverTestCase):
TokenLookupResult( TokenLookupResult(
user_id="@baldrick:matrix.org", user_id="@baldrick:matrix.org",
device_id="device", device_id="device",
token_id=5,
token_owner="@admin:matrix.org", token_owner="@admin:matrix.org",
token_used=True,
) )
) )
self.store.insert_client_ip = simple_async_mock(None) self.store.insert_client_ip = simple_async_mock(None)
self.store.mark_access_token_as_used = simple_async_mock(None)
request = Mock(args={}) request = Mock(args={})
request.getClientAddress.return_value.host = "127.0.0.1" request.getClientAddress.return_value.host = "127.0.0.1"
request.args[b"access_token"] = [self.test_token] request.args[b"access_token"] = [self.test_token]
@ -301,10 +304,13 @@ class AuthTestCase(unittest.HomeserverTestCase):
TokenLookupResult( TokenLookupResult(
user_id="@baldrick:matrix.org", user_id="@baldrick:matrix.org",
device_id="device", device_id="device",
token_id=5,
token_owner="@admin:matrix.org", token_owner="@admin:matrix.org",
token_used=True,
) )
) )
self.store.insert_client_ip = simple_async_mock(None) self.store.insert_client_ip = simple_async_mock(None)
self.store.mark_access_token_as_used = simple_async_mock(None)
request = Mock(args={}) request = Mock(args={})
request.getClientAddress.return_value.host = "127.0.0.1" request.getClientAddress.return_value.host = "127.0.0.1"
request.args[b"access_token"] = [self.test_token] request.args[b"access_token"] = [self.test_token]
@ -347,7 +353,7 @@ class AuthTestCase(unittest.HomeserverTestCase):
serialized = macaroon.serialize() serialized = macaroon.serialize()
user_info = self.get_success(self.auth.get_user_by_access_token(serialized)) user_info = self.get_success(self.auth.get_user_by_access_token(serialized))
self.assertEqual(user_id, user_info.user_id) self.assertEqual(user_id, user_info.user.to_string())
self.assertTrue(user_info.is_guest) self.assertTrue(user_info.is_guest)
self.store.get_user_by_id.assert_called_with(user_id) self.store.get_user_by_id.assert_called_with(user_id)

View File

@ -25,7 +25,7 @@ from synapse.api.constants import EduTypes
from synapse.api.errors import AuthError from synapse.api.errors import AuthError
from synapse.federation.transport.server import TransportLayerServer from synapse.federation.transport.server import TransportLayerServer
from synapse.server import HomeServer from synapse.server import HomeServer
from synapse.types import JsonDict, UserID, create_requester from synapse.types import JsonDict, Requester, UserID, create_requester
from synapse.util import Clock from synapse.util import Clock
from tests import unittest from tests import unittest
@ -117,8 +117,10 @@ class TypingNotificationsTestCase(unittest.HomeserverTestCase):
self.room_members = [] self.room_members = []
async def check_user_in_room(room_id: str, user_id: str) -> None: async def check_user_in_room(room_id: str, requester: Requester) -> None:
if user_id not in [u.to_string() for u in self.room_members]: if requester.user.to_string() not in [
u.to_string() for u in self.room_members
]:
raise AuthError(401, "User is not in the room") raise AuthError(401, "User is not in the room")
return None return None

View File

@ -159,6 +159,62 @@ class ServerNoticeTestCase(unittest.HomeserverTestCase):
self.assertEqual(Codes.UNKNOWN, channel.json_body["errcode"]) self.assertEqual(Codes.UNKNOWN, channel.json_body["errcode"])
self.assertEqual("'msgtype' not in content", channel.json_body["error"]) self.assertEqual("'msgtype' not in content", channel.json_body["error"])
@override_config(
{
"server_notices": {
"system_mxid_localpart": "notices",
"system_mxid_avatar_url": "somthingwrong",
},
"max_avatar_size": "10M",
}
)
def test_invalid_avatar_url(self) -> None:
"""If avatar url in homeserver.yaml is invalid and
"check avatar size and mime type" is set, an error is returned.
TODO: Should be checked when reading the configuration."""
channel = self.make_request(
"POST",
self.url,
access_token=self.admin_user_tok,
content={
"user_id": self.other_user,
"content": {"msgtype": "m.text", "body": "test msg"},
},
)
self.assertEqual(500, channel.code, msg=channel.json_body)
self.assertEqual(Codes.UNKNOWN, channel.json_body["errcode"])
@override_config(
{
"server_notices": {
"system_mxid_localpart": "notices",
"system_mxid_display_name": "test display name",
"system_mxid_avatar_url": None,
},
"max_avatar_size": "10M",
}
)
def test_displayname_is_set_avatar_is_none(self) -> None:
"""
Tests that sending a server notices is successfully,
if a display_name is set, avatar_url is `None` and
"check avatar size and mime type" is set.
"""
channel = self.make_request(
"POST",
self.url,
access_token=self.admin_user_tok,
content={
"user_id": self.other_user,
"content": {"msgtype": "m.text", "body": "test msg"},
},
)
self.assertEqual(200, channel.code, msg=channel.json_body)
# user has one invite
self._check_invite_and_join_status(self.other_user, 1, 0)
def test_server_notice_disabled(self) -> None: def test_server_notice_disabled(self) -> None:
"""Tests that server returns error if server notice is disabled""" """Tests that server returns error if server notice is disabled"""
channel = self.make_request( channel = self.make_request(

View File

@ -20,7 +20,7 @@ from synapse.api.constants import EventTypes
from synapse.rest import admin from synapse.rest import admin
from synapse.rest.client import login, room from synapse.rest.client import login, room
from synapse.server import HomeServer from synapse.server import HomeServer
from synapse.types import JsonDict from synapse.types import JsonDict, create_requester
from synapse.util import Clock from synapse.util import Clock
from synapse.visibility import filter_events_for_client from synapse.visibility import filter_events_for_client
@ -188,7 +188,7 @@ class RetentionTestCase(unittest.HomeserverTestCase):
message_handler = self.hs.get_message_handler() message_handler = self.hs.get_message_handler()
create_event = self.get_success( create_event = self.get_success(
message_handler.get_room_data( message_handler.get_room_data(
self.user_id, room_id, EventTypes.Create, state_key="" create_requester(self.user_id), room_id, EventTypes.Create, state_key=""
) )
) )

View File

@ -26,7 +26,7 @@ from synapse.rest.client import (
room_upgrade_rest_servlet, room_upgrade_rest_servlet,
) )
from synapse.server import HomeServer from synapse.server import HomeServer
from synapse.types import UserID from synapse.types import UserID, create_requester
from synapse.util import Clock from synapse.util import Clock
from tests import unittest from tests import unittest
@ -275,7 +275,7 @@ class ProfileTestCase(_ShadowBannedBase):
message_handler = self.hs.get_message_handler() message_handler = self.hs.get_message_handler()
event = self.get_success( event = self.get_success(
message_handler.get_room_data( message_handler.get_room_data(
self.banned_user_id, create_requester(self.banned_user_id),
room_id, room_id,
"m.room.member", "m.room.member",
self.banned_user_id, self.banned_user_id,
@ -310,7 +310,7 @@ class ProfileTestCase(_ShadowBannedBase):
message_handler = self.hs.get_message_handler() message_handler = self.hs.get_message_handler()
event = self.get_success( event = self.get_success(
message_handler.get_room_data( message_handler.get_room_data(
self.banned_user_id, create_requester(self.banned_user_id),
room_id, room_id,
"m.room.member", "m.room.member",
self.banned_user_id, self.banned_user_id,

View File

@ -11,16 +11,19 @@
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# 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 unittest.mock import Mock from unittest.mock import Mock
from twisted.test.proto_helpers import MemoryReactor
from synapse.api.constants import EventTypes, LimitBlockingTypes, ServerNoticeMsgType from synapse.api.constants import EventTypes, LimitBlockingTypes, ServerNoticeMsgType
from synapse.api.errors import ResourceLimitError from synapse.api.errors import ResourceLimitError
from synapse.rest import admin from synapse.rest import admin
from synapse.rest.client import login, room, sync from synapse.rest.client import login, room, sync
from synapse.server import HomeServer
from synapse.server_notices.resource_limits_server_notices import ( from synapse.server_notices.resource_limits_server_notices import (
ResourceLimitsServerNotices, ResourceLimitsServerNotices,
) )
from synapse.util import Clock
from tests import unittest from tests import unittest
from tests.test_utils import make_awaitable from tests.test_utils import make_awaitable
@ -52,7 +55,7 @@ class TestResourceLimitsServerNotices(unittest.HomeserverTestCase):
return config return config
def prepare(self, reactor, clock, hs): def prepare(self, reactor: MemoryReactor, clock: Clock, hs: HomeServer) -> None:
self.server_notices_sender = self.hs.get_server_notices_sender() self.server_notices_sender = self.hs.get_server_notices_sender()
# relying on [1] is far from ideal, but the only case where # relying on [1] is far from ideal, but the only case where
@ -251,7 +254,7 @@ class TestResourceLimitsServerNoticesWithRealRooms(unittest.HomeserverTestCase):
c["admin_contact"] = "mailto:user@test.com" c["admin_contact"] = "mailto:user@test.com"
return c return c
def prepare(self, reactor, clock, hs): def prepare(self, reactor: MemoryReactor, clock: Clock, hs: HomeServer) -> None:
self.store = self.hs.get_datastores().main self.store = self.hs.get_datastores().main
self.server_notices_sender = self.hs.get_server_notices_sender() self.server_notices_sender = self.hs.get_server_notices_sender()
self.server_notices_manager = self.hs.get_server_notices_manager() self.server_notices_manager = self.hs.get_server_notices_manager()