diff --git a/plugin/web.py b/plugin/web.py index 5300bfc..1f325b4 100644 --- a/plugin/web.py +++ b/plugin/web.py @@ -14,6 +14,7 @@ # along with this program. If not, see . import json +import jsonschema import select import socket @@ -177,7 +178,8 @@ class WebServer: try: params = json.loads(req.body.decode('utf-8')) - except ValueError as e: + jsonschema.validate(params, request_schema) + except (ValueError, jsonschema.ValidationError) as e: if allowed: if len(req.body) == 0: body = f"AnkiConnect v.{util.setting('apiVersion')}".encode() @@ -286,3 +288,14 @@ def format_success_reply(api_version, result): def format_exception_reply(_api_version, exception): return {"result": None, "error": str(exception)} + + +request_schema = { + "type": "object", + "properties": { + "action": {"type": "string", "minLength": 1}, + "version": {"type": "integer"}, + "params": {"type": "object"}, + }, + "required": ["action"], +} \ No newline at end of file diff --git a/tests/test_server.py b/tests/test_server.py index 1f13157..f0d098d 100644 --- a/tests/test_server.py +++ b/tests/test_server.py @@ -169,6 +169,24 @@ def test_failing_request_due_to_bad_json(external_anki): assert "in double quotes" in response["error"] +def test_failing_request_due_to_json_root_not_being_an_object(external_anki): + response = json.loads(external_anki.send_bytes(b"1.2")) + assert response["result"] is None + assert "is not of type 'object'" in response["error"] + + +def test_failing_request_due_to_json_missing_wanted_properties(external_anki): + response = json.loads(external_anki.send_bytes(b"{}")) + assert response["result"] is None + assert "'action' is a required property" in response["error"] + + +def test_failing_request_due_to_json_properties_being_of_wrong_types(external_anki): + response = json.loads(external_anki.send_bytes(b'{"action": 1}')) + assert response["result"] is None + assert "1 is not of type 'string'" in response["error"] + + def test_403_in_case_of_disallowed_origin(external_anki): with pytest.raises(urllib.error.HTTPError, match="403"): # good request/json json_bytes = json.dumps(Client.make_request("version")).encode("utf-8")