Skip to content

Commit cb8bca9

Browse files
committed
notes
1 parent 3d40c4b commit cb8bca9

File tree

2 files changed

+24
-15
lines changed

2 files changed

+24
-15
lines changed

services/web/server/src/simcore_service_webserver/licenses/_itis_vip_models.py

Lines changed: 17 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,25 @@
11
import re
22
from typing import Annotated, Any, Literal
33

4-
from pydantic import BaseModel, BeforeValidator, Field, HttpUrl
4+
from pydantic import (
5+
BaseModel,
6+
BeforeValidator,
7+
Field,
8+
HttpUrl,
9+
StringConstraints,
10+
TypeAdapter,
11+
)
512

6-
_MAX_LENGTH = 1_000
13+
_max_str_adapter = TypeAdapter(
14+
Annotated[str, StringConstraints(strip_whitespace=True, max_length=1_000)]
15+
)
716

817

918
def _feature_descriptor_to_dict(descriptor: str) -> dict[str, Any]:
1019
# NOTE: this is manually added in the server side so be more robust to errors
11-
# Safe against polynomial runtime vulnerability due to backtracking
12-
if (size := len(descriptor)) and size > _MAX_LENGTH:
13-
msg = f"Features field too long [{size=}]"
14-
raise ValueError(msg)
15-
20+
descriptor = _max_str_adapter.validate_python(descriptor.strip("{}"))
1621
pattern = r"(\w{1,100}): ([^,]{1,100})"
17-
18-
matches = re.findall(pattern, descriptor.strip("{}"))
22+
matches = re.findall(pattern, descriptor)
1923
return dict(matches)
2024

2125

@@ -38,5 +42,8 @@ class AvailableDownload(BaseModel):
3842
class ResponseData(BaseModel):
3943
msg: int | None = None # still not used
4044
available_downloads: Annotated[
41-
list[AvailableDownload], Field(alias="availableDownloads")
45+
list[AvailableDownload],
46+
Field(alias="availableDownloads")
47+
# TODO: consider just parsing those that you are interested in instead of performing so many checks
48+
# and then throw them
4249
]

services/web/server/tests/unit/with_dbs/04/licenses/test_itis_vip_service.py

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,13 @@
2222
from simcore_service_webserver.licenses._itis_vip_settings import ItisVipSettings
2323

2424

25+
def test_pre_validator_feature_descriptor_to_dict():
26+
# Makes sure the regex used here, which is vulnerable to polynomial runtime due to backtracking, cannot lead to denial of service.
27+
with pytest.raises(ValidationError) as err_info:
28+
_feature_descriptor_to_dict("a" * 10000 + ": " + "b" * 10000)
29+
assert err_info.value.errors()[0]["type"] == "string_too_long"
30+
31+
2532
@pytest.fixture(scope="session")
2633
def fake_api_base_url() -> str:
2734
return "https://testserver"
@@ -111,8 +118,3 @@ async def test_get_category_items(
111118
items = await _itis_vip_service.get_category_items(client, url)
112119

113120
assert items[0].features["functionality"] == "Posable"
114-
115-
116-
def test_pre_validator_feature_descriptor_to_dict():
117-
with pytest.raises(ValueError):
118-
_feature_descriptor_to_dict("a" * 10000 + ": " + "b" * 10000)

0 commit comments

Comments
 (0)