Skip to content

Commit f6b27f2

Browse files
committed
Require ASCII digits in Finnish, French and Indian identifiers
fi_ssn(), fr_ssn(), ind_aadhar() and ind_pan() matched digits with \d and separators with \s, which for str patterns match any Unicode decimal digit or whitespace, and the checksums use int(), which accepts the same digits. An identifier with one digit swapped for its Arabic-Indic or fullwidth form, or a space for a no-break space, still validated. Add re.ASCII to the four patterns.
1 parent f93bc7c commit f6b27f2

6 files changed

Lines changed: 37 additions & 4 deletions

File tree

‎src/validators/i18n/fi.py‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ def _ssn_pattern(ssn_check_marks: str):
2626
(?P<century>[ABCDEFYXWVU+-])
2727
(?P<serial>(\d{{3}}))
2828
(?P<checksum>[{check_marks}])$""".format(check_marks=ssn_check_marks),
29-
re.VERBOSE,
29+
re.VERBOSE | re.ASCII,
3030
)
3131

3232

‎src/validators/i18n/fr.py‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ def _ssn_pattern():
2020
r"\s(\d{2,3})" # town of birth
2121
r"\s(\d{3})" # registration number
2222
r"(?:\s(\d{2}))?$", # control key (may or may not be provided)
23-
re.VERBOSE,
23+
re.VERBOSE | re.ASCII,
2424
)
2525

2626

‎src/validators/i18n/ind.py‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ def ind_aadhar(value: str):
2424
(Literal[True]): If `value` is a valid aadhar card number.
2525
(ValidationError): If `value` is an invalid aadhar card number.
2626
"""
27-
return re.fullmatch(r"^[2-9]{1}\d{3}\s\d{4}\s\d{4}$", value)
27+
return re.fullmatch(r"^[2-9]{1}\d{3}\s\d{4}\s\d{4}$", value, re.ASCII)
2828

2929

3030
@validator
@@ -44,4 +44,4 @@ def ind_pan(value: str):
4444
(Literal[True]): If `value` is a valid PAN card number.
4545
(ValidationError): If `value` is an invalid PAN card number.
4646
"""
47-
return re.fullmatch(r"[A-Z]{5}\d{4}[A-Z]{1}", value)
47+
return re.fullmatch(r"[A-Z]{5}\d{4}[A-Z]{1}", value, re.ASCII)

‎tests/i18n/test_fi.py‎

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,3 +102,9 @@ def test_ssn_validates_birth_date_in_its_century(birth_date: str, century: str,
102102
checksum = "0123456789ABCDEFHJKLMNPRSTUVWXY"[int(birth_date + serial) % 31]
103103
value = birth_date + century + serial + checksum
104104
assert bool(fi_ssn(value)) is valid
105+
106+
107+
@pytest.mark.parametrize("value", ["1\u06631052-308T", "1310\u06652-308T", "131052-3\u06608T"])
108+
def test_returns_failed_validation_on_non_ascii_digits_in_ssn(value: str):
109+
"""Test returns failed validation when a script other than ASCII supplies the digits."""
110+
assert isinstance(fi_ssn(value), ValidationError)

‎tests/i18n/test_fr.py‎

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,3 +85,16 @@ def test_returns_true_on_valid_department(value: Union[str, int]):
8585
def test_returns_failed_validation_on_invalid_department(value: Union[str, int]):
8686
"""Test returns failed validation on invalid department."""
8787
assert isinstance(fr_department(value), ValidationError)
88+
89+
90+
@pytest.mark.parametrize(
91+
"value",
92+
[
93+
"1 \u06684 12 76 451 089 46", # Arabic-Indic digit
94+
"1 84 12 76 451 089 \uff146", # fullwidth digit
95+
"1\u00a084 12 76 451 089 46", # no-break space
96+
],
97+
)
98+
def test_returns_failed_validation_on_non_ascii_digits_or_spaces_in_ssn(value: str):
99+
"""Test returns failed validation on digits or spaces outside ASCII."""
100+
assert isinstance(fr_ssn(value), ValidationError)

‎tests/i18n/test_ind.py‎

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,3 +32,17 @@ def test_returns_true_on_valid_ind_pan(value: str):
3232
def test_returns_failed_validation_on_invalid_ind_pan(value: str):
3333
"""Test returns failed validation on invalid ind pan."""
3434
assert isinstance(ind_pan(value), ValidationError)
35+
36+
37+
@pytest.mark.parametrize(
38+
"value", ["3\u066675 9834 6012", "3675 9834 601\uff12", "3675\u00a09834 6012"]
39+
)
40+
def test_returns_failed_validation_on_non_ascii_digits_or_spaces_in_ind_aadhar(value: str):
41+
"""Test returns failed validation on digits or spaces outside ASCII."""
42+
assert isinstance(ind_aadhar(value), ValidationError)
43+
44+
45+
@pytest.mark.parametrize("value", ["ABCDE\u0669999K", "ABCDE999\uff19K"])
46+
def test_returns_failed_validation_on_non_ascii_digits_in_ind_pan(value: str):
47+
"""Test returns failed validation when a script other than ASCII supplies the digits."""
48+
assert isinstance(ind_pan(value), ValidationError)

0 commit comments

Comments
 (0)