From 041bd63864429ac74ff7b7e267a0a96b04553383 Mon Sep 17 00:00:00 2001 From: Emmanuel Gil Peyrot Date: Thu, 20 Aug 2015 20:03:32 +0100 Subject: Add a function to convert a domain name to punycode. --- slixmpp/stringprep.py | 16 ++++++++++++++++ slixmpp/stringprep.pyx | 20 +++++++++++++++++++- 2 files changed, 35 insertions(+), 1 deletion(-) diff --git a/slixmpp/stringprep.py b/slixmpp/stringprep.py index e0757ef2..99506d78 100644 --- a/slixmpp/stringprep.py +++ b/slixmpp/stringprep.py @@ -101,5 +101,21 @@ def idna(domain): 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.') diff --git a/slixmpp/stringprep.pyx b/slixmpp/stringprep.pyx index e17c62c3..e751c8ea 100644 --- a/slixmpp/stringprep.pyx +++ b/slixmpp/stringprep.pyx @@ -19,7 +19,8 @@ from libc.stdlib cimport free # Those are Cython declarations for the C function we’ll be using. cdef extern from "stringprep.h" nogil: - int stringprep_profile(const char* in_, char** out, const char* profile, int flags) + int stringprep_profile(const char* in_, char** out, const char* profile, + int flags) cdef extern from "idna.h" nogil: int idna_to_ascii_8z(const char* in_, char** out, int flags) @@ -40,16 +41,19 @@ cdef str _stringprep(str in_, const char* profile): free(out) return unicode_out + def nodeprep(str node): """The nodeprep profile of stringprep used to validate the local, or username, portion of a JID.""" return _stringprep(node, 'Nodeprep') + def resourceprep(str resource): """The resourceprep profile of stringprep, which is used to validate the resource portion of a JID.""" return _stringprep(resource, 'Resourceprep') + def idna(str domain): """The idna conversion functions, which are used to validate the domain portion of a JID.""" @@ -69,3 +73,17 @@ def idna(str domain): unicode_domain = utf8_domain.decode('utf-8') free(utf8_domain) return unicode_domain + + +def punycode(str domain): + """Converts a domain name to its punycode representation.""" + + cdef char* ascii_domain + cdef bytes bytes_domain + + ret = idna_to_ascii_8z(domain.encode('utf-8'), &ascii_domain, 0) + if ret != 0: + raise StringprepError(ret) + bytes_domain = ascii_domain + free(ascii_domain) + return bytes_domain -- cgit v1.2.3