/usr/share/mopidy/mopidy/config/keyring.py is in mopidy 0.17.0-3.
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 | from __future__ import unicode_literals
import logging
logger = logging.getLogger('mopidy.config.keyring')
try:
import dbus
except ImportError:
dbus = None
# XXX: Hack to workaround introspection bug caused by gnome-keyring, should be
# fixed by version 3.5 per:
# https://git.gnome.org/browse/gnome-keyring/commit/?id=5dccbe88eb94eea9934e2b7
if dbus:
EMPTY_STRING = dbus.String('', variant_level=1)
else:
EMPTY_STRING = ''
def fetch():
if not dbus:
logger.debug('Fetching from keyring failed: dbus not installed.')
return []
try:
bus = dbus.SessionBus()
except dbus.exceptions.DBusException as e:
logger.debug('Fetching from keyring failed: %s', e)
return []
if not bus.name_has_owner('org.freedesktop.secrets'):
logger.debug(
'Fetching from keyring failed: secrets service not running.')
return []
service = _service(bus)
session = service.OpenSession('plain', EMPTY_STRING)[1]
items, locked = service.SearchItems({'service': 'mopidy'})
if not locked and not items:
return []
if locked:
# There is a chance we can unlock without prompting the users...
items, prompt = service.Unlock(locked)
if prompt != '/':
_prompt(bus, prompt).Dismiss()
logger.debug('Fetching from keyring failed: keyring is locked.')
return []
result = []
secrets = service.GetSecrets(items, session, byte_arrays=True)
for item_path, values in secrets.iteritems():
session_path, parameters, value, content_type = values
attrs = _item_attributes(bus, item_path)
result.append((attrs['section'], attrs['key'], bytes(value)))
return result
def set(section, key, value):
"""Store a secret config value for a given section/key.
Indicates if storage failed or succeeded.
"""
if not dbus:
logger.debug('Saving %s/%s to keyring failed: dbus not installed.',
section, key)
return False
try:
bus = dbus.SessionBus()
except dbus.exceptions.DBusException as e:
logger.debug('Saving %s/%s to keyring failed: %s', section, key, e)
return False
if not bus.name_has_owner('org.freedesktop.secrets'):
logger.debug(
'Saving %s/%s to keyring failed: secrets service not running.',
section, key)
return False
service = _service(bus)
collection = _collection(bus)
if not collection:
return False
if isinstance(value, unicode):
value = value.encode('utf-8')
session = service.OpenSession('plain', EMPTY_STRING)[1]
secret = dbus.Struct((session, '', dbus.ByteArray(value),
'plain/text; charset=utf8'))
label = 'mopidy: %s/%s' % (section, key)
attributes = {'service': 'mopidy', 'section': section, 'key': key}
properties = {'org.freedesktop.Secret.Item.Label': label,
'org.freedesktop.Secret.Item.Attributes': attributes}
try:
item, prompt = collection.CreateItem(properties, secret, True)
except dbus.exceptions.DBusException as e:
# TODO: catch IsLocked errors etc.
logger.debug('Saving %s/%s to keyring failed: %s', section, key, e)
return False
if prompt == '/':
return True
_prompt(bus, prompt).Dismiss()
logger.debug('Saving secret %s/%s failed: Keyring is locked',
section, key)
return False
def _service(bus):
return _interface(bus, '/org/freedesktop/secrets',
'org.freedesktop.Secret.Service')
# NOTE: depending on versions and setup 'default' might not exists, so try and
# use it but fall back to the 'login' collection, and finally the 'session' one
# if all else fails. We should probably create a keyring/collection setting
# that allows users to set this so they have control over where their secrets
# get stored.
def _collection(bus):
for name in 'aliases/default', 'collection/login', 'collection/session':
path = '/org/freedesktop/secrets/' + name
if _collection_exists(bus, path):
break
else:
return None
return _interface(bus, path, 'org.freedesktop.Secret.Collection')
# NOTE: Hack to probe if a given collection actually exists. Needed to work
# around an introspection bug in setting passwords for non-existant aliases.
def _collection_exists(bus, path):
try:
item = _interface(bus, path, 'org.freedesktop.DBus.Properties')
item.Get('org.freedesktop.Secret.Collection', 'Label')
return True
except dbus.exceptions.DBusException:
return False
# NOTE: We could call prompt.Prompt('') to unlock the keyring when it is not
# '/', but we would then also have to arrange to setup signals to wait until
# this has been completed. So for now we just dismiss the prompt and expect
# keyrings to be unlocked.
def _prompt(bus, path):
return _interface(bus, path, 'Prompt')
def _item_attributes(bus, path):
item = _interface(bus, path, 'org.freedesktop.DBus.Properties')
result = item.Get('org.freedesktop.Secret.Item', 'Attributes')
return dict((bytes(k), bytes(v)) for k, v in result.iteritems())
def _interface(bus, path, interface):
obj = bus.get_object('org.freedesktop.secrets', path)
return dbus.Interface(obj, interface)
|