widgets: Validate todo data on the backend.

This commit is contained in:
Steve Howell
2021-06-28 16:55:42 +00:00
committed by Tim Abbott
parent a89ba9c7d6
commit 7d46bed507
3 changed files with 86 additions and 1 deletions

View File

@@ -498,6 +498,37 @@ def validate_poll_data(poll_data: object, is_widget_author: bool) -> None:
raise ValidationError(f"Unknown type for poll data: {poll_data['type']}")
def validate_todo_data(todo_data: object) -> None:
check_dict([("type", check_string)])("todo data", todo_data)
assert isinstance(todo_data, dict)
if todo_data["type"] == "new_task":
checker = check_dict_only(
[
("type", check_string),
("key", check_int),
("task", check_string),
("desc", check_string),
("completed", check_bool),
]
)
checker("todo data", todo_data)
return
if todo_data["type"] == "strike":
checker = check_dict_only(
[
("type", check_string),
("key", check_string),
]
)
checker("todo data", todo_data)
return
raise ValidationError(f"Unknown type for todo data: {todo_data['type']}")
# Converter functions for use with has_request_variables
def to_non_negative_int(s: str, max_int_size: int = 2 ** 32 - 1) -> int:
x = int(s)

View File

@@ -312,6 +312,54 @@ class WidgetContentTestCase(ZulipTestCase):
assert_success(dict(type="new_option", idx=7, option="maybe"))
assert_success(dict(type="question", question="what's for dinner?"))
def test_todo_type_validation(self) -> None:
sender = self.example_user("cordelia")
stream_name = "Verona"
content = "/todo"
payload = dict(
type="stream",
to=stream_name,
client="test suite",
topic="whatever",
content=content,
)
result = self.api_post(sender, "/api/v1/messages", payload)
self.assert_json_success(result)
message = self.get_last_message()
def post_submessage(content: str) -> HttpResponse:
payload = dict(
message_id=message.id,
msg_type="widget",
content=content,
)
return self.api_post(sender, "/api/v1/submessage", payload)
def assert_error(content: str, error: str) -> None:
result = post_submessage(content)
self.assert_json_error_contains(result, error)
assert_error('{"type": "bogus"}', "Unknown type for todo data: bogus")
assert_error('{"type": "new_task"}', "key is missing")
assert_error(
'{"type": "new_task", "key": 7, "task": 7, "desc": "", "completed": false}',
'data["task"] is not a string',
)
assert_error('{"type": "strike"}', "key is missing")
assert_error('{"type": "strike", "key": 999}', 'data["key"] is not a string')
def assert_success(data: Dict[str, object]) -> None:
content = orjson.dumps(data).decode()
result = post_submessage(content)
self.assert_json_success(result)
assert_success(dict(type="new_task", key=7, task="eat", desc="", completed=False))
assert_success(dict(type="strike", key="5,9"))
def test_get_widget_type(self) -> None:
sender = self.example_user("cordelia")
stream_name = "Verona"

View File

@@ -8,7 +8,7 @@ from zerver.lib.actions import do_add_submessage, verify_submessage_sender
from zerver.lib.exceptions import JsonableError
from zerver.lib.message import access_message
from zerver.lib.response import json_error, json_success
from zerver.lib.validator import check_int, validate_poll_data
from zerver.lib.validator import check_int, validate_poll_data, validate_todo_data
from zerver.lib.widget import get_widget_type
from zerver.models import UserProfile
@@ -44,6 +44,12 @@ def process_submessage(
except ValidationError as error:
raise JsonableError(error.message)
if widget_type == "todo":
try:
validate_todo_data(todo_data=widget_data)
except ValidationError as error:
raise JsonableError(error.message)
do_add_submessage(
realm=user_profile.realm,
sender_id=user_profile.id,