/usr/lib/python2.7/dist-packages/keyring/backend.py is in python-keyring 4.0-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 | """
Keyring implementation support
"""
from __future__ import absolute_import
import abc
try:
import importlib
except ImportError:
pass
from . import errors, util
from . import backends
from .util import properties
from .py27compat import add_metaclass, filter
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)
@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"
if 'importlib' in globals():
package = backends.__package__ or backends.__name__
mod = importlib.import_module('.'+name, package)
else:
# Python 2.6 support
ns = {}
exec("from .backends import {name} as mod".format(name=name),
globals(), ns)
mod = ns['mod']
# invoke __name__ on each module to ensure it's loaded in demand-import
# environments
mod.__name__
def _load_backends():
"ensure that all keyring backends are loaded"
backends = ('file', 'Gnome', 'Google', 'keyczar', 'kwallet', 'multi',
'OS_X', 'pyfs', 'SecretService', 'Windows')
list(map(_load_backend, backends))
@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))
|