server: properly enforce validation regex

cf. #669
Previously it would incorrectly allow strings with a trailing newline.
>>> re.match(r"^\S+$", "test\n")
<re.Match object; span=(0, 4), match='test'>
This commit is contained in:
Eva
2025-03-27 17:17:09 +01:00
parent 782f069031
commit 13e102b487
7 changed files with 13 additions and 13 deletions

View File

@ -31,7 +31,7 @@ class InvalidPoolCategoryColorError(errors.ValidationError):
def _verify_name_validity(name: str) -> None:
name_regex = config.config["pool_category_name_regex"]
if not re.match(name_regex, name):
if not re.fullmatch(name_regex, name):
raise InvalidPoolCategoryNameError(
"Name must satisfy regex %r." % name_regex
)
@ -110,7 +110,7 @@ def update_category_color(category: model.PoolCategory, color: str) -> None:
assert category
if not color:
raise InvalidPoolCategoryColorError("Color cannot be empty.")
if not re.match(r"^#?[0-9a-z]+$", color):
if not re.fullmatch(r"^#?[0-9a-z]+$", color):
raise InvalidPoolCategoryColorError("Invalid color.")
if util.value_exceeds_column_size(color, model.PoolCategory.color):
raise InvalidPoolCategoryColorError("Color is too long.")

View File

@ -48,7 +48,7 @@ def _verify_name_validity(name: str) -> None:
if util.value_exceeds_column_size(name, model.PoolName.name):
raise InvalidPoolNameError("Name is too long.")
name_regex = config.config["pool_name_regex"]
if not re.match(name_regex, name):
if not re.fullmatch(name_regex, name):
raise InvalidPoolNameError("Name must satisfy regex %r." % name_regex)

View File

@ -31,7 +31,7 @@ class InvalidTagCategoryColorError(errors.ValidationError):
def _verify_name_validity(name: str) -> None:
name_regex = config.config["tag_category_name_regex"]
if not re.match(name_regex, name):
if not re.fullmatch(name_regex, name):
raise InvalidTagCategoryNameError(
"Name must satisfy regex %r." % name_regex
)
@ -115,7 +115,7 @@ def update_category_color(category: model.TagCategory, color: str) -> None:
assert category
if not color:
raise InvalidTagCategoryColorError("Color cannot be empty.")
if not re.match(r"^#?[0-9a-z]+$", color):
if not re.fullmatch(r"^#?[0-9a-z]+$", color):
raise InvalidTagCategoryColorError("Invalid color.")
if util.value_exceeds_column_size(color, model.TagCategory.color):
raise InvalidTagCategoryColorError("Color is too long.")

View File

@ -40,7 +40,7 @@ def _verify_name_validity(name: str) -> None:
if util.value_exceeds_column_size(name, model.TagName.name):
raise InvalidTagNameError("Name is too long.")
name_regex = config.config["tag_name_regex"]
if not re.match(name_regex, name):
if not re.fullmatch(name_regex, name):
raise InvalidTagNameError("Name must satisfy regex %r." % name_regex)

View File

@ -235,7 +235,7 @@ def update_user_name(user: model.User, name: str) -> None:
raise InvalidUserNameError("User name is too long.")
name = name.strip()
name_regex = config.config["user_name_regex"]
if not re.match(name_regex, name):
if not re.fullmatch(name_regex, name):
raise InvalidUserNameError(
"User name %r must satisfy regex %r." % (name, name_regex)
)
@ -252,7 +252,7 @@ def update_user_password(user: model.User, password: str) -> None:
if not password:
raise InvalidPasswordError("Password cannot be empty.")
password_regex = config.config["password_regex"]
if not re.match(password_regex, password):
if not re.fullmatch(password_regex, password):
raise InvalidPasswordError(
"Password must satisfy regex %r." % password_regex
)

View File

@ -84,7 +84,7 @@ def flip(source: Dict[Any, Any]) -> Dict[Any, Any]:
def is_valid_email(email: Optional[str]) -> bool:
"""Return whether given email address is valid or empty."""
return not email or re.match(r"^[^@]*@[^@]*\.[^@]*$", email) is not None
return not email or re.fullmatch(r"^[^@]*@[^@]*\.[^@]*$", email) is not None
class dotdict(dict):
@ -121,12 +121,12 @@ def parse_time_range(value: str) -> Tuple[datetime, datetime]:
datetime(now.year, now.month, now.day, 0, 0, 0) - one_second,
)
match = re.match(r"^(\d{4})$", value)
match = re.fullmatch(r"^(\d{4})$", value)
if match:
year = int(match.group(1))
return (datetime(year, 1, 1), datetime(year + 1, 1, 1) - one_second)
match = re.match(r"^(\d{4})-(\d{1,2})$", value)
match = re.fullmatch(r"^(\d{4})-(\d{1,2})$", value)
if match:
year = int(match.group(1))
month = int(match.group(2))
@ -135,7 +135,7 @@ def parse_time_range(value: str) -> Tuple[datetime, datetime]:
datetime(year, month + 1, 1) - one_second,
)
match = re.match(r"^(\d{4})-(\d{1,2})-(\d{1,2})$", value)
match = re.fullmatch(r"^(\d{4})-(\d{1,2})-(\d{1,2})$", value)
if match:
year = int(match.group(1))
month = int(match.group(2))

View File

@ -81,7 +81,7 @@ class Parser:
negated = True
if not chunk:
raise errors.SearchError("Empty negated token.")
match = re.match(r"^(.*?)(?<!\\):(.*)$", chunk)
match = re.fullmatch(r"^(.*?)(?<!\\):(.*)$", chunk)
if match:
key, value = list(match.groups())
key = util.unescape(key)