diff options
author | Philipp Hörist <philipp@hoerist.com> | 2022-09-10 13:43:38 +0300 |
---|---|---|
committer | Philipp Hörist <philipp@hoerist.com> | 2022-09-10 16:14:53 +0300 |
commit | 93bb40ad402cefaedddfa5c4399d125fbe396d08 (patch) | |
tree | e9fbb86b4a2b9373f0ad232b3f09e5559507559e | |
parent | f7ee69faa20dcf2dec6e2f7a9d9e0e39473babf2 (diff) |
cfix: Fallback to PRECIS for localpart and resourcepart
Instead of enforcing stringprep or precis, try stringprep and fallback
to precis otherwise.
-rw-r--r-- | nbxmpp/precis.py | 19 | ||||
-rw-r--r-- | nbxmpp/protocol.py | 27 | ||||
-rw-r--r-- | test/unit/test_jid_parsing.py | 4 |
3 files changed, 35 insertions, 15 deletions
diff --git a/nbxmpp/precis.py b/nbxmpp/precis.py new file mode 100644 index 0000000..a910205 --- /dev/null +++ b/nbxmpp/precis.py @@ -0,0 +1,19 @@ + + +from precis_i18n import get_profile + + +_localpart_disallowed_chars = set('"&\'/:<>@') + + +def enforce_precis_username(localpart: str) -> str: + if _localpart_disallowed_chars & set(localpart): + raise ValueError('Input contains prohibited codepoint: %s' % localpart) + + username = get_profile('UsernameCaseMapped') + return username.enforce(localpart) + + +def enforce_precis_opaque(resourcepart: str) -> str: + opaque = get_profile('OpaqueString') + return opaque.enforce(resourcepart) diff --git a/nbxmpp/protocol.py b/nbxmpp/protocol.py index 0b86015..704530a 100644 --- a/nbxmpp/protocol.py +++ b/nbxmpp/protocol.py @@ -37,11 +37,12 @@ from dataclasses import asdict from gi.repository import GLib import idna -from precis_i18n import get_profile from nbxmpp.simplexml import Node from nbxmpp.namespaces import Namespace from nbxmpp.stringprep import nodeprep from nbxmpp.stringprep import resourceprep +from nbxmpp.precis import enforce_precis_username +from nbxmpp.precis import enforce_precis_opaque def ascii_upper(s): @@ -256,7 +257,6 @@ _errorcodes = { } -_localpart_disallowed_chars = set('"&\'/:<>@') _localpart_escape_chars = ' "&\'/:<>@' @@ -487,18 +487,17 @@ def validate_localpart(localpart: str) -> str: if not localpart or len(localpart.encode()) > 1023: raise LocalpartByteLimit - if os.environ.get('NBXMPP_USE_PRECIS') is None: + if os.environ.get('NBXMPP_ENFORCE_PRECIS') is None: try: return nodeprep(localpart) except Exception: - raise LocalpartNotAllowedChar - - if _localpart_disallowed_chars & set(localpart): - raise LocalpartNotAllowedChar + try: + return enforce_precis_username(localpart) + except Exception: + raise LocalpartNotAllowedChar try: - username = get_profile('UsernameCaseMapped') - return username.enforce(localpart) + return enforce_precis_username(localpart) except Exception: raise LocalpartNotAllowedChar @@ -508,15 +507,17 @@ def validate_resourcepart(resourcepart: str) -> str: if not resourcepart or len(resourcepart.encode()) > 1023: raise ResourcepartByteLimit - if os.environ.get('NBXMPP_USE_PRECIS') is None: + if os.environ.get('NBXMPP_ENFORCE_PRECIS') is None: try: return resourceprep(resourcepart) except Exception: - raise ResourcepartNotAllowedChar + try: + return enforce_precis_opaque(resourcepart) + except Exception: + raise ResourcepartNotAllowedChar try: - opaque = get_profile('OpaqueString') - return opaque.enforce(resourcepart) + return enforce_precis_opaque(resourcepart) except Exception: raise ResourcepartNotAllowedChar diff --git a/test/unit/test_jid_parsing.py b/test/unit/test_jid_parsing.py index 374c942..a91c667 100644 --- a/test/unit/test_jid_parsing.py +++ b/test/unit/test_jid_parsing.py @@ -51,7 +51,7 @@ class JIDParsing(unittest.TestCase): JID.from_string(jid) def test_invalid_precis_jids(self): - os.environ['NBXMPP_USE_PRECIS'] = 'true' + os.environ['NBXMPP_ENFORCE_PRECIS'] = 'true' tests = [ ('henry\U00002163@example.com', LocalpartNotAllowedChar), ('\U0000265A@example.com', LocalpartNotAllowedChar), @@ -61,7 +61,7 @@ class JIDParsing(unittest.TestCase): with self.assertRaises(exception): JID.from_string(jid) - del os.environ['NBXMPP_USE_PRECIS'] + del os.environ['NBXMPP_ENFORCE_PRECIS'] def test_ip_literals(self): tests = [ |