summaryrefslogtreecommitdiff
path: root/slixmpp/stringprep.py
diff options
context:
space:
mode:
Diffstat (limited to 'slixmpp/stringprep.py')
-rw-r--r--slixmpp/stringprep.py121
1 files changed, 121 insertions, 0 deletions
diff --git a/slixmpp/stringprep.py b/slixmpp/stringprep.py
new file mode 100644
index 00000000..99506d78
--- /dev/null
+++ b/slixmpp/stringprep.py
@@ -0,0 +1,121 @@
+# -*- coding: utf-8 -*-
+"""
+ slixmpp.stringprep
+ ~~~~~~~~~~~~~~~~~~~~~~~
+
+ This module is a fallback using python’s stringprep instead of libidn’s.
+
+ Part of Slixmpp: The Slick XMPP Library
+
+ :copyright: (c) 2015 Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
+ :license: MIT, see LICENSE for more details
+"""
+
+import logging
+import stringprep
+from slixmpp.util import stringprep_profiles
+import encodings.idna
+
+class StringprepError(Exception):
+ pass
+
+#: These characters are not allowed to appear in a domain part.
+ILLEGAL_CHARS = ('\x00\x01\x02\x03\x04\x05\x06\x07\x08\t\n\x0b\x0c\r'
+ '\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19'
+ '\x1a\x1b\x1c\x1d\x1e\x1f'
+ ' !"#$%&\'()*+,./:;<=>?@[\\]^_`{|}~\x7f')
+
+
+# pylint: disable=c0103
+#: The nodeprep profile of stringprep used to validate the local,
+#: or username, portion of a JID.
+_nodeprep = stringprep_profiles.create(
+ nfkc=True,
+ bidi=True,
+ mappings=[
+ stringprep_profiles.b1_mapping,
+ stringprep.map_table_b2],
+ prohibited=[
+ stringprep.in_table_c11,
+ stringprep.in_table_c12,
+ stringprep.in_table_c21,
+ stringprep.in_table_c22,
+ stringprep.in_table_c3,
+ stringprep.in_table_c4,
+ stringprep.in_table_c5,
+ stringprep.in_table_c6,
+ stringprep.in_table_c7,
+ stringprep.in_table_c8,
+ stringprep.in_table_c9,
+ lambda c: c in ' \'"&/:<>@'],
+ unassigned=[stringprep.in_table_a1])
+
+def nodeprep(node):
+ try:
+ return _nodeprep(node)
+ except stringprep_profiles.StringPrepError:
+ raise StringprepError
+
+# pylint: disable=c0103
+#: The resourceprep profile of stringprep, which is used to validate
+#: the resource portion of a JID.
+_resourceprep = stringprep_profiles.create(
+ nfkc=True,
+ bidi=True,
+ mappings=[stringprep_profiles.b1_mapping],
+ prohibited=[
+ stringprep.in_table_c12,
+ stringprep.in_table_c21,
+ stringprep.in_table_c22,
+ stringprep.in_table_c3,
+ stringprep.in_table_c4,
+ stringprep.in_table_c5,
+ stringprep.in_table_c6,
+ stringprep.in_table_c7,
+ stringprep.in_table_c8,
+ stringprep.in_table_c9],
+ unassigned=[stringprep.in_table_a1])
+
+def resourceprep(resource):
+ try:
+ return _resourceprep(resource)
+ except stringprep_profiles.StringPrepError:
+ raise StringprepError
+
+def idna(domain):
+ domain_parts = []
+ for label in domain.split('.'):
+ try:
+ label = encodings.idna.nameprep(label)
+ encodings.idna.ToASCII(label)
+ except UnicodeError:
+ raise StringprepError
+
+ if label.startswith('xn--'):
+ label = encodings.idna.ToUnicode(label)
+
+ for char in label:
+ if char in ILLEGAL_CHARS:
+ raise StringprepError
+
+ domain_parts.append(label)
+ return '.'.join(domain_parts)
+
+def punycode(domain):
+ domain_parts = []
+ for label in domain.split('.'):
+ try:
+ label = encodings.idna.nameprep(label)
+ encodings.idna.ToASCII(label)
+ except UnicodeError:
+ raise StringprepError
+
+ for char in label:
+ if char in ILLEGAL_CHARS:
+ raise StringprepError
+
+ domain_parts.append(label)
+ return b'.'.join(domain_parts)
+
+logging.getLogger(__name__).warning('Using slower stringprep, consider '
+ 'compiling the faster cython/libidn one.')