Validate device_keys for C-S /keys/query requests (#10593)
* Validate device_keys for C-S /keys/query requests Closes #10354 A small, not particularly critical fix. I'm interested in seeing if we can find a more systematic approach though. #8445 is the place for any discussion.pull/10667/head
parent
e81d62009e
commit
ee3b2ac59a
|
@ -0,0 +1 @@
|
|||
Reject Client-Server /keys/query requests which provide device_ids incorrectly.
|
|
@ -147,6 +147,14 @@ class SynapseError(CodeMessageException):
|
|||
return cs_error(self.msg, self.errcode)
|
||||
|
||||
|
||||
class InvalidAPICallError(SynapseError):
|
||||
"""You called an existing API endpoint, but fed that endpoint
|
||||
invalid or incomplete data."""
|
||||
|
||||
def __init__(self, msg: str):
|
||||
super().__init__(HTTPStatus.BAD_REQUEST, msg, Codes.BAD_JSON)
|
||||
|
||||
|
||||
class ProxiedRequestError(SynapseError):
|
||||
"""An error from a general matrix endpoint, eg. from a proxied Matrix API call.
|
||||
|
||||
|
|
|
@ -15,8 +15,9 @@
|
|||
# limitations under the License.
|
||||
|
||||
import logging
|
||||
from typing import Any
|
||||
|
||||
from synapse.api.errors import SynapseError
|
||||
from synapse.api.errors import InvalidAPICallError, SynapseError
|
||||
from synapse.http.servlet import (
|
||||
RestServlet,
|
||||
parse_integer,
|
||||
|
@ -163,6 +164,19 @@ class KeyQueryServlet(RestServlet):
|
|||
device_id = requester.device_id
|
||||
timeout = parse_integer(request, "timeout", 10 * 1000)
|
||||
body = parse_json_object_from_request(request)
|
||||
|
||||
device_keys = body.get("device_keys")
|
||||
if not isinstance(device_keys, dict):
|
||||
raise InvalidAPICallError("'device_keys' must be a JSON object")
|
||||
|
||||
def is_list_of_strings(values: Any) -> bool:
|
||||
return isinstance(values, list) and all(isinstance(v, str) for v in values)
|
||||
|
||||
if any(not is_list_of_strings(keys) for keys in device_keys.values()):
|
||||
raise InvalidAPICallError(
|
||||
"'device_keys' values must be a list of strings",
|
||||
)
|
||||
|
||||
result = await self.e2e_keys_handler.query_devices(
|
||||
body, timeout, user_id, device_id
|
||||
)
|
||||
|
|
|
@ -0,0 +1,77 @@
|
|||
from http import HTTPStatus
|
||||
|
||||
from synapse.api.errors import Codes
|
||||
from synapse.rest import admin
|
||||
from synapse.rest.client import keys, login
|
||||
|
||||
from tests import unittest
|
||||
|
||||
|
||||
class KeyQueryTestCase(unittest.HomeserverTestCase):
|
||||
servlets = [
|
||||
keys.register_servlets,
|
||||
admin.register_servlets_for_client_rest_resource,
|
||||
login.register_servlets,
|
||||
]
|
||||
|
||||
def test_rejects_device_id_ice_key_outside_of_list(self):
|
||||
self.register_user("alice", "wonderland")
|
||||
alice_token = self.login("alice", "wonderland")
|
||||
bob = self.register_user("bob", "uncle")
|
||||
channel = self.make_request(
|
||||
"POST",
|
||||
"/_matrix/client/r0/keys/query",
|
||||
{
|
||||
"device_keys": {
|
||||
bob: "device_id1",
|
||||
},
|
||||
},
|
||||
alice_token,
|
||||
)
|
||||
self.assertEqual(channel.code, HTTPStatus.BAD_REQUEST, channel.result)
|
||||
self.assertEqual(
|
||||
channel.json_body["errcode"],
|
||||
Codes.BAD_JSON,
|
||||
channel.result,
|
||||
)
|
||||
|
||||
def test_rejects_device_key_given_as_map_to_bool(self):
|
||||
self.register_user("alice", "wonderland")
|
||||
alice_token = self.login("alice", "wonderland")
|
||||
bob = self.register_user("bob", "uncle")
|
||||
channel = self.make_request(
|
||||
"POST",
|
||||
"/_matrix/client/r0/keys/query",
|
||||
{
|
||||
"device_keys": {
|
||||
bob: {
|
||||
"device_id1": True,
|
||||
},
|
||||
},
|
||||
},
|
||||
alice_token,
|
||||
)
|
||||
|
||||
self.assertEqual(channel.code, HTTPStatus.BAD_REQUEST, channel.result)
|
||||
self.assertEqual(
|
||||
channel.json_body["errcode"],
|
||||
Codes.BAD_JSON,
|
||||
channel.result,
|
||||
)
|
||||
|
||||
def test_requires_device_key(self):
|
||||
"""`device_keys` is required. We should complain if it's missing."""
|
||||
self.register_user("alice", "wonderland")
|
||||
alice_token = self.login("alice", "wonderland")
|
||||
channel = self.make_request(
|
||||
"POST",
|
||||
"/_matrix/client/r0/keys/query",
|
||||
{},
|
||||
alice_token,
|
||||
)
|
||||
self.assertEqual(channel.code, HTTPStatus.BAD_REQUEST, channel.result)
|
||||
self.assertEqual(
|
||||
channel.json_body["errcode"],
|
||||
Codes.BAD_JSON,
|
||||
channel.result,
|
||||
)
|
Loading…
Reference in New Issue