From 2ab0b3d4fc12067cb8b604d7763b4176c1a6dc1a Mon Sep 17 00:00:00 2001 From: Anders Kaseorg Date: Tue, 15 Dec 2020 13:38:55 -0800 Subject: [PATCH] validator: Reject ISO 8601 dates missing leading zeros. Signed-off-by: Anders Kaseorg --- version.py | 2 +- zerver/lib/validator.py | 3 ++- .../0306_custom_profile_field_date_format.py | 27 +++++++++++++++++++ zerver/openapi/zulip.yaml | 6 ++--- zerver/tests/test_custom_profile_data.py | 4 ++- zerver/tests/test_users.py | 2 +- zilencer/management/commands/populate_db.py | 4 +-- 7 files changed, 39 insertions(+), 9 deletions(-) create mode 100644 zerver/migrations/0306_custom_profile_field_date_format.py diff --git a/version.py b/version.py index 4baecc585a..f0914efd52 100644 --- a/version.py +++ b/version.py @@ -43,4 +43,4 @@ API_FEATURE_LEVEL = 35 # historical commits sharing the same major version, in which case a # minor version bump suffices. -PROVISION_VERSION = '117.2' +PROVISION_VERSION = '117.3' diff --git a/zerver/lib/validator.py b/zerver/lib/validator.py index d989b2b4d9..c4c06ffd63 100644 --- a/zerver/lib/validator.py +++ b/zerver/lib/validator.py @@ -92,7 +92,8 @@ def check_date(var_name: str, val: object) -> str: if not isinstance(val, str): raise ValidationError(_('{var_name} is not a string').format(var_name=var_name)) try: - datetime.strptime(val, '%Y-%m-%d') + if datetime.strptime(val, '%Y-%m-%d').strftime('%Y-%m-%d') != val: + raise ValidationError(_('{var_name} is not a date').format(var_name=var_name)) except ValueError: raise ValidationError(_('{var_name} is not a date').format(var_name=var_name)) return val diff --git a/zerver/migrations/0306_custom_profile_field_date_format.py b/zerver/migrations/0306_custom_profile_field_date_format.py new file mode 100644 index 0000000000..14fd87fbb8 --- /dev/null +++ b/zerver/migrations/0306_custom_profile_field_date_format.py @@ -0,0 +1,27 @@ +from django.db import migrations + + +class Migration(migrations.Migration): + """ + We previously accepted invalid ISO 8601 dates like 1909-3-5 for + date values of custom profile fields. Correct them by adding the + missing leading zeros: 1909-03-05. + """ + + dependencies = [ + ("zerver", "0305_realm_deactivated_redirect"), + ] + + operations = [ + migrations.RunSQL( + sql="""\ + UPDATE zerver_customprofilefieldvalue + SET value = to_char(to_date(value, 'YYYY-MM-DD'), 'YYYY-MM-DD') + FROM zerver_customprofilefield AS f + WHERE f.id = field_id + AND f.field_type = 4 + AND value <> to_char(to_date(value, 'YYYY-MM-DD'), 'YYYY-MM-DD'); + """, + reverse_sql="", + ), + ] diff --git a/zerver/openapi/zulip.yaml b/zerver/openapi/zulip.yaml index 6630d77dd0..cb514f8454 100644 --- a/zerver/openapi/zulip.yaml +++ b/zerver/openapi/zulip.yaml @@ -4133,7 +4133,7 @@ paths: "value": "I am:\n* The prince of Denmark\n* Nephew to the usurping Claudius", "rendered_value": "

I am:

\n", }, - "5": {"value": "1900-1-1"}, + "5": {"value": "1900-01-01"}, "7": {"value": "[11]"}, "6": {"value": "https://blog.zulig.org"}, "1": @@ -4488,7 +4488,7 @@ paths: "user_id": 5, "profile_data": { - "5": {"value": "2000-1-1"}, + "5": {"value": "2000-01-01"}, "4": {"value": "emacs"}, "7": {"value": "[10]"}, "1": @@ -5538,7 +5538,7 @@ paths: "value": "I am:\n* The prince of Denmark\n* Nephew to the usurping Claudius", "rendered_value": "

I am:

\n", }, - "5": {"value": "1900-1-1"}, + "5": {"value": "1900-01-01"}, "7": {"value": "[11]"}, "6": {"value": "https://blog.zulig.org"}, "1": diff --git a/zerver/tests/test_custom_profile_data.py b/zerver/tests/test_custom_profile_data.py index 2cd1d3126c..b890655d7c 100644 --- a/zerver/tests/test_custom_profile_data.py +++ b/zerver/tests/test_custom_profile_data.py @@ -504,6 +504,8 @@ class UpdateCustomProfileFieldTest(CustomProfileFieldTestCase): field_name = "Birthday" self.assert_error_update_invalid_value(field_name, "a-b-c", f"{field_name} is not a date") + self.assert_error_update_invalid_value(field_name, "1909-3-5", + f"{field_name} is not a date") self.assert_error_update_invalid_value(field_name, 123, f"{field_name} is not a string") @@ -526,7 +528,7 @@ class UpdateCustomProfileFieldTest(CustomProfileFieldTestCase): ('Biography', '~~short~~ **long** text data'), ('Favorite food', 'long short text data'), ('Favorite editor', 'vim'), - ('Birthday', '1909-3-5'), + ('Birthday', '1909-03-05'), ('Favorite website', 'https://zulip.com'), ('Mentor', [self.example_user("cordelia").id]), ('GitHub', 'zulip-mobile'), diff --git a/zerver/tests/test_users.py b/zerver/tests/test_users.py index 941bd49399..fd0110c2f9 100644 --- a/zerver/tests/test_users.py +++ b/zerver/tests/test_users.py @@ -598,7 +598,7 @@ class PermissionTest(ZulipTestCase): 'Biography': 'long text data', 'Favorite food': 'short text data', 'Favorite editor': 'vim', - 'Birthday': '1909-3-5', + 'Birthday': '1909-03-05', 'Favorite website': 'https://zulip.com', 'Mentor': [cordelia.id], 'GitHub': 'timabbott', diff --git a/zilencer/management/commands/populate_db.py b/zilencer/management/commands/populate_db.py index 87c7623477..e1fbe197ff 100644 --- a/zilencer/management/commands/populate_db.py +++ b/zilencer/management/commands/populate_db.py @@ -505,7 +505,7 @@ class Command(BaseCommand): {"id": biography.id, "value": "Betrayer of Othello."}, {"id": favorite_food.id, "value": "Apples"}, {"id": favorite_editor.id, "value": "emacs"}, - {"id": birthday.id, "value": "2000-1-1"}, + {"id": birthday.id, "value": "2000-01-01"}, {"id": favorite_website.id, "value": "https://zulip.readthedocs.io/en/latest/"}, {"id": mentor.id, "value": [hamlet.id]}, {"id": github_profile.id, "value": 'zulip'}, @@ -518,7 +518,7 @@ class Command(BaseCommand): }, {"id": favorite_food.id, "value": "Dark chocolate"}, {"id": favorite_editor.id, "value": "vim"}, - {"id": birthday.id, "value": "1900-1-1"}, + {"id": birthday.id, "value": "1900-01-01"}, {"id": favorite_website.id, "value": "https://blog.zulig.org"}, {"id": mentor.id, "value": [iago.id]}, {"id": github_profile.id, "value": 'zulipbot'},