1. Kang Zhang
  2. Python Keyring Lib

Commits

Tarek Ziadé  committed 3beab2c Merge

merge dance

  • Participants
  • Parent commits c75348c, 0989ff9
  • Branches default

Comments (0)

Files changed (1)

File keyring/backend.py

View file
         return "wincrypto_pass.cfg"
 
     def supported(self):
-        """Recommend for all Windows is higher than Windows 2000.
+        """Recommend when other Windows backends are unavailable
         """
-        if self.crypt_handler is not None and sys.platform == 'win32':
-            major, minor, build, platform, text = sys.getwindowsversion()
-            if platform == 2:
-                # recommend for windows 2k+
-                return 1
-        return -1
+        recommended = select_windows_backend()
+        if recommended == None:
+            return -1
+        elif recommended == 'file':
+            return 1
+        else:
+            return 0
 
     def encrypt(self, password):
         """Encrypt the password using the CryptAPI.
         return self.crypt_handler.decrypt(password_encrypted)
 
 
+class WinVaultKeyring(KeyringBackend):
+    def __init__(self):
+        super(WinVaultKeyring, self).__init__()
+        try:
+            import pywintypes, win32cred
+            self.win32cred = win32cred
+            self.pywintypes = pywintypes
+        except ImportError:
+            self.win32cred = None
+    
+    def supported(self):
+        '''Default Windows backend, when it is available
+        '''
+        recommended = select_windows_backend()
+        if recommended == None:
+            return -1
+        elif recommended == 'cred':
+            return 1
+        else:
+            return 0
+    
+    def get_password(self, service, username):
+        try:
+            blob = self.win32cred.CredRead(Type=self.win32cred.CRED_TYPE_GENERIC, 
+                                           TargetName=service)['CredentialBlob']
+        except self.pywintypes.error, e:
+            if e[:2] == (1168, 'CredRead'):
+                return None
+            raise
+        return blob.decode("utf16")
+    
+    def set_password(self, service, username, password):
+        credential = dict(Type=self.win32cred.CRED_TYPE_GENERIC, 
+                          TargetName=service,
+                          UserName=username,
+                          CredentialBlob=unicode(password),
+                          Comment="Stored using python-keyring",
+                          Persist=self.win32cred.CRED_PERSIST_ENTERPRISE)
+        self.win32cred.CredWrite(credential, 0)
+
+
+class Win32CryptoRegistry(KeyringBackend):
+    """Win32CryptoRegistry is a keyring which use Windows CryptAPI to encrypt
+    the user's passwords and store them under registry keys
+    """
+    def __init__(self):
+        super(Win32CryptoRegistry, self).__init__()
+
+        try:
+            import win32_crypto
+            import _winreg
+            self.crypt_handler = win32_crypto
+        except ImportError:
+            self.crypt_handler = None
+
+    def supported(self):
+        """Return if this keyring supports current enviroment.
+        -1: not applicable
+         0: suitable
+         1: recommended
+        """
+        recommended = select_windows_backend()
+        if recommended == None:
+            return -1
+        elif recommended == 'reg':
+            return 1
+        else:
+            return 0
+
+    def get_password(self, service, username):
+        """Get password of the username for the service
+        """
+        from _winreg import HKEY_CURRENT_USER, OpenKey, QueryValueEx
+        try:
+            # fetch the password
+            key = r'Software\%s\Keyring' % service
+            hkey = OpenKey(HKEY_CURRENT_USER, key)
+            password_base64 = QueryValueEx(hkey, username)[0]
+            # decode with base64
+            password_encrypted = password_base64.decode("base64")
+            # decrypted the password
+            password = self.crypt_handler.decrypt(password_encrypted)
+        except EnvironmentError:
+            password = None
+        return password
+
+
+    def set_password(self, service, username, password):
+        """Write the password to the registry
+        """
+        # encrypt the password
+        password_encrypted = self.crypt_handler.encrypt(password)
+        # encode with base64
+        password_base64 = password_encrypted.encode("base64")
+
+        # store the password
+        from _winreg import HKEY_CURRENT_USER, CreateKey, SetValueEx, REG_SZ
+        hkey = CreateKey(HKEY_CURRENT_USER, r'Software\%s\Keyring' % service)
+        SetValueEx(hkey, username, 0, REG_SZ, password_base64)
+
+def select_windows_backend():
+    if os.name != 'nt':
+        return None
+    major, minor, build, platform, text = sys.getwindowsversion()
+    try:
+        import pywintypes, win32cred
+        if (major, minor) >= (5, 1):
+            # recommend for windows xp+
+            return 'cred'
+    except ImportError:
+        pass
+    try:
+        import win32_crypto, _winreg
+        if (major, minor) >= (5, 0):
+            # recommend for windows 2k+
+            return 'reg'
+    except ImportError:
+        pass
+    try:
+        import win32_crypto
+        return 'file'
+    except ImportError:
+        pass
+    return None
+
+
 _all_keyring = None
 
 def get_all_keyring():
     if _all_keyring is None:
         _all_keyring = [ OSXKeychain(), GnomeKeyring(), KDEKWallet(),
                          CryptedFileKeyring(), UncryptedFileKeyring(),
-                         Win32CryptoKeyring()]
+                         Win32CryptoKeyring(), Win32CryptoRegistry(),
+                         WinVaultKeyring()]
     return _all_keyring