vorta/src/vorta/keyring/secretstorage.py

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

82 lines
2.7 KiB
Python
Raw Normal View History

import asyncio
import logging
import os
import secretstorage
from vorta.keyring.abc import VortaKeyring
logger = logging.getLogger(__name__)
LABEL_TEMPLATE = "Vorta Backup Repo {repo_url}"
class VortaSecretStorageKeyring(VortaKeyring):
"""A wrapper for the secretstorage package to support the custom keyring backend"""
def __init__(self):
"""
Test whether DBus and a SecretStorage provider are available.
"""
try:
self.connection = secretstorage.dbus_init()
except secretstorage.exceptions.SecretServiceNotAvailableException as e:
logger.debug("SecretStorage provider or DBus daemon is not available.")
raise e
asyncio.set_event_loop(asyncio.new_event_loop())
self.collection = secretstorage.get_default_collection(self.connection)
def set_password(self, service, repo_url, password):
"""
Writes a password to the underlying store.
"""
if self.is_unlocked:
asyncio.set_event_loop(asyncio.new_event_loop())
attributes = {
'application': 'Vorta',
'service': service,
'repo_url': repo_url,
'xdg:schema': 'org.freedesktop.Secret.Generic',
}
self.collection.create_item(
LABEL_TEMPLATE.format(repo_url=repo_url),
attributes,
password,
replace=True,
)
logger.debug(f"Saved password for repo {repo_url}")
def get_password(self, service, repo_url):
"""
Retrieve a password from the underlying store. Return None if not found.
"""
if self.is_unlocked:
asyncio.set_event_loop(asyncio.new_event_loop())
attributes = {
'application': 'Vorta',
'service': service,
'repo_url': repo_url,
}
items = list(self.collection.search_items(attributes))
logger.debug('Found %i passwords matching repo URL.', len(items))
if len(items) > 0:
item = items[0]
if item.is_locked() and item.unlock():
return None
logger.debug(f"Retrieved password for repo {repo_url}")
return item.get_secret().decode("utf-8")
return None
@property
def is_unlocked(self):
# unlock() will return True if the unlock prompt is dismissed
return not (self.collection.is_locked() and self.collection.unlock())
@classmethod
def get_priority(cls):
return 6 if "GNOME" in os.getenv("XDG_CURRENT_DESKTOP", "") else 5
@property
def is_system(self):
return True