Commits

Marcin Kasperski committed d0eee1a

Simple escape/unescape routine which should be backward-compatible for ascii usernames/services

Comments (0)

Files changed (4)

 syntax: regexp
 
 \.py[co]$
+^build/
+~$

keyring/tests/test_util.py

+# -*- coding: utf-8 -*-
+
+"""
+Test for simple escape/unescape routine
+"""
+
+
+import unittest
+import os
+import sys
+import tempfile
+import shutil
+
+from keyring.util import escape
+
+class EscapeTestCase(unittest.TestCase):
+
+    def check_escape_unescape(self, initial):
+        escaped = escape.escape(initial)
+        self.assertTrue(all( c in (escape.LEGAL_CHARS + escape.ESCAPE_CHAR)
+                             for c in escaped))
+        unescaped = escape.unescape(escaped)
+        self.assertEqual(initial, unescaped)
+
+    def test_escape_unescape(self):
+        self.check_escape_unescape("aaaa")
+        self.check_escape_unescape("aaaa bbbb cccc")
+        self.check_escape_unescape(u"Zażółć gęślą jaźń".encode("utf-8"))
+        self.check_escape_unescape("(((P{{{{'''---; ;; '\"|%^")
+
+def test_suite():
+    suite = unittest.TestSuite()
+    suite.addTest(unittest.makeSuite(EscapeTestCase))
+    return suite
+
+if __name__ == "__main__":
+    unittest.main(defaultTest="test_suite")

keyring/util/__init__.py

Empty file added.

keyring/util/escape.py

+"""
+escape/unescape routines available for backends which need
+alphanumeric usernames, services, or other values
+"""
+
+import string, re
+
+LEGAL_CHARS = string.letters + string.digits
+ESCAPE_CHAR = "_"
+
+def escape(value):
+    """Escapes given value so the result consists of alphanumeric chars and underscore
+    only, and alphanumeric chars are preserved"""
+    def escape_char(c, legal = LEGAL_CHARS):
+        # Single char escape. Either normal char, or _<hexcode>
+        if c in legal:
+            return c
+        else:
+            return "%s%X" % (ESCAPE_CHAR, ord(c))
+    return "".join( escape_char(c) for c in value )
+
+def unescape(value):
+    """Reverts escape"""
+    re_esc = re.compile("_([0-9A-F]{2})")
+    return re_esc.sub(lambda i: chr(int(i.group(1),16)), value)