From 628e84dd8d77cd1a792db9e010c670a345244cbe Mon Sep 17 00:00:00 2001 From: Erik Johnston Date: Tue, 17 Nov 2020 10:24:39 +0000 Subject: [PATCH] Fixup --- synapse/rest/admin/__init__.py | 2 ++ synapse/rest/admin/rooms.py | 63 +++++++++++++++++++++++++++------- 2 files changed, 53 insertions(+), 12 deletions(-) diff --git a/synapse/rest/admin/__init__.py b/synapse/rest/admin/__init__.py index 2a4f7a1740..afb7a2fbfe 100644 --- a/synapse/rest/admin/__init__.py +++ b/synapse/rest/admin/__init__.py @@ -42,6 +42,7 @@ from synapse.rest.admin.rooms import ( DeleteRoomRestServlet, JoinRoomAliasServlet, ListRoomRestServlet, + MakeRoomAdminRoomServlet, RoomMembersRestServlet, RoomRestServlet, ShutdownRoomRestServlet, @@ -232,6 +233,7 @@ def register_servlets(hs, http_server): EventReportDetailRestServlet(hs).register(http_server) EventReportsRestServlet(hs).register(http_server) PushersRestServlet(hs).register(http_server) + MakeRoomAdminRoomServlet(hs).register(http_server) def register_servlets_for_client_rest_resource(hs, http_server): diff --git a/synapse/rest/admin/rooms.py b/synapse/rest/admin/rooms.py index 40891f9226..b07172aa26 100644 --- a/synapse/rest/admin/rooms.py +++ b/synapse/rest/admin/rooms.py @@ -17,7 +17,7 @@ from http import HTTPStatus from typing import TYPE_CHECKING, List, Optional from synapse.api.constants import EventTypes, JoinRules, Membership -from synapse.api.errors import Codes, NotFoundError, SynapseError +from synapse.api.errors import AuthError, Codes, NotFoundError, SynapseError from synapse.http.servlet import ( RestServlet, assert_params_in_dict, @@ -344,6 +344,17 @@ class JoinRoomAliasServlet(RestServlet): class MakeRoomAdminRoomServlet(RestServlet): + """Allows a server admin to get power in a room if a local user has power in + a room. Will also invite the user if they're not in the room and its a + private room. Can specify another user (rather than the admin user) to be + granted power, e.g.: + + POST /_synapse/admin/v1/make_room_admin/ + { + "user_id": "@foo:example.com" + } + """ + PATTERNS = admin_patterns("/make_room_admin/(?P[^/]*)") def __init__(self, hs: "HomeServer"): @@ -359,6 +370,7 @@ class MakeRoomAdminRoomServlet(RestServlet): await assert_user_is_admin(self.auth, requester.user) content = parse_json_object_from_request(request, allow_empty_body=True) + # Resolve to a room ID, if necessary. if RoomID.is_valid(room_identifier): room_id = room_identifier elif RoomAlias.is_valid(room_identifier): @@ -370,10 +382,11 @@ class MakeRoomAdminRoomServlet(RestServlet): 400, "%s was not legal room ID or room alias" % (room_identifier,) ) + # Which user to grant room admin rights to. user_to_add = content.get("user_id", requester.user.to_string()) + # Figure out which local users currently have power in the room, if any. room_state = await self.state_handler.get_current_state(room_id) - if not room_state: raise SynapseError(400, "Server not in room") @@ -381,33 +394,59 @@ class MakeRoomAdminRoomServlet(RestServlet): power_levels = room_state.get((EventTypes.PowerLevels, "")) if power_levels is not None: + # We pick the local user with the highest power. + user_power = power_levels.content.get("users", {}) admin_users = [ user_id - for user_id, power in power_levels.content.get("users") + for user_id, power in user_power.items() if self.is_mine_id(user_id) ] - admin_users.sort(key=lambda user: power_levels.content.get("users")[user]) + admin_users.sort(key=lambda user: user_power[user]) + + if not admin_users: + raise SynapseError(400, "No local admin user in room") admin_user_id = admin_users[-1] pl_content = power_levels.content else: + # If there is no power level events then the creator has rights. + pl_content = {} admin_user_id = create_event.sender if not self.is_mine_id(admin_user_id): - raise SynapseError(400, "No local admin user in room") + raise SynapseError( + 400, "No local admin user in room", + ) + + # Grant the user power equal to the room admin by attempting to send an + # updated power level event. + new_pl_content = dict(pl_content) + new_pl_content["users"] = dict(pl_content.get("users", {})) + new_pl_content["users"][user_to_add] = new_pl_content["users"][admin_user_id] fake_requester = create_requester( admin_user_id, authenticated_entity=requester.authenticated_entity, ) - new_pl_content = dict(pl_content) - new_pl_content["users"] = dict(pl_content.get("users", {})) - new_pl_content["users"][user_to_add] = new_pl_content["users"][admin_user_id] - - await self.event_creation_handler.create_and_send_nonmember_event( - fake_requester, event_dict=new_pl_content, - ) + try: + await self.event_creation_handler.create_and_send_nonmember_event( + fake_requester, + event_dict={ + "content": new_pl_content, + "sender": admin_user_id, + "type": EventTypes.PowerLevels, + "state_key": "", + "room_id": room_id, + }, + ) + except AuthError: + # The admin user we found turned out not to have enough power. + raise SynapseError( + 400, "No local admin user in room with power to update power levels." + ) + # Now we check if the user we're granting admin rights to is already in + # the room. If not and its not a public room we invite them. member_event = room_state.get((EventTypes.Member, user_to_add)) is_joined = False if member_event: