widgets: Add range checks on backend for indexes.

This commit is contained in:
Steve Howell
2021-06-28 17:56:23 +00:00
committed by Tim Abbott
parent 7d46bed507
commit 0fab79c027
2 changed files with 29 additions and 2 deletions

View File

@@ -141,6 +141,19 @@ def check_int_in(possible_values: List[int]) -> Validator[int]:
return validator
def check_int_range(low: int, high: int) -> Validator[int]:
# low and high are both treated as valid values
def validator(var_name: str, val: object) -> int:
n = check_int(var_name, val)
if n < low:
raise ValidationError(_("{var_name} is too small").format(var_name=var_name))
if n > high:
raise ValidationError(_("{var_name} is too large").format(var_name=var_name))
return n
return validator
def check_float(var_name: str, val: object) -> float:
if not isinstance(val, float):
raise ValidationError(_("{var_name} is not a float").format(var_name=var_name))
@@ -455,6 +468,10 @@ def check_widget_content(widget_content: object) -> Dict[str, Any]:
raise ValidationError("unknown widget type: " + widget_type)
# This should match MAX_IDX in our client widgets. It is somewhat arbitrary.
MAX_IDX = 1000
def validate_poll_data(poll_data: object, is_widget_author: bool) -> None:
check_dict([("type", check_string)])("poll data", poll_data)
@@ -489,7 +506,7 @@ def validate_poll_data(poll_data: object, is_widget_author: bool) -> None:
[
("type", check_string),
("option", check_string),
("idx", check_int),
("idx", check_int_range(0, MAX_IDX)),
]
)
checker("poll data", poll_data)
@@ -507,7 +524,7 @@ def validate_todo_data(todo_data: object) -> None:
checker = check_dict_only(
[
("type", check_string),
("key", check_int),
("key", check_int_range(0, MAX_IDX)),
("task", check_string),
("desc", check_string),
("completed", check_bool),

View File

@@ -297,6 +297,8 @@ class WidgetContentTestCase(ZulipTestCase):
assert_error('{"type": "new_option"}', "key is missing")
assert_error('{"type": "new_option", "idx": 7, "option": 999}', "not a string")
assert_error('{"type": "new_option", "idx": -1, "option": "pizza"}', "too small")
assert_error('{"type": "new_option", "idx": 1001, "option": "pizza"}', "too large")
assert_error('{"type": "new_option", "idx": "bogus", "option": "maybe"}', "not an int")
def assert_success(data: Dict[str, object]) -> None:
@@ -348,6 +350,14 @@ class WidgetContentTestCase(ZulipTestCase):
'{"type": "new_task", "key": 7, "task": 7, "desc": "", "completed": false}',
'data["task"] is not a string',
)
assert_error(
'{"type": "new_task", "key": -1, "task": "eat", "desc": "", "completed": false}',
'data["key"] is too small',
)
assert_error(
'{"type": "new_task", "key": 1001, "task": "eat", "desc": "", "completed": false}',
'data["key"] is too large',
)
assert_error('{"type": "strike"}', "key is missing")
assert_error('{"type": "strike", "key": 999}', 'data["key"] is not a string')