Skip to content
This repository was archived by the owner on Apr 26, 2024. It is now read-only.

Commit 81b18fe

Browse files
authored
Add dedicated admin API for blocking a room (#11324)
1 parent 5f81c0c commit 81b18fe

File tree

6 files changed

+404
-0
lines changed

6 files changed

+404
-0
lines changed

changelog.d/11324.feature

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Add dedicated admin API for blocking a room.

docs/admin_api/rooms.md

+78
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
- [Room Details API](#room-details-api)
44
- [Room Members API](#room-members-api)
55
- [Room State API](#room-state-api)
6+
- [Block Room API](#block-room-api)
67
- [Delete Room API](#delete-room-api)
78
* [Version 1 (old version)](#version-1-old-version)
89
* [Version 2 (new version)](#version-2-new-version)
@@ -386,6 +387,83 @@ A response body like the following is returned:
386387
}
387388
```
388389

390+
# Block Room API
391+
The Block Room admin API allows server admins to block and unblock rooms,
392+
and query to see if a given room is blocked.
393+
This API can be used to pre-emptively block a room, even if it's unknown to this
394+
homeserver. Users will be prevented from joining a blocked room.
395+
396+
## Block or unblock a room
397+
398+
The API is:
399+
400+
```
401+
PUT /_synapse/admin/v1/rooms/<room_id>/block
402+
```
403+
404+
with a body of:
405+
406+
```json
407+
{
408+
"block": true
409+
}
410+
```
411+
412+
A response body like the following is returned:
413+
414+
```json
415+
{
416+
"block": true
417+
}
418+
```
419+
420+
**Parameters**
421+
422+
The following parameters should be set in the URL:
423+
424+
- `room_id` - The ID of the room.
425+
426+
The following JSON body parameters are available:
427+
428+
- `block` - If `true` the room will be blocked and if `false` the room will be unblocked.
429+
430+
**Response**
431+
432+
The following fields are possible in the JSON response body:
433+
434+
- `block` - A boolean. `true` if the room is blocked, otherwise `false`
435+
436+
## Get block status
437+
438+
The API is:
439+
440+
```
441+
GET /_synapse/admin/v1/rooms/<room_id>/block
442+
```
443+
444+
A response body like the following is returned:
445+
446+
```json
447+
{
448+
"block": true,
449+
"user_id": "<user_id>"
450+
}
451+
```
452+
453+
**Parameters**
454+
455+
The following parameters should be set in the URL:
456+
457+
- `room_id` - The ID of the room.
458+
459+
**Response**
460+
461+
The following fields are possible in the JSON response body:
462+
463+
- `block` - A boolean. `true` if the room is blocked, otherwise `false`
464+
- `user_id` - An optional string. If the room is blocked (`block` is `true`) shows
465+
the user who has add the room to blocking list. Otherwise it is not displayed.
466+
389467
# Delete Room API
390468

391469
The Delete Room admin API allows server admins to remove rooms from the server

synapse/rest/admin/__init__.py

+2
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@
4646
RegistrationTokenRestServlet,
4747
)
4848
from synapse.rest.admin.rooms import (
49+
BlockRoomRestServlet,
4950
DeleteRoomStatusByDeleteIdRestServlet,
5051
DeleteRoomStatusByRoomIdRestServlet,
5152
ForwardExtremitiesRestServlet,
@@ -223,6 +224,7 @@ def register_servlets(hs: "HomeServer", http_server: HttpServer) -> None:
223224
Register all the admin servlets.
224225
"""
225226
register_servlets_for_client_rest_resource(hs, http_server)
227+
BlockRoomRestServlet(hs).register(http_server)
226228
ListRoomRestServlet(hs).register(http_server)
227229
RoomStateRestServlet(hs).register(http_server)
228230
RoomRestServlet(hs).register(http_server)

synapse/rest/admin/rooms.py

+63
Original file line numberDiff line numberDiff line change
@@ -782,3 +782,66 @@ async def on_GET(
782782
)
783783

784784
return 200, results
785+
786+
787+
class BlockRoomRestServlet(RestServlet):
788+
"""
789+
Manage blocking of rooms.
790+
On PUT: Add or remove a room from blocking list.
791+
On GET: Get blocking status of room and user who has blocked this room.
792+
"""
793+
794+
PATTERNS = admin_patterns("/rooms/(?P<room_id>[^/]+)/block$")
795+
796+
def __init__(self, hs: "HomeServer"):
797+
self._auth = hs.get_auth()
798+
self._store = hs.get_datastore()
799+
800+
async def on_GET(
801+
self, request: SynapseRequest, room_id: str
802+
) -> Tuple[int, JsonDict]:
803+
await assert_requester_is_admin(self._auth, request)
804+
805+
if not RoomID.is_valid(room_id):
806+
raise SynapseError(
807+
HTTPStatus.BAD_REQUEST, "%s is not a legal room ID" % (room_id,)
808+
)
809+
810+
blocked_by = await self._store.room_is_blocked_by(room_id)
811+
# Test `not None` if `user_id` is an empty string
812+
# if someone add manually an entry in database
813+
if blocked_by is not None:
814+
response = {"block": True, "user_id": blocked_by}
815+
else:
816+
response = {"block": False}
817+
818+
return HTTPStatus.OK, response
819+
820+
async def on_PUT(
821+
self, request: SynapseRequest, room_id: str
822+
) -> Tuple[int, JsonDict]:
823+
requester = await self._auth.get_user_by_req(request)
824+
await assert_user_is_admin(self._auth, requester.user)
825+
826+
content = parse_json_object_from_request(request)
827+
828+
if not RoomID.is_valid(room_id):
829+
raise SynapseError(
830+
HTTPStatus.BAD_REQUEST, "%s is not a legal room ID" % (room_id,)
831+
)
832+
833+
assert_params_in_dict(content, ["block"])
834+
block = content.get("block")
835+
if not isinstance(block, bool):
836+
raise SynapseError(
837+
HTTPStatus.BAD_REQUEST,
838+
"Param 'block' must be a boolean.",
839+
Codes.BAD_JSON,
840+
)
841+
842+
if block:
843+
await self._store.block_room(room_id, requester.user.to_string())
844+
else:
845+
await self._store.unblock_room(room_id)
846+
847+
return HTTPStatus.OK, {"block": block}

synapse/storage/databases/main/room.py

+32
Original file line numberDiff line numberDiff line change
@@ -397,6 +397,20 @@ async def is_room_blocked(self, room_id: str) -> Optional[bool]:
397397
desc="is_room_blocked",
398398
)
399399

400+
async def room_is_blocked_by(self, room_id: str) -> Optional[str]:
401+
"""
402+
Function to retrieve user who has blocked the room.
403+
user_id is non-nullable
404+
It returns None if the room is not blocked.
405+
"""
406+
return await self.db_pool.simple_select_one_onecol(
407+
table="blocked_rooms",
408+
keyvalues={"room_id": room_id},
409+
retcol="user_id",
410+
allow_none=True,
411+
desc="room_is_blocked_by",
412+
)
413+
400414
async def get_rooms_paginate(
401415
self,
402416
start: int,
@@ -1775,3 +1789,21 @@ async def block_room(self, room_id: str, user_id: str) -> None:
17751789
self.is_room_blocked,
17761790
(room_id,),
17771791
)
1792+
1793+
async def unblock_room(self, room_id: str) -> None:
1794+
"""Remove the room from blocking list.
1795+
1796+
Args:
1797+
room_id: Room to unblock
1798+
"""
1799+
await self.db_pool.simple_delete(
1800+
table="blocked_rooms",
1801+
keyvalues={"room_id": room_id},
1802+
desc="unblock_room",
1803+
)
1804+
await self.db_pool.runInteraction(
1805+
"block_room_invalidation",
1806+
self._invalidate_cache_and_stream,
1807+
self.is_room_blocked,
1808+
(room_id,),
1809+
)

0 commit comments

Comments
 (0)