Add a helper to check whether a user ID is compliant without parsing it

This commit is contained in:
Paul Chobert committed 2026-10-09 15:24:00 +02:00
1 parent 5e78aad7d7
commit 1fc46fdbb9
2 files changed
+34

No files matched your search

+18
View File
@@ -593,6 +593,24 @@ def is_compliant_user_id_localpart(localpart: str) -> bool:
return all(0x21 <= ord(c) <= 0x7E for c in localpart)
def is_compliant_user_id(user_id: str) -> bool:
"""
Validates that the localpart of the given user ID is within the "compliant"
range. See `is_compliant_user_id_localpart`.
Unlike parsing the user ID with `UserID.from_string`, this never raises on a
malformed user ID.
Args:
user_id: the user ID to be checked
Returns:
True if the localpart of the user ID is compliant, False otherwise
"""
localpart, _, _ = user_id[1:].partition(":")
return is_compliant_user_id_localpart(localpart)
UPPER_CASE_PATTERN = re.compile(b"[A-Z_]")
# the following is a pattern which matches '=', and bytes which are not allowed in a mxid
+16
View File
@@ -37,6 +37,7 @@ from synapse.types import (
UserID,
get_domain_from_id,
get_localpart_from_id,
is_compliant_user_id,
map_username_to_mxid_localpart,
)
@@ -142,6 +143,21 @@ class MapUsernameTestCase(unittest.TestCase):
self.assertEqual(map_username_to_mxid_localpart("têst".encode()), "t=c3=aast")
class IsCompliantUserIdTestCase(unittest.TestCase):
def test_compliant(self) -> None:
self.assertTrue(is_compliant_user_id("@test_1234:test"))
self.assertTrue(is_compliant_user_id("@TEST!~:test"))
def test_non_compliant(self) -> None:
self.assertFalse(is_compliant_user_id("@têst:test"))
self.assertFalse(is_compliant_user_id("@te st:test"))
self.assertFalse(is_compliant_user_id("@:test"))
def test_malformed_does_not_raise(self) -> None:
self.assertFalse(is_compliant_user_id(""))
self.assertFalse(is_compliant_user_id("@"))
@parameterized_class(
("token_type",),
[