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

Commit 8269942

Browse files
authored
Validate input to POST /key/v2/query endpoint. (#16183)
To avoid 500 internal server errors with garbage input.
1 parent fcf7a57 commit 8269942

File tree

2 files changed

+30
-10
lines changed

2 files changed

+30
-10
lines changed

changelog.d/16183.misc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Improve error reporting of invalid data passed to `/_matrix/key/v2/query`.

synapse/rest/key/v2/remote_key_resource.py

Lines changed: 29 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
import re
1717
from typing import TYPE_CHECKING, Dict, Mapping, Optional, Set, Tuple
1818

19+
from pydantic import Extra, StrictInt, StrictStr
1920
from signedjson.sign import sign_json
2021

2122
from twisted.web.server import Request
@@ -24,9 +25,10 @@
2425
from synapse.http.server import HttpServer
2526
from synapse.http.servlet import (
2627
RestServlet,
28+
parse_and_validate_json_object_from_request,
2729
parse_integer,
28-
parse_json_object_from_request,
2930
)
31+
from synapse.rest.models import RequestBodyModel
3032
from synapse.storage.keys import FetchKeyResultForRemote
3133
from synapse.types import JsonDict
3234
from synapse.util import json_decoder
@@ -38,6 +40,13 @@
3840
logger = logging.getLogger(__name__)
3941

4042

43+
class _KeyQueryCriteriaDataModel(RequestBodyModel):
44+
class Config:
45+
extra = Extra.allow
46+
47+
minimum_valid_until_ts: Optional[StrictInt]
48+
49+
4150
class RemoteKey(RestServlet):
4251
"""HTTP resource for retrieving the TLS certificate and NACL signature
4352
verification keys for a collection of servers. Checks that the reported
@@ -96,6 +105,9 @@ class RemoteKey(RestServlet):
96105

97106
CATEGORY = "Federation requests"
98107

108+
class PostBody(RequestBodyModel):
109+
server_keys: Dict[StrictStr, Dict[StrictStr, _KeyQueryCriteriaDataModel]]
110+
99111
def __init__(self, hs: "HomeServer"):
100112
self.fetcher = ServerKeyFetcher(hs)
101113
self.store = hs.get_datastores().main
@@ -137,24 +149,29 @@ async def on_GET(
137149
)
138150

139151
minimum_valid_until_ts = parse_integer(request, "minimum_valid_until_ts")
140-
arguments = {}
141-
if minimum_valid_until_ts is not None:
142-
arguments["minimum_valid_until_ts"] = minimum_valid_until_ts
143-
query = {server: {key_id: arguments}}
152+
query = {
153+
server: {
154+
key_id: _KeyQueryCriteriaDataModel(
155+
minimum_valid_until_ts=minimum_valid_until_ts
156+
)
157+
}
158+
}
144159
else:
145160
query = {server: {}}
146161

147162
return 200, await self.query_keys(query, query_remote_on_cache_miss=True)
148163

149164
async def on_POST(self, request: Request) -> Tuple[int, JsonDict]:
150-
content = parse_json_object_from_request(request)
165+
content = parse_and_validate_json_object_from_request(request, self.PostBody)
151166

152-
query = content["server_keys"]
167+
query = content.server_keys
153168

154169
return 200, await self.query_keys(query, query_remote_on_cache_miss=True)
155170

156171
async def query_keys(
157-
self, query: JsonDict, query_remote_on_cache_miss: bool = False
172+
self,
173+
query: Dict[str, Dict[str, _KeyQueryCriteriaDataModel]],
174+
query_remote_on_cache_miss: bool = False,
158175
) -> JsonDict:
159176
logger.info("Handling query for keys %r", query)
160177

@@ -196,8 +213,10 @@ async def query_keys(
196213
else:
197214
ts_added_ms = key_result.added_ts
198215
ts_valid_until_ms = key_result.valid_until_ts
199-
req_key = query.get(server_name, {}).get(key_id, {})
200-
req_valid_until = req_key.get("minimum_valid_until_ts")
216+
req_key = query.get(server_name, {}).get(
217+
key_id, _KeyQueryCriteriaDataModel(minimum_valid_until_ts=None)
218+
)
219+
req_valid_until = req_key.minimum_valid_until_ts
201220
if req_valid_until is not None:
202221
if ts_valid_until_ms < req_valid_until:
203222
logger.debug(

0 commit comments

Comments
 (0)