~foosoft/anki-connect

9c3310a8b6202f93ed42ec13461566659b1e2036 — oakkitten 2 years ago bffbb05
Don't crash if JSON is valid but of wrong schema
2 files changed, 32 insertions(+), 1 deletions(-)

M plugin/web.py
M tests/test_server.py
M plugin/web.py => plugin/web.py +14 -1
@@ 14,6 14,7 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.

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

M tests/test_server.py => tests/test_server.py +18 -0
@@ 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")

Do not follow this link