/usr/lib/python3/dist-packages/keyring/backend.py is in python3-keyring 10.1-1.
This file is owned by root:root, with mode 0o644.
The actual contents of the file can be viewed below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 | """
Keyring implementation support
"""
from __future__ import absolute_import
import abc
import logging
import importlib
try:
import pkg_resources
except ImportError:
pass
from . import errors, util
from . import backends
from .util import properties
from .py27compat import add_metaclass, filter
log = logging.getLogger(__name__)
class KeyringBackendMeta(abc.ABCMeta):
"""
A metaclass that's both an ABCMeta and a type that keeps a registry of
all (non-abstract) types.
"""
def __init__(cls, name, bases, dict):
super(KeyringBackendMeta, cls).__init__(name, bases, dict)
if not hasattr(cls, '_classes'):
cls._classes = set()
classes = cls._classes
if not cls.__abstractmethods__:
classes.add(cls)
@add_metaclass(KeyringBackendMeta)
class KeyringBackend(object):
"""The abstract base class of the keyring, every backend must implement
this interface.
"""
#@abc.abstractproperty
def priority(cls):
"""
Each backend class must supply a priority, a number (float or integer)
indicating the priority of the backend relative to all other backends.
The priority need not be static -- it may (and should) vary based
attributes of the environment in which is runs (platform, available
packages, etc.).
A higher number indicates a higher priority. The priority should raise
a RuntimeError with a message indicating the underlying cause if the
backend is not suitable for the current environment.
As a rule of thumb, a priority between zero but less than one is
suitable, but a priority of one or greater is recommended.
"""
@properties.ClassProperty
@classmethod
def viable(cls):
with errors.ExceptionRaisedContext() as exc:
cls.priority
return not bool(exc)
@properties.ClassProperty
@classmethod
def name(cls):
"""
The keyring name, suitable for display.
The name is derived from module and class name.
"""
parent, sep, mod_name = cls.__module__.rpartition('.')
mod_name = mod_name.replace('_', ' ')
return ' '.join([mod_name, cls.__name__])
@abc.abstractmethod
def get_password(self, service, username):
"""Get password of the username for the service
"""
return None
@abc.abstractmethod
def set_password(self, service, username, password):
"""Set password for the username of the service
"""
raise errors.PasswordSetError("reason")
# for backward-compatibility, don't require a backend to implement
# delete_password
#@abc.abstractmethod
def delete_password(self, service, username):
"""Delete the password for the username of the service.
"""
raise errors.PasswordDeleteError("reason")
class Crypter(object):
"""Base class providing encryption and decryption
"""
@abc.abstractmethod
def encrypt(self, value):
"""Encrypt the value.
"""
pass
@abc.abstractmethod
def decrypt(self, value):
"""Decrypt the value.
"""
pass
class NullCrypter(Crypter):
"""A crypter that does nothing
"""
def encrypt(self, value):
return value
def decrypt(self, value):
return value
def _load_backend(name):
"Load a backend by name"
package = backends.__package__ or backends.__name__
mod = importlib.import_module('.'+name, package)
# invoke __name__ on each module to ensure it's loaded in demand-import
# environments
mod.__name__
def _load_backends():
"ensure that native keyring backends are loaded"
backends = 'kwallet', 'OS_X', 'SecretService', 'Windows'
list(map(_load_backend, backends))
_load_plugins()
def _load_plugins():
"""
Locate all setuptools entry points by the name 'keyring backends'
and initialize them.
Any third-party library may register an entry point by adding the
following to their setup.py::
entry_points = {
'keyring.backends': [
'plugin_name = mylib.mymodule:initialize_func',
],
},
`plugin_name` can be anything, and is only used to display the name
of the plugin at initialization time.
`initialize_func` is optional, but will be invoked if callable.
"""
if 'pkg_resources' not in globals():
return
group = 'keyring.backends'
entry_points = pkg_resources.iter_entry_points(group=group)
for ep in entry_points:
try:
log.info('Loading %s', ep.name)
init_func = ep.load()
if callable(init_func):
init_func()
except Exception:
log.exception("Error initializing plugin %s." % ep)
@util.once
def get_all_keyring():
"""
Return a list of all implemented keyrings that can be constructed without
parameters.
"""
_load_backends()
def is_class_viable(keyring_cls):
try:
keyring_cls.priority
except RuntimeError:
return False
return True
all_classes = KeyringBackend._classes
viable_classes = filter(is_class_viable, all_classes)
return list(util.suppress_exceptions(viable_classes,
exceptions=TypeError))
|