From cf0277278c1b2b08a89f29ff08212ab29bfbcadf Mon Sep 17 00:00:00 2001 From: dklimpel <5740567+dklimpel@users.noreply.github.com> Date: Thu, 30 Dec 2021 12:59:18 +0100 Subject: [PATCH 1/4] Add admin API to get users' account data --- changelog.d/11664.feature | 1 + docs/admin_api/user_admin_api.md | 75 ++++++++++ synapse/rest/admin/__init__.py | 2 + synapse/rest/admin/users.py | 238 +++++++++++++++++-------------- tests/rest/admin/test_user.py | 90 ++++++++++++ 5 files changed, 302 insertions(+), 104 deletions(-) create mode 100644 changelog.d/11664.feature diff --git a/changelog.d/11664.feature b/changelog.d/11664.feature new file mode 100644 index 000000000000..df81783c66a0 --- /dev/null +++ b/changelog.d/11664.feature @@ -0,0 +1 @@ +Add admin API to get users' account data. \ No newline at end of file diff --git a/docs/admin_api/user_admin_api.md b/docs/admin_api/user_admin_api.md index ba574d795fcc..b8a46a51afcf 100644 --- a/docs/admin_api/user_admin_api.md +++ b/docs/admin_api/user_admin_api.md @@ -480,6 +480,81 @@ The following fields are returned in the JSON response body: - `joined_rooms` - An array of `room_id`. - `total` - Number of rooms. +## Account Data +Gets information about account data for a specific `user_id`. + +The API is: + +``` +GET /_synapse/admin/v1/users//accountdata +``` + +A response body like the following is returned: + +```json +{ + "account_data": { + "global": { + "m.secret_storage.key.LmIGHTg5W": { + "algorithm": "m.secret_storage.v1.aes-hmac-sha2", + "iv": "fwjNZatxg==", + "mac": "eWh9kNnLWZUNOgnc=" + }, + "im.vector.hide_profile": { + "hide_profile": true + }, + "org.matrix.preview_urls": { + "disable": false + }, + "im.vector.riot.breadcrumb_rooms": { + "rooms": [ + "!LxcBDAsDUVAfJDEo:matrix.org", + "!MAhRxqasbItjOqxu:matrix.org" + ] + }, + "m.accepted_terms": { + "accepted": [ + "https://example.org/somewhere/privacy-1.2-en.html", + "https://example.org/somewhere/terms-2.0-en.html" + ] + }, + "im.vector.setting.breadcrumbs": { + "recent_rooms": [ + "!MAhRxqasbItqxuEt:matrix.org", + "!ZtSaPCawyWtxiImy:matrix.org" + ] + } + }, + "rooms": { + "!GUdfZSHUJibpiVqHYd:matrix.org": { + "m.fully_read": { + "event_id": "$156334540fYIhZ:matrix.org" + } + }, + "!tOZwOOiqwCYQkLhV:matrix.org": { + "m.fully_read": { + "event_id": "$xjsIyp4_NaVl2yPvIZs_k1Jl8tsC_Sp23wjqXPno" + } + } + } + } +} +``` + +**Parameters** + +The following parameters should be set in the URL: + +- `user_id` - fully qualified: for example, `@user:server.com`. + +**Response** + +The following fields are returned in the JSON response body: + +- `account_data` - An array containing the account data for the user + - `global` - An array containing the global account data for the user + - `rooms` - An array containing the account data per room for the user + ## User media ### List media uploaded by a user diff --git a/synapse/rest/admin/__init__.py b/synapse/rest/admin/__init__.py index 701c609c1208..465e06772b26 100644 --- a/synapse/rest/admin/__init__.py +++ b/synapse/rest/admin/__init__.py @@ -69,6 +69,7 @@ from synapse.rest.admin.statistics import UserMediaStatisticsRestServlet from synapse.rest.admin.username_available import UsernameAvailableRestServlet from synapse.rest.admin.users import ( + AccountDataRestServlet, AccountValidityRenewServlet, DeactivateAccountRestServlet, PushersRestServlet, @@ -255,6 +256,7 @@ def register_servlets(hs: "HomeServer", http_server: HttpServer) -> None: UserMediaStatisticsRestServlet(hs).register(http_server) EventReportDetailRestServlet(hs).register(http_server) EventReportsRestServlet(hs).register(http_server) + AccountDataRestServlet(hs).register(http_server) PushersRestServlet(hs).register(http_server) MakeRoomAdminRestServlet(hs).register(http_server) ShadowBanRestServlet(hs).register(http_server) diff --git a/synapse/rest/admin/users.py b/synapse/rest/admin/users.py index db678da4cf14..6b9deef5845b 100644 --- a/synapse/rest/admin/users.py +++ b/synapse/rest/admin/users.py @@ -66,12 +66,12 @@ class UsersRestServletV2(RestServlet): """ def __init__(self, hs: "HomeServer"): - self.store = hs.get_datastore() - self.auth = hs.get_auth() + self._store = hs.get_datastore() + self._auth = hs.get_auth() self.admin_handler = hs.get_admin_handler() async def on_GET(self, request: SynapseRequest) -> Tuple[int, JsonDict]: - await assert_requester_is_admin(self.auth, request) + await assert_requester_is_admin(self._auth, request) start = parse_integer(request, "from", default=0) limit = parse_integer(request, "limit", default=100) @@ -114,7 +114,7 @@ async def on_GET(self, request: SynapseRequest) -> Tuple[int, JsonDict]: direction = parse_string(request, "dir", default="f", allowed_values=("f", "b")) - users, total = await self.store.get_users_paginate( + users, total = await self._store.get_users_paginate( start, limit, user_id, name, guests, deactivated, order_by, direction ) ret = {"users": users, "total": total} @@ -154,10 +154,10 @@ class UserRestServletV2(RestServlet): def __init__(self, hs: "HomeServer"): self.hs = hs - self.auth = hs.get_auth() + self._auth = hs.get_auth() self.admin_handler = hs.get_admin_handler() - self.store = hs.get_datastore() - self.auth_handler = hs.get_auth_handler() + self._store = hs.get_datastore() + self._auth_handler = hs.get_auth_handler() self.profile_handler = hs.get_profile_handler() self.set_password_handler = hs.get_set_password_handler() self.deactivate_account_handler = hs.get_deactivate_account_handler() @@ -167,7 +167,7 @@ def __init__(self, hs: "HomeServer"): async def on_GET( self, request: SynapseRequest, user_id: str ) -> Tuple[int, JsonDict]: - await assert_requester_is_admin(self.auth, request) + await assert_requester_is_admin(self._auth, request) target_user = UserID.from_string(user_id) if not self.hs.is_mine(target_user): @@ -183,8 +183,8 @@ async def on_GET( async def on_PUT( self, request: SynapseRequest, user_id: str ) -> Tuple[int, JsonDict]: - requester = await self.auth.get_user_by_req(request) - await assert_user_is_admin(self.auth, requester.user) + requester = await self._auth.get_user_by_req(request) + await assert_user_is_admin(self._auth, requester.user) target_user = UserID.from_string(user_id) body = parse_json_object_from_request(request) @@ -257,7 +257,7 @@ async def on_PUT( # convert List[Dict[str, Any]] into Set[Tuple[str, str]] cur_threepids = { (threepid["medium"], threepid["address"]) - for threepid in await self.store.user_get_threepids(user_id) + for threepid in await self._store.user_get_threepids(user_id) } add_threepids = new_threepids - cur_threepids del_threepids = cur_threepids - new_threepids @@ -265,7 +265,7 @@ async def on_PUT( # remove old threepids for medium, address in del_threepids: try: - await self.auth_handler.delete_threepid( + await self._auth_handler.delete_threepid( user_id, medium, address, None ) except Exception: @@ -275,13 +275,13 @@ async def on_PUT( # add new threepids current_time = self.hs.get_clock().time_msec() for medium, address in add_threepids: - await self.auth_handler.add_threepid( + await self._auth_handler.add_threepid( user_id, medium, address, current_time ) if external_ids is not None: try: - await self.store.replace_user_external_id( + await self._store.replace_user_external_id( new_external_ids, user_id, ) @@ -303,11 +303,11 @@ async def on_PUT( HTTPStatus.BAD_REQUEST, "You may not demote yourself." ) - await self.store.set_server_admin(target_user, set_admin_to) + await self._store.set_server_admin(target_user, set_admin_to) if password is not None: logout_devices = True - new_password_hash = await self.auth_handler.hash(password) + new_password_hash = await self._auth_handler.hash(password) await self.set_password_handler.set_password( target_user.to_string(), @@ -324,7 +324,7 @@ async def on_PUT( elif not deactivate and user["deactivated"]: if ( "password" not in body - and self.auth_handler.can_change_password() + and self._auth_handler.can_change_password() ): raise SynapseError( HTTPStatus.BAD_REQUEST, @@ -336,7 +336,7 @@ async def on_PUT( ) if "user_type" in body: - await self.store.set_user_type(target_user, user_type) + await self._store.set_user_type(target_user, user_type) user = await self.admin_handler.get_user(target_user) assert user is not None @@ -348,7 +348,7 @@ async def on_PUT( password_hash = None if password is not None: - password_hash = await self.auth_handler.hash(password) + password_hash = await self._auth_handler.hash(password) user_id = await self.registration_handler.register_user( localpart=target_user.localpart, @@ -362,7 +362,7 @@ async def on_PUT( if threepids is not None: current_time = self.hs.get_clock().time_msec() for medium, address in new_threepids: - await self.auth_handler.add_threepid( + await self._auth_handler.add_threepid( user_id, medium, address, current_time ) if ( @@ -384,7 +384,7 @@ async def on_PUT( if external_ids is not None: try: for auth_provider, external_id in new_external_ids: - await self.store.record_user_external_id( + await self._store.record_user_external_id( auth_provider, external_id, user_id, @@ -417,7 +417,7 @@ class UserRegisterServlet(RestServlet): NONCE_TIMEOUT = 60 def __init__(self, hs: "HomeServer"): - self.auth_handler = hs.get_auth_handler() + self._auth_handler = hs.get_auth_handler() self.reactor = hs.get_reactor() self.nonces: Dict[str, int] = {} self.hs = hs @@ -496,7 +496,7 @@ async def on_POST(self, request: SynapseRequest) -> Tuple[int, JsonDict]: if b"\x00" in password_bytes: raise SynapseError(HTTPStatus.BAD_REQUEST, "Invalid password") - password_hash = await self.auth_handler.hash(password) + password_hash = await self._auth_handler.hash(password) admin = body.get("admin", None) user_type = body.get("user_type", None) @@ -560,21 +560,21 @@ class WhoisRestServlet(RestServlet): ] def __init__(self, hs: "HomeServer"): - self.auth = hs.get_auth() + self._auth = hs.get_auth() self.admin_handler = hs.get_admin_handler() - self.is_mine = hs.is_mine + self._is_mine = hs.is_mine async def on_GET( self, request: SynapseRequest, user_id: str ) -> Tuple[int, JsonDict]: 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: - await assert_user_is_admin(self.auth, auth_user) + await assert_user_is_admin(self._auth, auth_user) - 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") ret = await self.admin_handler.get_whois(target_user) @@ -587,22 +587,22 @@ class DeactivateAccountRestServlet(RestServlet): def __init__(self, hs: "HomeServer"): self._deactivate_account_handler = hs.get_deactivate_account_handler() - self.auth = hs.get_auth() - self.is_mine = hs.is_mine - self.store = hs.get_datastore() + self._auth = hs.get_auth() + self._is_mine = hs.is_mine + self._store = hs.get_datastore() async def on_POST( self, request: SynapseRequest, target_user_id: str ) -> Tuple[int, JsonDict]: - requester = await self.auth.get_user_by_req(request) - await assert_user_is_admin(self.auth, requester.user) + requester = await self._auth.get_user_by_req(request) + await assert_user_is_admin(self._auth, requester.user) - if not self.is_mine(UserID.from_string(target_user_id)): + if not self._is_mine(UserID.from_string(target_user_id)): raise SynapseError( HTTPStatus.BAD_REQUEST, "Can only deactivate local users" ) - if not await self.store.get_user_by_id(target_user_id): + if not await self._store.get_user_by_id(target_user_id): raise NotFoundError("User not found") body = parse_json_object_from_request(request, allow_empty_body=True) @@ -630,10 +630,10 @@ class AccountValidityRenewServlet(RestServlet): def __init__(self, hs: "HomeServer"): self.account_activity_handler = hs.get_account_validity_handler() - self.auth = hs.get_auth() + self._auth = hs.get_auth() async def on_POST(self, request: SynapseRequest) -> Tuple[int, JsonDict]: - await assert_requester_is_admin(self.auth, request) + await assert_requester_is_admin(self._auth, request) if self.account_activity_handler.on_legacy_admin_request_callback: expiration_ts = await ( @@ -675,9 +675,9 @@ class ResetPasswordRestServlet(RestServlet): PATTERNS = admin_patterns("/reset_password/(?P[^/]*)$") def __init__(self, hs: "HomeServer"): - self.store = hs.get_datastore() - self.auth = hs.get_auth() - self.auth_handler = hs.get_auth_handler() + self._store = hs.get_datastore() + self._auth = hs.get_auth() + self._auth_handler = hs.get_auth_handler() self._set_password_handler = hs.get_set_password_handler() async def on_POST( @@ -686,8 +686,8 @@ async def on_POST( """Post request to allow an administrator reset password for a user. This needs user to have administrator access in Synapse. """ - requester = await self.auth.get_user_by_req(request) - await assert_user_is_admin(self.auth, requester.user) + requester = await self._auth.get_user_by_req(request) + await assert_user_is_admin(self._auth, requester.user) UserID.from_string(target_user_id) @@ -696,7 +696,7 @@ async def on_POST( new_password = params["new_password"] logout_devices = params.get("logout_devices", True) - new_password_hash = await self.auth_handler.hash(new_password) + new_password_hash = await self._auth_handler.hash(new_password) await self._set_password_handler.set_password( target_user_id, new_password_hash, logout_devices, requester @@ -718,9 +718,9 @@ class SearchUsersRestServlet(RestServlet): PATTERNS = admin_patterns("/search_users/(?P[^/]*)$") def __init__(self, hs: "HomeServer"): - self.store = hs.get_datastore() - self.auth = hs.get_auth() - self.is_mine = hs.is_mine + self._store = hs.get_datastore() + self._auth = hs.get_auth() + self._is_mine = hs.is_mine async def on_GET( self, request: SynapseRequest, target_user_id: str @@ -729,7 +729,7 @@ async def on_GET( search term. This needs user to have a administrator access in Synapse. """ - await assert_requester_is_admin(self.auth, request) + await assert_requester_is_admin(self._auth, request) target_user = UserID.from_string(target_user_id) @@ -737,13 +737,13 @@ async def on_GET( # if not is_admin and target_user != auth_user: # raise AuthError(HTTPStatus.FORBIDDEN, "You are not a server admin") - if not self.is_mine(target_user): + if not self._is_mine(target_user): raise SynapseError(HTTPStatus.BAD_REQUEST, "Can only users a local user") term = parse_string(request, "term", required=True) logger.info("term: %s ", term) - ret = await self.store.search_users(term) + ret = await self._store.search_users(term) return HTTPStatus.OK, ret @@ -776,32 +776,32 @@ class UserAdminServlet(RestServlet): PATTERNS = admin_patterns("/users/(?P[^/]*)/admin$") def __init__(self, hs: "HomeServer"): - self.store = hs.get_datastore() - self.auth = hs.get_auth() - self.is_mine = hs.is_mine + self._store = hs.get_datastore() + self._auth = hs.get_auth() + self._is_mine = hs.is_mine async def on_GET( self, request: SynapseRequest, user_id: str ) -> Tuple[int, JsonDict]: - await assert_requester_is_admin(self.auth, request) + await assert_requester_is_admin(self._auth, request) target_user = UserID.from_string(user_id) - if not self.is_mine(target_user): + if not self._is_mine(target_user): raise SynapseError( HTTPStatus.BAD_REQUEST, "Only local users can be admins of this homeserver", ) - is_admin = await self.store.is_server_admin(target_user) + is_admin = await self._store.is_server_admin(target_user) return HTTPStatus.OK, {"admin": is_admin} async def on_PUT( self, request: SynapseRequest, user_id: str ) -> Tuple[int, JsonDict]: - requester = await self.auth.get_user_by_req(request) - await assert_user_is_admin(self.auth, requester.user) + requester = await self._auth.get_user_by_req(request) + await assert_user_is_admin(self._auth, requester.user) auth_user = requester.user target_user = UserID.from_string(user_id) @@ -810,7 +810,7 @@ async def on_PUT( assert_params_in_dict(body, ["admin"]) - if not self.is_mine(target_user): + if not self._is_mine(target_user): raise SynapseError( HTTPStatus.BAD_REQUEST, "Only local users can be admins of this homeserver", @@ -821,7 +821,7 @@ async def on_PUT( if target_user == auth_user and not set_admin_to: raise SynapseError(HTTPStatus.BAD_REQUEST, "You may not demote yourself.") - await self.store.set_server_admin(target_user, set_admin_to) + await self._store.set_server_admin(target_user, set_admin_to) return HTTPStatus.OK, {} @@ -834,16 +834,16 @@ class UserMembershipRestServlet(RestServlet): PATTERNS = admin_patterns("/users/(?P[^/]*)/joined_rooms$") def __init__(self, hs: "HomeServer"): - self.is_mine = hs.is_mine - self.auth = hs.get_auth() - self.store = hs.get_datastore() + self._is_mine = hs.is_mine + self._auth = hs.get_auth() + self._store = hs.get_datastore() async def on_GET( self, request: SynapseRequest, user_id: str ) -> Tuple[int, JsonDict]: - await assert_requester_is_admin(self.auth, request) + await assert_requester_is_admin(self._auth, request) - room_ids = await self.store.get_rooms_for_user(user_id) + room_ids = await self._store.get_rooms_for_user(user_id) ret = {"joined_rooms": list(room_ids), "total": len(room_ids)} return HTTPStatus.OK, ret @@ -864,22 +864,22 @@ class PushersRestServlet(RestServlet): PATTERNS = admin_patterns("/users/(?P[^/]*)/pushers$") def __init__(self, hs: "HomeServer"): - self.is_mine = hs.is_mine - self.store = hs.get_datastore() - self.auth = hs.get_auth() + self._is_mine = hs.is_mine + self._store = hs.get_datastore() + self._auth = hs.get_auth() async def on_GET( self, request: SynapseRequest, user_id: str ) -> Tuple[int, JsonDict]: - await assert_requester_is_admin(self.auth, request) + await assert_requester_is_admin(self._auth, request) - if not self.is_mine(UserID.from_string(user_id)): + if not self._is_mine(UserID.from_string(user_id)): raise SynapseError(HTTPStatus.BAD_REQUEST, "Can only look up local users") - if not await self.store.get_user_by_id(user_id): + if not await self._store.get_user_by_id(user_id): raise NotFoundError("User not found") - pushers = await self.store.get_pushers_by_user_id(user_id) + pushers = await self._store.get_pushers_by_user_id(user_id) filtered_pushers = [p.as_dict() for p in pushers] @@ -906,19 +906,19 @@ class UserTokenRestServlet(RestServlet): PATTERNS = admin_patterns("/users/(?P[^/]*)/login$") def __init__(self, hs: "HomeServer"): - self.store = hs.get_datastore() - self.auth = hs.get_auth() - self.auth_handler = hs.get_auth_handler() - self.is_mine_id = hs.is_mine_id + self._store = hs.get_datastore() + self._auth = hs.get_auth() + self._auth_handler = hs.get_auth_handler() + self._is_mine_id = hs.is_mine_id async def on_POST( self, request: SynapseRequest, user_id: str ) -> Tuple[int, JsonDict]: - requester = await self.auth.get_user_by_req(request) - await assert_user_is_admin(self.auth, requester.user) + requester = await self._auth.get_user_by_req(request) + await assert_user_is_admin(self._auth, requester.user) auth_user = requester.user - if not self.is_mine_id(user_id): + if not self._is_mine_id(user_id): raise SynapseError( HTTPStatus.BAD_REQUEST, "Only local users can be logged in as" ) @@ -936,7 +936,7 @@ async def on_POST( HTTPStatus.BAD_REQUEST, "Cannot use admin API to login as self" ) - token = await self.auth_handler.create_access_token_for_user_id( + token = await self._auth_handler.create_access_token_for_user_id( user_id=auth_user.to_string(), device_id=None, valid_until_ms=valid_until_ms, @@ -975,35 +975,35 @@ class ShadowBanRestServlet(RestServlet): PATTERNS = admin_patterns("/users/(?P[^/]*)/shadow_ban$") def __init__(self, hs: "HomeServer"): - self.store = hs.get_datastore() - self.auth = hs.get_auth() - self.is_mine_id = hs.is_mine_id + self._store = hs.get_datastore() + self._auth = hs.get_auth() + self._is_mine_id = hs.is_mine_id async def on_POST( self, request: SynapseRequest, user_id: str ) -> Tuple[int, JsonDict]: - await assert_requester_is_admin(self.auth, request) + await assert_requester_is_admin(self._auth, request) - if not self.is_mine_id(user_id): + if not self._is_mine_id(user_id): raise SynapseError( HTTPStatus.BAD_REQUEST, "Only local users can be shadow-banned" ) - await self.store.set_shadow_banned(UserID.from_string(user_id), True) + await self._store.set_shadow_banned(UserID.from_string(user_id), True) return HTTPStatus.OK, {} async def on_DELETE( self, request: SynapseRequest, user_id: str ) -> Tuple[int, JsonDict]: - await assert_requester_is_admin(self.auth, request) + await assert_requester_is_admin(self._auth, request) - if not self.is_mine_id(user_id): + if not self._is_mine_id(user_id): raise SynapseError( HTTPStatus.BAD_REQUEST, "Only local users can be shadow-banned" ) - await self.store.set_shadow_banned(UserID.from_string(user_id), False) + await self._store.set_shadow_banned(UserID.from_string(user_id), False) return HTTPStatus.OK, {} @@ -1027,22 +1027,22 @@ class RateLimitRestServlet(RestServlet): PATTERNS = admin_patterns("/users/(?P[^/]*)/override_ratelimit$") def __init__(self, hs: "HomeServer"): - self.store = hs.get_datastore() - self.auth = hs.get_auth() - self.is_mine_id = hs.is_mine_id + self._store = hs.get_datastore() + self._auth = hs.get_auth() + self._is_mine_id = hs.is_mine_id async def on_GET( self, request: SynapseRequest, user_id: str ) -> Tuple[int, JsonDict]: - await assert_requester_is_admin(self.auth, request) + await assert_requester_is_admin(self._auth, request) - if not self.is_mine_id(user_id): + if not self._is_mine_id(user_id): raise SynapseError(HTTPStatus.BAD_REQUEST, "Can only look up local users") - if not await self.store.get_user_by_id(user_id): + if not await self._store.get_user_by_id(user_id): raise NotFoundError("User not found") - ratelimit = await self.store.get_ratelimit_for_user(user_id) + ratelimit = await self._store.get_ratelimit_for_user(user_id) if ratelimit: # convert `null` to `0` for consistency @@ -1063,14 +1063,14 @@ async def on_GET( async def on_POST( self, request: SynapseRequest, user_id: str ) -> Tuple[int, JsonDict]: - await assert_requester_is_admin(self.auth, request) + await assert_requester_is_admin(self._auth, request) - if not self.is_mine_id(user_id): + if not self._is_mine_id(user_id): raise SynapseError( HTTPStatus.BAD_REQUEST, "Only local users can be ratelimited" ) - if not await self.store.get_user_by_id(user_id): + if not await self._store.get_user_by_id(user_id): raise NotFoundError("User not found") body = parse_json_object_from_request(request, allow_empty_body=True) @@ -1092,10 +1092,10 @@ async def on_POST( errcode=Codes.INVALID_PARAM, ) - await self.store.set_ratelimit_for_user( + await self._store.set_ratelimit_for_user( user_id, messages_per_second, burst_count ) - ratelimit = await self.store.get_ratelimit_for_user(user_id) + ratelimit = await self._store.get_ratelimit_for_user(user_id) assert ratelimit is not None ret = { @@ -1108,16 +1108,46 @@ async def on_POST( async def on_DELETE( self, request: SynapseRequest, user_id: str ) -> Tuple[int, JsonDict]: - await assert_requester_is_admin(self.auth, request) + await assert_requester_is_admin(self._auth, request) - if not self.is_mine_id(user_id): + if not self._is_mine_id(user_id): raise SynapseError( HTTPStatus.BAD_REQUEST, "Only local users can be ratelimited" ) - if not await self.store.get_user_by_id(user_id): + if not await self._store.get_user_by_id(user_id): raise NotFoundError("User not found") - await self.store.delete_ratelimit_for_user(user_id) + await self._store.delete_ratelimit_for_user(user_id) return HTTPStatus.OK, {} + + +class AccountDataRestServlet(RestServlet): + """Retrieve the given user's account data""" + + PATTERNS = admin_patterns("/users/(?P[^/]*)/accountdata") + + def __init__(self, hs: "HomeServer"): + self._auth = hs.get_auth() + self._store = hs.get_datastore() + self._is_mine_id = hs.is_mine_id + + async def on_GET( + self, request: SynapseRequest, user_id: str + ) -> Tuple[int, JsonDict]: + await assert_requester_is_admin(self._auth, request) + + if not self._is_mine_id(user_id): + raise SynapseError(HTTPStatus.BAD_REQUEST, "Can only look up local users") + + if not await self._store.get_user_by_id(user_id): + raise NotFoundError("User not found") + + global_data, by_room_data = await self._store.get_account_data_for_user(user_id) + return HTTPStatus.OK, { + "account_data": { + "global": global_data, + "rooms": by_room_data, + }, + } diff --git a/tests/rest/admin/test_user.py b/tests/rest/admin/test_user.py index eea675991cbc..a6b071a0f75d 100644 --- a/tests/rest/admin/test_user.py +++ b/tests/rest/admin/test_user.py @@ -3883,3 +3883,93 @@ def test_success(self): self.assertEqual(HTTPStatus.OK, channel.code, msg=channel.json_body) self.assertNotIn("messages_per_second", channel.json_body) self.assertNotIn("burst_count", channel.json_body) + + +class AccountDataTestCase(unittest.HomeserverTestCase): + + servlets = [ + synapse.rest.admin.register_servlets, + login.register_servlets, + ] + + def prepare(self, reactor, clock, hs) -> None: + self.store = hs.get_datastore() + + self.admin_user = self.register_user("admin", "pass", admin=True) + self.admin_user_tok = self.login("admin", "pass") + + self.other_user = self.register_user("user", "pass") + self.url = f"/_synapse/admin/v1/users/{self.other_user}/accountdata" + + def test_no_auth(self) -> None: + """Try to get information of a user without authentication.""" + channel = self.make_request("GET", self.url, {}) + + self.assertEqual(HTTPStatus.UNAUTHORIZED, channel.code, msg=channel.json_body) + self.assertEqual(Codes.MISSING_TOKEN, channel.json_body["errcode"]) + + def test_requester_is_no_admin(self) -> None: + """If the user is not a server admin, an error is returned.""" + other_user_token = self.login("user", "pass") + + channel = self.make_request( + "GET", + self.url, + access_token=other_user_token, + ) + + self.assertEqual(HTTPStatus.FORBIDDEN, channel.code, msg=channel.json_body) + self.assertEqual(Codes.FORBIDDEN, channel.json_body["errcode"]) + + def test_user_does_not_exist(self) -> None: + """Tests that a lookup for a user that does not exist returns a 404""" + url = "/_synapse/admin/v1/users/@unknown_person:test/override_ratelimit" + + channel = self.make_request( + "GET", + url, + access_token=self.admin_user_tok, + ) + + self.assertEqual(HTTPStatus.NOT_FOUND, channel.code, msg=channel.json_body) + self.assertEqual(Codes.NOT_FOUND, channel.json_body["errcode"]) + + def test_user_is_not_local(self) -> None: + """Tests that a lookup for a user that is not a local returns a 400""" + url = f"/_synapse/admin/v1/users/@unknown_person:unknown_domain/accountdata" + + channel = self.make_request( + "GET", + url, + access_token=self.admin_user_tok, + ) + + self.assertEqual(HTTPStatus.BAD_REQUEST, channel.code, msg=channel.json_body) + self.assertEqual("Can only look up local users", channel.json_body["error"]) + + def test_success(self) -> None: + """Request account data should succeed for an admin.""" + + # add account data + self.get_success( + self.store.add_account_data_for_user(self.other_user, "m.global", {"a": 1}) + ) + self.get_success( + self.store.add_account_data_to_room( + self.other_user, "test_room", "m.per_room", {"b": 2} + ) + ) + + channel = self.make_request( + "GET", + self.url, + access_token=self.admin_user_tok, + ) + self.assertEqual(HTTPStatus.OK, channel.code, msg=channel.json_body) + self.assertEqual( + {"a": 1}, channel.json_body["account_data"]["global"]["m.global"] + ) + self.assertEqual( + {"b": 2}, + channel.json_body["account_data"]["rooms"]["test_room"]["m.per_room"], + ) From 68f143e25a00ba250911fb036d2fbae3fa305043 Mon Sep 17 00:00:00 2001 From: dklimpel <5740567+dklimpel@users.noreply.github.com> Date: Thu, 30 Dec 2021 13:02:05 +0100 Subject: [PATCH 2/4] fix codestyle --- tests/rest/admin/test_user.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/rest/admin/test_user.py b/tests/rest/admin/test_user.py index a6b071a0f75d..e0b9fe8e91b3 100644 --- a/tests/rest/admin/test_user.py +++ b/tests/rest/admin/test_user.py @@ -3936,7 +3936,7 @@ def test_user_does_not_exist(self) -> None: def test_user_is_not_local(self) -> None: """Tests that a lookup for a user that is not a local returns a 400""" - url = f"/_synapse/admin/v1/users/@unknown_person:unknown_domain/accountdata" + url = "/_synapse/admin/v1/users/@unknown_person:unknown_domain/accountdata" channel = self.make_request( "GET", From 2bf69702c47f228cbf12acceceb2c9300598fcf4 Mon Sep 17 00:00:00 2001 From: dklimpel <5740567+dklimpel@users.noreply.github.com> Date: Thu, 30 Dec 2021 19:11:26 +0100 Subject: [PATCH 3/4] revert rename of private vars --- synapse/rest/admin/users.py | 208 ++++++++++++++++++------------------ 1 file changed, 104 insertions(+), 104 deletions(-) diff --git a/synapse/rest/admin/users.py b/synapse/rest/admin/users.py index 6b9deef5845b..78e795c34764 100644 --- a/synapse/rest/admin/users.py +++ b/synapse/rest/admin/users.py @@ -66,12 +66,12 @@ class UsersRestServletV2(RestServlet): """ def __init__(self, hs: "HomeServer"): - self._store = hs.get_datastore() - self._auth = hs.get_auth() + self.store = hs.get_datastore() + self.auth = hs.get_auth() self.admin_handler = hs.get_admin_handler() async def on_GET(self, request: SynapseRequest) -> Tuple[int, JsonDict]: - await assert_requester_is_admin(self._auth, request) + await assert_requester_is_admin(self.auth, request) start = parse_integer(request, "from", default=0) limit = parse_integer(request, "limit", default=100) @@ -114,7 +114,7 @@ async def on_GET(self, request: SynapseRequest) -> Tuple[int, JsonDict]: direction = parse_string(request, "dir", default="f", allowed_values=("f", "b")) - users, total = await self._store.get_users_paginate( + users, total = await self.store.get_users_paginate( start, limit, user_id, name, guests, deactivated, order_by, direction ) ret = {"users": users, "total": total} @@ -154,10 +154,10 @@ class UserRestServletV2(RestServlet): def __init__(self, hs: "HomeServer"): self.hs = hs - self._auth = hs.get_auth() + self.auth = hs.get_auth() self.admin_handler = hs.get_admin_handler() - self._store = hs.get_datastore() - self._auth_handler = hs.get_auth_handler() + self.store = hs.get_datastore() + self.auth_handler = hs.get_auth_handler() self.profile_handler = hs.get_profile_handler() self.set_password_handler = hs.get_set_password_handler() self.deactivate_account_handler = hs.get_deactivate_account_handler() @@ -167,7 +167,7 @@ def __init__(self, hs: "HomeServer"): async def on_GET( self, request: SynapseRequest, user_id: str ) -> Tuple[int, JsonDict]: - await assert_requester_is_admin(self._auth, request) + await assert_requester_is_admin(self.auth, request) target_user = UserID.from_string(user_id) if not self.hs.is_mine(target_user): @@ -183,8 +183,8 @@ async def on_GET( async def on_PUT( self, request: SynapseRequest, user_id: str ) -> Tuple[int, JsonDict]: - requester = await self._auth.get_user_by_req(request) - await assert_user_is_admin(self._auth, requester.user) + requester = await self.auth.get_user_by_req(request) + await assert_user_is_admin(self.auth, requester.user) target_user = UserID.from_string(user_id) body = parse_json_object_from_request(request) @@ -257,7 +257,7 @@ async def on_PUT( # convert List[Dict[str, Any]] into Set[Tuple[str, str]] cur_threepids = { (threepid["medium"], threepid["address"]) - for threepid in await self._store.user_get_threepids(user_id) + for threepid in await self.store.user_get_threepids(user_id) } add_threepids = new_threepids - cur_threepids del_threepids = cur_threepids - new_threepids @@ -265,7 +265,7 @@ async def on_PUT( # remove old threepids for medium, address in del_threepids: try: - await self._auth_handler.delete_threepid( + await self.auth_handler.delete_threepid( user_id, medium, address, None ) except Exception: @@ -275,13 +275,13 @@ async def on_PUT( # add new threepids current_time = self.hs.get_clock().time_msec() for medium, address in add_threepids: - await self._auth_handler.add_threepid( + await self.auth_handler.add_threepid( user_id, medium, address, current_time ) if external_ids is not None: try: - await self._store.replace_user_external_id( + await self.store.replace_user_external_id( new_external_ids, user_id, ) @@ -303,11 +303,11 @@ async def on_PUT( HTTPStatus.BAD_REQUEST, "You may not demote yourself." ) - await self._store.set_server_admin(target_user, set_admin_to) + await self.store.set_server_admin(target_user, set_admin_to) if password is not None: logout_devices = True - new_password_hash = await self._auth_handler.hash(password) + new_password_hash = await self.auth_handler.hash(password) await self.set_password_handler.set_password( target_user.to_string(), @@ -324,7 +324,7 @@ async def on_PUT( elif not deactivate and user["deactivated"]: if ( "password" not in body - and self._auth_handler.can_change_password() + and self.auth_handler.can_change_password() ): raise SynapseError( HTTPStatus.BAD_REQUEST, @@ -336,7 +336,7 @@ async def on_PUT( ) if "user_type" in body: - await self._store.set_user_type(target_user, user_type) + await self.store.set_user_type(target_user, user_type) user = await self.admin_handler.get_user(target_user) assert user is not None @@ -348,7 +348,7 @@ async def on_PUT( password_hash = None if password is not None: - password_hash = await self._auth_handler.hash(password) + password_hash = await self.auth_handler.hash(password) user_id = await self.registration_handler.register_user( localpart=target_user.localpart, @@ -362,7 +362,7 @@ async def on_PUT( if threepids is not None: current_time = self.hs.get_clock().time_msec() for medium, address in new_threepids: - await self._auth_handler.add_threepid( + await self.auth_handler.add_threepid( user_id, medium, address, current_time ) if ( @@ -384,7 +384,7 @@ async def on_PUT( if external_ids is not None: try: for auth_provider, external_id in new_external_ids: - await self._store.record_user_external_id( + await self.store.record_user_external_id( auth_provider, external_id, user_id, @@ -417,7 +417,7 @@ class UserRegisterServlet(RestServlet): NONCE_TIMEOUT = 60 def __init__(self, hs: "HomeServer"): - self._auth_handler = hs.get_auth_handler() + self.auth_handler = hs.get_auth_handler() self.reactor = hs.get_reactor() self.nonces: Dict[str, int] = {} self.hs = hs @@ -496,7 +496,7 @@ async def on_POST(self, request: SynapseRequest) -> Tuple[int, JsonDict]: if b"\x00" in password_bytes: raise SynapseError(HTTPStatus.BAD_REQUEST, "Invalid password") - password_hash = await self._auth_handler.hash(password) + password_hash = await self.auth_handler.hash(password) admin = body.get("admin", None) user_type = body.get("user_type", None) @@ -560,21 +560,21 @@ class WhoisRestServlet(RestServlet): ] def __init__(self, hs: "HomeServer"): - self._auth = hs.get_auth() + self.auth = hs.get_auth() self.admin_handler = hs.get_admin_handler() - self._is_mine = hs.is_mine + self.is_mine = hs.is_mine async def on_GET( self, request: SynapseRequest, user_id: str ) -> Tuple[int, JsonDict]: 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: - await assert_user_is_admin(self._auth, auth_user) + await assert_user_is_admin(self.auth, auth_user) - 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") ret = await self.admin_handler.get_whois(target_user) @@ -587,22 +587,22 @@ class DeactivateAccountRestServlet(RestServlet): def __init__(self, hs: "HomeServer"): self._deactivate_account_handler = hs.get_deactivate_account_handler() - self._auth = hs.get_auth() - self._is_mine = hs.is_mine - self._store = hs.get_datastore() + self.auth = hs.get_auth() + self.is_mine = hs.is_mine + self.store = hs.get_datastore() async def on_POST( self, request: SynapseRequest, target_user_id: str ) -> Tuple[int, JsonDict]: - requester = await self._auth.get_user_by_req(request) - await assert_user_is_admin(self._auth, requester.user) + requester = await self.auth.get_user_by_req(request) + await assert_user_is_admin(self.auth, requester.user) - if not self._is_mine(UserID.from_string(target_user_id)): + if not self.is_mine(UserID.from_string(target_user_id)): raise SynapseError( HTTPStatus.BAD_REQUEST, "Can only deactivate local users" ) - if not await self._store.get_user_by_id(target_user_id): + if not await self.store.get_user_by_id(target_user_id): raise NotFoundError("User not found") body = parse_json_object_from_request(request, allow_empty_body=True) @@ -630,10 +630,10 @@ class AccountValidityRenewServlet(RestServlet): def __init__(self, hs: "HomeServer"): self.account_activity_handler = hs.get_account_validity_handler() - self._auth = hs.get_auth() + self.auth = hs.get_auth() async def on_POST(self, request: SynapseRequest) -> Tuple[int, JsonDict]: - await assert_requester_is_admin(self._auth, request) + await assert_requester_is_admin(self.auth, request) if self.account_activity_handler.on_legacy_admin_request_callback: expiration_ts = await ( @@ -675,9 +675,9 @@ class ResetPasswordRestServlet(RestServlet): PATTERNS = admin_patterns("/reset_password/(?P[^/]*)$") def __init__(self, hs: "HomeServer"): - self._store = hs.get_datastore() - self._auth = hs.get_auth() - self._auth_handler = hs.get_auth_handler() + self.store = hs.get_datastore() + self.auth = hs.get_auth() + self.auth_handler = hs.get_auth_handler() self._set_password_handler = hs.get_set_password_handler() async def on_POST( @@ -686,8 +686,8 @@ async def on_POST( """Post request to allow an administrator reset password for a user. This needs user to have administrator access in Synapse. """ - requester = await self._auth.get_user_by_req(request) - await assert_user_is_admin(self._auth, requester.user) + requester = await self.auth.get_user_by_req(request) + await assert_user_is_admin(self.auth, requester.user) UserID.from_string(target_user_id) @@ -696,7 +696,7 @@ async def on_POST( new_password = params["new_password"] logout_devices = params.get("logout_devices", True) - new_password_hash = await self._auth_handler.hash(new_password) + new_password_hash = await self.auth_handler.hash(new_password) await self._set_password_handler.set_password( target_user_id, new_password_hash, logout_devices, requester @@ -718,9 +718,9 @@ class SearchUsersRestServlet(RestServlet): PATTERNS = admin_patterns("/search_users/(?P[^/]*)$") def __init__(self, hs: "HomeServer"): - self._store = hs.get_datastore() - self._auth = hs.get_auth() - self._is_mine = hs.is_mine + self.store = hs.get_datastore() + self.auth = hs.get_auth() + self.is_mine = hs.is_mine async def on_GET( self, request: SynapseRequest, target_user_id: str @@ -729,7 +729,7 @@ async def on_GET( search term. This needs user to have a administrator access in Synapse. """ - await assert_requester_is_admin(self._auth, request) + await assert_requester_is_admin(self.auth, request) target_user = UserID.from_string(target_user_id) @@ -737,13 +737,13 @@ async def on_GET( # if not is_admin and target_user != auth_user: # raise AuthError(HTTPStatus.FORBIDDEN, "You are not a server admin") - if not self._is_mine(target_user): + if not self.is_mine(target_user): raise SynapseError(HTTPStatus.BAD_REQUEST, "Can only users a local user") term = parse_string(request, "term", required=True) logger.info("term: %s ", term) - ret = await self._store.search_users(term) + ret = await self.store.search_users(term) return HTTPStatus.OK, ret @@ -776,32 +776,32 @@ class UserAdminServlet(RestServlet): PATTERNS = admin_patterns("/users/(?P[^/]*)/admin$") def __init__(self, hs: "HomeServer"): - self._store = hs.get_datastore() - self._auth = hs.get_auth() - self._is_mine = hs.is_mine + self.store = hs.get_datastore() + self.auth = hs.get_auth() + self.is_mine = hs.is_mine async def on_GET( self, request: SynapseRequest, user_id: str ) -> Tuple[int, JsonDict]: - await assert_requester_is_admin(self._auth, request) + await assert_requester_is_admin(self.auth, request) target_user = UserID.from_string(user_id) - if not self._is_mine(target_user): + if not self.is_mine(target_user): raise SynapseError( HTTPStatus.BAD_REQUEST, "Only local users can be admins of this homeserver", ) - is_admin = await self._store.is_server_admin(target_user) + is_admin = await self.store.is_server_admin(target_user) return HTTPStatus.OK, {"admin": is_admin} async def on_PUT( self, request: SynapseRequest, user_id: str ) -> Tuple[int, JsonDict]: - requester = await self._auth.get_user_by_req(request) - await assert_user_is_admin(self._auth, requester.user) + requester = await self.auth.get_user_by_req(request) + await assert_user_is_admin(self.auth, requester.user) auth_user = requester.user target_user = UserID.from_string(user_id) @@ -810,7 +810,7 @@ async def on_PUT( assert_params_in_dict(body, ["admin"]) - if not self._is_mine(target_user): + if not self.is_mine(target_user): raise SynapseError( HTTPStatus.BAD_REQUEST, "Only local users can be admins of this homeserver", @@ -821,7 +821,7 @@ async def on_PUT( if target_user == auth_user and not set_admin_to: raise SynapseError(HTTPStatus.BAD_REQUEST, "You may not demote yourself.") - await self._store.set_server_admin(target_user, set_admin_to) + await self.store.set_server_admin(target_user, set_admin_to) return HTTPStatus.OK, {} @@ -834,16 +834,16 @@ class UserMembershipRestServlet(RestServlet): PATTERNS = admin_patterns("/users/(?P[^/]*)/joined_rooms$") def __init__(self, hs: "HomeServer"): - self._is_mine = hs.is_mine - self._auth = hs.get_auth() - self._store = hs.get_datastore() + self.is_mine = hs.is_mine + self.auth = hs.get_auth() + self.store = hs.get_datastore() async def on_GET( self, request: SynapseRequest, user_id: str ) -> Tuple[int, JsonDict]: - await assert_requester_is_admin(self._auth, request) + await assert_requester_is_admin(self.auth, request) - room_ids = await self._store.get_rooms_for_user(user_id) + room_ids = await self.store.get_rooms_for_user(user_id) ret = {"joined_rooms": list(room_ids), "total": len(room_ids)} return HTTPStatus.OK, ret @@ -864,22 +864,22 @@ class PushersRestServlet(RestServlet): PATTERNS = admin_patterns("/users/(?P[^/]*)/pushers$") def __init__(self, hs: "HomeServer"): - self._is_mine = hs.is_mine - self._store = hs.get_datastore() - self._auth = hs.get_auth() + self.is_mine = hs.is_mine + self.store = hs.get_datastore() + self.auth = hs.get_auth() async def on_GET( self, request: SynapseRequest, user_id: str ) -> Tuple[int, JsonDict]: - await assert_requester_is_admin(self._auth, request) + await assert_requester_is_admin(self.auth, request) - if not self._is_mine(UserID.from_string(user_id)): + if not self.is_mine(UserID.from_string(user_id)): raise SynapseError(HTTPStatus.BAD_REQUEST, "Can only look up local users") - if not await self._store.get_user_by_id(user_id): + if not await self.store.get_user_by_id(user_id): raise NotFoundError("User not found") - pushers = await self._store.get_pushers_by_user_id(user_id) + pushers = await self.store.get_pushers_by_user_id(user_id) filtered_pushers = [p.as_dict() for p in pushers] @@ -906,19 +906,19 @@ class UserTokenRestServlet(RestServlet): PATTERNS = admin_patterns("/users/(?P[^/]*)/login$") def __init__(self, hs: "HomeServer"): - self._store = hs.get_datastore() - self._auth = hs.get_auth() - self._auth_handler = hs.get_auth_handler() - self._is_mine_id = hs.is_mine_id + self.store = hs.get_datastore() + self.auth = hs.get_auth() + self.auth_handler = hs.get_auth_handler() + self.is_mine_id = hs.is_mine_id async def on_POST( self, request: SynapseRequest, user_id: str ) -> Tuple[int, JsonDict]: - requester = await self._auth.get_user_by_req(request) - await assert_user_is_admin(self._auth, requester.user) + requester = await self.auth.get_user_by_req(request) + await assert_user_is_admin(self.auth, requester.user) auth_user = requester.user - if not self._is_mine_id(user_id): + if not self.is_mine_id(user_id): raise SynapseError( HTTPStatus.BAD_REQUEST, "Only local users can be logged in as" ) @@ -936,7 +936,7 @@ async def on_POST( HTTPStatus.BAD_REQUEST, "Cannot use admin API to login as self" ) - token = await self._auth_handler.create_access_token_for_user_id( + token = await self.auth_handler.create_access_token_for_user_id( user_id=auth_user.to_string(), device_id=None, valid_until_ms=valid_until_ms, @@ -975,35 +975,35 @@ class ShadowBanRestServlet(RestServlet): PATTERNS = admin_patterns("/users/(?P[^/]*)/shadow_ban$") def __init__(self, hs: "HomeServer"): - self._store = hs.get_datastore() - self._auth = hs.get_auth() - self._is_mine_id = hs.is_mine_id + self.store = hs.get_datastore() + self.auth = hs.get_auth() + self.is_mine_id = hs.is_mine_id async def on_POST( self, request: SynapseRequest, user_id: str ) -> Tuple[int, JsonDict]: - await assert_requester_is_admin(self._auth, request) + await assert_requester_is_admin(self.auth, request) - if not self._is_mine_id(user_id): + if not self.is_mine_id(user_id): raise SynapseError( HTTPStatus.BAD_REQUEST, "Only local users can be shadow-banned" ) - await self._store.set_shadow_banned(UserID.from_string(user_id), True) + await self.store.set_shadow_banned(UserID.from_string(user_id), True) return HTTPStatus.OK, {} async def on_DELETE( self, request: SynapseRequest, user_id: str ) -> Tuple[int, JsonDict]: - await assert_requester_is_admin(self._auth, request) + await assert_requester_is_admin(self.auth, request) - if not self._is_mine_id(user_id): + if not self.is_mine_id(user_id): raise SynapseError( HTTPStatus.BAD_REQUEST, "Only local users can be shadow-banned" ) - await self._store.set_shadow_banned(UserID.from_string(user_id), False) + await self.store.set_shadow_banned(UserID.from_string(user_id), False) return HTTPStatus.OK, {} @@ -1027,22 +1027,22 @@ class RateLimitRestServlet(RestServlet): PATTERNS = admin_patterns("/users/(?P[^/]*)/override_ratelimit$") def __init__(self, hs: "HomeServer"): - self._store = hs.get_datastore() - self._auth = hs.get_auth() - self._is_mine_id = hs.is_mine_id + self.store = hs.get_datastore() + self.auth = hs.get_auth() + self.is_mine_id = hs.is_mine_id async def on_GET( self, request: SynapseRequest, user_id: str ) -> Tuple[int, JsonDict]: - await assert_requester_is_admin(self._auth, request) + await assert_requester_is_admin(self.auth, request) - if not self._is_mine_id(user_id): + if not self.is_mine_id(user_id): raise SynapseError(HTTPStatus.BAD_REQUEST, "Can only look up local users") - if not await self._store.get_user_by_id(user_id): + if not await self.store.get_user_by_id(user_id): raise NotFoundError("User not found") - ratelimit = await self._store.get_ratelimit_for_user(user_id) + ratelimit = await self.store.get_ratelimit_for_user(user_id) if ratelimit: # convert `null` to `0` for consistency @@ -1063,14 +1063,14 @@ async def on_GET( async def on_POST( self, request: SynapseRequest, user_id: str ) -> Tuple[int, JsonDict]: - await assert_requester_is_admin(self._auth, request) + await assert_requester_is_admin(self.auth, request) - if not self._is_mine_id(user_id): + if not self.is_mine_id(user_id): raise SynapseError( HTTPStatus.BAD_REQUEST, "Only local users can be ratelimited" ) - if not await self._store.get_user_by_id(user_id): + if not await self.store.get_user_by_id(user_id): raise NotFoundError("User not found") body = parse_json_object_from_request(request, allow_empty_body=True) @@ -1092,10 +1092,10 @@ async def on_POST( errcode=Codes.INVALID_PARAM, ) - await self._store.set_ratelimit_for_user( + await self.store.set_ratelimit_for_user( user_id, messages_per_second, burst_count ) - ratelimit = await self._store.get_ratelimit_for_user(user_id) + ratelimit = await self.store.get_ratelimit_for_user(user_id) assert ratelimit is not None ret = { @@ -1108,17 +1108,17 @@ async def on_POST( async def on_DELETE( self, request: SynapseRequest, user_id: str ) -> Tuple[int, JsonDict]: - await assert_requester_is_admin(self._auth, request) + await assert_requester_is_admin(self.auth, request) - if not self._is_mine_id(user_id): + if not self.is_mine_id(user_id): raise SynapseError( HTTPStatus.BAD_REQUEST, "Only local users can be ratelimited" ) - if not await self._store.get_user_by_id(user_id): + if not await self.store.get_user_by_id(user_id): raise NotFoundError("User not found") - await self._store.delete_ratelimit_for_user(user_id) + await self.store.delete_ratelimit_for_user(user_id) return HTTPStatus.OK, {} From 0466a9835e2bc24391b847aa264267818d5d53d2 Mon Sep 17 00:00:00 2001 From: Dirk Klimpel <5740567+dklimpel@users.noreply.github.com> Date: Fri, 31 Dec 2021 19:15:04 +0100 Subject: [PATCH 4/4] Update docs/admin_api/user_admin_api.md Co-authored-by: reivilibre --- docs/admin_api/user_admin_api.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/admin_api/user_admin_api.md b/docs/admin_api/user_admin_api.md index b8a46a51afcf..74933d2fcf0e 100644 --- a/docs/admin_api/user_admin_api.md +++ b/docs/admin_api/user_admin_api.md @@ -551,9 +551,9 @@ The following parameters should be set in the URL: The following fields are returned in the JSON response body: -- `account_data` - An array containing the account data for the user - - `global` - An array containing the global account data for the user - - `rooms` - An array containing the account data per room for the user +- `account_data` - A map containing the account data for the user + - `global` - A map containing the global account data for the user + - `rooms` - A map containing the account data per room for the user ## User media