diff --git a/flatpak/com.borgbase.Vorta.json b/flatpak/com.borgbase.Vorta.json index 49dc97b3..0dbb7160 100644 --- a/flatpak/com.borgbase.Vorta.json +++ b/flatpak/com.borgbase.Vorta.json @@ -16,6 +16,7 @@ "--talk-name=org.freedesktop.DBus.*", "--talk-name=org.freedesktop.Flatpak.*", "--talk-name=org.freedesktop.secrets", + "--talk-name=org.kde.kwalletd5", "--socket=ssh-auth", "--talk-name=org.freedesktop.Notifications", "--system-talk-name=org.freedesktop.NetworkManager" @@ -57,4 +58,4 @@ ] } ] -} \ No newline at end of file +} diff --git a/src/vorta/keyring/abc.py b/src/vorta/keyring/abc.py index f969e692..5d48ce03 100644 --- a/src/vorta/keyring/abc.py +++ b/src/vorta/keyring/abc.py @@ -36,14 +36,17 @@ def get_keyring(): if _keyring is None or not _keyring.is_primary: if sys.platform == 'darwin': # Use Keychain on macOS from .darwin import VortaDarwinKeyring - return VortaDarwinKeyring() + _keyring = VortaDarwinKeyring() else: # Try to use DBus and Gnome-Keyring (available on Linux and *BSD) import secretstorage from .secretstorage import VortaSecretStorageKeyring try: _keyring = VortaSecretStorageKeyring() - # Save passwords in DB, if all else fails. - except secretstorage.SecretServiceNotAvailableException: - from .db import VortaDBKeyring - _keyring = VortaDBKeyring() + except secretstorage.SecretServiceNotAvailableException: # Try to use KWallet + from .kwallet import VortaKWallet5Keyring, KWalletNotAvailableException + try: + _keyring = VortaKWallet5Keyring() + except KWalletNotAvailableException: # Save passwords in DB, if all else fails. + from .db import VortaDBKeyring + _keyring = VortaDBKeyring() return _keyring diff --git a/src/vorta/keyring/kwallet.py b/src/vorta/keyring/kwallet.py new file mode 100644 index 00000000..975fb5a2 --- /dev/null +++ b/src/vorta/keyring/kwallet.py @@ -0,0 +1,56 @@ +from PyQt5 import QtDBus +from PyQt5.QtCore import QVariant +from vorta.keyring.abc import VortaKeyring + + +class VortaKWallet5Keyring(VortaKeyring): + """A wrapper for the qtdbus package to support the custom keyring backend""" + + folder_name = 'Vorta' + service_name = "org.kde.kwalletd5" + object_path = "/modules/kwalletd5" + interface_name = 'org.kde.KWallet' + + def __init__(self): + """ + Test whether DBus and KDEWallet are available. + """ + self.iface = QtDBus.QDBusInterface( + self.service_name, + self.object_path, + self.interface_name, + QtDBus.QDBusConnection.sessionBus()) + if not (self.iface.isValid() and self.get_result("isEnabled")): + raise KWalletNotAvailableException + + def set_password(self, service, repo_url, password): + self.get_result("writePassword", args=[self.handle, self.folder_name, repo_url, password, service]) + + def get_password(self, service, repo_url): + if not (self.is_unlocked and self.get_result("hasEntry", + args=[self.handle, self.folder_name, repo_url, service])): + return None + return self.get_result("readPassword", args=[self.handle, self.folder_name, repo_url, service]) + + def get_result(self, method, args=[]): + if args: + result = self.iface.callWithArgumentList(QtDBus.QDBus.AutoDetect, method, args) + else: + result = self.iface.call(QtDBus.QDBus.AutoDetect, method) + return result.arguments()[0] + + @property + def is_unlocked(self): + self.get_handle() + return self.handle > 0 + + def get_handle(self): + wallet_name = self.get_result("networkWallet") + wId = QVariant(0) + wId.convert(4) + output = self.get_result("open", args=[wallet_name, wId, 'vorta-repo']) + self.handle = int(output) + + +class KWalletNotAvailableException(Exception): + pass