1. Robert Leftwich
  2. Python Keyring Lib

Commits

Robert Leftwich  committed a3f5b33

Handle unicode only passwords on os x. Tighten up regex used for password matching return value of security call on os x and ensure unicode chars are unicode-only. Fixes #85

  • Participants
  • Parent commits c846684
  • Branches default

Comments (0)

Files changed (3)

File keyring/backends/OS_X.py

View file
 class Keyring(KeyringBackend):
     """Mac OS X Keychain"""
 
+    # regex for extracting password from security call
+    password_regex = re.compile("""password:\s*(?:0x(?P<hex>[0-9A-F]+)\s*)?"""
+                                """(?:"(?P<pw>.*)")?""")
+
     def supported(self):
         """Recommended for all OSX environment.
         """
             if output == 'password: \n':
                 return ''
             # search for special password pattern.
-            matches = re.search('password:(?P<hex>.*?)"(?P<pw>.*)"', output)
+            matches = Keyring.password_regex.search(output)
             if matches:
-                hex = matches.group('hex').strip()
-                pw = matches.group('pw')
+                group_dict = matches.groupdict()
+                hex = group_dict.get('hex')
+                pw = group_dict.get('pw')
                 if hex:
                     # it's a weird hex password, decode it.
-                    return binascii.unhexlify(hex[2:])
+                    return unicode(binascii.unhexlify(hex), 'utf-8')
                 else:
                     # it's a normal password, send it back.
                     return pw

File keyring/tests/backends/test_OS_X.py

View file
 
     def init_keyring(self):
         return OS_X.Keyring()
+
+    @unittest.expectedFailure
+    def test_delete_present(self):
+        """Not implemented"""
+        super(OSXKeychainTestCase, self).test_delete_present()
+
+

File keyring/tests/test_backend.py

View file
 from keyring import errors
 
 DIFFICULT_CHARS = string.whitespace + string.punctuation
-UNICODE_CHARS = escape.u("""κόσμεНа берегу пустынных волнSîne klâwen durh die
-wolken sint geslagen, er stîget ûf mit grôzer kraft""")
+# unicode only characters
+# Sourced from The Quick Brown Fox... Pangrams
+# http://www.columbia.edu/~fdc/utf8/
+UNICODE_CHARS = escape.u(
+    """זהכיףסתםלשמועאיךתנצחקרפדעץטובבגן"""
+    """ξεσκεπάζωτηνψυχοφθόραβδελυγμία"""
+    """Съешьжеещёэтихмягкихфранцузскихбулокдавыпейчаю"""
+    """Жълтатадюлябешещастливачепухъткойтоцъфназамръзнакатогьон"""
+)
 
+# ensure no-ascii chars slip by - watch your editor!
+assert min(ord(char) for char in UNICODE_CHARS) > 127
 
 class BackendBasicTests(object):
-    """Test for the keyring's basic funtions. password_set and password_get
+    """Test for the keyring's basic functions. password_set and password_get
     """
 
     def setUp(self):
         service = random_string(20, UNICODE_CHARS)
         self.check_set_get(service, username, password)
 
+    def test_unicode_and_ascii_chars(self):
+        source = (random_string(10, UNICODE_CHARS) + random_string(10) +
+                 random_string(10, DIFFICULT_CHARS))
+        password = random_string(20, source)
+        username = random_string(20, source)
+        service = random_string(20, source)
+        self.check_set_get(service, username, password)
+
     def test_different_user(self):
         """
         Issue #47 reports that WinVault isn't storing passwords for