Source code for pysasl.prep
from stringprep import (
in_table_a1,
in_table_b1,
in_table_c12,
in_table_c21_c22,
in_table_c3,
in_table_c4,
in_table_c5,
in_table_c6,
in_table_c7,
in_table_c8,
in_table_c9,
in_table_d1,
in_table_d2,
)
from typing import Callable
from typing_extensions import TypeAlias
from unicodedata import normalize
__all__ = ['Preparation', 'noprep', 'saslprep']
#: Any callable that prepares a string value to improve the likelihood that
#: comparisons behave in an expected manner.
#:
#: See Also:
#: `RFC 4422 5. <https://datatracker.ietf.org/doc/html/rfc4422#section-5>`_
Preparation: TypeAlias = Callable[[str], str]
def _always_false(code: str) -> bool:
return False
[docs]def noprep(source: str) -> str:
"""Returns *source* unmodified."""
return source
[docs]def saslprep(source: str, *, allow_unassigned: bool = False) -> str:
"""The SASLprep algorithm defined by `RFC 4013
<https://datatracker.ietf.org/doc/html/rfc4013>`_.
Args:
source: The string to prepare.
allow_unassigned: Allow unassigned code points in the result string,
Per `RFC 3454 7.
<https://datatracker.ietf.org/doc/html/rfc3454#section-7>`_, this
should only be used "queries" and never stored strings.
"""
mapped = ''.join(
' ' if in_table_c12(code) else code
for code in source
if not in_table_b1(code)
)
normalized = normalize('NFKC', mapped)
check_unassigned = _always_false if allow_unassigned else in_table_a1
any_d1 = False
any_d2 = False
for code in normalized:
if check_unassigned(code) \
or in_table_c21_c22(code) \
or in_table_c3(code) \
or in_table_c4(code) \
or in_table_c5(code) \
or in_table_c6(code) \
or in_table_c7(code) \
or in_table_c8(code) \
or in_table_c9(code):
raise ValueError(source)
elif in_table_d1(code):
any_d1 = True
elif in_table_d2(code):
any_d2 = True
if any_d1:
if any_d2:
raise ValueError(source)
elif not in_table_d1(source[0]) \
or not in_table_d1(source[-1]):
raise ValueError(source)
return normalized