refactor(chalice): validate regex expression
This commit is contained in:
parent
bb6e2cbbdc
commit
d378b00bf7
2 changed files with 67 additions and 2 deletions
|
|
@ -3,12 +3,13 @@ from typing import Optional, List, Union, Literal
|
||||||
|
|
||||||
from pydantic import Field, EmailStr, HttpUrl, SecretStr, AnyHttpUrl
|
from pydantic import Field, EmailStr, HttpUrl, SecretStr, AnyHttpUrl
|
||||||
from pydantic import field_validator, model_validator, computed_field
|
from pydantic import field_validator, model_validator, computed_field
|
||||||
|
from pydantic import AfterValidator
|
||||||
from pydantic.functional_validators import BeforeValidator
|
from pydantic.functional_validators import BeforeValidator
|
||||||
|
|
||||||
from chalicelib.utils.TimeUTC import TimeUTC
|
from chalicelib.utils.TimeUTC import TimeUTC
|
||||||
from .overrides import BaseModel, Enum, ORUnion
|
from .overrides import BaseModel, Enum, ORUnion
|
||||||
from .transformers_validators import transform_email, remove_whitespace, remove_duplicate_values, single_to_list, \
|
from .transformers_validators import transform_email, remove_whitespace, remove_duplicate_values, single_to_list, \
|
||||||
force_is_event, NAME_PATTERN, int_to_string, check_alphanumeric
|
force_is_event, NAME_PATTERN, int_to_string, check_alphanumeric, check_regex
|
||||||
|
|
||||||
|
|
||||||
class _GRecaptcha(BaseModel):
|
class _GRecaptcha(BaseModel):
|
||||||
|
|
@ -537,7 +538,7 @@ class GraphqlFilterType(str, Enum):
|
||||||
class RequestGraphqlFilterSchema(BaseModel):
|
class RequestGraphqlFilterSchema(BaseModel):
|
||||||
type: Union[FetchFilterType, GraphqlFilterType] = Field(...)
|
type: Union[FetchFilterType, GraphqlFilterType] = Field(...)
|
||||||
value: List[Union[int, str]] = Field(...)
|
value: List[Union[int, str]] = Field(...)
|
||||||
operator: Union[SearchEventOperator, MathOperator] = Field(...)
|
operator: Annotated[Union[SearchEventOperator, MathOperator], AfterValidator(check_regex)] = Field(...)
|
||||||
|
|
||||||
@model_validator(mode="before")
|
@model_validator(mode="before")
|
||||||
@classmethod
|
@classmethod
|
||||||
|
|
@ -612,6 +613,13 @@ class PropertyFilterSchema(BaseModel):
|
||||||
self.name = self.name.value
|
self.name = self.name.value
|
||||||
return self
|
return self
|
||||||
|
|
||||||
|
@model_validator(mode='after')
|
||||||
|
def _check_regex_value(self):
|
||||||
|
if self.operator == SearchEventOperator.PATTERN:
|
||||||
|
for v in self.value:
|
||||||
|
check_regex(v)
|
||||||
|
return self
|
||||||
|
|
||||||
|
|
||||||
class EventPropertiesSchema(BaseModel):
|
class EventPropertiesSchema(BaseModel):
|
||||||
operator: Literal["and", "or"] = Field(...)
|
operator: Literal["and", "or"] = Field(...)
|
||||||
|
|
@ -657,6 +665,13 @@ class SessionSearchEventSchema(BaseModel):
|
||||||
f"operator:{self.operator} is only available for event-type: {EventType.CLICK}"
|
f"operator:{self.operator} is only available for event-type: {EventType.CLICK}"
|
||||||
return self
|
return self
|
||||||
|
|
||||||
|
@model_validator(mode='after')
|
||||||
|
def _check_regex_value(self):
|
||||||
|
if self.operator == SearchEventOperator.PATTERN:
|
||||||
|
for v in self.value:
|
||||||
|
check_regex(v)
|
||||||
|
return self
|
||||||
|
|
||||||
|
|
||||||
class SessionSearchFilterSchema(BaseModel):
|
class SessionSearchFilterSchema(BaseModel):
|
||||||
is_event: Literal[False] = False
|
is_event: Literal[False] = False
|
||||||
|
|
@ -714,6 +729,13 @@ class SessionSearchFilterSchema(BaseModel):
|
||||||
|
|
||||||
return self
|
return self
|
||||||
|
|
||||||
|
@model_validator(mode='after')
|
||||||
|
def _check_regex_value(self):
|
||||||
|
if self.operator == SearchEventOperator.PATTERN:
|
||||||
|
for v in self.value:
|
||||||
|
check_regex(v)
|
||||||
|
return self
|
||||||
|
|
||||||
|
|
||||||
class _PaginatedSchema(BaseModel):
|
class _PaginatedSchema(BaseModel):
|
||||||
limit: int = Field(default=200, gt=0, le=200)
|
limit: int = Field(default=200, gt=0, le=200)
|
||||||
|
|
@ -880,6 +902,13 @@ class PathAnalysisSubFilterSchema(BaseModel):
|
||||||
values["isEvent"] = True
|
values["isEvent"] = True
|
||||||
return values
|
return values
|
||||||
|
|
||||||
|
@model_validator(mode='after')
|
||||||
|
def _check_regex_value(self):
|
||||||
|
if self.operator == SearchEventOperator.PATTERN:
|
||||||
|
for v in self.value:
|
||||||
|
check_regex(v)
|
||||||
|
return self
|
||||||
|
|
||||||
|
|
||||||
class _ProductAnalyticsFilter(BaseModel):
|
class _ProductAnalyticsFilter(BaseModel):
|
||||||
is_event: Literal[False] = False
|
is_event: Literal[False] = False
|
||||||
|
|
@ -890,6 +919,13 @@ class _ProductAnalyticsFilter(BaseModel):
|
||||||
|
|
||||||
_remove_duplicate_values = field_validator('value', mode='before')(remove_duplicate_values)
|
_remove_duplicate_values = field_validator('value', mode='before')(remove_duplicate_values)
|
||||||
|
|
||||||
|
@model_validator(mode='after')
|
||||||
|
def _check_regex_value(self):
|
||||||
|
if self.operator == SearchEventOperator.PATTERN:
|
||||||
|
for v in self.value:
|
||||||
|
check_regex(v)
|
||||||
|
return self
|
||||||
|
|
||||||
|
|
||||||
class _ProductAnalyticsEventFilter(BaseModel):
|
class _ProductAnalyticsEventFilter(BaseModel):
|
||||||
is_event: Literal[True] = True
|
is_event: Literal[True] = True
|
||||||
|
|
@ -900,6 +936,13 @@ class _ProductAnalyticsEventFilter(BaseModel):
|
||||||
|
|
||||||
_remove_duplicate_values = field_validator('value', mode='before')(remove_duplicate_values)
|
_remove_duplicate_values = field_validator('value', mode='before')(remove_duplicate_values)
|
||||||
|
|
||||||
|
@model_validator(mode='after')
|
||||||
|
def _check_regex_value(self):
|
||||||
|
if self.operator == SearchEventOperator.PATTERN:
|
||||||
|
for v in self.value:
|
||||||
|
check_regex(v)
|
||||||
|
return self
|
||||||
|
|
||||||
|
|
||||||
# this type is created to allow mixing events&filters and specifying a discriminator for PathAnalysis series filter
|
# this type is created to allow mixing events&filters and specifying a discriminator for PathAnalysis series filter
|
||||||
ProductAnalyticsFilter = Annotated[Union[_ProductAnalyticsFilter, _ProductAnalyticsEventFilter],
|
ProductAnalyticsFilter = Annotated[Union[_ProductAnalyticsFilter, _ProductAnalyticsEventFilter],
|
||||||
|
|
@ -1344,6 +1387,13 @@ class LiveSessionSearchFilterSchema(BaseModel):
|
||||||
assert len(self.source) > 0, "source should not be empty for METADATA type"
|
assert len(self.source) > 0, "source should not be empty for METADATA type"
|
||||||
return self
|
return self
|
||||||
|
|
||||||
|
@model_validator(mode='after')
|
||||||
|
def _check_regex_value(self):
|
||||||
|
if self.operator == SearchEventOperator.PATTERN:
|
||||||
|
for v in self.value:
|
||||||
|
check_regex(v)
|
||||||
|
return self
|
||||||
|
|
||||||
|
|
||||||
class LiveSessionsSearchPayloadSchema(_PaginatedSchema):
|
class LiveSessionsSearchPayloadSchema(_PaginatedSchema):
|
||||||
filters: List[LiveSessionSearchFilterSchema] = Field([])
|
filters: List[LiveSessionSearchFilterSchema] = Field([])
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,4 @@
|
||||||
|
import re
|
||||||
from typing import Union, Any, Type
|
from typing import Union, Any, Type
|
||||||
|
|
||||||
from pydantic import ValidationInfo
|
from pydantic import ValidationInfo
|
||||||
|
|
@ -57,3 +58,17 @@ def check_alphanumeric(v: str, info: ValidationInfo) -> str:
|
||||||
is_alphanumeric = v.replace(' ', '').isalnum()
|
is_alphanumeric = v.replace(' ', '').isalnum()
|
||||||
assert is_alphanumeric, f'{info.field_name} must be alphanumeric'
|
assert is_alphanumeric, f'{info.field_name} must be alphanumeric'
|
||||||
return v
|
return v
|
||||||
|
|
||||||
|
|
||||||
|
def check_regex(v: str) -> str:
|
||||||
|
assert v is not None, "Regex is null"
|
||||||
|
assert isinstance(v, str), "Regex value must be a string"
|
||||||
|
assert len(v) > 0, "Regex is empty"
|
||||||
|
is_valid = None
|
||||||
|
try:
|
||||||
|
re.compile(v)
|
||||||
|
except re.error as exc:
|
||||||
|
is_valid = f"Invalid regex: {exc} (at position {exc.pos})"
|
||||||
|
|
||||||
|
assert is_valid is None, is_valid
|
||||||
|
return v
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue