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

Commit ccce8cd

Browse files
author
David Robertson
authored
Use Pydantic when PUTting room aliases (#14179)
1 parent 2c2c3f8 commit ccce8cd

File tree

3 files changed

+47
-31
lines changed

3 files changed

+47
-31
lines changed

changelog.d/14179.feature

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Improve the validation of the following PUT endpoints: [`/directory/room/{roomAlias}`](https://spec.matrix.org/v1.4/client-server-api/#put_matrixclientv3directoryroomroomalias), [`/directory/list/room/{roomId}`](https://spec.matrix.org/v1.4/client-server-api/#put_matrixclientv3directorylistroomroomid) and [`/directory/list/appservice/{networkId}/{roomId}`](https://spec.matrix.org/v1.4/application-service-api/#put_matrixclientv3directorylistappservicenetworkidroomid).

synapse/handlers/directory.py

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@
1616
import string
1717
from typing import TYPE_CHECKING, Iterable, List, Optional
1818

19+
from typing_extensions import Literal
20+
1921
from synapse.api.constants import MAX_ALIAS_LENGTH, EventTypes
2022
from synapse.api.errors import (
2123
AuthError,
@@ -429,7 +431,10 @@ async def _user_can_delete_alias(
429431
return await self.auth.check_can_change_room_list(room_id, requester)
430432

431433
async def edit_published_room_list(
432-
self, requester: Requester, room_id: str, visibility: str
434+
self,
435+
requester: Requester,
436+
room_id: str,
437+
visibility: Literal["public", "private"],
433438
) -> None:
434439
"""Edit the entry of the room in the published room list.
435440
@@ -451,9 +456,6 @@ async def edit_published_room_list(
451456
if requester.is_guest:
452457
raise AuthError(403, "Guests cannot edit the published room list")
453458

454-
if visibility not in ["public", "private"]:
455-
raise SynapseError(400, "Invalid visibility setting")
456-
457459
if visibility == "public" and not self.enable_room_list_search:
458460
# The room list has been disabled.
459461
raise AuthError(
@@ -505,7 +507,11 @@ async def edit_published_room_list(
505507
await self.store.set_room_is_public(room_id, making_public)
506508

507509
async def edit_published_appservice_room_list(
508-
self, appservice_id: str, network_id: str, room_id: str, visibility: str
510+
self,
511+
appservice_id: str,
512+
network_id: str,
513+
room_id: str,
514+
visibility: Literal["public", "private"],
509515
) -> None:
510516
"""Add or remove a room from the appservice/network specific public
511517
room list.
@@ -516,9 +522,6 @@ async def edit_published_appservice_room_list(
516522
room_id
517523
visibility: either "public" or "private"
518524
"""
519-
if visibility not in ["public", "private"]:
520-
raise SynapseError(400, "Invalid visibility setting")
521-
522525
await self.store.set_room_is_public_appservice(
523526
room_id, appservice_id, network_id, visibility == "public"
524527
)

synapse/rest/client/directory.py

Lines changed: 35 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -13,15 +13,22 @@
1313
# limitations under the License.
1414

1515
import logging
16-
from typing import TYPE_CHECKING, Tuple
16+
from typing import TYPE_CHECKING, List, Optional, Tuple
17+
18+
from pydantic import StrictStr
19+
from typing_extensions import Literal
1720

1821
from twisted.web.server import Request
1922

2023
from synapse.api.errors import AuthError, Codes, NotFoundError, SynapseError
2124
from synapse.http.server import HttpServer
22-
from synapse.http.servlet import RestServlet, parse_json_object_from_request
25+
from synapse.http.servlet import (
26+
RestServlet,
27+
parse_and_validate_json_object_from_request,
28+
)
2329
from synapse.http.site import SynapseRequest
2430
from synapse.rest.client._base import client_patterns
31+
from synapse.rest.models import RequestBodyModel
2532
from synapse.types import JsonDict, RoomAlias
2633

2734
if TYPE_CHECKING:
@@ -54,38 +61,35 @@ async def on_GET(self, request: Request, room_alias: str) -> Tuple[int, JsonDict
5461

5562
return 200, res
5663

64+
class PutBody(RequestBodyModel):
65+
# TODO: get Pydantic to validate that this is a valid room id?
66+
room_id: StrictStr
67+
# `servers` is unspecced
68+
servers: Optional[List[StrictStr]] = None
69+
5770
async def on_PUT(
5871
self, request: SynapseRequest, room_alias: str
5972
) -> Tuple[int, JsonDict]:
6073
if not RoomAlias.is_valid(room_alias):
6174
raise SynapseError(400, "Room alias invalid", errcode=Codes.INVALID_PARAM)
6275
room_alias_obj = RoomAlias.from_string(room_alias)
6376

64-
content = parse_json_object_from_request(request)
65-
if "room_id" not in content:
66-
raise SynapseError(
67-
400, 'Missing params: ["room_id"]', errcode=Codes.BAD_JSON
68-
)
77+
content = parse_and_validate_json_object_from_request(request, self.PutBody)
6978

7079
logger.debug("Got content: %s", content)
7180
logger.debug("Got room name: %s", room_alias_obj.to_string())
7281

73-
room_id = content["room_id"]
74-
servers = content["servers"] if "servers" in content else None
75-
76-
logger.debug("Got room_id: %s", room_id)
77-
logger.debug("Got servers: %s", servers)
82+
logger.debug("Got room_id: %s", content.room_id)
83+
logger.debug("Got servers: %s", content.servers)
7884

79-
# TODO(erikj): Check types.
80-
81-
room = await self.store.get_room(room_id)
85+
room = await self.store.get_room(content.room_id)
8286
if room is None:
8387
raise SynapseError(400, "Room does not exist")
8488

8589
requester = await self.auth.get_user_by_req(request)
8690

8791
await self.directory_handler.create_association(
88-
requester, room_alias_obj, room_id, servers
92+
requester, room_alias_obj, content.room_id, content.servers
8993
)
9094

9195
return 200, {}
@@ -137,16 +141,18 @@ async def on_GET(self, request: Request, room_id: str) -> Tuple[int, JsonDict]:
137141

138142
return 200, {"visibility": "public" if room["is_public"] else "private"}
139143

144+
class PutBody(RequestBodyModel):
145+
visibility: Literal["public", "private"] = "public"
146+
140147
async def on_PUT(
141148
self, request: SynapseRequest, room_id: str
142149
) -> Tuple[int, JsonDict]:
143150
requester = await self.auth.get_user_by_req(request)
144151

145-
content = parse_json_object_from_request(request)
146-
visibility = content.get("visibility", "public")
152+
content = parse_and_validate_json_object_from_request(request, self.PutBody)
147153

148154
await self.directory_handler.edit_published_room_list(
149-
requester, room_id, visibility
155+
requester, room_id, content.visibility
150156
)
151157

152158
return 200, {}
@@ -163,20 +169,26 @@ def __init__(self, hs: "HomeServer"):
163169
self.directory_handler = hs.get_directory_handler()
164170
self.auth = hs.get_auth()
165171

172+
class PutBody(RequestBodyModel):
173+
visibility: Literal["public", "private"] = "public"
174+
166175
async def on_PUT(
167176
self, request: SynapseRequest, network_id: str, room_id: str
168177
) -> Tuple[int, JsonDict]:
169-
content = parse_json_object_from_request(request)
170-
visibility = content.get("visibility", "public")
171-
return await self._edit(request, network_id, room_id, visibility)
178+
content = parse_and_validate_json_object_from_request(request, self.PutBody)
179+
return await self._edit(request, network_id, room_id, content.visibility)
172180

173181
async def on_DELETE(
174182
self, request: SynapseRequest, network_id: str, room_id: str
175183
) -> Tuple[int, JsonDict]:
176184
return await self._edit(request, network_id, room_id, "private")
177185

178186
async def _edit(
179-
self, request: SynapseRequest, network_id: str, room_id: str, visibility: str
187+
self,
188+
request: SynapseRequest,
189+
network_id: str,
190+
room_id: str,
191+
visibility: Literal["public", "private"],
180192
) -> Tuple[int, JsonDict]:
181193
requester = await self.auth.get_user_by_req(request)
182194
if not requester.app_service:

0 commit comments

Comments
 (0)