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

Use Pydantic to systematically validate a first batch of endpoints in synapse.rest.client.account. #13188

Merged
merged 32 commits into from
Aug 15, 2022
Merged
Show file tree
Hide file tree
Changes from 11 commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
c932ed5
Lock pydantic
Jun 30, 2022
c40edbd
Use pydantic mypy plugin
May 22, 2022
52b0ef3
Helper for validating a json body with pydantic
Jul 4, 2022
87a6e79
Validate `client/account/deactivate`
Jul 4, 2022
c7caf5b
Validate `/client/account/password`
Jul 5, 2022
3319732
Changelog
Jul 5, 2022
9a47994
Better errcode when pw reset emails are disabled
Jul 5, 2022
0a87861
Validate `/client/account/passsword/email/requestToken`
Jul 5, 2022
3e2d003
move out RequestToken body to models
Jul 5, 2022
ba71e02
Validate `/client/account/3pid/email/requestToken`
Jul 5, 2022
e4926c2
Ooops, use Strict* types for EmailRequestTokenBody
Jul 5, 2022
b81faf4
Fix linter whoops
Jul 5, 2022
dc1f188
Revert "Better errcode when pw reset emails are disabled"
Jul 20, 2022
61f8f25
Move the models into the servlet classes
Jul 20, 2022
296467e
Revert another status code change.
Jul 20, 2022
94ca8d3
Merge branch 'develop' into dmr/rest/client/account
Jul 20, 2022
a273870
Relax pydantic version Bound
Jul 20, 2022
07ba995
Fix bad merge?
Jul 20, 2022
74cceab
Argh, fix linter
Jul 20, 2022
ff80b3f
A few str -> StrictStr when TYPE_CHECKING
Aug 8, 2022
a256487
Merge remote-tracking branch 'origin/develop' into dmr/rest/client/ac…
Aug 8, 2022
7294fc2
Use Pydantic 1.7.4
Aug 8, 2022
f20226e
Update changelog
Aug 8, 2022
df1f840
Require access token if id server is provided
Aug 8, 2022
c4074aa
Ignore unused fields; create frozen instances
Aug 8, 2022
fefb0a8
Fix mypy
Aug 8, 2022
4dbafed
Fix lint
Aug 8, 2022
bd917d3
Update changelog
Aug 10, 2022
f8f6037
Add a missing `strict=True`.
Aug 10, 2022
c404f8f
Move the BaseModel subclass to synapse.rest
Aug 10, 2022
1597977
Try to break circular import?
Aug 10, 2022
22aee7a
Fix lint durr
Aug 10, 2022
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions changelog.d/13188.misc
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Dummy changelog.
2 changes: 1 addition & 1 deletion mypy.ini
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[mypy]
namespace_packages = True
plugins = mypy_zope:plugin, scripts-dev/mypy_synapse_plugin.py
plugins = pydantic.mypy, mypy_zope:plugin, scripts-dev/mypy_synapse_plugin.py
follow_imports = normal
check_untyped_defs = True
show_error_codes = True
Expand Down
54 changes: 53 additions & 1 deletion poetry.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,7 @@ hiredis = { version = "*", optional = true }
Pympler = { version = "*", optional = true }
parameterized = { version = ">=0.7.4", optional = true }
idna = { version = ">=2.5", optional = true }
pydantic = "^1.9.1"

[tool.poetry.extras]
# NB: Packages that should be part of `pip install matrix-synapse[all]` need to be specified
Expand Down
25 changes: 25 additions & 0 deletions synapse/http/servlet.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,12 @@
Optional,
Sequence,
Tuple,
Type,
TypeVar,
overload,
)

from pydantic import BaseModel, ValidationError
from typing_extensions import Literal

from twisted.web.server import Request
Expand Down Expand Up @@ -694,6 +697,28 @@ def parse_json_object_from_request(
return content


Model = TypeVar("Model", bound=BaseModel)


def parse_and_validate_json_object_from_request(
request: Request, model_type: Type[Model]
) -> Model:
"""Parse a JSON object from the body of a twisted HTTP request, then deserialise and
validate using the given pydantic model.

Raises:
SynapseError if the request body couldn't be decoded as JSON or
if it wasn't a JSON object.
"""
content = parse_json_object_from_request(request, allow_empty_body=False)
try:
instance = model_type.parse_obj(content)
except ValidationError as e:
raise SynapseError(HTTPStatus.BAD_REQUEST, str(e), errcode=Codes.BAD_JSON)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It might be nice to define a new subclass of SynapseError for this. Not going to block this PR on it though.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, so we could catch a validation failure specifically? Happy to revisit this i the future if it turns out we need it

DMRobertson marked this conversation as resolved.
Show resolved Hide resolved

return instance


def assert_params_in_dict(body: JsonDict, required: Iterable[str]) -> None:
absent = []
for k in required:
Expand Down
Loading