Extract credential decoding into DecodingCredential, consolidating the decoding handling.
@@ -43,6 +43,19 @@ class Persistence:
setattr(keyring, '_persist', value)
+class DecodingCredential(dict):
+ @property
+ def value(self):
+ """
+ Attempt to decode the credential blob as UTF-16 then UTF-8.
+ """
+ cred = self['CredentialBlob']
+ try:
+ return cred.decode('utf-16')
+ except UnicodeDecodeError:
+ return cred.decode('utf-8')
+
+
class WinVaultKeyring(KeyringBackend):
"""
WinVaultKeyring stores encrypted passwords using the Windows Credential
@@ -85,11 +98,7 @@ class WinVaultKeyring(KeyringBackend):
res = self._get_password(self._compound_name(username, service))
if not res:
return None
- blob = res['CredentialBlob']
- try:
- return blob.decode('utf-16')
- except UnicodeDecodeError:
- return blob.decode('utf-8')
+ return res.value
def _get_password(self, target):
try:
@@ -101,7 +110,7 @@ class WinVaultKeyring(KeyringBackend):
if e.winerror == 1168 and e.funcname == 'CredRead': # not found
return None
raise
- return res
+ return DecodingCredential(res)
def set_password(self, service, username, password):
existing_pw = self._get_password(service)
@@ -112,7 +121,7 @@ class WinVaultKeyring(KeyringBackend):
self._set_password(
target,
existing_username,
- existing_pw['CredentialBlob'].decode('utf-16'),
+ existing_pw.value,
)
self._set_password(service, username, str(password))
@@ -157,14 +166,7 @@ class WinVaultKeyring(KeyringBackend):
res = self._get_password(service)
if not res:
return None
- try:
- return SimpleCredential(
- res['UserName'], res['CredentialBlob'].decode('utf-16')
- )
- except UnicodeDecodeError:
- return SimpleCredential(
- res['UserName'], res['CredentialBlob'].decode('utf-8')
- )
+ return SimpleCredential(res['UserName'], res.value)
class OldPywinError:
