Skip to content

Commit 59fabe0

Browse files
committed
Add trace profile, doctests, cleanup.
1 parent 6a7f150 commit 59fabe0

File tree

1 file changed

+76
-15
lines changed

1 file changed

+76
-15
lines changed

sasl/stringprep.py

Lines changed: 76 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,38 @@
1-
"""SASL stringprep profile
1+
"""SASL stringprep_ profiles
22
3-
<http://www.ietf.org/rfc/rfc4013.txt>
4-
<http://www.ietf.org/rfc/rfc3454.txt>
3+
Defines functions which implement a few SASL-related stringprep
4+
profiles. Each function takes a (unicode) string and either returns
5+
the prepared string or raises an exception, usually a UnicodeError.
56
6-
Copyright (C) 2012, Wim Lewis <wiml@hhhh.org>.
7+
.. _stringprep: http://www.ietf.org/rfc/rfc3454.txt
78
"""
89

10+
# Written in 2012 by Wim Lewis <wiml@hhhh.org>.
11+
# This file is in the public domain. It may be used,
12+
# distributed, and modified without restriction.
13+
914
from __future__ import absolute_import
1015
from stringprep import *
1116
import unicodedata
1217

13-
__all__ = ( 'prepare', )
18+
__all__ = ( 'traceprep', 'saslprep' )
19+
__docformat__ = 'reStructuredText en'
20+
21+
def saslprep(s):
22+
"""Prepare a string according to the SASLprep_ stringprep profile.
23+
24+
>>> saslprep(u'Hi\u2003\uff2d\uff4f\uff4d!')
25+
u'Hi Mom!'
1426
15-
def prepare(s):
16-
"""Prepare a Unicode string according to the SASLprep stringprep profile.
17-
Returns the prepared string, or raises a UnicodeError on failue."""
27+
>>> saslprep(u'Hi\\rMom!')
28+
Traceback (most recent call last):
29+
UnicodeError: Prohibited character u'\\r'
30+
31+
>>> saslprep(u'Num\u00ADber \u2168')
32+
u'Number IX'
33+
34+
.. _SASLprep: http://www.ietf.org/rfc/rfc4013.txt
35+
"""
1836

1937
# Step 1 - Map
2038
buf = u''
@@ -23,10 +41,10 @@ def prepare(s):
2341
buf += u' '
2442
elif not in_table_b1(ch):
2543
buf += ch
26-
44+
2745
# Step 2 - Normalize
2846
buf = unicodedata.normalize('NFKC', buf)
29-
47+
3048
# Step 3 - Prohibited characters
3149
for ch in buf:
3250
if ( in_table_c21(ch) or
@@ -38,10 +56,16 @@ def prepare(s):
3856
in_table_c7(ch) or
3957
in_table_c8(ch) or
4058
in_table_c9(ch) ):
41-
raise UnicodeError("Invalid character %r" % (ch,))
42-
59+
raise UnicodeError("Prohibited character %r" % (ch,))
60+
4361
# Step 4 - bidi mark checking
44-
# If there are any characters in categort D1 (randAL), then do extra checks.
62+
_bidi_check(buf)
63+
64+
return buf
65+
66+
def _bidi_check(buf):
67+
"Perform the checks from RFC3454 section 6, and raise on failure."
68+
# If there are any characters in category D1 (R and AL), then do extra checks.
4569
if any(map(in_table_d1, buf)):
4670
# If there are any R+AL characters, the first and last
4771
# characters must be R+AL.
@@ -50,6 +74,43 @@ def prepare(s):
5074
# And there must not be any L (table d2).
5175
if any(map(in_table_d2, buf)):
5276
raise UnicodeError("bidi rejected by stringprep (6.2)")
53-
54-
return buf
5577

78+
def traceprep(s):
79+
"""Prepare a Unicode string according to the trace_ stringprep profile.
80+
81+
.. _trace: http://www.ietf.org/rfc/rfc4505.txt
82+
"""
83+
84+
# Trace defines no mapping or normalization.
85+
86+
# Prohibited characters
87+
for ch in s:
88+
if ( in_table_c21(ch) or
89+
in_table_c22(ch) or
90+
in_table_c3(ch) or
91+
in_table_c4(ch) or
92+
in_table_c5(ch) or
93+
in_table_c6(ch) or
94+
# But not table C.7.
95+
in_table_c8(ch) or
96+
in_table_c9(ch) ):
97+
raise UnicodeError("Prohibited character %r" % (ch,))
98+
99+
# Step 4 - bidi mark checking
100+
_bidi_check(s)
101+
102+
return s
103+
104+
__test__ = {
105+
'bidi': """
106+
>>> _bidi_check(u'\u0627\u0031\u0628')
107+
108+
>>> _bidi_check(u'\u0627' + u'1')
109+
Traceback (most recent call last):
110+
UnicodeError: bidi rejected by stringprep (6.3)
111+
112+
>>> _bidi_check(u'\u05c0 foo \u05c0')
113+
Traceback (most recent call last):
114+
UnicodeError: bidi rejected by stringprep (6.2)
115+
"""
116+
}

0 commit comments

Comments
 (0)