import json
from ...logger import logger
from ...enums import KeyringEnum
from ... import exceptions
from ._base import KeyringBackend
import os
class KeyringBackendLinux(KeyringBackend):
def __init__(self, keyring_backend):
self.__keyring_backend = keyring_backend
self.__keyring_service = KeyringEnum.DEFAULT_KEYRING_SERVICE.value
def __getitem__(self, key):
logger.info("Get key {}".format(key))
import keyring
self._ensure_key_is_valid(key)
try:
stored_data = self.__keyring_backend.get_password(
self.__keyring_service,
key
)
except (keyring.errors.InitError) as e:
logger.exception("AccessKeyringError: {}".format(e))
raise exceptions.AccessKeyringError(
"Could not fetch from keychain: {}".format(e)
)
except (Exception, keyring.errors.KeyringError) as e:
logger.exception("KeyringError: {}".format(e))
raise exceptions.KeyringError(e)
# Since we're borrowing the dict interface,
# be consistent and throw a KeyError if it doesn't exist
if stored_data is None:
raise KeyError(key)
try:
return json.loads(stored_data)
except json.decoder.JSONDecodeError as e:
logger.exception(e)
raise exceptions.JSONDataEmptyError(e)
except TypeError as e:
logger.exception(e)
raise exceptions.JSONDataNoneError(e)
except Exception as e:
logger.exception(e)
raise exceptions.JSONDataError(e)
def __delitem__(self, key):
logger.info("Delete key {}".format(key))
import keyring
self._ensure_key_is_valid(key)
try:
self.__keyring_backend.delete_password(self.__keyring_service, key)
except (
keyring.errors.InitError
) as e:
logger.exception("AccessKeyringError: {}".format(e))
raise exceptions.AccessKeyringError(
"Could not access keychain: {}".format(e)
)
except keyring.errors.PasswordDeleteError as e:
logger.exception("KeyringDataNotFound: {}".format(e))
raise KeyError(key)
except (Exception, keyring.errors.KeyringError) as e:
logger.exception("Unknown exception: {}".format(e))
# We shouldn't ignore exceptions!
raise exceptions.KeyringError(e)
# capture_exception(e)
def __setitem__(self, key, value):
logger.info("Set key {}".format(key))
"""Add data entry to keyring.
Args:
data (dict(json)): data to be stored
keyring_username (string): the keyring username
keyring_service (string): the keyring servicename
"""
import keyring
self._ensure_key_is_valid(key)
self._ensure_value_is_valid(value)
json_data = json.dumps(value)
try:
self.__keyring_backend.set_password(
self.__keyring_service,
key,
json_data
)
except (
keyring.errors.InitError,
keyring.errors.PasswordSetError
) as e:
logger.exception("AccessKeyringError: {}".format(e))
raise exceptions.AccessKeyringError(
"Could not access keychain: {}".format(e)
)
except (Exception, keyring.errors.KeyringError) as e:
logger.error("Exception: {}".format(e))
raise exceptions.KeyringError(e)
def _ensure_backend_is_working(self):
"""Ensure that a backend is working properly.
It can happen so that a backend is installed but it might be
missonfigured. But adding this test, we can asses if the backend
is working correctly or not. If not then another backend should be tried instead.
keyring.errors.InitError will be thrown if the backend system can not be initialized,
indicating that possibly it might be missconfigured.
"""
import keyring
try:
self.__keyring_backend.get_password(
self.__keyring_service,
"TestingThatBackendIsWorking"
)
except (keyring.errors.InitError) as e:
logger.debug(e)
logger.exception("Unable to select {} backend".format(self.__keyring_backend))
raise exceptions.AccessKeyringError(
"Unable to select {} backend".format(self.__keyring_backend)
)
except: # noqa
pass
class KeyringBackendLinuxKwallet(KeyringBackendLinux):
priority = (
5.1
if "KDE" in os.getenv(
"XDG_CURRENT_DESKTOP", ""
).split(":")
else 4.9
)
def __init__(self):
from keyring.backends import kwallet
backend = kwallet.DBusKeyring()
super().__init__(backend)
self._ensure_backend_is_working()
class KeyringBackendLinuxSecretService(KeyringBackendLinux):
priority = 5
def __init__(self):
from keyring.backends import SecretService
backend = SecretService.Keyring()
super().__init__(backend)
self._ensure_backend_is_working()