1
- """SASL stringprep profile
1
+ """SASL stringprep_ profiles
2
2
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.
5
6
6
- Copyright (C) 2012, Wim Lewis <wiml@hhhh. org>.
7
+ .. _stringprep: http://www.ietf. org/rfc/rfc3454.txt
7
8
"""
8
9
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
+
9
14
from __future__ import absolute_import
10
15
from stringprep import *
11
16
import unicodedata
12
17
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!'
14
26
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\u00AD ber \u2168 ')
32
+ u'Number IX'
33
+
34
+ .. _SASLprep: http://www.ietf.org/rfc/rfc4013.txt
35
+ """
18
36
19
37
# Step 1 - Map
20
38
buf = u''
@@ -23,10 +41,10 @@ def prepare(s):
23
41
buf += u' '
24
42
elif not in_table_b1 (ch ):
25
43
buf += ch
26
-
44
+
27
45
# Step 2 - Normalize
28
46
buf = unicodedata .normalize ('NFKC' , buf )
29
-
47
+
30
48
# Step 3 - Prohibited characters
31
49
for ch in buf :
32
50
if ( in_table_c21 (ch ) or
@@ -38,10 +56,16 @@ def prepare(s):
38
56
in_table_c7 (ch ) or
39
57
in_table_c8 (ch ) or
40
58
in_table_c9 (ch ) ):
41
- raise UnicodeError ("Invalid character %r" % (ch ,))
42
-
59
+ raise UnicodeError ("Prohibited character %r" % (ch ,))
60
+
43
61
# 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.
45
69
if any (map (in_table_d1 , buf )):
46
70
# If there are any R+AL characters, the first and last
47
71
# characters must be R+AL.
@@ -50,6 +74,43 @@ def prepare(s):
50
74
# And there must not be any L (table d2).
51
75
if any (map (in_table_d2 , buf )):
52
76
raise UnicodeError ("bidi rejected by stringprep (6.2)" )
53
-
54
- return buf
55
77
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