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

Commit

Permalink
Add dedicated admin API for blocking a room (#11324)
Browse files Browse the repository at this point in the history
  • Loading branch information
dklimpel authored Nov 18, 2021
1 parent 5f81c0c commit 81b18fe
Show file tree
Hide file tree
Showing 6 changed files with 404 additions and 0 deletions.
1 change: 1 addition & 0 deletions changelog.d/11324.feature
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Add dedicated admin API for blocking a room.
78 changes: 78 additions & 0 deletions docs/admin_api/rooms.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
- [Room Details API](#room-details-api)
- [Room Members API](#room-members-api)
- [Room State API](#room-state-api)
- [Block Room API](#block-room-api)
- [Delete Room API](#delete-room-api)
* [Version 1 (old version)](#version-1-old-version)
* [Version 2 (new version)](#version-2-new-version)
Expand Down Expand Up @@ -386,6 +387,83 @@ A response body like the following is returned:
}
```

# Block Room API
The Block Room admin API allows server admins to block and unblock rooms,
and query to see if a given room is blocked.
This API can be used to pre-emptively block a room, even if it's unknown to this
homeserver. Users will be prevented from joining a blocked room.

## Block or unblock a room

The API is:

```
PUT /_synapse/admin/v1/rooms/<room_id>/block
```

with a body of:

```json
{
"block": true
}
```

A response body like the following is returned:

```json
{
"block": true
}
```

**Parameters**

The following parameters should be set in the URL:

- `room_id` - The ID of the room.

The following JSON body parameters are available:

- `block` - If `true` the room will be blocked and if `false` the room will be unblocked.

**Response**

The following fields are possible in the JSON response body:

- `block` - A boolean. `true` if the room is blocked, otherwise `false`

## Get block status

The API is:

```
GET /_synapse/admin/v1/rooms/<room_id>/block
```

A response body like the following is returned:

```json
{
"block": true,
"user_id": "<user_id>"
}
```

**Parameters**

The following parameters should be set in the URL:

- `room_id` - The ID of the room.

**Response**

The following fields are possible in the JSON response body:

- `block` - A boolean. `true` if the room is blocked, otherwise `false`
- `user_id` - An optional string. If the room is blocked (`block` is `true`) shows
the user who has add the room to blocking list. Otherwise it is not displayed.

# Delete Room API

The Delete Room admin API allows server admins to remove rooms from the server
Expand Down
2 changes: 2 additions & 0 deletions synapse/rest/admin/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@
RegistrationTokenRestServlet,
)
from synapse.rest.admin.rooms import (
BlockRoomRestServlet,
DeleteRoomStatusByDeleteIdRestServlet,
DeleteRoomStatusByRoomIdRestServlet,
ForwardExtremitiesRestServlet,
Expand Down Expand Up @@ -223,6 +224,7 @@ def register_servlets(hs: "HomeServer", http_server: HttpServer) -> None:
Register all the admin servlets.
"""
register_servlets_for_client_rest_resource(hs, http_server)
BlockRoomRestServlet(hs).register(http_server)
ListRoomRestServlet(hs).register(http_server)
RoomStateRestServlet(hs).register(http_server)
RoomRestServlet(hs).register(http_server)
Expand Down
63 changes: 63 additions & 0 deletions synapse/rest/admin/rooms.py
Original file line number Diff line number Diff line change
Expand Up @@ -782,3 +782,66 @@ async def on_GET(
)

return 200, results


class BlockRoomRestServlet(RestServlet):
"""
Manage blocking of rooms.
On PUT: Add or remove a room from blocking list.
On GET: Get blocking status of room and user who has blocked this room.
"""

PATTERNS = admin_patterns("/rooms/(?P<room_id>[^/]+)/block$")

def __init__(self, hs: "HomeServer"):
self._auth = hs.get_auth()
self._store = hs.get_datastore()

async def on_GET(
self, request: SynapseRequest, room_id: str
) -> Tuple[int, JsonDict]:
await assert_requester_is_admin(self._auth, request)

if not RoomID.is_valid(room_id):
raise SynapseError(
HTTPStatus.BAD_REQUEST, "%s is not a legal room ID" % (room_id,)
)

blocked_by = await self._store.room_is_blocked_by(room_id)
# Test `not None` if `user_id` is an empty string
# if someone add manually an entry in database
if blocked_by is not None:
response = {"block": True, "user_id": blocked_by}
else:
response = {"block": False}

return HTTPStatus.OK, response

async def on_PUT(
self, request: SynapseRequest, room_id: str
) -> Tuple[int, JsonDict]:
requester = await self._auth.get_user_by_req(request)
await assert_user_is_admin(self._auth, requester.user)

content = parse_json_object_from_request(request)

if not RoomID.is_valid(room_id):
raise SynapseError(
HTTPStatus.BAD_REQUEST, "%s is not a legal room ID" % (room_id,)
)

assert_params_in_dict(content, ["block"])
block = content.get("block")
if not isinstance(block, bool):
raise SynapseError(
HTTPStatus.BAD_REQUEST,
"Param 'block' must be a boolean.",
Codes.BAD_JSON,
)

if block:
await self._store.block_room(room_id, requester.user.to_string())
else:
await self._store.unblock_room(room_id)

return HTTPStatus.OK, {"block": block}
32 changes: 32 additions & 0 deletions synapse/storage/databases/main/room.py
Original file line number Diff line number Diff line change
Expand Up @@ -397,6 +397,20 @@ async def is_room_blocked(self, room_id: str) -> Optional[bool]:
desc="is_room_blocked",
)

async def room_is_blocked_by(self, room_id: str) -> Optional[str]:
"""
Function to retrieve user who has blocked the room.
user_id is non-nullable
It returns None if the room is not blocked.
"""
return await self.db_pool.simple_select_one_onecol(
table="blocked_rooms",
keyvalues={"room_id": room_id},
retcol="user_id",
allow_none=True,
desc="room_is_blocked_by",
)

async def get_rooms_paginate(
self,
start: int,
Expand Down Expand Up @@ -1775,3 +1789,21 @@ async def block_room(self, room_id: str, user_id: str) -> None:
self.is_room_blocked,
(room_id,),
)

async def unblock_room(self, room_id: str) -> None:
"""Remove the room from blocking list.
Args:
room_id: Room to unblock
"""
await self.db_pool.simple_delete(
table="blocked_rooms",
keyvalues={"room_id": room_id},
desc="unblock_room",
)
await self.db_pool.runInteraction(
"block_room_invalidation",
self._invalidate_cache_and_stream,
self.is_room_blocked,
(room_id,),
)
Loading

0 comments on commit 81b18fe

Please sign in to comment.