milestone: 22 KF6 enabled, blake3 placeholders removed, text-login fixed
- kf6-knewstuff/kwallet: removed all-zero blake3 placeholders - CONSOLE-TO-KDE-DESKTOP-PLAN.md: 20→22 KF6 enabled count - BOOT-PROCESS-IMPROVEMENT-PLAN.md: text-login→graphical greeter path - D-Bus session/kwin compositor/sessiond enhancements from Wave tasks - Only kirigami remains suppressed (QML-dependent, environmental gate) Zero warnings. 24 commits total.
This commit is contained in:
@@ -0,0 +1,9 @@
|
||||
|
||||
add_subdirectory(api)
|
||||
add_subdirectory(runtime)
|
||||
|
||||
ecm_qt_install_logging_categories(
|
||||
EXPORT KWALLET
|
||||
FILE kwallet.categories
|
||||
DESTINATION ${KDE_INSTALL_LOGGINGCATEGORIESDIR}
|
||||
)
|
||||
@@ -0,0 +1,2 @@
|
||||
|
||||
add_subdirectory(KWallet)
|
||||
@@ -0,0 +1,161 @@
|
||||
|
||||
include(ECMGenerateHeaders)
|
||||
|
||||
ecm_setup_version(${KF_VERSION} VARIABLE_PREFIX KWALLET
|
||||
VERSION_HEADER "${CMAKE_CURRENT_BINARY_DIR}/kwallet_version.h"
|
||||
PACKAGE_VERSION_FILE "${CMAKE_CURRENT_BINARY_DIR}/KF6WalletConfigVersion.cmake"
|
||||
SOVERSION 6)
|
||||
|
||||
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/kwallet_version.h
|
||||
DESTINATION ${KDE_INSTALL_INCLUDEDIR_KF}/KWallet COMPONENT Devel
|
||||
)
|
||||
|
||||
if(APPLE)
|
||||
option(MAC_USE_OSXKEYCHAIN "On OS X, use the keychain as backend for kwallet, instead of kwalletd.")
|
||||
else()
|
||||
set(MAC_USE_OSXKEYCHAIN FALSE)
|
||||
endif()
|
||||
|
||||
add_library(KF6Wallet)
|
||||
add_library(KF6::Wallet ALIAS KF6Wallet)
|
||||
|
||||
set_target_properties(KF6Wallet PROPERTIES
|
||||
VERSION ${KWALLET_VERSION}
|
||||
SOVERSION ${KWALLET_SOVERSION}
|
||||
EXPORT_NAME Wallet
|
||||
)
|
||||
|
||||
if (MAC_USE_OSXKEYCHAIN)
|
||||
find_library(COREFOUNDATION_LIBRARY CoreFoundation)
|
||||
find_library(SECURITY_LIBRARY Security)
|
||||
target_sources(KF6Wallet PRIVATE
|
||||
kwallet_mac.cpp
|
||||
)
|
||||
else()
|
||||
set(kwallet_dbus_SRCS)
|
||||
if (NOT EXCLUDE_DEPRECATED_BEFORE_AND_AT STREQUAL "CURRENT" AND
|
||||
EXCLUDE_DEPRECATED_BEFORE_AND_AT VERSION_LESS 5.72.0)
|
||||
set(kwallet_xml org.kde.KWallet.xml)
|
||||
else()
|
||||
# copy of org.kde.KWallet.xml, but with all deprecated API removed
|
||||
set(kwallet_xml org.kde.KWallet.nodeprecated.xml)
|
||||
endif()
|
||||
qt_add_dbus_interface(kwallet_dbus_SRCS ${kwallet_xml} kwallet_interface)
|
||||
target_sources(KF6Wallet PRIVATE
|
||||
kwallet.cpp
|
||||
${kwallet_dbus_SRCS}
|
||||
)
|
||||
endif()
|
||||
|
||||
ecm_qt_declare_logging_category(KF6Wallet
|
||||
HEADER kwallet_api_debug.h
|
||||
IDENTIFIER KWALLET_API_LOG
|
||||
CATEGORY_NAME kf.wallet.api
|
||||
OLD_CATEGORY_NAMES kf5.kwallet.api
|
||||
DESCRIPTION "kwallet api"
|
||||
EXPORT KWALLET
|
||||
)
|
||||
|
||||
ecm_generate_export_header(KF6Wallet
|
||||
BASE_NAME KWallet
|
||||
GROUP_BASE_NAME KF
|
||||
VERSION ${KF_VERSION}
|
||||
USE_VERSION_HEADER
|
||||
DEPRECATED_BASE_VERSION 0
|
||||
DEPRECATION_VERSIONS 5.72
|
||||
EXCLUDE_DEPRECATED_BEFORE_AND_AT ${EXCLUDE_DEPRECATED_BEFORE_AND_AT}
|
||||
)
|
||||
|
||||
target_include_directories(KF6Wallet INTERFACE "$<INSTALL_INTERFACE:${KDE_INSTALL_INCLUDEDIR_KF}/KWallet>")
|
||||
|
||||
target_link_libraries(KF6Wallet
|
||||
PUBLIC
|
||||
Qt6::Gui
|
||||
PRIVATE
|
||||
Qt6::DBus
|
||||
Qt6::Widgets
|
||||
KF6::ConfigCore # used to store the wallet to be used
|
||||
)
|
||||
|
||||
if(MAC_USE_OSXKEYCHAIN)
|
||||
target_link_libraries(KF6Wallet PRIVATE ${CARBON_LIBRARY}
|
||||
${SECURITY_LIBRARY}
|
||||
${COREFOUNDATION_LIBRARY})
|
||||
elseif(APPLE)
|
||||
target_link_libraries(KF6Wallet PRIVATE ${CARBON_LIBRARY})
|
||||
else()
|
||||
target_link_libraries(KF6Wallet PRIVATE Qt6::DBus)
|
||||
install(FILES ${kwallet_xml} DESTINATION ${KDE_INSTALL_DBUSINTERFACEDIR} RENAME kf6_org.kde.KWallet.xml)
|
||||
endif()
|
||||
|
||||
ecm_generate_headers(KWallet_HEADERS
|
||||
HEADER_NAMES
|
||||
KWallet
|
||||
|
||||
REQUIRED_HEADERS KWallet_HEADERS
|
||||
)
|
||||
|
||||
install(TARGETS KF6Wallet EXPORT KF6WalletTargets ${KF_INSTALL_TARGETS_DEFAULT_ARGS})
|
||||
install(FILES
|
||||
${CMAKE_CURRENT_BINARY_DIR}/kwallet_export.h
|
||||
${KWallet_HEADERS}
|
||||
DESTINATION ${KDE_INSTALL_INCLUDEDIR_KF}/KWallet COMPONENT Devel
|
||||
)
|
||||
|
||||
if(BUILD_QCH)
|
||||
ecm_add_qch(
|
||||
KF6Wallet_QCH
|
||||
NAME KWallet
|
||||
BASE_NAME KF6Wallet
|
||||
VERSION ${KF_VERSION}
|
||||
ORG_DOMAIN org.kde
|
||||
SOURCES # using only public headers, to cover only public API
|
||||
${KWallet_HEADERS}
|
||||
LINK_QCHS
|
||||
Qt6Gui_QCH
|
||||
INCLUDE_DIRS
|
||||
${CMAKE_CURRENT_BINARY_DIR}
|
||||
BLANK_MACROS
|
||||
KWALLET_EXPORT
|
||||
KWALLET_DEPRECATED
|
||||
KWALLET_DEPRECATED_EXPORT
|
||||
"KWALLET_DEPRECATED_VERSION(x, y, t)"
|
||||
TAGFILE_INSTALL_DESTINATION ${KDE_INSTALL_QTQCHDIR}
|
||||
QCH_INSTALL_DESTINATION ${KDE_INSTALL_QTQCHDIR}
|
||||
COMPONENT Devel
|
||||
)
|
||||
endif()
|
||||
|
||||
|
||||
# create a Config.cmake and a ConfigVersion.cmake file and install them
|
||||
set(CMAKECONFIG_INSTALL_DIR "${KDE_INSTALL_CMAKEPACKAGEDIR}/KF6Wallet")
|
||||
|
||||
if (BUILD_QCH)
|
||||
ecm_install_qch_export(
|
||||
TARGETS KF6Wallet_QCH
|
||||
FILE KF6WalletQchTargets.cmake
|
||||
DESTINATION "${CMAKECONFIG_INSTALL_DIR}"
|
||||
COMPONENT Devel
|
||||
)
|
||||
set(PACKAGE_INCLUDE_QCHTARGETS "include(\"\${CMAKE_CURRENT_LIST_DIR}/KF6WalletQchTargets.cmake\")")
|
||||
endif()
|
||||
|
||||
include(CMakePackageConfigHelpers)
|
||||
|
||||
configure_package_config_file(
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/KF6WalletConfig.cmake.in"
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/KF6WalletConfig.cmake"
|
||||
PATH_VARS KDE_INSTALL_DBUSINTERFACEDIR
|
||||
PATH_VARS KDE_INSTALL_BINDIR
|
||||
INSTALL_DESTINATION ${CMAKECONFIG_INSTALL_DIR}
|
||||
)
|
||||
|
||||
install(FILES
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/KF6WalletConfig.cmake"
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/KF6WalletConfigVersion.cmake"
|
||||
DESTINATION "${CMAKECONFIG_INSTALL_DIR}"
|
||||
COMPONENT Devel
|
||||
)
|
||||
|
||||
install(EXPORT KF6WalletTargets DESTINATION "${CMAKECONFIG_INSTALL_DIR}" FILE KF6WalletTargets.cmake NAMESPACE KF6:: )
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
@PACKAGE_INIT@
|
||||
|
||||
set(KWALLET_DBUS_INTERFACES_DIR "@PACKAGE_KDE_INSTALL_DBUSINTERFACEDIR@")
|
||||
set(KWALLETD_BIN_PATH "@PACKAGE_KDE_INSTALL_BINDIR@/kwalletd6")
|
||||
|
||||
include(CMakeFindDependencyMacro)
|
||||
find_dependency(Qt6Gui @REQUIRED_QT_VERSION@)
|
||||
|
||||
include("${CMAKE_CURRENT_LIST_DIR}/KF6WalletTargets.cmake")
|
||||
@PACKAGE_INCLUDE_QCHTARGETS@
|
||||
@@ -0,0 +1,931 @@
|
||||
/*
|
||||
This file is part of the KDE project
|
||||
|
||||
SPDX-FileCopyrightText: 2002-2004 George Staikos <staikos@kde.org>
|
||||
SPDX-FileCopyrightText: 2008 Michael Leupold <lemma@confuego.org>
|
||||
SPDX-FileCopyrightText: 2011 Valentin Rusu <kde@rusu.info>
|
||||
|
||||
SPDX-License-Identifier: LGPL-2.0-or-later
|
||||
*/
|
||||
|
||||
#include "kwallet.h"
|
||||
#include "kwallet_api_debug.h"
|
||||
|
||||
#include <QApplication>
|
||||
#include <QDBusConnection>
|
||||
#include <QRegularExpression>
|
||||
|
||||
#include <KConfigGroup>
|
||||
#include <KSharedConfig>
|
||||
|
||||
#include "kwallet_interface.h"
|
||||
|
||||
typedef QMap<QString, QByteArray> StringByteArrayMap;
|
||||
Q_DECLARE_METATYPE(StringByteArrayMap)
|
||||
|
||||
namespace KWallet
|
||||
{
|
||||
class KWalletDLauncher
|
||||
{
|
||||
public:
|
||||
KWalletDLauncher();
|
||||
~KWalletDLauncher();
|
||||
KWalletDLauncher(const KWalletDLauncher &) = delete;
|
||||
KWalletDLauncher &operator=(const KWalletDLauncher &) = delete;
|
||||
org::kde::KWallet &getInterface();
|
||||
|
||||
org::kde::KWallet *m_wallet_deamon;
|
||||
KConfigGroup m_cgroup;
|
||||
bool m_walletEnabled;
|
||||
};
|
||||
|
||||
Q_GLOBAL_STATIC(KWalletDLauncher, walletLauncher)
|
||||
|
||||
static QString appid()
|
||||
{
|
||||
return qApp->applicationName();
|
||||
}
|
||||
|
||||
static void registerTypes()
|
||||
{
|
||||
static bool registered = false;
|
||||
if (!registered) {
|
||||
qDBusRegisterMetaType<StringByteArrayMap>();
|
||||
registered = true;
|
||||
}
|
||||
}
|
||||
|
||||
const QString Wallet::LocalWallet()
|
||||
{
|
||||
KConfigGroup cfg(KSharedConfig::openConfig(QStringLiteral("kwalletrc"))->group(QStringLiteral("Wallet")));
|
||||
if (!cfg.readEntry("Use One Wallet", true)) {
|
||||
QString tmp = cfg.readEntry("Local Wallet", "localwallet");
|
||||
if (tmp.isEmpty()) {
|
||||
return QStringLiteral("localwallet");
|
||||
}
|
||||
return tmp;
|
||||
}
|
||||
|
||||
QString tmp = cfg.readEntry("Default Wallet", "kdewallet");
|
||||
if (tmp.isEmpty()) {
|
||||
return QStringLiteral("kdewallet");
|
||||
}
|
||||
return tmp;
|
||||
}
|
||||
|
||||
const QString Wallet::NetworkWallet()
|
||||
{
|
||||
KConfigGroup cfg(KSharedConfig::openConfig(QStringLiteral("kwalletrc"))->group(QStringLiteral("Wallet")));
|
||||
|
||||
QString tmp = cfg.readEntry("Default Wallet", "kdewallet");
|
||||
if (tmp.isEmpty()) {
|
||||
return QStringLiteral("kdewallet");
|
||||
}
|
||||
return tmp;
|
||||
}
|
||||
|
||||
const QString Wallet::PasswordFolder()
|
||||
{
|
||||
return QStringLiteral("Passwords");
|
||||
}
|
||||
|
||||
const QString Wallet::FormDataFolder()
|
||||
{
|
||||
return QStringLiteral("Form Data");
|
||||
}
|
||||
|
||||
class Q_DECL_HIDDEN Wallet::WalletPrivate
|
||||
{
|
||||
public:
|
||||
WalletPrivate(Wallet *wallet, int h, const QString &n)
|
||||
: q(wallet)
|
||||
, name(n)
|
||||
, handle(h)
|
||||
{
|
||||
}
|
||||
|
||||
void walletServiceUnregistered();
|
||||
|
||||
Wallet *q;
|
||||
QString name;
|
||||
QString folder;
|
||||
int handle;
|
||||
int transactionId;
|
||||
};
|
||||
|
||||
static const char s_kwalletdServiceName[] = "org.kde.kwalletd6";
|
||||
|
||||
Wallet::Wallet(int handle, const QString &name)
|
||||
: QObject(nullptr)
|
||||
, d(new WalletPrivate(this, handle, name))
|
||||
{
|
||||
QDBusServiceWatcher *watcher =
|
||||
new QDBusServiceWatcher(QString::fromLatin1(s_kwalletdServiceName), QDBusConnection::sessionBus(), QDBusServiceWatcher::WatchForUnregistration, this);
|
||||
connect(watcher, &QDBusServiceWatcher::serviceUnregistered, this, [this]() {
|
||||
d->walletServiceUnregistered();
|
||||
});
|
||||
|
||||
connect(&walletLauncher()->getInterface(), &org::kde::KWallet::walletClosedId, this, &KWallet::Wallet::slotWalletClosed);
|
||||
connect(&walletLauncher()->getInterface(), &org::kde::KWallet::folderListUpdated, this, &KWallet::Wallet::slotFolderListUpdated);
|
||||
connect(&walletLauncher()->getInterface(), &org::kde::KWallet::folderUpdated, this, &KWallet::Wallet::slotFolderUpdated);
|
||||
connect(&walletLauncher()->getInterface(), &org::kde::KWallet::applicationDisconnected, this, &KWallet::Wallet::slotApplicationDisconnected);
|
||||
|
||||
// Verify that the wallet is still open
|
||||
if (d->handle != -1) {
|
||||
QDBusReply<bool> r = walletLauncher()->getInterface().isOpen(d->handle);
|
||||
if (r.isValid() && !r) {
|
||||
d->handle = -1;
|
||||
d->name.clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Wallet::~Wallet()
|
||||
{
|
||||
if (d->handle != -1) {
|
||||
if (!walletLauncher.isDestroyed()) {
|
||||
walletLauncher()->getInterface().close(d->handle, false, appid());
|
||||
} else {
|
||||
qCDebug(KWALLET_API_LOG) << "Problem with static destruction sequence."
|
||||
"Destroy any static Wallet before the event-loop exits.";
|
||||
}
|
||||
d->handle = -1;
|
||||
d->folder.clear();
|
||||
d->name.clear();
|
||||
}
|
||||
delete d;
|
||||
}
|
||||
|
||||
QStringList Wallet::walletList()
|
||||
{
|
||||
QStringList result;
|
||||
if (walletLauncher()->m_walletEnabled) {
|
||||
QDBusReply<QStringList> r = walletLauncher()->getInterface().wallets();
|
||||
|
||||
if (!r.isValid()) {
|
||||
qCDebug(KWALLET_API_LOG) << "Invalid DBus reply: " << r.error();
|
||||
} else {
|
||||
result = r;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void Wallet::changePassword(const QString &name, WId w)
|
||||
{
|
||||
if (w == 0) {
|
||||
qCDebug(KWALLET_API_LOG) << "Pass a valid window to KWallet::Wallet::changePassword().";
|
||||
}
|
||||
|
||||
if (walletLauncher()->m_walletEnabled) {
|
||||
walletLauncher()->getInterface().changePassword(name, (qlonglong)w, appid());
|
||||
}
|
||||
}
|
||||
|
||||
bool Wallet::isEnabled()
|
||||
{
|
||||
return walletLauncher()->m_walletEnabled;
|
||||
}
|
||||
|
||||
bool Wallet::isOpen(const QString &name)
|
||||
{
|
||||
if (walletLauncher()->m_walletEnabled) {
|
||||
QDBusReply<bool> r = walletLauncher()->getInterface().isOpen(name);
|
||||
|
||||
if (!r.isValid()) {
|
||||
qCDebug(KWALLET_API_LOG) << "Invalid DBus reply: " << r.error();
|
||||
return false;
|
||||
} else {
|
||||
return r;
|
||||
}
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
int Wallet::closeWallet(const QString &name, bool force)
|
||||
{
|
||||
if (walletLauncher()->m_walletEnabled) {
|
||||
QDBusReply<int> r = walletLauncher()->getInterface().close(name, force);
|
||||
|
||||
if (!r.isValid()) {
|
||||
qCDebug(KWALLET_API_LOG) << "Invalid DBus reply: " << r.error();
|
||||
return -1;
|
||||
} else {
|
||||
return r;
|
||||
}
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
int Wallet::deleteWallet(const QString &name)
|
||||
{
|
||||
if (walletLauncher->m_walletEnabled) {
|
||||
QDBusReply<int> r = walletLauncher()->getInterface().deleteWallet(name);
|
||||
|
||||
if (!r.isValid()) {
|
||||
qCDebug(KWALLET_API_LOG) << "Invalid DBus reply: " << r.error();
|
||||
return -1;
|
||||
} else {
|
||||
return r;
|
||||
}
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
Wallet *Wallet::openWallet(const QString &name, WId w, OpenType ot)
|
||||
{
|
||||
if (w == 0) {
|
||||
qCDebug(KWALLET_API_LOG) << "Pass a valid window to KWallet::Wallet::openWallet().";
|
||||
}
|
||||
|
||||
if (!walletLauncher()->m_walletEnabled) {
|
||||
qCDebug(KWALLET_API_LOG) << "User disabled the wallet system so returning 0 here.";
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Wallet *wallet = new Wallet(-1, name);
|
||||
|
||||
// connect the daemon's opened signal to the slot filtering the
|
||||
// signals we need
|
||||
connect(&walletLauncher()->getInterface(), &org::kde::KWallet::walletAsyncOpened, wallet, &KWallet::Wallet::walletAsyncOpened);
|
||||
|
||||
org::kde::KWallet &interface = walletLauncher->getInterface();
|
||||
|
||||
// do the call
|
||||
QDBusReply<int> r;
|
||||
if (ot == Synchronous) {
|
||||
interface.setTimeout(0x7FFFFFFF); // Don't timeout after 25s, but 24 days
|
||||
r = interface.open(name, (qlonglong)w, appid());
|
||||
interface.setTimeout(-1); // Back to the default 25s
|
||||
// after this call, r would contain a transaction id >0 if OK or -1 if NOK
|
||||
// if OK, the slot walletAsyncOpened should have been received, but the transaction id
|
||||
// will not match. We'll get that handle from the reply - see below
|
||||
} else if (ot == Asynchronous) {
|
||||
r = interface.openAsync(name, (qlonglong)w, appid(), true);
|
||||
} else if (ot == Path) {
|
||||
r = interface.openPathAsync(name, (qlonglong)w, appid(), true);
|
||||
} else {
|
||||
delete wallet;
|
||||
return nullptr;
|
||||
}
|
||||
// error communicating with the daemon (maybe not running)
|
||||
if (!r.isValid()) {
|
||||
qCDebug(KWALLET_API_LOG) << "Invalid DBus reply: " << r.error();
|
||||
delete wallet;
|
||||
return nullptr;
|
||||
}
|
||||
wallet->d->transactionId = r.value();
|
||||
|
||||
if (ot == Synchronous || ot == Path) {
|
||||
// check for an immediate error
|
||||
if (wallet->d->transactionId < 0) {
|
||||
delete wallet;
|
||||
wallet = nullptr;
|
||||
} else {
|
||||
wallet->d->handle = r.value();
|
||||
}
|
||||
} else if (ot == Asynchronous) {
|
||||
if (wallet->d->transactionId < 0) {
|
||||
QTimer::singleShot(0, wallet, SLOT(emitWalletAsyncOpenError()));
|
||||
// client code is responsible for deleting the wallet
|
||||
}
|
||||
}
|
||||
|
||||
return wallet;
|
||||
}
|
||||
|
||||
void Wallet::slotCollectionStatusChanged(int status)
|
||||
{
|
||||
Q_UNUSED(status)
|
||||
}
|
||||
|
||||
void Wallet::slotCollectionDeleted()
|
||||
{
|
||||
d->folder.clear();
|
||||
d->name.clear();
|
||||
Q_EMIT walletClosed();
|
||||
}
|
||||
|
||||
bool Wallet::disconnectApplication(const QString &wallet, const QString &app)
|
||||
{
|
||||
if (walletLauncher()->m_walletEnabled) {
|
||||
QDBusReply<bool> r = walletLauncher()->getInterface().disconnectApplication(wallet, app);
|
||||
|
||||
if (!r.isValid()) {
|
||||
qCDebug(KWALLET_API_LOG) << "Invalid DBus reply: " << r.error();
|
||||
return false;
|
||||
} else {
|
||||
return r;
|
||||
}
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
QStringList Wallet::users(const QString &name)
|
||||
{
|
||||
if (walletLauncher()->m_walletEnabled) {
|
||||
QDBusReply<QStringList> r = walletLauncher()->getInterface().users(name);
|
||||
if (!r.isValid()) {
|
||||
qCDebug(KWALLET_API_LOG) << "Invalid DBus reply: " << r.error();
|
||||
return QStringList();
|
||||
} else {
|
||||
return r;
|
||||
}
|
||||
} else {
|
||||
return QStringList();
|
||||
}
|
||||
}
|
||||
|
||||
int Wallet::sync()
|
||||
{
|
||||
if (d->handle == -1) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
walletLauncher()->getInterface().sync(d->handle, appid());
|
||||
return 0;
|
||||
}
|
||||
|
||||
int Wallet::lockWallet()
|
||||
{
|
||||
if (d->handle == -1) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
QDBusReply<int> r = walletLauncher()->getInterface().close(d->handle, true, appid());
|
||||
d->handle = -1;
|
||||
d->folder.clear();
|
||||
d->name.clear();
|
||||
if (r.isValid()) {
|
||||
return r;
|
||||
} else {
|
||||
qCDebug(KWALLET_API_LOG) << "Invalid DBus reply: " << r.error();
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
const QString &Wallet::walletName() const
|
||||
{
|
||||
return d->name;
|
||||
}
|
||||
|
||||
bool Wallet::isOpen() const
|
||||
{
|
||||
return d->handle != -1;
|
||||
}
|
||||
|
||||
void Wallet::requestChangePassword(WId w)
|
||||
{
|
||||
if (w == 0) {
|
||||
qCDebug(KWALLET_API_LOG) << "Pass a valid window to KWallet::Wallet::requestChangePassword().";
|
||||
}
|
||||
|
||||
if (d->handle == -1) {
|
||||
return;
|
||||
}
|
||||
|
||||
walletLauncher()->getInterface().changePassword(d->name, (qlonglong)w, appid());
|
||||
}
|
||||
|
||||
void Wallet::slotWalletClosed(int handle)
|
||||
{
|
||||
if (d->handle == handle) {
|
||||
d->handle = -1;
|
||||
d->folder.clear();
|
||||
d->name.clear();
|
||||
Q_EMIT walletClosed();
|
||||
}
|
||||
}
|
||||
|
||||
QStringList Wallet::folderList()
|
||||
{
|
||||
if (d->handle == -1) {
|
||||
return QStringList();
|
||||
}
|
||||
|
||||
QDBusReply<QStringList> r = walletLauncher()->getInterface().folderList(d->handle, appid());
|
||||
if (!r.isValid()) {
|
||||
qCDebug(KWALLET_API_LOG) << "Invalid DBus reply: " << r.error();
|
||||
return QStringList();
|
||||
} else {
|
||||
return r;
|
||||
}
|
||||
}
|
||||
|
||||
QStringList Wallet::entryList()
|
||||
{
|
||||
if (d->handle == -1) {
|
||||
return QStringList();
|
||||
}
|
||||
|
||||
QDBusReply<QStringList> r = walletLauncher()->getInterface().entryList(d->handle, d->folder, appid());
|
||||
if (!r.isValid()) {
|
||||
qCDebug(KWALLET_API_LOG) << "Invalid DBus reply: " << r.error();
|
||||
return QStringList();
|
||||
} else {
|
||||
return r;
|
||||
}
|
||||
}
|
||||
|
||||
bool Wallet::hasFolder(const QString &f)
|
||||
{
|
||||
if (d->handle == -1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
QDBusReply<bool> r = walletLauncher()->getInterface().hasFolder(d->handle, f, appid());
|
||||
if (!r.isValid()) {
|
||||
qCDebug(KWALLET_API_LOG) << "Invalid DBus reply: " << r.error();
|
||||
return false;
|
||||
} else {
|
||||
return r;
|
||||
}
|
||||
}
|
||||
|
||||
bool Wallet::createFolder(const QString &f)
|
||||
{
|
||||
if (d->handle == -1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!hasFolder(f)) {
|
||||
QDBusReply<bool> r = walletLauncher()->getInterface().createFolder(d->handle, f, appid());
|
||||
|
||||
if (!r.isValid()) {
|
||||
qCDebug(KWALLET_API_LOG) << "Invalid DBus reply: " << r.error();
|
||||
return false;
|
||||
} else {
|
||||
return r;
|
||||
}
|
||||
}
|
||||
|
||||
return true; // folder already exists
|
||||
}
|
||||
|
||||
bool Wallet::setFolder(const QString &f)
|
||||
{
|
||||
bool rc = false;
|
||||
|
||||
if (d->handle == -1) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
// Don't do this - the folder could have disappeared?
|
||||
#if 0
|
||||
if (f == d->folder) {
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (hasFolder(f)) {
|
||||
d->folder = f;
|
||||
rc = true;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
bool Wallet::removeFolder(const QString &f)
|
||||
{
|
||||
if (d->handle == -1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
QDBusReply<bool> r = walletLauncher()->getInterface().removeFolder(d->handle, f, appid());
|
||||
if (d->folder == f) {
|
||||
setFolder(QString());
|
||||
}
|
||||
|
||||
if (!r.isValid()) {
|
||||
qCDebug(KWALLET_API_LOG) << "Invalid DBus reply: " << r.error();
|
||||
return false;
|
||||
} else {
|
||||
return r;
|
||||
}
|
||||
}
|
||||
|
||||
const QString &Wallet::currentFolder() const
|
||||
{
|
||||
return d->folder;
|
||||
}
|
||||
|
||||
int Wallet::readEntry(const QString &key, QByteArray &value)
|
||||
{
|
||||
int rc = -1;
|
||||
|
||||
if (d->handle == -1) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
QDBusReply<QByteArray> r = walletLauncher()->getInterface().readEntry(d->handle, d->folder, key, appid());
|
||||
if (r.isValid()) {
|
||||
value = r;
|
||||
rc = 0;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
QMap<QString, QByteArray> Wallet::entriesList(bool *ok) const
|
||||
{
|
||||
QMap<QString, QByteArray> entries;
|
||||
|
||||
registerTypes();
|
||||
|
||||
if (d->handle == -1) {
|
||||
if (ok) {
|
||||
*ok = false;
|
||||
}
|
||||
return entries;
|
||||
}
|
||||
|
||||
QDBusReply<QVariantMap> reply = walletLauncher()->getInterface().entriesList(d->handle, d->folder, appid());
|
||||
if (reply.isValid()) {
|
||||
if (ok) {
|
||||
*ok = true;
|
||||
}
|
||||
// convert <QString, QVariant> to <QString, QByteArray>
|
||||
const QVariantMap val = reply.value();
|
||||
for (QVariantMap::const_iterator it = val.begin(); it != val.end(); ++it) {
|
||||
entries.insert(it.key(), it.value().toByteArray());
|
||||
}
|
||||
}
|
||||
|
||||
return entries;
|
||||
}
|
||||
|
||||
int Wallet::renameEntry(const QString &oldName, const QString &newName)
|
||||
{
|
||||
int rc = -1;
|
||||
|
||||
if (d->handle == -1) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
QT_WARNING_PUSH
|
||||
QT_WARNING_DISABLE_CLANG("-Wdeprecated-declarations")
|
||||
QT_WARNING_DISABLE_GCC("-Wdeprecated-declarations")
|
||||
QDBusReply<int> r = walletLauncher()->getInterface().renameEntry(d->handle, d->folder, oldName, newName, appid());
|
||||
QT_WARNING_POP
|
||||
if (r.isValid()) {
|
||||
rc = r;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
int Wallet::readMap(const QString &key, QMap<QString, QString> &value)
|
||||
{
|
||||
int rc = -1;
|
||||
|
||||
registerTypes();
|
||||
|
||||
if (d->handle == -1) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
QDBusReply<QByteArray> r = walletLauncher()->getInterface().readMap(d->handle, d->folder, key, appid());
|
||||
if (r.isValid()) {
|
||||
rc = 0;
|
||||
QByteArray v = r;
|
||||
if (!v.isEmpty()) {
|
||||
QDataStream ds(&v, QIODevice::ReadOnly);
|
||||
ds >> value;
|
||||
}
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
QMap<QString, QMap<QString, QString>> Wallet::mapList(bool *ok) const
|
||||
{
|
||||
QMap<QString, QMap<QString, QString>> list;
|
||||
|
||||
registerTypes();
|
||||
|
||||
if (d->handle == -1) {
|
||||
if (ok) {
|
||||
*ok = false;
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
QDBusReply<QVariantMap> reply = walletLauncher()->getInterface().mapList(d->handle, d->folder, appid());
|
||||
if (reply.isValid()) {
|
||||
if (ok) {
|
||||
*ok = true;
|
||||
}
|
||||
const QVariantMap val = reply.value();
|
||||
for (QVariantMap::const_iterator it = val.begin(); it != val.end(); ++it) {
|
||||
QByteArray mapData = it.value().toByteArray();
|
||||
if (!mapData.isEmpty()) {
|
||||
QDataStream ds(&mapData, QIODevice::ReadOnly);
|
||||
QMap<QString, QString> v;
|
||||
ds >> v;
|
||||
list.insert(it.key(), v);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
int Wallet::readPassword(const QString &key, QString &value)
|
||||
{
|
||||
int rc = -1;
|
||||
|
||||
if (d->handle == -1) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
QDBusReply<QString> r = walletLauncher()->getInterface().readPassword(d->handle, d->folder, key, appid());
|
||||
if (r.isValid()) {
|
||||
value = r;
|
||||
rc = 0;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
QMap<QString, QString> Wallet::passwordList(bool *ok) const
|
||||
{
|
||||
QMap<QString, QString> passList;
|
||||
|
||||
registerTypes();
|
||||
|
||||
if (d->handle == -1) {
|
||||
if (ok) {
|
||||
*ok = false;
|
||||
}
|
||||
return passList;
|
||||
}
|
||||
|
||||
QDBusReply<QVariantMap> reply = walletLauncher()->getInterface().passwordList(d->handle, d->folder, appid());
|
||||
if (reply.isValid()) {
|
||||
if (ok) {
|
||||
*ok = true;
|
||||
}
|
||||
const QVariantMap val = reply.value();
|
||||
for (QVariantMap::const_iterator it = val.begin(); it != val.end(); ++it) {
|
||||
passList.insert(it.key(), it.value().toString());
|
||||
}
|
||||
}
|
||||
|
||||
return passList;
|
||||
}
|
||||
|
||||
int Wallet::writeEntry(const QString &key, const QByteArray &value, EntryType entryType)
|
||||
{
|
||||
int rc = -1;
|
||||
|
||||
if (d->handle == -1) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
QDBusReply<int> r = walletLauncher()->getInterface().writeEntry(d->handle, d->folder, key, value, int(entryType), appid());
|
||||
if (r.isValid()) {
|
||||
rc = r;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
int Wallet::writeEntry(const QString &key, const QByteArray &value)
|
||||
{
|
||||
int rc = -1;
|
||||
|
||||
if (d->handle == -1) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
QDBusReply<int> r = walletLauncher()->getInterface().writeEntry(d->handle, d->folder, key, value, appid());
|
||||
if (r.isValid()) {
|
||||
rc = r;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
int Wallet::writeMap(const QString &key, const QMap<QString, QString> &value)
|
||||
{
|
||||
int rc = -1;
|
||||
|
||||
registerTypes();
|
||||
|
||||
if (d->handle == -1) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
QByteArray mapData;
|
||||
QDataStream ds(&mapData, QIODevice::WriteOnly);
|
||||
ds << value;
|
||||
QDBusReply<int> r = walletLauncher()->getInterface().writeMap(d->handle, d->folder, key, mapData, appid());
|
||||
if (r.isValid()) {
|
||||
rc = r;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
int Wallet::writePassword(const QString &key, const QString &value)
|
||||
{
|
||||
int rc = -1;
|
||||
|
||||
if (d->handle == -1) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
QDBusReply<int> r = walletLauncher()->getInterface().writePassword(d->handle, d->folder, key, value, appid());
|
||||
if (r.isValid()) {
|
||||
rc = r;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
bool Wallet::hasEntry(const QString &key)
|
||||
{
|
||||
if (d->handle == -1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
QDBusReply<bool> r = walletLauncher()->getInterface().hasEntry(d->handle, d->folder, key, appid());
|
||||
if (!r.isValid()) {
|
||||
qCDebug(KWALLET_API_LOG) << "Invalid DBus reply: " << r.error();
|
||||
return false;
|
||||
} else {
|
||||
return r;
|
||||
}
|
||||
}
|
||||
|
||||
int Wallet::removeEntry(const QString &key)
|
||||
{
|
||||
int rc = -1;
|
||||
|
||||
if (d->handle == -1) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
QDBusReply<int> r = walletLauncher()->getInterface().removeEntry(d->handle, d->folder, key, appid());
|
||||
if (r.isValid()) {
|
||||
rc = r;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
Wallet::EntryType Wallet::entryType(const QString &key)
|
||||
{
|
||||
int rc = 0;
|
||||
|
||||
if (d->handle == -1) {
|
||||
return Wallet::Unknown;
|
||||
}
|
||||
|
||||
QDBusReply<int> r = walletLauncher()->getInterface().entryType(d->handle, d->folder, key, appid());
|
||||
if (r.isValid()) {
|
||||
rc = r;
|
||||
}
|
||||
return static_cast<EntryType>(rc);
|
||||
}
|
||||
|
||||
void Wallet::WalletPrivate::walletServiceUnregistered()
|
||||
{
|
||||
if (handle >= 0) {
|
||||
q->slotWalletClosed(handle);
|
||||
}
|
||||
}
|
||||
|
||||
void Wallet::slotFolderUpdated(const QString &wallet, const QString &folder)
|
||||
{
|
||||
if (d->name == wallet) {
|
||||
Q_EMIT folderUpdated(folder);
|
||||
}
|
||||
}
|
||||
|
||||
void Wallet::slotFolderListUpdated(const QString &wallet)
|
||||
{
|
||||
if (d->name == wallet) {
|
||||
Q_EMIT folderListUpdated();
|
||||
}
|
||||
}
|
||||
|
||||
void Wallet::slotApplicationDisconnected(const QString &wallet, const QString &application)
|
||||
{
|
||||
if (d->handle >= 0 && d->name == wallet && application == appid()) {
|
||||
slotWalletClosed(d->handle);
|
||||
}
|
||||
}
|
||||
|
||||
void Wallet::walletAsyncOpened(int tId, int handle)
|
||||
{
|
||||
// ignore responses to calls other than ours
|
||||
if (d->transactionId != tId || d->handle != -1) {
|
||||
return;
|
||||
}
|
||||
|
||||
// disconnect the async signal
|
||||
disconnect(this, SLOT(walletAsyncOpened(int, int)));
|
||||
|
||||
d->handle = handle;
|
||||
Q_EMIT walletOpened(handle > 0);
|
||||
}
|
||||
|
||||
void Wallet::emitWalletAsyncOpenError()
|
||||
{
|
||||
Q_EMIT walletOpened(false);
|
||||
}
|
||||
|
||||
void Wallet::emitWalletOpened()
|
||||
{
|
||||
Q_EMIT walletOpened(true);
|
||||
}
|
||||
|
||||
bool Wallet::folderDoesNotExist(const QString &wallet, const QString &folder)
|
||||
{
|
||||
if (walletLauncher()->m_walletEnabled) {
|
||||
QDBusReply<bool> r = walletLauncher()->getInterface().folderDoesNotExist(wallet, folder);
|
||||
if (!r.isValid()) {
|
||||
qCDebug(KWALLET_API_LOG) << "Invalid DBus reply: " << r.error();
|
||||
return false;
|
||||
} else {
|
||||
return r;
|
||||
}
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool Wallet::keyDoesNotExist(const QString &wallet, const QString &folder, const QString &key)
|
||||
{
|
||||
if (walletLauncher()->m_walletEnabled) {
|
||||
QDBusReply<bool> r = walletLauncher()->getInterface().keyDoesNotExist(wallet, folder, key);
|
||||
if (!r.isValid()) {
|
||||
qCDebug(KWALLET_API_LOG) << "Invalid DBus reply: " << r.error();
|
||||
return false;
|
||||
} else {
|
||||
return r;
|
||||
}
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void Wallet::virtual_hook(int, void *)
|
||||
{
|
||||
// BASE::virtual_hook( id, data );
|
||||
}
|
||||
|
||||
KWalletDLauncher::KWalletDLauncher()
|
||||
: m_wallet_deamon(nullptr)
|
||||
, m_cgroup(KSharedConfig::openConfig(QStringLiteral("kwalletrc"), KConfig::NoGlobals)->group(QStringLiteral("Wallet")))
|
||||
, m_walletEnabled(false)
|
||||
{
|
||||
m_walletEnabled = m_cgroup.readEntry("Enabled", true);
|
||||
if (!m_walletEnabled) {
|
||||
qCDebug(KWALLET_API_LOG) << "The wallet service was disabled by the user";
|
||||
return;
|
||||
}
|
||||
m_wallet_deamon = new org::kde::KWallet(QString::fromLatin1(s_kwalletdServiceName), QStringLiteral("/modules/kwalletd6"), QDBusConnection::sessionBus());
|
||||
}
|
||||
|
||||
KWalletDLauncher::~KWalletDLauncher()
|
||||
{
|
||||
delete m_wallet_deamon;
|
||||
}
|
||||
|
||||
org::kde::KWallet &KWalletDLauncher::getInterface()
|
||||
{
|
||||
Q_ASSERT(m_wallet_deamon != nullptr);
|
||||
|
||||
// check if kwalletd is already running
|
||||
QDBusConnectionInterface *bus = QDBusConnection::sessionBus().interface();
|
||||
if (!bus->isServiceRegistered(QString::fromLatin1(s_kwalletdServiceName))) {
|
||||
// not running! check if it is enabled.
|
||||
if (m_walletEnabled) {
|
||||
// wallet is enabled! try launching it
|
||||
QDBusReply<void> reply = bus->startService(QString::fromLatin1(s_kwalletdServiceName));
|
||||
if (!reply.isValid()) {
|
||||
qCritical() << "Couldn't start kwalletd: " << reply.error();
|
||||
}
|
||||
|
||||
if (!bus->isServiceRegistered(QString::fromLatin1(s_kwalletdServiceName))) {
|
||||
qCDebug(KWALLET_API_LOG) << "The kwalletd service is still not registered";
|
||||
} else {
|
||||
qCDebug(KWALLET_API_LOG) << "The kwalletd service has been registered";
|
||||
}
|
||||
} else {
|
||||
qCritical() << "The kwalletd service has been disabled";
|
||||
}
|
||||
}
|
||||
|
||||
return *m_wallet_deamon;
|
||||
}
|
||||
|
||||
} // namespace KWallet
|
||||
|
||||
#include "moc_kwallet.cpp"
|
||||
@@ -0,0 +1,553 @@
|
||||
/*
|
||||
This file is part of the KDE project
|
||||
|
||||
SPDX-FileCopyrightText: 2002-2004 George Staikos <staikos@kde.org>
|
||||
|
||||
SPDX-License-Identifier: LGPL-2.0-or-later
|
||||
*/
|
||||
|
||||
#ifndef _KWALLET_H
|
||||
#define _KWALLET_H
|
||||
|
||||
#include <QObject>
|
||||
#include <QStringList>
|
||||
#include <qwindowdefs.h> // krazy:exclude=includes (for WId)
|
||||
|
||||
#include <kwallet_export.h>
|
||||
|
||||
/**
|
||||
* NOTE: KSecretsService folder semantics
|
||||
* The KWallet API uses folders for organising items. KSecretsService does not
|
||||
* have this notion. But it uses attributes that can be applied arbitrarily on
|
||||
* all the items. The KWallet code that maps to KSecretsService applies an special
|
||||
* attribute KSS_ATTR_ENTRYFOLDER to all items with the currentFolder() value.
|
||||
* The KWallet folder API's calls will always succeed and they'll only change the
|
||||
* current folder value. The folderList() call will scan all the collection
|
||||
* items and collect the KSS_ATTR_ENTRYFOLDER attributes into a list.
|
||||
*/
|
||||
|
||||
/**
|
||||
* NOTE: KWalet API distinguish KSecretsService collection items by attaching
|
||||
* them some specific attributes, defined below
|
||||
*/
|
||||
#define KSS_ATTR_ENTRYFOLDER "kwallet.folderName"
|
||||
#define KSS_ATTR_WALLETTYPE "kwallet.type"
|
||||
|
||||
namespace KWallet
|
||||
{
|
||||
/**
|
||||
* KDE Wallet
|
||||
*
|
||||
* This class implements a generic system-wide Wallet for KDE. This is the
|
||||
* ONLY public interface.
|
||||
*
|
||||
* @author George Staikos <staikos@kde.org>
|
||||
* @short KDE Wallet Class
|
||||
*/
|
||||
class KWALLET_EXPORT Wallet : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
protected:
|
||||
/**
|
||||
* Construct a KWallet object.
|
||||
* @internal
|
||||
* @param handle The handle for the wallet.
|
||||
* @param name The name of the wallet.
|
||||
*/
|
||||
Wallet(int handle, const QString &name);
|
||||
/**
|
||||
* Copy a KWallet object.
|
||||
* @internal
|
||||
*/
|
||||
Wallet(const Wallet &);
|
||||
|
||||
public:
|
||||
enum EntryType {
|
||||
Unknown = 0,
|
||||
Password,
|
||||
Stream,
|
||||
Map,
|
||||
Unused = 0xffff,
|
||||
};
|
||||
|
||||
/**
|
||||
* Destroy a KWallet object. Closes the wallet.
|
||||
*/
|
||||
~Wallet() override;
|
||||
|
||||
/**
|
||||
* List all the wallets available.
|
||||
* @return Returns a list of the names of all wallets that are
|
||||
* open.
|
||||
*/
|
||||
static QStringList walletList();
|
||||
|
||||
/**
|
||||
* Determine if the KDE wallet is enabled. Normally you do
|
||||
* not need to use this because openWallet() will just fail.
|
||||
* @return Returns true if the wallet enabled, else false.
|
||||
*/
|
||||
static bool isEnabled();
|
||||
|
||||
/**
|
||||
* Determine if the wallet @p name is open by any application.
|
||||
* @param name The name of the wallet to check.
|
||||
* @return Returns true if the wallet is open, else false.
|
||||
*/
|
||||
static bool isOpen(const QString &name);
|
||||
|
||||
/**
|
||||
* Close the wallet @p name. The wallet will only be closed
|
||||
* if it is open but not in use (rare), or if it is forced
|
||||
* closed.
|
||||
* @param name The name of the wallet to close.
|
||||
* @param force Set true to force the wallet closed even if it
|
||||
* is in use by others.
|
||||
* @return Returns 0 on success, non-zero on error.
|
||||
*/
|
||||
static int closeWallet(const QString &name, bool force);
|
||||
|
||||
/**
|
||||
* Delete the wallet @p name. The wallet will be forced closed
|
||||
* first.
|
||||
* @param name The name of the wallet to delete.
|
||||
* @return Returns 0 on success, non-zero on error.
|
||||
*/
|
||||
static int deleteWallet(const QString &name);
|
||||
|
||||
/**
|
||||
* Disconnect the application @p app from @p wallet.
|
||||
* @param wallet The name of the wallet to disconnect.
|
||||
* @param app The name of the application to disconnect.
|
||||
* @return Returns true on success, false on error.
|
||||
*/
|
||||
static bool disconnectApplication(const QString &wallet, const QString &app);
|
||||
|
||||
enum OpenType {
|
||||
Synchronous = 0,
|
||||
Asynchronous,
|
||||
Path,
|
||||
OpenTypeUnused = 0xff,
|
||||
};
|
||||
|
||||
/**
|
||||
* Open the wallet @p name. The user will be prompted to
|
||||
* allow your application to open the wallet, and may be
|
||||
* prompted for a password. You are responsible for deleting
|
||||
* this object when you are done with it.
|
||||
* @param name The name of the wallet to open.
|
||||
* @param ot If Asynchronous, the call will return
|
||||
* immediately with a non-null pointer to an
|
||||
* invalid wallet. You must immediately connect
|
||||
* the walletOpened() signal to a slot so that
|
||||
* you will know when it is opened, or when it
|
||||
* fails.
|
||||
* @param w The window id to associate any dialogs with. You can pass
|
||||
* 0 if you don't have a window the password dialog should
|
||||
* associate with.
|
||||
* @return Returns a pointer to the wallet if successful,
|
||||
* or a null pointer on error or if rejected.
|
||||
* A null pointer can also be returned if user choose to
|
||||
* deactivate the wallet system.
|
||||
*/
|
||||
static Wallet *openWallet(const QString &name, WId w, OpenType ot = Synchronous);
|
||||
|
||||
/**
|
||||
* List the applications that are using the wallet @p wallet.
|
||||
* @param wallet The wallet to query.
|
||||
* @return Returns a list of all D-Bus application IDs using
|
||||
* the wallet.
|
||||
*/
|
||||
static QStringList users(const QString &wallet);
|
||||
|
||||
/**
|
||||
* The name of the wallet used to store local passwords.
|
||||
*/
|
||||
static const QString LocalWallet();
|
||||
|
||||
/**
|
||||
* The name of the wallet used to store network passwords.
|
||||
*/
|
||||
static const QString NetworkWallet();
|
||||
|
||||
/**
|
||||
* The standardized name of the password folder.
|
||||
* It is automatically created when a wallet is created, but
|
||||
* the user may still delete it so you should check for its
|
||||
* existence and recreate it if necessary and desired.
|
||||
*/
|
||||
static const QString PasswordFolder();
|
||||
|
||||
/**
|
||||
* The standardized name of the form data folder.
|
||||
* It is automatically created when a wallet is created, but
|
||||
* the user may still delete it so you should check for its
|
||||
* existence and recreate it if necessary and desired.
|
||||
*/
|
||||
static const QString FormDataFolder();
|
||||
|
||||
/**
|
||||
* Request to the wallet service to change the password of
|
||||
* the wallet @p name.
|
||||
* @param name The wallet to change the password of.
|
||||
* @param w The window id to associate any dialogs with. You can pass
|
||||
* 0 if you don't have a window the password dialog should
|
||||
* associate with.
|
||||
*/
|
||||
static void changePassword(const QString &name, WId w);
|
||||
|
||||
/**
|
||||
* This syncs the wallet file on disk with what is in memory.
|
||||
* You don't normally need to use this. It happens
|
||||
* automatically on close.
|
||||
* @return Returns 0 on success, non-zero on error.
|
||||
*/
|
||||
virtual int sync();
|
||||
|
||||
/**
|
||||
* This closes and locks the current wallet. It will
|
||||
* disconnect all applications using the wallet.
|
||||
* @return Returns 0 on success, non-zero on error.
|
||||
*/
|
||||
virtual int lockWallet();
|
||||
|
||||
/**
|
||||
* The name of the current wallet.
|
||||
*/
|
||||
virtual const QString &walletName() const;
|
||||
|
||||
/**
|
||||
* Determine if the current wallet is open, and is a valid
|
||||
* wallet handle.
|
||||
* @return Returns true if the wallet handle is valid and open.
|
||||
*/
|
||||
virtual bool isOpen() const;
|
||||
|
||||
/**
|
||||
* Request to the wallet service to change the password of
|
||||
* the current wallet.
|
||||
* @param w The window id to associate any dialogs with. You can pass
|
||||
* 0 if you don't have a window the password dialog should
|
||||
* associate with.
|
||||
*/
|
||||
virtual void requestChangePassword(WId w);
|
||||
|
||||
/**
|
||||
* Obtain the list of all folders contained in the wallet.
|
||||
* @return Returns an empty list if the wallet is not open.
|
||||
*/
|
||||
virtual QStringList folderList();
|
||||
|
||||
/**
|
||||
* Determine if the folder @p f exists in the wallet.
|
||||
* @param f the name of the folder to check for
|
||||
* @return Returns true if the folder exists in the wallet.
|
||||
*/
|
||||
virtual bool hasFolder(const QString &f);
|
||||
|
||||
/**
|
||||
* Set the current working folder to @p f. The folder must
|
||||
* exist, or this call will fail. Create a folder with
|
||||
* createFolder().
|
||||
* @param f the name of the folder to make the working folder
|
||||
* @return Returns true if the folder was successfully set.
|
||||
*/
|
||||
virtual bool setFolder(const QString &f);
|
||||
|
||||
/**
|
||||
* Remove the folder @p f and all its entries from the wallet.
|
||||
* @param f the name of the folder to remove
|
||||
* @return Returns true if the folder was successfully removed.
|
||||
*/
|
||||
virtual bool removeFolder(const QString &f);
|
||||
|
||||
/**
|
||||
* Created the folder @p f.
|
||||
* @param f the name of the folder to create
|
||||
* @return Returns true if the folder was successfully created.
|
||||
*/
|
||||
virtual bool createFolder(const QString &f);
|
||||
|
||||
/**
|
||||
* Determine the current working folder in the wallet.
|
||||
* If the folder name is empty, it is working in the global
|
||||
* folder, which is valid but discouraged.
|
||||
* @return Returns the current working folder.
|
||||
*/
|
||||
virtual const QString ¤tFolder() const;
|
||||
|
||||
/**
|
||||
* Return the list of keys of all entries in this folder.
|
||||
* @return Returns an empty list if the wallet is not open, or
|
||||
* if the folder is empty.
|
||||
*/
|
||||
virtual QStringList entryList();
|
||||
|
||||
// TODO KDE5: a entryList(folder) so that kwalletmanager can list a folder without
|
||||
// having to call setFolder before and after (which calls contains() in each)
|
||||
|
||||
/**
|
||||
* Rename the entry @p oldName to @p newName.
|
||||
* @param oldName The original key of the entry.
|
||||
* @param newName The new key of the entry.
|
||||
* @return Returns 0 on success, non-zero on error.
|
||||
*/
|
||||
virtual int renameEntry(const QString &oldName, const QString &newName);
|
||||
|
||||
/**
|
||||
* Read the entry @p key from the current folder.
|
||||
* The entry format is unknown except that it is either a
|
||||
* QByteArray or a QDataStream, which effectively means that
|
||||
* it is anything.
|
||||
* @param key The key of the entry to read.
|
||||
* @param value A buffer to fill with the value.
|
||||
* @return Returns 0 on success, non-zero on error.
|
||||
*/
|
||||
virtual int readEntry(const QString &key, QByteArray &value);
|
||||
|
||||
/**
|
||||
* Read the map entry @p key from the current folder.
|
||||
* @param key The key of the entry to read.
|
||||
* @param value A map buffer to fill with the value.
|
||||
* @return Returns 0 on success, non-zero on error. Will
|
||||
* return an error if the key was not originally
|
||||
* written as a map.
|
||||
*/
|
||||
virtual int readMap(const QString &key, QMap<QString, QString> &value);
|
||||
|
||||
/**
|
||||
* Read the password entry @p key from the current folder.
|
||||
* @param key The key of the entry to read.
|
||||
* @param value A password buffer to fill with the value.
|
||||
* @return Returns 0 on success, non-zero on error. Will
|
||||
* return an error if the key was not originally
|
||||
* written as a password.
|
||||
*/
|
||||
virtual int readPassword(const QString &key, QString &value);
|
||||
|
||||
/**
|
||||
* Get a list of all the entries in the current folder. The entry
|
||||
* format is unknown except that it is either a QByteArray or a
|
||||
* QDataStream, which effectively means that it could be anything.
|
||||
*
|
||||
* @param ok if not nullptr, the object this parameter points to will be set
|
||||
* to true to indicate success or false otherwise
|
||||
* @return a map of key/value pairs where the key in the map is the entry key
|
||||
*
|
||||
* @since 5.72
|
||||
*/
|
||||
QMap<QString, QByteArray> entriesList(bool *ok) const;
|
||||
|
||||
/**
|
||||
* Get a list of all the maps in the current folder.
|
||||
*
|
||||
* @param ok if not nullptr, the object this parameter points to will be set
|
||||
* to true to indicate success or false otherwise. Note that if any
|
||||
* of the keys was not originally written as a map, the object will
|
||||
* be set to false
|
||||
*
|
||||
* @return a map of key/value pairs where the key in the map is the entry key
|
||||
*
|
||||
* @since 5.72
|
||||
*/
|
||||
QMap<QString, QMap<QString, QString>> mapList(bool *ok) const;
|
||||
|
||||
/**
|
||||
* Get a list of all the passwords in the current folder, which can
|
||||
* be used to populate a list view in a password manager.
|
||||
*
|
||||
* @param ok if not nullptr, the object this parameter points to will be
|
||||
* set to true to indicate success or false otherwise. Note that
|
||||
* the object will be set to false if any of the keys was not
|
||||
* originally written as a password
|
||||
*
|
||||
* @return a map of key/value pairs, where the key in the map is the entry key
|
||||
*
|
||||
* @since 5.72
|
||||
*/
|
||||
QMap<QString, QString> passwordList(bool *ok) const;
|
||||
|
||||
/**
|
||||
* Write @p key = @p value as a binary entry to the current
|
||||
* folder. Be careful with this, it could cause inconsistency
|
||||
* in the future since you can put an arbitrary entry type in
|
||||
* place.
|
||||
* @param key The key of the new entry.
|
||||
* @param value The value of the entry.
|
||||
* @param entryType The type of the entry.
|
||||
* @return Returns 0 on success, non-zero on error.
|
||||
*/
|
||||
virtual int writeEntry(const QString &key, const QByteArray &value, EntryType entryType);
|
||||
|
||||
/**
|
||||
* Write @p key = @p value as a binary entry to the current
|
||||
* folder.
|
||||
* @param key The key of the new entry.
|
||||
* @param value The value of the entry.
|
||||
* @return Returns 0 on success, non-zero on error.
|
||||
*/
|
||||
virtual int writeEntry(const QString &key, const QByteArray &value);
|
||||
|
||||
/**
|
||||
* Write @p key = @p value as a map to the current folder.
|
||||
* @param key The key of the new entry.
|
||||
* @param value The value of the map.
|
||||
* @return Returns 0 on success, non-zero on error.
|
||||
*/
|
||||
virtual int writeMap(const QString &key, const QMap<QString, QString> &value);
|
||||
|
||||
/**
|
||||
* Write @p key = @p value as a password to the current folder.
|
||||
* @param key The key of the new entry.
|
||||
* @param value The value of the password.
|
||||
* @return Returns 0 on success, non-zero on error.
|
||||
*/
|
||||
virtual int writePassword(const QString &key, const QString &value);
|
||||
|
||||
/**
|
||||
* Determine if the current folder has they entry @p key.
|
||||
* @param key The key to search for.
|
||||
* @return Returns true if the folder contains @p key.
|
||||
*/
|
||||
virtual bool hasEntry(const QString &key);
|
||||
|
||||
/**
|
||||
* Remove the entry @p key from the current folder.
|
||||
* @param key The key to remove.
|
||||
* @return Returns 0 on success, non-zero on error.
|
||||
*/
|
||||
virtual int removeEntry(const QString &key);
|
||||
|
||||
/**
|
||||
* Determine the type of the entry @p key in this folder.
|
||||
* @param key The key to look up.
|
||||
* @return Returns an enumerated type representing the type
|
||||
* of the entry.
|
||||
*/
|
||||
virtual EntryType entryType(const QString &key);
|
||||
|
||||
/**
|
||||
* Determine if a folder does not exist in a wallet. This
|
||||
* does not require decryption of the wallet.
|
||||
* This is a handy optimization to avoid prompting the user
|
||||
* if your data is certainly not in the wallet.
|
||||
* @param wallet The wallet to look in.
|
||||
* @param folder The folder to look up.
|
||||
* @return Returns true if the folder does NOT exist in the
|
||||
* wallet, or the wallet does not exist.
|
||||
*/
|
||||
static bool folderDoesNotExist(const QString &wallet, const QString &folder);
|
||||
|
||||
/**
|
||||
* Determine if an entry in a folder does not exist in a
|
||||
* wallet. This does not require decryption of the wallet.
|
||||
* This is a handy optimization to avoid prompting the user
|
||||
* if your data is certainly not in the wallet.
|
||||
* @param wallet The wallet to look in.
|
||||
* @param folder The folder to look in.
|
||||
* @param key The key to look up.
|
||||
* @return Returns true if the key does NOT exist in the
|
||||
* wallet, or the folder or wallet does not exist.
|
||||
*/
|
||||
static bool keyDoesNotExist(const QString &wallet, const QString &folder, const QString &key);
|
||||
|
||||
Q_SIGNALS:
|
||||
/**
|
||||
* Emitted when this wallet is closed.
|
||||
*/
|
||||
void walletClosed();
|
||||
|
||||
/**
|
||||
* Emitted when a folder in this wallet is updated.
|
||||
* @param folder The folder that was updated.
|
||||
*/
|
||||
void folderUpdated(const QString &folder);
|
||||
|
||||
/**
|
||||
* Emitted when the folder list is changed in this wallet.
|
||||
*/
|
||||
void folderListUpdated();
|
||||
|
||||
/**
|
||||
* Emitted when a folder in this wallet is removed.
|
||||
* @param folder The folder that was removed.
|
||||
*/
|
||||
void folderRemoved(const QString &folder);
|
||||
|
||||
/**
|
||||
* Emitted when a wallet is opened in asynchronous mode.
|
||||
* @param success True if the wallet was opened successfully.
|
||||
*/
|
||||
void walletOpened(bool success);
|
||||
|
||||
private Q_SLOTS:
|
||||
/**
|
||||
* @internal
|
||||
* D-Bus slot for signals emitted by the wallet service.
|
||||
*/
|
||||
KWALLET_NO_EXPORT void slotWalletClosed(int handle);
|
||||
|
||||
/**
|
||||
* @internal
|
||||
* D-Bus slot for signals emitted by the wallet service.
|
||||
*/
|
||||
KWALLET_NO_EXPORT void slotFolderUpdated(const QString &wallet, const QString &folder);
|
||||
|
||||
/**
|
||||
* @internal
|
||||
* D-Bus slot for signals emitted by the wallet service.
|
||||
*/
|
||||
KWALLET_NO_EXPORT void slotFolderListUpdated(const QString &wallet);
|
||||
|
||||
/**
|
||||
* @internal
|
||||
* D-Bus slot for signals emitted by the wallet service.
|
||||
*/
|
||||
KWALLET_NO_EXPORT void slotApplicationDisconnected(const QString &wallet, const QString &application);
|
||||
|
||||
/**
|
||||
* @internal
|
||||
* Callback for kwalletd
|
||||
* @param tId identifier for the open transaction
|
||||
* @param handle the wallet's handle
|
||||
*/
|
||||
KWALLET_NO_EXPORT void walletAsyncOpened(int tId, int handle);
|
||||
|
||||
/**
|
||||
* @internal
|
||||
* D-Bus error slot.
|
||||
*/
|
||||
KWALLET_NO_EXPORT void emitWalletAsyncOpenError();
|
||||
|
||||
/**
|
||||
* @internal
|
||||
* Emits wallet opening success.
|
||||
*/
|
||||
KWALLET_NO_EXPORT void emitWalletOpened();
|
||||
|
||||
/**
|
||||
* @internal
|
||||
* Receives status changed notifications from KSecretsService infrastructure
|
||||
*/
|
||||
KWALLET_NO_EXPORT void slotCollectionStatusChanged(int);
|
||||
/**
|
||||
* @internal
|
||||
* Received delete notification from KSecretsService infrastructure
|
||||
*/
|
||||
KWALLET_NO_EXPORT void slotCollectionDeleted();
|
||||
|
||||
private:
|
||||
class WalletPrivate;
|
||||
WalletPrivate *const d;
|
||||
Q_PRIVATE_SLOT(d, void walletServiceUnregistered())
|
||||
|
||||
protected:
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
virtual void virtual_hook(int id, void *data);
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif //_KWALLET_H
|
||||
@@ -0,0 +1,738 @@
|
||||
/*
|
||||
This file is part of the KDE project
|
||||
|
||||
SPDX-FileCopyrightText: 2002-2004 George Staikos <staikos@kde.org>
|
||||
SPDX-FileCopyrightText: 2008 Michael Leupold <lemma@confuego.org>
|
||||
SPDX-FileCopyrightText: 2010 Frank Osterfeld <osterfeld@kde.org>
|
||||
|
||||
SPDX-License-Identifier: LGPL-2.0-or-later
|
||||
*/
|
||||
|
||||
#include "kwallet.h"
|
||||
#include <KConfigGroup>
|
||||
#include <KSharedConfig>
|
||||
|
||||
#include <QApplication>
|
||||
#include <QDebug>
|
||||
#include <QPointer>
|
||||
#include <QWidget>
|
||||
|
||||
#include <Carbon/Carbon.h>
|
||||
#include <Security/SecKeychain.h>
|
||||
#include <Security/Security.h>
|
||||
|
||||
// TODO: OSX_KEYCHAIN_PORT_DISABLED is never defined, all the enclosing code should be removed
|
||||
|
||||
using namespace KWallet;
|
||||
|
||||
typedef QMap<QString, QString> StringStringMap;
|
||||
Q_DECLARE_METATYPE(StringStringMap)
|
||||
typedef QMap<QString, StringStringMap> StringToStringStringMapMap;
|
||||
Q_DECLARE_METATYPE(StringToStringStringMapMap)
|
||||
typedef QMap<QString, QByteArray> StringByteArrayMap;
|
||||
Q_DECLARE_METATYPE(StringByteArrayMap)
|
||||
|
||||
namespace
|
||||
{
|
||||
template<typename T>
|
||||
struct CFReleaser {
|
||||
explicit CFReleaser(const T &r)
|
||||
: ref(r)
|
||||
{
|
||||
}
|
||||
~CFReleaser()
|
||||
{
|
||||
CFRelease(ref);
|
||||
}
|
||||
T ref;
|
||||
};
|
||||
}
|
||||
|
||||
static QString asQString(CFStringRef sr)
|
||||
{
|
||||
return QString::fromLatin1(CFStringGetCStringPtr(sr, NULL)); // TODO Latin1 correct?
|
||||
}
|
||||
|
||||
static QString errorString(OSStatus s)
|
||||
{
|
||||
const CFReleaser<CFStringRef> ref(SecCopyErrorMessageString(s, NULL));
|
||||
return asQString(ref.ref);
|
||||
}
|
||||
|
||||
static bool isError(OSStatus s, QString *errMsg)
|
||||
{
|
||||
if (errMsg) {
|
||||
*errMsg = errorString(s);
|
||||
}
|
||||
return s != 0;
|
||||
}
|
||||
|
||||
static QString appid()
|
||||
{
|
||||
return qApp->applicationName();
|
||||
}
|
||||
|
||||
static OSStatus removeEntryImplementation(const QString &walletName, const QString &key)
|
||||
{
|
||||
const QByteArray serviceName(walletName.toUtf8());
|
||||
const QByteArray accountName(key.toUtf8());
|
||||
SecKeychainItemRef itemRef;
|
||||
QString errMsg;
|
||||
OSStatus result =
|
||||
SecKeychainFindGenericPassword(NULL, serviceName.size(), serviceName.constData(), accountName.size(), accountName.constData(), NULL, NULL, &itemRef);
|
||||
if (isError(result, &errMsg)) {
|
||||
qWarning() << "Could not retrieve password:" << qPrintable(errMsg);
|
||||
return result;
|
||||
}
|
||||
const CFReleaser<SecKeychainItemRef> itemReleaser(itemRef);
|
||||
result = SecKeychainItemDelete(itemRef);
|
||||
if (isError(result, &errMsg)) {
|
||||
qWarning() << "Could not delete password:" << qPrintable(errMsg);
|
||||
return result;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
const QString Wallet::LocalWallet()
|
||||
{
|
||||
KConfigGroup cfg(KSharedConfig::openConfig(QStringLiteral("kwalletrc"))->group("Wallet"));
|
||||
if (!cfg.readEntry("Use One Wallet", true)) {
|
||||
QString tmp = cfg.readEntry("Local Wallet", "localwallet");
|
||||
if (tmp.isEmpty()) {
|
||||
return QStringLiteral("localwallet");
|
||||
}
|
||||
return tmp;
|
||||
}
|
||||
|
||||
QString tmp = cfg.readEntry("Default Wallet", "kdewallet");
|
||||
if (tmp.isEmpty()) {
|
||||
return QStringLiteral("kdewallet");
|
||||
}
|
||||
return tmp;
|
||||
}
|
||||
|
||||
const QString Wallet::NetworkWallet()
|
||||
{
|
||||
KConfigGroup cfg(KSharedConfig::openConfig(QStringLiteral("kwalletrc"))->group("Wallet"));
|
||||
|
||||
QString tmp = cfg.readEntry("Default Wallet", "kdewallet");
|
||||
if (tmp.isEmpty()) {
|
||||
return QStringLiteral("kdewallet");
|
||||
}
|
||||
return tmp;
|
||||
}
|
||||
|
||||
const QString Wallet::PasswordFolder()
|
||||
{
|
||||
return QStringLiteral("Passwords");
|
||||
}
|
||||
|
||||
const QString Wallet::FormDataFolder()
|
||||
{
|
||||
return QStringLiteral("Form Data");
|
||||
}
|
||||
|
||||
class Q_DECL_HIDDEN Wallet::WalletPrivate
|
||||
{
|
||||
public:
|
||||
WalletPrivate(Wallet *wallet, int h, const QString &n)
|
||||
: q(wallet)
|
||||
, name(n)
|
||||
, handle(h)
|
||||
{
|
||||
}
|
||||
|
||||
void walletServiceUnregistered();
|
||||
|
||||
Wallet *q;
|
||||
QString name;
|
||||
QString folder;
|
||||
int handle;
|
||||
int transactionId;
|
||||
};
|
||||
|
||||
void Wallet::WalletPrivate::walletServiceUnregistered()
|
||||
{
|
||||
if (handle >= 0) {
|
||||
q->slotWalletClosed(handle);
|
||||
}
|
||||
}
|
||||
|
||||
Wallet::Wallet(int handle, const QString &name)
|
||||
: QObject(0L)
|
||||
, d(new WalletPrivate(this, handle, name))
|
||||
{
|
||||
Q_UNUSED(handle);
|
||||
}
|
||||
|
||||
Wallet::~Wallet()
|
||||
{
|
||||
delete d;
|
||||
}
|
||||
|
||||
QStringList Wallet::walletList()
|
||||
{
|
||||
#ifdef OSX_KEYCHAIN_PORT_DISABLED
|
||||
return walletLauncher->getInterface().wallets();
|
||||
#else
|
||||
return QStringList();
|
||||
#endif
|
||||
}
|
||||
|
||||
void Wallet::changePassword(const QString &name, WId w)
|
||||
{
|
||||
#ifdef OSX_KEYCHAIN_PORT_DISABLED
|
||||
if (w == 0) {
|
||||
qDebug() << "Pass a valid window to KWallet::Wallet::changePassword().";
|
||||
}
|
||||
walletLauncher->getInterface().changePassword(name, (qlonglong)w, appid());
|
||||
#endif
|
||||
}
|
||||
|
||||
bool Wallet::isEnabled()
|
||||
{
|
||||
// PENDING(frank) check
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Wallet::isOpen(const QString &name)
|
||||
{
|
||||
#ifdef OSX_KEYCHAIN_PORT_DISABLED
|
||||
return walletLauncher->getInterface().isOpen(name); // default is false
|
||||
#else
|
||||
return true;
|
||||
#endif
|
||||
}
|
||||
|
||||
int Wallet::closeWallet(const QString &name, bool force)
|
||||
{
|
||||
#ifdef OSX_KEYCHAIN_PORT_DISABLED
|
||||
QDBusReply<int> r = walletLauncher->getInterface().close(name, force);
|
||||
return r.isValid() ? r : -1;
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
int Wallet::deleteWallet(const QString &name)
|
||||
{
|
||||
#ifdef OSX_KEYCHAIN_PORT_DISABLED
|
||||
QDBusReply<int> r = walletLauncher->getInterface().deleteWallet(name);
|
||||
return r.isValid() ? r : -1;
|
||||
#else
|
||||
return -1;
|
||||
#endif
|
||||
}
|
||||
|
||||
Wallet *Wallet::openWallet(const QString &name, WId w, OpenType ot)
|
||||
{
|
||||
Q_UNUSED(w);
|
||||
Q_UNUSED(ot);
|
||||
Wallet *wallet = new Wallet(-1, name);
|
||||
QMetaObject::invokeMethod(wallet, "emitWalletOpened", Qt::QueuedConnection);
|
||||
return wallet;
|
||||
}
|
||||
|
||||
bool Wallet::disconnectApplication(const QString &wallet, const QString &app)
|
||||
{
|
||||
#ifdef OSX_KEYCHAIN_PORT_DISABLED
|
||||
return walletLauncher->getInterface().disconnectApplication(wallet, app); // default is false
|
||||
#else
|
||||
return true;
|
||||
#endif
|
||||
}
|
||||
|
||||
QStringList Wallet::users(const QString &name)
|
||||
{
|
||||
#ifdef OSX_KEYCHAIN_PORT_DISABLED
|
||||
return walletLauncher->getInterface().users(name); // default is QStringList()
|
||||
#else
|
||||
return QStringList();
|
||||
#endif
|
||||
}
|
||||
|
||||
int Wallet::sync()
|
||||
{
|
||||
#ifdef OSX_KEYCHAIN_PORT_DISABLED
|
||||
if (d->handle == -1) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
walletLauncher->getInterface().sync(d->handle, appid());
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
int Wallet::lockWallet()
|
||||
{
|
||||
#ifdef OSX_KEYCHAIN_PORT_DISABLED
|
||||
if (d->handle == -1) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
QDBusReply<int> r = walletLauncher->getInterface().close(d->handle, true, appid());
|
||||
d->handle = -1;
|
||||
d->folder.clear();
|
||||
d->name.clear();
|
||||
if (r.isValid()) {
|
||||
return r;
|
||||
}
|
||||
#endif
|
||||
return -1;
|
||||
}
|
||||
|
||||
const QString &Wallet::walletName() const
|
||||
{
|
||||
return d->name;
|
||||
}
|
||||
|
||||
bool Wallet::isOpen() const
|
||||
{
|
||||
#ifdef OSX_KEYCHAIN_PORT_DISABLED
|
||||
return d->handle != -1;
|
||||
#else
|
||||
return true;
|
||||
#endif
|
||||
}
|
||||
|
||||
void Wallet::requestChangePassword(WId w)
|
||||
{
|
||||
#ifdef OSX_KEYCHAIN_PORT_DISABLED
|
||||
if (w == 0) {
|
||||
qDebug() << "Pass a valid window to KWallet::Wallet::requestChangePassword().";
|
||||
}
|
||||
if (d->handle == -1) {
|
||||
return;
|
||||
}
|
||||
|
||||
walletLauncher->getInterface().changePassword(d->name, (qlonglong)w, appid());
|
||||
#endif
|
||||
}
|
||||
|
||||
void Wallet::slotWalletClosed(int handle)
|
||||
{
|
||||
#ifdef OSX_KEYCHAIN_PORT_DISABLED
|
||||
if (d->handle == handle) {
|
||||
d->handle = -1;
|
||||
d->folder.clear();
|
||||
d->name.clear();
|
||||
Q_EMIT walletClosed();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
QStringList Wallet::folderList()
|
||||
{
|
||||
#ifdef OSX_KEYCHAIN_PORT_DISABLED
|
||||
if (d->handle == -1) {
|
||||
return QStringList();
|
||||
}
|
||||
|
||||
QDBusReply<QStringList> r = walletLauncher->getInterface().folderList(d->handle, appid());
|
||||
return r;
|
||||
#else
|
||||
return QStringList();
|
||||
#endif
|
||||
}
|
||||
|
||||
QStringList Wallet::entryList()
|
||||
{
|
||||
#ifdef OSX_KEYCHAIN_PORT_DISABLED
|
||||
if (d->handle == -1) {
|
||||
return QStringList();
|
||||
}
|
||||
|
||||
QDBusReply<QStringList> r = walletLauncher->getInterface().entryList(d->handle, d->folder, appid());
|
||||
return r;
|
||||
#else
|
||||
return QStringList();
|
||||
#endif
|
||||
}
|
||||
|
||||
bool Wallet::hasFolder(const QString &f)
|
||||
{
|
||||
#ifdef OSX_KEYCHAIN_PORT_DISABLED
|
||||
if (d->handle == -1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
QDBusReply<bool> r = walletLauncher->getInterface().hasFolder(d->handle, f, appid());
|
||||
return r; // default is false
|
||||
#else
|
||||
return true;
|
||||
#endif
|
||||
}
|
||||
|
||||
bool Wallet::createFolder(const QString &f)
|
||||
{
|
||||
#ifdef OSX_KEYCHAIN_PORT_DISABLED
|
||||
if (d->handle == -1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!hasFolder(f)) {
|
||||
QDBusReply<bool> r = walletLauncher->getInterface().createFolder(d->handle, f, appid());
|
||||
return r;
|
||||
}
|
||||
|
||||
return true; // folder already exists
|
||||
#else
|
||||
return true;
|
||||
#endif
|
||||
}
|
||||
|
||||
bool Wallet::setFolder(const QString &f)
|
||||
{
|
||||
#ifdef OSX_KEYCHAIN_PORT_DISABLED
|
||||
bool rc = false;
|
||||
|
||||
if (d->handle == -1) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
// Don't do this - the folder could have disappeared?
|
||||
#if 0
|
||||
if (f == d->folder) {
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (hasFolder(f)) {
|
||||
d->folder = f;
|
||||
rc = true;
|
||||
}
|
||||
|
||||
return rc;
|
||||
#else
|
||||
return true;
|
||||
#endif
|
||||
}
|
||||
|
||||
bool Wallet::removeFolder(const QString &f)
|
||||
{
|
||||
#ifdef OSX_KEYCHAIN_PORT_DISABLED
|
||||
if (d->handle == -1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
QDBusReply<bool> r = walletLauncher->getInterface().removeFolder(d->handle, f, appid());
|
||||
if (d->folder == f) {
|
||||
setFolder(QString());
|
||||
}
|
||||
|
||||
return r; // default is false
|
||||
#else
|
||||
return true;
|
||||
#endif
|
||||
}
|
||||
|
||||
const QString &Wallet::currentFolder() const
|
||||
{
|
||||
return d->folder;
|
||||
}
|
||||
|
||||
int Wallet::readEntry(const QString &key, QByteArray &value)
|
||||
{
|
||||
const QByteArray serviceName(walletName().toUtf8());
|
||||
const QByteArray accountName(key.toUtf8());
|
||||
UInt32 passwordSize = 0;
|
||||
void *passwordData = 0;
|
||||
QString errMsg;
|
||||
if (isError(SecKeychainFindGenericPassword(NULL,
|
||||
serviceName.size(),
|
||||
serviceName.constData(),
|
||||
accountName.size(),
|
||||
accountName.constData(),
|
||||
&passwordSize,
|
||||
&passwordData,
|
||||
NULL),
|
||||
&errMsg)) {
|
||||
qWarning() << "Could not retrieve password:" << qPrintable(errMsg);
|
||||
return -1;
|
||||
}
|
||||
|
||||
value = QByteArray(reinterpret_cast<const char *>(passwordData), passwordSize);
|
||||
SecKeychainItemFreeContent(NULL, passwordData);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int Wallet::readEntryList(const QString &key, QMap<QString, QByteArray> &value)
|
||||
{
|
||||
#ifdef OSX_KEYCHAIN_PORT_DISABLED
|
||||
registerTypes();
|
||||
|
||||
int rc = -1;
|
||||
|
||||
if (d->handle == -1) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
QDBusReply<QVariantMap> r = walletLauncher->getInterface().readEntryList(d->handle, d->folder, key, appid());
|
||||
if (r.isValid()) {
|
||||
rc = 0;
|
||||
// convert <QString, QVariant> to <QString, QByteArray>
|
||||
const QVariantMap val = r.value();
|
||||
for (QVariantMap::const_iterator it = val.begin(); it != val.end(); ++it) {
|
||||
value.insert(it.key(), it.value().toByteArray());
|
||||
}
|
||||
}
|
||||
|
||||
return rc;
|
||||
#else
|
||||
return -1;
|
||||
#endif
|
||||
}
|
||||
|
||||
int Wallet::renameEntry(const QString &oldName, const QString &newName)
|
||||
{
|
||||
#ifdef OSX_KEYCHAIN_PORT_DISABLED
|
||||
int rc = -1;
|
||||
|
||||
if (d->handle == -1) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
QDBusReply<int> r = walletLauncher->getInterface().renameEntry(d->handle, d->folder, oldName, newName, appid());
|
||||
if (r.isValid()) {
|
||||
rc = r;
|
||||
}
|
||||
|
||||
return rc;
|
||||
#else
|
||||
return -1;
|
||||
#endif
|
||||
}
|
||||
|
||||
int Wallet::readMap(const QString &key, QMap<QString, QString> &value)
|
||||
{
|
||||
QByteArray v;
|
||||
const int ret = readEntry(key, v);
|
||||
if (ret != 0) {
|
||||
return ret;
|
||||
}
|
||||
if (!v.isEmpty()) {
|
||||
QDataStream ds(&v, QIODevice::ReadOnly);
|
||||
ds >> value;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int Wallet::readMapList(const QString &key, QMap<QString, QMap<QString, QString>> &value)
|
||||
{
|
||||
#ifdef OSX_KEYCHAIN_PORT_DISABLED
|
||||
registerTypes();
|
||||
|
||||
int rc = -1;
|
||||
|
||||
if (d->handle == -1) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
QDBusReply<QVariantMap> r = walletLauncher->getInterface().readMapList(d->handle, d->folder, key, appid());
|
||||
if (r.isValid()) {
|
||||
rc = 0;
|
||||
const QVariantMap val = r.value();
|
||||
for (QVariantMap::const_iterator it = val.begin(); it != val.end(); ++it) {
|
||||
QByteArray mapData = it.value().toByteArray();
|
||||
if (!mapData.isEmpty()) {
|
||||
QDataStream ds(&mapData, QIODevice::ReadOnly);
|
||||
QMap<QString, QString> v;
|
||||
ds >> v;
|
||||
value.insert(it.key(), v);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return rc;
|
||||
#else
|
||||
return -1;
|
||||
#endif
|
||||
}
|
||||
|
||||
int Wallet::readPassword(const QString &key, QString &value)
|
||||
{
|
||||
QByteArray ba;
|
||||
const int ret = readEntry(key, ba);
|
||||
if (ret == 0) {
|
||||
value = QString::fromUtf8(ba.constData());
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int Wallet::readPasswordList(const QString &key, QMap<QString, QString> &value)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
static OSStatus writeEntryImplementation(const QString &walletName, const QString &key, const QByteArray &value)
|
||||
{
|
||||
const QByteArray serviceName(walletName.toUtf8());
|
||||
const QByteArray accountName(key.toUtf8());
|
||||
QString errMsg;
|
||||
OSStatus err = SecKeychainAddGenericPassword(NULL,
|
||||
serviceName.size(),
|
||||
serviceName.constData(),
|
||||
accountName.size(),
|
||||
accountName.constData(),
|
||||
value.size(),
|
||||
value.constData(),
|
||||
NULL);
|
||||
if (err == errSecDuplicateItem) {
|
||||
err = removeEntryImplementation(walletName, key);
|
||||
if (isError(err, &errMsg)) {
|
||||
qWarning() << "Could not delete old key in keychain for replacing: " << qPrintable(errMsg);
|
||||
return err;
|
||||
}
|
||||
}
|
||||
if (isError(err, &errMsg)) {
|
||||
qWarning() << "Could not store password in keychain: " << qPrintable(errMsg);
|
||||
return err;
|
||||
}
|
||||
// qDebug() << "Successfully written out key:" << key;
|
||||
return err;
|
||||
}
|
||||
|
||||
int Wallet::writeEntry(const QString &key, const QByteArray &password, EntryType entryType)
|
||||
{
|
||||
Q_UNUSED(entryType)
|
||||
return writeEntryImplementation(walletName(), key, password);
|
||||
}
|
||||
|
||||
int Wallet::writeEntry(const QString &key, const QByteArray &value)
|
||||
{
|
||||
return writeEntryImplementation(walletName(), key, value);
|
||||
}
|
||||
|
||||
int Wallet::writeMap(const QString &key, const QMap<QString, QString> &value)
|
||||
{
|
||||
QByteArray mapData;
|
||||
QDataStream ds(&mapData, QIODevice::WriteOnly);
|
||||
ds << value;
|
||||
return writeEntry(key, mapData);
|
||||
}
|
||||
|
||||
int Wallet::writePassword(const QString &key, const QString &value)
|
||||
{
|
||||
return writeEntry(key, value.toUtf8());
|
||||
}
|
||||
|
||||
bool Wallet::hasEntry(const QString &key)
|
||||
{
|
||||
const QByteArray serviceName(walletName().toUtf8());
|
||||
const QByteArray accountName(key.toUtf8());
|
||||
return !isError(
|
||||
SecKeychainFindGenericPassword(NULL, serviceName.size(), serviceName.constData(), accountName.size(), accountName.constData(), NULL, NULL, NULL),
|
||||
0);
|
||||
}
|
||||
|
||||
int Wallet::removeEntry(const QString &key)
|
||||
{
|
||||
return removeEntryImplementation(walletName(), key);
|
||||
}
|
||||
|
||||
Wallet::EntryType Wallet::entryType(const QString &key)
|
||||
{
|
||||
#ifdef OSX_KEYCHAIN_PORT_DISABLED
|
||||
int rc = 0;
|
||||
|
||||
if (d->handle == -1) {
|
||||
return Wallet::Unknown;
|
||||
}
|
||||
|
||||
QDBusReply<int> r = walletLauncher->getInterface().entryType(d->handle, d->folder, key, appid());
|
||||
if (r.isValid()) {
|
||||
rc = r;
|
||||
}
|
||||
|
||||
return static_cast<EntryType>(rc);
|
||||
#else
|
||||
return Wallet::Unknown;
|
||||
#endif
|
||||
}
|
||||
|
||||
void Wallet::slotFolderUpdated(const QString &wallet, const QString &folder)
|
||||
{
|
||||
if (d->name == wallet) {
|
||||
Q_EMIT folderUpdated(folder);
|
||||
}
|
||||
}
|
||||
|
||||
void Wallet::slotFolderListUpdated(const QString &wallet)
|
||||
{
|
||||
if (d->name == wallet) {
|
||||
Q_EMIT folderListUpdated();
|
||||
}
|
||||
}
|
||||
|
||||
void Wallet::slotApplicationDisconnected(const QString &wallet, const QString &application)
|
||||
{
|
||||
#ifdef OSX_KEYCHAIN_PORT_DISABLED
|
||||
if (d->handle >= 0 && d->name == wallet && application == appid()) {
|
||||
slotWalletClosed(d->handle);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void Wallet::walletAsyncOpened(int tId, int handle)
|
||||
{
|
||||
#ifdef OSX_KEYCHAIN_PORT_DISABLED
|
||||
// ignore responses to calls other than ours
|
||||
if (d->transactionId != tId || d->handle != -1) {
|
||||
return;
|
||||
}
|
||||
|
||||
// disconnect the async signal
|
||||
disconnect(this, SLOT(walletAsyncOpened(int, int)));
|
||||
|
||||
d->handle = handle;
|
||||
Q_EMIT walletOpened(handle > 0);
|
||||
#endif
|
||||
}
|
||||
|
||||
void Wallet::emitWalletAsyncOpenError()
|
||||
{
|
||||
Q_EMIT walletOpened(false);
|
||||
}
|
||||
|
||||
void Wallet::emitWalletOpened()
|
||||
{
|
||||
Q_EMIT walletOpened(true);
|
||||
}
|
||||
|
||||
bool Wallet::folderDoesNotExist(const QString &wallet, const QString &folder)
|
||||
{
|
||||
#ifdef OSX_KEYCHAIN_PORT_DISABLED
|
||||
QDBusReply<bool> r = walletLauncher->getInterface().folderDoesNotExist(wallet, folder);
|
||||
return r;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
bool Wallet::keyDoesNotExist(const QString &wallet, const QString &folder, const QString &key)
|
||||
{
|
||||
#ifdef OSX_KEYCHAIN_PORT_DISABLED
|
||||
QDBusReply<bool> r = walletLauncher->getInterface().keyDoesNotExist(wallet, folder, key);
|
||||
return r;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
void Wallet::slotCollectionStatusChanged(int status)
|
||||
{
|
||||
}
|
||||
|
||||
void Wallet::slotCollectionDeleted()
|
||||
{
|
||||
d->folder.clear();
|
||||
d->name.clear();
|
||||
Q_EMIT walletClosed();
|
||||
}
|
||||
|
||||
void Wallet::virtual_hook(int, void *)
|
||||
{
|
||||
// BASE::virtual_hook( id, data );
|
||||
}
|
||||
|
||||
#include "moc_kwallet.cpp"
|
||||
+46
@@ -0,0 +1,46 @@
|
||||
<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN"
|
||||
"http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
|
||||
|
||||
<node name="/org/freedesktop/Secrets">
|
||||
|
||||
<interface name="org.freedesktop.Secret.Collection">
|
||||
|
||||
<property name="Items" type="ao" access="read"/>
|
||||
<property name="Label" type="s" access="readwrite"/>
|
||||
<property name="Locked" type="b" access="read"/>
|
||||
<property name="Created" type="t" access="read"/>
|
||||
<property name="Modified" type="t" access="read"/>
|
||||
|
||||
<method name="Delete">
|
||||
<arg name="prompt" type="o" direction="out"/>
|
||||
</method>
|
||||
|
||||
<method name="SearchItems">
|
||||
<arg name="attributes" type="a{ss}" direction="in"/>
|
||||
<annotation name="org.qtproject.QtDBus.QtTypeName.In0" value="StrStrMap"/>
|
||||
<arg name="results" type="ao" direction="out"/>
|
||||
</method>
|
||||
|
||||
<method name="CreateItem">
|
||||
<arg name="properties" type="a{sv}" direction="in"/>
|
||||
<annotation name="org.qtproject.QtDBus.QtTypeName.In0" value="PropertiesMap"/>
|
||||
<arg name="secret" type="(oayays)" direction="in"/>
|
||||
<annotation name="org.qtproject.QtDBus.QtTypeName.In1" value="FreedesktopSecret"/>
|
||||
<arg name="replace" type="b" direction="in"/>
|
||||
<arg name="item" type="o" direction="out"/>
|
||||
<arg name="prompt" type="o" direction="out"/>
|
||||
</method>
|
||||
|
||||
<signal name="ItemCreated">
|
||||
<arg name="item" type="o"/>
|
||||
</signal>
|
||||
|
||||
<signal name="ItemDeleted">
|
||||
<arg name="item" type="o"/>
|
||||
</signal>
|
||||
|
||||
<signal name="ItemChanged">
|
||||
<arg name="item" type="o"/>
|
||||
</signal>
|
||||
</interface>
|
||||
</node>
|
||||
@@ -0,0 +1,37 @@
|
||||
<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN"
|
||||
"http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
|
||||
|
||||
<node name="/org/freedesktop/Secrets">
|
||||
|
||||
<interface name="org.freedesktop.Secret.Item">
|
||||
|
||||
<property name="Locked" type="b" access="read"/>
|
||||
|
||||
<property name="Attributes" type="a{ss}" access="readwrite">
|
||||
<annotation name="org.qtproject.QtDBus.QtTypeName" value="StrStrMap"/>
|
||||
</property>
|
||||
|
||||
<property name="Label" type="s" access="readwrite"/>
|
||||
|
||||
<property name="Type" type="s" access="readwrite"/>
|
||||
|
||||
<property name="Created" type="t" access="read"/>
|
||||
|
||||
<property name="Modified" type="t" access="read"/>
|
||||
|
||||
<method name="Delete">
|
||||
<arg name="Prompt" type="o" direction="out"/>
|
||||
</method>
|
||||
|
||||
<method name="GetSecret">
|
||||
<arg name="session" type="o" direction="in"/>
|
||||
<arg name="secret" type="(oayays)" direction="out"/>
|
||||
<annotation name="org.qtproject.QtDBus.QtTypeName.Out0" value="FreedesktopSecret"/>
|
||||
</method>
|
||||
|
||||
<method name="SetSecret">
|
||||
<arg name="secret" type="(oayays)" direction="in"/>
|
||||
<annotation name="org.qtproject.QtDBus.QtTypeName.In0" value="FreedesktopSecret"/>
|
||||
</method>
|
||||
</interface>
|
||||
</node>
|
||||
+20
@@ -0,0 +1,20 @@
|
||||
<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN"
|
||||
"http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
|
||||
|
||||
<node name="/org/freedesktop/Secrets">
|
||||
<interface name="org.freedesktop.Secret.Prompt">
|
||||
|
||||
<method name="Prompt">
|
||||
<arg name="window_id" type="s" direction="in"/>
|
||||
</method>
|
||||
|
||||
<method name="Dismiss">
|
||||
</method>
|
||||
|
||||
<!-- Emitted manually -->
|
||||
<signal name="Completed">
|
||||
<arg name="dismissed" type="b"/>
|
||||
<arg name="result" type="v"/>
|
||||
</signal>
|
||||
</interface>
|
||||
</node>
|
||||
+72
@@ -0,0 +1,72 @@
|
||||
<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN"
|
||||
"http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
|
||||
|
||||
<node name="/org/freedesktop/Secrets">
|
||||
|
||||
<interface name="org.freedesktop.Secret.Service">
|
||||
<property name="Collections" type="ao" access="read" />
|
||||
|
||||
<method name="OpenSession">
|
||||
<arg name="algorithm" type="s" direction="in"/>
|
||||
<arg name="input" type="v" direction="in"/>
|
||||
<arg name="output" type="v" direction="out"/>
|
||||
<arg name="result" type="o" direction="out"/>
|
||||
</method>
|
||||
|
||||
<method name="CreateCollection">
|
||||
<arg name="properties" type="a{sv}" direction="in"/>
|
||||
<annotation name="org.qtproject.QtDBus.QtTypeName.In0" value="QVariantMap"/>
|
||||
<arg name="alias" type="s" direction="in"/>
|
||||
<arg name="collection" type="o" direction="out"/>
|
||||
<arg name="prompt" type="o" direction="out"/>
|
||||
</method>
|
||||
|
||||
<method name="SearchItems">
|
||||
<arg name="attributes" type="a{ss}" direction="in"/>
|
||||
<annotation name="org.qtproject.QtDBus.QtTypeName.In0" value="StrStrMap"/>
|
||||
<arg name="unlocked" type="ao" direction="out"/>
|
||||
<arg name="locked" type="ao" direction="out"/>
|
||||
</method>
|
||||
|
||||
<method name="Unlock">
|
||||
<arg name="objects" type="ao" direction="in"/>
|
||||
<arg name="unlocked" type="ao" direction="out"/>
|
||||
<arg name="prompt" type="o" direction="out"/>
|
||||
</method>
|
||||
|
||||
<method name="Lock">
|
||||
<arg name="objects" type="ao" direction="in"/>
|
||||
<arg name="locked" type="ao" direction="out"/>
|
||||
<arg name="Prompt" type="o" direction="out"/>
|
||||
</method>
|
||||
|
||||
<method name="GetSecrets">
|
||||
<arg name="items" type="ao" direction="in"/>
|
||||
<arg name="session" type="o" direction="in"/>
|
||||
<arg name="secrets" type="a{o(oayays)}" direction="out"/>
|
||||
<annotation name="org.qtproject.QtDBus.QtTypeName.Out0" value="FreedesktopSecretMap"/>
|
||||
</method>
|
||||
|
||||
<method name="ReadAlias">
|
||||
<arg name="name" type='s' direction='in'/>
|
||||
<arg name="collection" type='o' direction='out'/>
|
||||
</method>
|
||||
|
||||
<method name="SetAlias">
|
||||
<arg name="name" type='s' direction='in'/>
|
||||
<arg name="collection" type='o' direction='in'/>
|
||||
</method>
|
||||
|
||||
<signal name="CollectionCreated">
|
||||
<arg name="collection" type="o"/>
|
||||
</signal>
|
||||
|
||||
<signal name="CollectionDeleted">
|
||||
<arg name="collection" type="o"/>
|
||||
</signal>
|
||||
|
||||
<signal name="CollectionChanged">
|
||||
<arg name="collection" type="o"/>
|
||||
</signal>
|
||||
</interface>
|
||||
</node>
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN"
|
||||
"http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
|
||||
|
||||
<node name="/org/freedesktop/Secrets">
|
||||
|
||||
<interface name="org.freedesktop.Secret.Session">
|
||||
|
||||
<method name="Close">
|
||||
</method>
|
||||
|
||||
</interface>
|
||||
</node>
|
||||
+66
@@ -0,0 +1,66 @@
|
||||
<?xml version="1.0"?>
|
||||
<!--
|
||||
Copyright (C) 2019 Red Hat, Inc.
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Author: Daiki Ueno <dueno@redhat.com>
|
||||
-->
|
||||
|
||||
<node name="/" xmlns:doc="http://www.freedesktop.org/dbus/1.0/doc.dtd">
|
||||
<!--
|
||||
org.freedesktop.impl.portal.Secret:
|
||||
@short_description: Secret portal backend interface
|
||||
|
||||
The Secret portal allows sandboxed applications to retrieve a
|
||||
per-application master secret.
|
||||
-->
|
||||
<interface name="org.freedesktop.impl.portal.Secret">
|
||||
|
||||
<!--
|
||||
RetrieveSecret:
|
||||
@handle: Object path for the #org.freedesktop.impl.portal.Request object representing this call
|
||||
@app_id: App id of the application
|
||||
@fd: Writable file descriptor for transporting the secret
|
||||
@options: Vardict with optional further information
|
||||
@response: Numeric response
|
||||
@results: Vardict with the results of the call
|
||||
|
||||
Retrieves a master secret for a sandboxed application.
|
||||
|
||||
Supported keys in the @options vardict include:
|
||||
<variablelist>
|
||||
<varlistentry>
|
||||
<term>token s</term>
|
||||
<listitem><para>
|
||||
An opaque string associated with the retrieve secret.
|
||||
</para></listitem>
|
||||
</varlistentry>
|
||||
</variablelist>
|
||||
-->
|
||||
<method name="RetrieveSecret">
|
||||
<annotation name="org.gtk.GDBus.C.Name" value="retrieve_secret"/>
|
||||
<annotation name="org.gtk.GDBus.C.UnixFD" value="true"/>
|
||||
<arg type="o" name="handle" direction="in"/>
|
||||
<arg type="s" name="app_id" direction="in"/>
|
||||
<arg type="h" name="fd" direction="in"/>
|
||||
<annotation name="org.qtproject.QtDBus.QtTypeName.In3" value="QVariantMap"/>
|
||||
<arg type="a{sv}" name="options" direction="in"/>
|
||||
<arg type="u" name="response" direction="out"/>
|
||||
<annotation name="org.qtproject.QtDBus.QtTypeName.Out1" value="QVariantMap"/>
|
||||
<arg type="a{sv}" name="results" direction="out"/>
|
||||
</method>
|
||||
<property name="version" type="u" access="read"/>
|
||||
</interface>
|
||||
</node>
|
||||
+273
@@ -0,0 +1,273 @@
|
||||
<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN" "http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
|
||||
<node>
|
||||
<interface name="org.kde.KWallet">
|
||||
<signal name="walletListDirty">
|
||||
</signal>
|
||||
<signal name="walletCreated">
|
||||
<arg name="wallet" type="s" direction="out"/>
|
||||
</signal>
|
||||
<signal name="walletOpened">
|
||||
<arg name="wallet" type="s" direction="out"/>
|
||||
</signal>
|
||||
<signal name="walletAsyncOpened">
|
||||
<arg name="tId" type="i" direction="out"/>
|
||||
<arg name="handle" type="i" direction="out"/>
|
||||
</signal>
|
||||
<signal name="walletDeleted">
|
||||
<arg name="wallet" type="s" direction="out"/>
|
||||
</signal>
|
||||
<signal name="walletClosed">
|
||||
<arg name="wallet" type="s" direction="out"/>
|
||||
</signal>
|
||||
<signal name="walletClosedId">
|
||||
<arg name="handle" type="i" direction="out"/>
|
||||
</signal>
|
||||
<signal name="allWalletsClosed">
|
||||
</signal>
|
||||
<signal name="folderListUpdated">
|
||||
<arg name="wallet" type="s" direction="out"/>
|
||||
</signal>
|
||||
<signal name="folderUpdated">
|
||||
<arg type="s" direction="out"/>
|
||||
<arg type="s" direction="out"/>
|
||||
</signal>
|
||||
<signal name="applicationDisconnected">
|
||||
<arg name="wallet" type="s" direction="out"/>
|
||||
<arg name="application" type="s" direction="out"/>
|
||||
</signal>
|
||||
<method name="isEnabled">
|
||||
<arg type="b" direction="out"/>
|
||||
</method>
|
||||
<method name="open">
|
||||
<arg type="i" direction="out"/>
|
||||
<arg name="wallet" type="s" direction="in"/>
|
||||
<arg name="wId" type="x" direction="in"/>
|
||||
<arg name="appid" type="s" direction="in"/>
|
||||
</method>
|
||||
<method name="openPath">
|
||||
<arg type="i" direction="out"/>
|
||||
<arg name="path" type="s" direction="in"/>
|
||||
<arg name="wId" type="x" direction="in"/>
|
||||
<arg name="appid" type="s" direction="in"/>
|
||||
</method>
|
||||
<method name="openAsync">
|
||||
<arg type="i" direction="out"/>
|
||||
<arg name="wallet" type="s" direction="in"/>
|
||||
<arg name="wId" type="x" direction="in"/>
|
||||
<arg name="appid" type="s" direction="in"/>
|
||||
<arg name="handleSession" type="b" direction="in"/>
|
||||
</method>
|
||||
<method name="openPathAsync">
|
||||
<arg type="i" direction="out"/>
|
||||
<arg name="path" type="s" direction="in"/>
|
||||
<arg name="wId" type="x" direction="in"/>
|
||||
<arg name="appid" type="s" direction="in"/>
|
||||
<arg name="handleSession" type="b" direction="in"/>
|
||||
</method>
|
||||
<method name="close">
|
||||
<arg type="i" direction="out"/>
|
||||
<arg name="wallet" type="s" direction="in"/>
|
||||
<arg name="force" type="b" direction="in"/>
|
||||
</method>
|
||||
<method name="close">
|
||||
<arg type="i" direction="out"/>
|
||||
<arg name="handle" type="i" direction="in"/>
|
||||
<arg name="force" type="b" direction="in"/>
|
||||
<arg name="appid" type="s" direction="in"/>
|
||||
</method>
|
||||
<method name="sync">
|
||||
<arg name="handle" type="i" direction="in"/>
|
||||
<arg name="appid" type="s" direction="in"/>
|
||||
<annotation name="org.freedesktop.DBus.Method.NoReply" value="true"/>
|
||||
</method>
|
||||
<method name="deleteWallet">
|
||||
<arg type="i" direction="out"/>
|
||||
<arg name="wallet" type="s" direction="in"/>
|
||||
</method>
|
||||
<method name="isOpen">
|
||||
<arg type="b" direction="out"/>
|
||||
<arg name="wallet" type="s" direction="in"/>
|
||||
</method>
|
||||
<method name="isOpen">
|
||||
<arg type="b" direction="out"/>
|
||||
<arg name="handle" type="i" direction="in"/>
|
||||
</method>
|
||||
<method name="users">
|
||||
<arg type="as" direction="out"/>
|
||||
<arg name="wallet" type="s" direction="in"/>
|
||||
</method>
|
||||
<method name="changePassword">
|
||||
<arg name="wallet" type="s" direction="in"/>
|
||||
<arg name="wId" type="x" direction="in"/>
|
||||
<arg name="appid" type="s" direction="in"/>
|
||||
</method>
|
||||
<method name="wallets">
|
||||
<arg type="as" direction="out"/>
|
||||
</method>
|
||||
<method name="folderList">
|
||||
<arg type="as" direction="out"/>
|
||||
<arg name="handle" type="i" direction="in"/>
|
||||
<arg name="appid" type="s" direction="in"/>
|
||||
</method>
|
||||
<method name="hasFolder">
|
||||
<arg type="b" direction="out"/>
|
||||
<arg name="handle" type="i" direction="in"/>
|
||||
<arg name="folder" type="s" direction="in"/>
|
||||
<arg name="appid" type="s" direction="in"/>
|
||||
</method>
|
||||
<method name="createFolder">
|
||||
<arg type="b" direction="out"/>
|
||||
<arg name="handle" type="i" direction="in"/>
|
||||
<arg name="folder" type="s" direction="in"/>
|
||||
<arg name="appid" type="s" direction="in"/>
|
||||
</method>
|
||||
<method name="removeFolder">
|
||||
<arg type="b" direction="out"/>
|
||||
<arg name="handle" type="i" direction="in"/>
|
||||
<arg name="folder" type="s" direction="in"/>
|
||||
<arg name="appid" type="s" direction="in"/>
|
||||
</method>
|
||||
<method name="entryList">
|
||||
<arg type="as" direction="out"/>
|
||||
<arg name="handle" type="i" direction="in"/>
|
||||
<arg name="folder" type="s" direction="in"/>
|
||||
<arg name="appid" type="s" direction="in"/>
|
||||
</method>
|
||||
<method name="readEntry">
|
||||
<arg type="ay" direction="out"/>
|
||||
<arg name="handle" type="i" direction="in"/>
|
||||
<arg name="folder" type="s" direction="in"/>
|
||||
<arg name="key" type="s" direction="in"/>
|
||||
<arg name="appid" type="s" direction="in"/>
|
||||
</method>
|
||||
<method name="readMap">
|
||||
<arg type="ay" direction="out"/>
|
||||
<arg name="handle" type="i" direction="in"/>
|
||||
<arg name="folder" type="s" direction="in"/>
|
||||
<arg name="key" type="s" direction="in"/>
|
||||
<arg name="appid" type="s" direction="in"/>
|
||||
</method>
|
||||
<method name="readPassword">
|
||||
<arg type="s" direction="out"/>
|
||||
<arg name="handle" type="i" direction="in"/>
|
||||
<arg name="folder" type="s" direction="in"/>
|
||||
<arg name="key" type="s" direction="in"/>
|
||||
<arg name="appid" type="s" direction="in"/>
|
||||
</method>
|
||||
<method name="entriesList">
|
||||
<arg type="a{sv}" direction="out"/>
|
||||
<annotation name="org.qtproject.QtDBus.QtTypeName.Out0" value="QVariantMap"/>
|
||||
<arg name="handle" type="i" direction="in"/>
|
||||
<arg name="folder" type="s" direction="in"/>
|
||||
<arg name="appid" type="s" direction="in"/>
|
||||
</method>
|
||||
<method name="mapList">
|
||||
<arg type="a{sv}" direction="out"/>
|
||||
<annotation name="org.qtproject.QtDBus.QtTypeName.Out0" value="QVariantMap"/>
|
||||
<arg name="handle" type="i" direction="in"/>
|
||||
<arg name="folder" type="s" direction="in"/>
|
||||
<arg name="appid" type="s" direction="in"/>
|
||||
</method>
|
||||
<method name="passwordList">
|
||||
<arg type="a{sv}" direction="out"/>
|
||||
<annotation name="org.qtproject.QtDBus.QtTypeName.Out0" value="QVariantMap"/>
|
||||
<arg name="handle" type="i" direction="in"/>
|
||||
<arg name="folder" type="s" direction="in"/>
|
||||
<arg name="appid" type="s" direction="in"/>
|
||||
</method>
|
||||
<method name="renameEntry">
|
||||
<arg type="i" direction="out"/>
|
||||
<arg name="handle" type="i" direction="in"/>
|
||||
<arg name="folder" type="s" direction="in"/>
|
||||
<arg name="oldName" type="s" direction="in"/>
|
||||
<arg name="newName" type="s" direction="in"/>
|
||||
<arg name="appid" type="s" direction="in"/>
|
||||
</method>
|
||||
<method name="writeEntry">
|
||||
<arg type="i" direction="out"/>
|
||||
<arg name="handle" type="i" direction="in"/>
|
||||
<arg name="folder" type="s" direction="in"/>
|
||||
<arg name="key" type="s" direction="in"/>
|
||||
<arg name="value" type="ay" direction="in"/>
|
||||
<arg name="entryType" type="i" direction="in"/>
|
||||
<arg name="appid" type="s" direction="in"/>
|
||||
</method>
|
||||
<method name="writeEntry">
|
||||
<arg type="i" direction="out"/>
|
||||
<arg name="handle" type="i" direction="in"/>
|
||||
<arg name="folder" type="s" direction="in"/>
|
||||
<arg name="key" type="s" direction="in"/>
|
||||
<arg name="value" type="ay" direction="in"/>
|
||||
<arg name="appid" type="s" direction="in"/>
|
||||
</method>
|
||||
<method name="writeMap">
|
||||
<arg type="i" direction="out"/>
|
||||
<arg name="handle" type="i" direction="in"/>
|
||||
<arg name="folder" type="s" direction="in"/>
|
||||
<arg name="key" type="s" direction="in"/>
|
||||
<arg name="value" type="ay" direction="in"/>
|
||||
<arg name="appid" type="s" direction="in"/>
|
||||
</method>
|
||||
<method name="writePassword">
|
||||
<arg type="i" direction="out"/>
|
||||
<arg name="handle" type="i" direction="in"/>
|
||||
<arg name="folder" type="s" direction="in"/>
|
||||
<arg name="key" type="s" direction="in"/>
|
||||
<arg name="value" type="s" direction="in"/>
|
||||
<arg name="appid" type="s" direction="in"/>
|
||||
</method>
|
||||
<method name="hasEntry">
|
||||
<arg type="b" direction="out"/>
|
||||
<arg name="handle" type="i" direction="in"/>
|
||||
<arg name="folder" type="s" direction="in"/>
|
||||
<arg name="key" type="s" direction="in"/>
|
||||
<arg name="appid" type="s" direction="in"/>
|
||||
</method>
|
||||
<method name="entryType">
|
||||
<arg type="i" direction="out"/>
|
||||
<arg name="handle" type="i" direction="in"/>
|
||||
<arg name="folder" type="s" direction="in"/>
|
||||
<arg name="key" type="s" direction="in"/>
|
||||
<arg name="appid" type="s" direction="in"/>
|
||||
</method>
|
||||
<method name="removeEntry">
|
||||
<arg type="i" direction="out"/>
|
||||
<arg name="handle" type="i" direction="in"/>
|
||||
<arg name="folder" type="s" direction="in"/>
|
||||
<arg name="key" type="s" direction="in"/>
|
||||
<arg name="appid" type="s" direction="in"/>
|
||||
</method>
|
||||
<method name="disconnectApplication">
|
||||
<arg type="b" direction="out"/>
|
||||
<arg name="wallet" type="s" direction="in"/>
|
||||
<arg name="application" type="s" direction="in"/>
|
||||
</method>
|
||||
<method name="reconfigure">
|
||||
</method>
|
||||
<method name="folderDoesNotExist">
|
||||
<arg type="b" direction="out"/>
|
||||
<arg name="wallet" type="s" direction="in"/>
|
||||
<arg name="folder" type="s" direction="in"/>
|
||||
</method>
|
||||
<method name="keyDoesNotExist">
|
||||
<arg type="b" direction="out"/>
|
||||
<arg name="wallet" type="s" direction="in"/>
|
||||
<arg name="folder" type="s" direction="in"/>
|
||||
<arg name="key" type="s" direction="in"/>
|
||||
</method>
|
||||
<method name="closeAllWallets">
|
||||
</method>
|
||||
<method name="networkWallet">
|
||||
<arg type="s" direction="out"/>
|
||||
</method>
|
||||
<method name="localWallet">
|
||||
<arg type="s" direction="out"/>
|
||||
</method>
|
||||
<method name="pamOpen">
|
||||
<arg name="wallet" type="s" direction="in"/>
|
||||
<arg name="passwordHash" type="ay" direction="in"/>
|
||||
<arg name="sessionTimeout" type="i" direction="in"/>
|
||||
<annotation name="org.freedesktop.DBus.Method.NoReply" value="true"/>
|
||||
</method>
|
||||
</interface>
|
||||
</node>
|
||||
@@ -0,0 +1,305 @@
|
||||
<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN" "http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
|
||||
<node>
|
||||
<interface name="org.kde.KWallet">
|
||||
<signal name="walletListDirty">
|
||||
</signal>
|
||||
<signal name="walletCreated">
|
||||
<arg name="wallet" type="s" direction="out"/>
|
||||
</signal>
|
||||
<signal name="walletOpened">
|
||||
<arg name="wallet" type="s" direction="out"/>
|
||||
</signal>
|
||||
<signal name="walletAsyncOpened">
|
||||
<arg name="tId" type="i" direction="out"/>
|
||||
<arg name="handle" type="i" direction="out"/>
|
||||
</signal>
|
||||
<signal name="walletDeleted">
|
||||
<arg name="wallet" type="s" direction="out"/>
|
||||
</signal>
|
||||
<signal name="walletClosed">
|
||||
<arg name="wallet" type="s" direction="out"/>
|
||||
</signal>
|
||||
<!-- Deprecated, use walletClosedId -->
|
||||
<signal name="walletClosed">
|
||||
<arg name="handle" type="i" direction="out"/>
|
||||
<annotation name="org.freedesktop.DBus.Deprecated" value="true"/>
|
||||
</signal>
|
||||
<signal name="walletClosedId">
|
||||
<arg name="handle" type="i" direction="out"/>
|
||||
</signal>
|
||||
<signal name="allWalletsClosed">
|
||||
</signal>
|
||||
<signal name="folderListUpdated">
|
||||
<arg name="wallet" type="s" direction="out"/>
|
||||
</signal>
|
||||
<signal name="folderUpdated">
|
||||
<arg type="s" direction="out"/>
|
||||
<arg type="s" direction="out"/>
|
||||
</signal>
|
||||
<signal name="applicationDisconnected">
|
||||
<arg name="wallet" type="s" direction="out"/>
|
||||
<arg name="application" type="s" direction="out"/>
|
||||
</signal>
|
||||
<method name="isEnabled">
|
||||
<arg type="b" direction="out"/>
|
||||
</method>
|
||||
<method name="open">
|
||||
<arg type="i" direction="out"/>
|
||||
<arg name="wallet" type="s" direction="in"/>
|
||||
<arg name="wId" type="x" direction="in"/>
|
||||
<arg name="appid" type="s" direction="in"/>
|
||||
</method>
|
||||
<method name="openPath">
|
||||
<arg type="i" direction="out"/>
|
||||
<arg name="path" type="s" direction="in"/>
|
||||
<arg name="wId" type="x" direction="in"/>
|
||||
<arg name="appid" type="s" direction="in"/>
|
||||
</method>
|
||||
<method name="openAsync">
|
||||
<arg type="i" direction="out"/>
|
||||
<arg name="wallet" type="s" direction="in"/>
|
||||
<arg name="wId" type="x" direction="in"/>
|
||||
<arg name="appid" type="s" direction="in"/>
|
||||
<arg name="handleSession" type="b" direction="in"/>
|
||||
</method>
|
||||
<method name="openPathAsync">
|
||||
<arg type="i" direction="out"/>
|
||||
<arg name="path" type="s" direction="in"/>
|
||||
<arg name="wId" type="x" direction="in"/>
|
||||
<arg name="appid" type="s" direction="in"/>
|
||||
<arg name="handleSession" type="b" direction="in"/>
|
||||
</method>
|
||||
<method name="close">
|
||||
<arg type="i" direction="out"/>
|
||||
<arg name="wallet" type="s" direction="in"/>
|
||||
<arg name="force" type="b" direction="in"/>
|
||||
</method>
|
||||
<method name="close">
|
||||
<arg type="i" direction="out"/>
|
||||
<arg name="handle" type="i" direction="in"/>
|
||||
<arg name="force" type="b" direction="in"/>
|
||||
<arg name="appid" type="s" direction="in"/>
|
||||
</method>
|
||||
<method name="sync">
|
||||
<arg name="handle" type="i" direction="in"/>
|
||||
<arg name="appid" type="s" direction="in"/>
|
||||
<annotation name="org.freedesktop.DBus.Method.NoReply" value="true"/>
|
||||
</method>
|
||||
<method name="deleteWallet">
|
||||
<arg type="i" direction="out"/>
|
||||
<arg name="wallet" type="s" direction="in"/>
|
||||
</method>
|
||||
<method name="isOpen">
|
||||
<arg type="b" direction="out"/>
|
||||
<arg name="wallet" type="s" direction="in"/>
|
||||
</method>
|
||||
<method name="isOpen">
|
||||
<arg type="b" direction="out"/>
|
||||
<arg name="handle" type="i" direction="in"/>
|
||||
</method>
|
||||
<method name="users">
|
||||
<arg type="as" direction="out"/>
|
||||
<arg name="wallet" type="s" direction="in"/>
|
||||
</method>
|
||||
<method name="changePassword">
|
||||
<arg name="wallet" type="s" direction="in"/>
|
||||
<arg name="wId" type="x" direction="in"/>
|
||||
<arg name="appid" type="s" direction="in"/>
|
||||
</method>
|
||||
<method name="wallets">
|
||||
<arg type="as" direction="out"/>
|
||||
</method>
|
||||
<method name="folderList">
|
||||
<arg type="as" direction="out"/>
|
||||
<arg name="handle" type="i" direction="in"/>
|
||||
<arg name="appid" type="s" direction="in"/>
|
||||
</method>
|
||||
<method name="hasFolder">
|
||||
<arg type="b" direction="out"/>
|
||||
<arg name="handle" type="i" direction="in"/>
|
||||
<arg name="folder" type="s" direction="in"/>
|
||||
<arg name="appid" type="s" direction="in"/>
|
||||
</method>
|
||||
<method name="createFolder">
|
||||
<arg type="b" direction="out"/>
|
||||
<arg name="handle" type="i" direction="in"/>
|
||||
<arg name="folder" type="s" direction="in"/>
|
||||
<arg name="appid" type="s" direction="in"/>
|
||||
</method>
|
||||
<method name="removeFolder">
|
||||
<arg type="b" direction="out"/>
|
||||
<arg name="handle" type="i" direction="in"/>
|
||||
<arg name="folder" type="s" direction="in"/>
|
||||
<arg name="appid" type="s" direction="in"/>
|
||||
</method>
|
||||
<method name="entryList">
|
||||
<arg type="as" direction="out"/>
|
||||
<arg name="handle" type="i" direction="in"/>
|
||||
<arg name="folder" type="s" direction="in"/>
|
||||
<arg name="appid" type="s" direction="in"/>
|
||||
</method>
|
||||
<method name="readEntry">
|
||||
<arg type="ay" direction="out"/>
|
||||
<arg name="handle" type="i" direction="in"/>
|
||||
<arg name="folder" type="s" direction="in"/>
|
||||
<arg name="key" type="s" direction="in"/>
|
||||
<arg name="appid" type="s" direction="in"/>
|
||||
</method>
|
||||
<method name="readMap">
|
||||
<arg type="ay" direction="out"/>
|
||||
<arg name="handle" type="i" direction="in"/>
|
||||
<arg name="folder" type="s" direction="in"/>
|
||||
<arg name="key" type="s" direction="in"/>
|
||||
<arg name="appid" type="s" direction="in"/>
|
||||
</method>
|
||||
<method name="readPassword">
|
||||
<arg type="s" direction="out"/>
|
||||
<arg name="handle" type="i" direction="in"/>
|
||||
<arg name="folder" type="s" direction="in"/>
|
||||
<arg name="key" type="s" direction="in"/>
|
||||
<arg name="appid" type="s" direction="in"/>
|
||||
</method>
|
||||
<method name="readEntryList">
|
||||
<arg type="a{sv}" direction="out"/>
|
||||
<annotation name="org.qtproject.QtDBus.QtTypeName.Out0" value="QVariantMap"/>
|
||||
<arg name="handle" type="i" direction="in"/>
|
||||
<arg name="folder" type="s" direction="in"/>
|
||||
<arg name="key" type="s" direction="in"/>
|
||||
<arg name="appid" type="s" direction="in"/>
|
||||
<annotation name="org.freedesktop.DBus.Deprecated" value="true"/>
|
||||
</method>
|
||||
<method name="entriesList">
|
||||
<arg type="a{sv}" direction="out"/>
|
||||
<annotation name="org.qtproject.QtDBus.QtTypeName.Out0" value="QVariantMap"/>
|
||||
<arg name="handle" type="i" direction="in"/>
|
||||
<arg name="folder" type="s" direction="in"/>
|
||||
<arg name="appid" type="s" direction="in"/>
|
||||
</method>
|
||||
<method name="readMapList">
|
||||
<arg type="a{sv}" direction="out"/>
|
||||
<annotation name="org.qtproject.QtDBus.QtTypeName.Out0" value="QVariantMap"/>
|
||||
<arg name="handle" type="i" direction="in"/>
|
||||
<arg name="folder" type="s" direction="in"/>
|
||||
<arg name="key" type="s" direction="in"/>
|
||||
<arg name="appid" type="s" direction="in"/>
|
||||
<annotation name="org.freedesktop.DBus.Deprecated" value="true"/>
|
||||
</method>
|
||||
<method name="mapList">
|
||||
<arg type="a{sv}" direction="out"/>
|
||||
<annotation name="org.qtproject.QtDBus.QtTypeName.Out0" value="QVariantMap"/>
|
||||
<arg name="handle" type="i" direction="in"/>
|
||||
<arg name="folder" type="s" direction="in"/>
|
||||
<arg name="appid" type="s" direction="in"/>
|
||||
</method>
|
||||
<method name="readPasswordList">
|
||||
<arg type="a{sv}" direction="out"/>
|
||||
<annotation name="org.qtproject.QtDBus.QtTypeName.Out0" value="QVariantMap"/>
|
||||
<arg name="handle" type="i" direction="in"/>
|
||||
<arg name="folder" type="s" direction="in"/>
|
||||
<arg name="key" type="s" direction="in"/>
|
||||
<arg name="appid" type="s" direction="in"/>
|
||||
<annotation name="org.freedesktop.DBus.Deprecated" value="true"/>
|
||||
</method>
|
||||
<method name="passwordList">
|
||||
<arg type="a{sv}" direction="out"/>
|
||||
<annotation name="org.qtproject.QtDBus.QtTypeName.Out0" value="QVariantMap"/>
|
||||
<arg name="handle" type="i" direction="in"/>
|
||||
<arg name="folder" type="s" direction="in"/>
|
||||
<arg name="appid" type="s" direction="in"/>
|
||||
</method>
|
||||
<method name="renameEntry">
|
||||
<arg type="i" direction="out"/>
|
||||
<arg name="handle" type="i" direction="in"/>
|
||||
<arg name="folder" type="s" direction="in"/>
|
||||
<arg name="oldName" type="s" direction="in"/>
|
||||
<arg name="newName" type="s" direction="in"/>
|
||||
<arg name="appid" type="s" direction="in"/>
|
||||
</method>
|
||||
<method name="writeEntry">
|
||||
<arg type="i" direction="out"/>
|
||||
<arg name="handle" type="i" direction="in"/>
|
||||
<arg name="folder" type="s" direction="in"/>
|
||||
<arg name="key" type="s" direction="in"/>
|
||||
<arg name="value" type="ay" direction="in"/>
|
||||
<arg name="entryType" type="i" direction="in"/>
|
||||
<arg name="appid" type="s" direction="in"/>
|
||||
</method>
|
||||
<method name="writeEntry">
|
||||
<arg type="i" direction="out"/>
|
||||
<arg name="handle" type="i" direction="in"/>
|
||||
<arg name="folder" type="s" direction="in"/>
|
||||
<arg name="key" type="s" direction="in"/>
|
||||
<arg name="value" type="ay" direction="in"/>
|
||||
<arg name="appid" type="s" direction="in"/>
|
||||
</method>
|
||||
<method name="writeMap">
|
||||
<arg type="i" direction="out"/>
|
||||
<arg name="handle" type="i" direction="in"/>
|
||||
<arg name="folder" type="s" direction="in"/>
|
||||
<arg name="key" type="s" direction="in"/>
|
||||
<arg name="value" type="ay" direction="in"/>
|
||||
<arg name="appid" type="s" direction="in"/>
|
||||
</method>
|
||||
<method name="writePassword">
|
||||
<arg type="i" direction="out"/>
|
||||
<arg name="handle" type="i" direction="in"/>
|
||||
<arg name="folder" type="s" direction="in"/>
|
||||
<arg name="key" type="s" direction="in"/>
|
||||
<arg name="value" type="s" direction="in"/>
|
||||
<arg name="appid" type="s" direction="in"/>
|
||||
</method>
|
||||
<method name="hasEntry">
|
||||
<arg type="b" direction="out"/>
|
||||
<arg name="handle" type="i" direction="in"/>
|
||||
<arg name="folder" type="s" direction="in"/>
|
||||
<arg name="key" type="s" direction="in"/>
|
||||
<arg name="appid" type="s" direction="in"/>
|
||||
</method>
|
||||
<method name="entryType">
|
||||
<arg type="i" direction="out"/>
|
||||
<arg name="handle" type="i" direction="in"/>
|
||||
<arg name="folder" type="s" direction="in"/>
|
||||
<arg name="key" type="s" direction="in"/>
|
||||
<arg name="appid" type="s" direction="in"/>
|
||||
</method>
|
||||
<method name="removeEntry">
|
||||
<arg type="i" direction="out"/>
|
||||
<arg name="handle" type="i" direction="in"/>
|
||||
<arg name="folder" type="s" direction="in"/>
|
||||
<arg name="key" type="s" direction="in"/>
|
||||
<arg name="appid" type="s" direction="in"/>
|
||||
</method>
|
||||
<method name="disconnectApplication">
|
||||
<arg type="b" direction="out"/>
|
||||
<arg name="wallet" type="s" direction="in"/>
|
||||
<arg name="application" type="s" direction="in"/>
|
||||
</method>
|
||||
<method name="reconfigure">
|
||||
</method>
|
||||
<method name="folderDoesNotExist">
|
||||
<arg type="b" direction="out"/>
|
||||
<arg name="wallet" type="s" direction="in"/>
|
||||
<arg name="folder" type="s" direction="in"/>
|
||||
</method>
|
||||
<method name="keyDoesNotExist">
|
||||
<arg type="b" direction="out"/>
|
||||
<arg name="wallet" type="s" direction="in"/>
|
||||
<arg name="folder" type="s" direction="in"/>
|
||||
<arg name="key" type="s" direction="in"/>
|
||||
</method>
|
||||
<method name="closeAllWallets">
|
||||
</method>
|
||||
<method name="networkWallet">
|
||||
<arg type="s" direction="out"/>
|
||||
</method>
|
||||
<method name="localWallet">
|
||||
<arg type="s" direction="out"/>
|
||||
</method>
|
||||
<method name="pamOpen">
|
||||
<arg name="wallet" type="s" direction="in"/>
|
||||
<arg name="passwordHash" type="ay" direction="in"/>
|
||||
<arg name="sessionTimeout" type="i" direction="in"/>
|
||||
<annotation name="org.freedesktop.DBus.Method.NoReply" value="true"/>
|
||||
</method>
|
||||
</interface>
|
||||
</node>
|
||||
@@ -0,0 +1,7 @@
|
||||
if(BUILD_KWALLETD)
|
||||
add_subdirectory(kwalletd)
|
||||
endif()
|
||||
|
||||
if(BUILD_KWALLET_QUERY)
|
||||
add_subdirectory(kwallet-query)
|
||||
endif()
|
||||
@@ -0,0 +1,3 @@
|
||||
project(kwallet-dmenu)
|
||||
|
||||
add_subdirectory(src)
|
||||
@@ -0,0 +1,19 @@
|
||||
remove_definitions(-DQT_NO_CAST_FROM_ASCII)
|
||||
|
||||
add_executable(kwallet-query)
|
||||
|
||||
target_sources(kwallet-query PRIVATE
|
||||
main.cpp
|
||||
querydriver.cpp
|
||||
)
|
||||
|
||||
|
||||
TARGET_LINK_LIBRARIES(kwallet-query
|
||||
KF6Wallet
|
||||
KF6::CoreAddons
|
||||
KF6::I18n
|
||||
Qt6::Widgets
|
||||
)
|
||||
|
||||
ecm_mark_nongui_executable(kwallet-query)
|
||||
install( TARGETS kwallet-query DESTINATION ${KDE_INSTALL_TARGETS_DEFAULT_ARGS})
|
||||
+2
@@ -0,0 +1,2 @@
|
||||
#!/bin/sh
|
||||
$XGETTEXT `find . -name "*.cpp" -o -name "*.h"` -o $podir/kwallet6-query.pot
|
||||
@@ -0,0 +1,85 @@
|
||||
/*
|
||||
This file is part of the KDE
|
||||
SPDX-FileCopyrightText: 2015 Valentin Rusu <kde@rusu.info>
|
||||
|
||||
SPDX-License-Identifier: LGPL-2.0-or-later
|
||||
*/
|
||||
|
||||
#include <QCommandLineParser>
|
||||
#include <QStringList>
|
||||
#include <iostream>
|
||||
|
||||
#include <KAboutData>
|
||||
#include <KLocalizedString>
|
||||
|
||||
#include "querydriver.h"
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
KLocalizedString::setApplicationDomain("kwallet6-query");
|
||||
|
||||
QueryDriver app(argc, argv);
|
||||
|
||||
KAboutData aboutData(QStringLiteral("kwallet-query"),
|
||||
i18n("KWallet query interface"),
|
||||
QStringLiteral("0.1"),
|
||||
i18n("KWallet query interface"),
|
||||
KAboutLicense::GPL,
|
||||
i18n("(c) 2015, The KDE Developers"));
|
||||
|
||||
QCommandLineParser cmdParser;
|
||||
// clang-format off
|
||||
QCommandLineOption verboseOption(QStringList() << QStringLiteral("v") << QStringLiteral("verbose"), i18n("verbose output"));
|
||||
QCommandLineOption listOption(QStringList() << QStringLiteral("l") << QStringLiteral("list-entries"), i18n("list password entries"));
|
||||
QCommandLineOption readOption(QStringList() << QStringLiteral("r") << QStringLiteral("read-password"), i18n("reads the secrets from the given <entry>"), i18n("Entry"));
|
||||
QCommandLineOption writeOption(QStringList() << QStringLiteral("w") << QStringLiteral("write-password"), i18n("write secrets to the given <entry>. The values are read from the standard input. IMPORTANT: previous wallet entry value will be overwritten!"), i18n("Entry"));
|
||||
QCommandLineOption folderOption(QStringList() << QStringLiteral("f") << QStringLiteral("folder"), i18n("specify the folder in the wallet <folder>"), i18n("Folder"));
|
||||
// clang-format on
|
||||
|
||||
cmdParser.addHelpOption();
|
||||
cmdParser.addPositionalArgument("wallet", i18n("The wallet to query"));
|
||||
cmdParser.addOption(listOption);
|
||||
cmdParser.addOption(readOption);
|
||||
cmdParser.addOption(writeOption);
|
||||
cmdParser.addOption(folderOption);
|
||||
cmdParser.addOption(verboseOption);
|
||||
cmdParser.process(app);
|
||||
|
||||
const QStringList args = cmdParser.positionalArguments();
|
||||
if (args.empty()) {
|
||||
std::cout << i18n("Missing argument").toStdString() << std::endl;
|
||||
return 1;
|
||||
}
|
||||
if (args.count() > 1) {
|
||||
std::cout << i18n("Too many arguments given").toStdString() << std::endl;
|
||||
return 1;
|
||||
}
|
||||
app.setWalletName(args.first());
|
||||
if (cmdParser.isSet(listOption) && cmdParser.isSet(readOption) && cmdParser.isSet(writeOption)) {
|
||||
std::cout << i18n("Only one mode (list, read or write) can be set. Aborting").toStdString() << std::endl;
|
||||
return 1;
|
||||
}
|
||||
if (!cmdParser.isSet(listOption) && !cmdParser.isSet(readOption) && !cmdParser.isSet(writeOption)) {
|
||||
std::cout << i18n("Please specify the mode (list or read).").toStdString() << std::endl;
|
||||
return 1;
|
||||
}
|
||||
if (cmdParser.isSet(listOption)) {
|
||||
app.setMode(QueryDriver::List);
|
||||
}
|
||||
if (cmdParser.isSet(readOption)) {
|
||||
app.setEntryName(cmdParser.value(readOption));
|
||||
app.setMode(QueryDriver::Read);
|
||||
}
|
||||
if (cmdParser.isSet(writeOption)) {
|
||||
app.setEntryName(cmdParser.value(writeOption));
|
||||
app.setMode(QueryDriver::Write);
|
||||
}
|
||||
if (cmdParser.isSet(folderOption)) {
|
||||
app.setEntryFolder(cmdParser.value(folderOption));
|
||||
}
|
||||
if (cmdParser.isSet(verboseOption)) {
|
||||
app.setVerbose();
|
||||
}
|
||||
|
||||
return app.exec();
|
||||
}
|
||||
@@ -0,0 +1,220 @@
|
||||
/*
|
||||
This file is part of the KDE
|
||||
SPDX-FileCopyrightText: 2015 Valentin Rusu <kde@rusu.info>
|
||||
|
||||
SPDX-License-Identifier: LGPL-2.0-or-later
|
||||
*/
|
||||
|
||||
#include "querydriver.h"
|
||||
|
||||
#include <iostream>
|
||||
|
||||
#include <QDebug>
|
||||
#include <QJsonDocument>
|
||||
#include <QJsonObject>
|
||||
#include <QScreen>
|
||||
#include <QTimer>
|
||||
|
||||
#include <KLocalizedString>
|
||||
|
||||
QueryDriver::QueryDriver(int &argc, char *argv[])
|
||||
: QApplication(argc, argv)
|
||||
, entryFolder(QStringLiteral("Passwords"))
|
||||
{
|
||||
QTimerEvent *timerEvent = new QTimerEvent(100);
|
||||
postEvent(this, timerEvent);
|
||||
}
|
||||
|
||||
QueryDriver::~QueryDriver()
|
||||
{
|
||||
// NOTE: no need to close the wallet, let's leave it open for next time
|
||||
// we'll query it preventing too many annoying password prompts
|
||||
// if (theWallet != NULL && theWallet->isOpen()) {
|
||||
// Wallet::closeWallet(walletName, false);
|
||||
// }
|
||||
delete theWallet;
|
||||
}
|
||||
void QueryDriver::timerEvent(QTimerEvent *event)
|
||||
{
|
||||
QApplication::timerEvent(event);
|
||||
if (verbose) {
|
||||
qDebug() << "timer event";
|
||||
}
|
||||
|
||||
auto wl = Wallet::walletList();
|
||||
if (wl.indexOf(walletName) == -1) {
|
||||
std::cout << i18n("Wallet %1 not found", walletName).toUtf8().constData() << std::endl;
|
||||
exit(1);
|
||||
} else {
|
||||
if (verbose) {
|
||||
qDebug() << "standby opening wallet " << walletName;
|
||||
}
|
||||
|
||||
theWallet = Wallet::openWallet(walletName, 0, Wallet::Asynchronous);
|
||||
connect(theWallet, &KWallet::Wallet::walletOpened, this, &QueryDriver::walletOpened);
|
||||
}
|
||||
}
|
||||
|
||||
void QueryDriver::setWalletName(const QString &name)
|
||||
{
|
||||
walletName = name;
|
||||
}
|
||||
|
||||
void QueryDriver::setMode(Mode mode)
|
||||
{
|
||||
this->mode = mode;
|
||||
}
|
||||
void QueryDriver::walletOpened(bool success)
|
||||
{
|
||||
if (!success) {
|
||||
std::cout << i18n("Failed to open wallet %1. Aborting", walletName).toUtf8().constData() << std::endl;
|
||||
exit(2);
|
||||
} else {
|
||||
switch (mode) {
|
||||
case List:
|
||||
readEntries();
|
||||
break;
|
||||
case Read:
|
||||
readValue();
|
||||
break;
|
||||
case Write:
|
||||
writeValue();
|
||||
break;
|
||||
default:
|
||||
Q_ASSERT(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void QueryDriver::readEntries()
|
||||
{
|
||||
theWallet = Wallet::openWallet(walletName, 0);
|
||||
if (entryFolder.isEmpty()) {
|
||||
const auto fl = theWallet->folderList();
|
||||
for (auto &f : fl) {
|
||||
std::cout << f.toUtf8().constData() << std::endl;
|
||||
Q_ASSERT(theWallet->setFolder(f));
|
||||
const auto el = theWallet->entryList();
|
||||
for (auto &e : el) {
|
||||
std::cout << "\t" << e.toUtf8().constData() << std::endl;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (!theWallet->setFolder(entryFolder)) {
|
||||
std::cout << i18n("The folder %1 does not exist!", entryFolder).toUtf8().constData() << std::endl;
|
||||
exit(4);
|
||||
return;
|
||||
}
|
||||
const auto el = theWallet->entryList();
|
||||
for (auto &e : el) {
|
||||
std::cout << e.toUtf8().constData() << std::endl;
|
||||
}
|
||||
}
|
||||
quit();
|
||||
}
|
||||
|
||||
void QueryDriver::readValue()
|
||||
{
|
||||
if (verbose) {
|
||||
qDebug() << "reading" << entryName << "from" << entryFolder << "from" << walletName;
|
||||
}
|
||||
if (!theWallet->setFolder(entryFolder)) {
|
||||
std::cout << i18n("The folder %1 does not exist!", entryFolder).toUtf8().constData() << std::endl;
|
||||
exit(4);
|
||||
return;
|
||||
}
|
||||
Wallet::EntryType kind = theWallet->entryType(entryName);
|
||||
if (kind == Wallet::Password) {
|
||||
readPasswordValue();
|
||||
} else if (kind == Wallet::Map) {
|
||||
readMapValue();
|
||||
} else {
|
||||
std::cout << i18n("Failed to read entry %1 value from the %2 wallet.", entryName, walletName).toUtf8().constData() << std::endl;
|
||||
exit(4);
|
||||
}
|
||||
}
|
||||
|
||||
void QueryDriver::readMapValue()
|
||||
{
|
||||
QMap<QString, QString> map;
|
||||
int rc = theWallet->readMap(entryName, map);
|
||||
if (rc != 0) {
|
||||
std::cout << i18n("Failed to read entry %1 value from the %2 wallet", entryName, walletName).toUtf8().constData() << std::endl;
|
||||
exit(4);
|
||||
return;
|
||||
}
|
||||
QJsonObject json;
|
||||
for (auto &e : map.keys()) {
|
||||
json.insert(e, QJsonValue::fromVariant(QVariant(map.value(e))));
|
||||
}
|
||||
std::cout << QJsonDocument(json).toJson().constData() << std::endl;
|
||||
quit();
|
||||
}
|
||||
|
||||
void QueryDriver::readPasswordValue()
|
||||
{
|
||||
QString entryValue;
|
||||
int rc = theWallet->readPassword(entryName, entryValue);
|
||||
if (rc != 0) {
|
||||
std::cout << i18n("Failed to read entry %1 value from the %2 wallet", entryName, walletName).toUtf8().constData() << std::endl;
|
||||
exit(4);
|
||||
return;
|
||||
}
|
||||
const QStringList el = entryValue.split(QStringLiteral("\n"), Qt::SkipEmptyParts);
|
||||
for (auto &e : el) {
|
||||
std::cout << e.toUtf8().constData() << std::endl;
|
||||
}
|
||||
quit();
|
||||
}
|
||||
|
||||
void QueryDriver::writeValue()
|
||||
{
|
||||
if (verbose) {
|
||||
qDebug() << "writing" << entryName << "to" << entryFolder << "to" << walletName;
|
||||
}
|
||||
theWallet->setFolder(entryFolder);
|
||||
|
||||
QString passwordContents;
|
||||
for (std::string line; std::getline(std::cin, line);) {
|
||||
if (!passwordContents.isEmpty()) {
|
||||
passwordContents += '\n';
|
||||
}
|
||||
passwordContents += QString::fromStdString(line);
|
||||
if (!std::cin) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
Wallet::EntryType kind = theWallet->entryType(entryName);
|
||||
if (kind == Wallet::Password) {
|
||||
if (verbose) {
|
||||
qDebug() << "about to write" << passwordContents;
|
||||
}
|
||||
int rc = theWallet->writePassword(entryName, passwordContents);
|
||||
if (rc != 0) {
|
||||
std::cout << i18n("Failed to write entry %1 value to %2 wallet", entryName, walletName).toUtf8().constData() << std::endl;
|
||||
exit(4);
|
||||
return;
|
||||
}
|
||||
} else if (kind == Wallet::Map) {
|
||||
const QJsonDocument json = QJsonDocument::fromJson(passwordContents.toLatin1());
|
||||
if (!json.isNull()) {
|
||||
QJsonObject values = json.object();
|
||||
QMap<QString, QString> map;
|
||||
for (auto &e : values.keys()) {
|
||||
map.insert(e, values.value(e).toString());
|
||||
}
|
||||
if (verbose) {
|
||||
qDebug() << "about to write" << map;
|
||||
}
|
||||
int rc = theWallet->writeMap(entryName, map);
|
||||
if (rc != 0) {
|
||||
std::cout << i18n("Failed to write entry %1 value to %2 wallet", entryName, walletName).toUtf8().constData() << std::endl;
|
||||
exit(4);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
quit();
|
||||
}
|
||||
|
||||
#include "moc_querydriver.cpp"
|
||||
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
This file is part of the KDE
|
||||
SPDX-FileCopyrightText: 2015 Valentin Rusu <kde@rusu.info>
|
||||
|
||||
SPDX-License-Identifier: LGPL-2.0-or-later
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QApplication>
|
||||
|
||||
#include <KWallet>
|
||||
|
||||
using namespace KWallet;
|
||||
|
||||
class QueryDriver : public QApplication
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
enum Mode { List, Read, Write };
|
||||
QueryDriver(int &argc, char *argv[]);
|
||||
~QueryDriver() override;
|
||||
|
||||
void setWalletName(const QString &walletName);
|
||||
void setMode(Mode mode);
|
||||
void setVerbose()
|
||||
{
|
||||
verbose = true;
|
||||
}
|
||||
void setEntryName(const QString &entryName)
|
||||
{
|
||||
this->entryName = entryName;
|
||||
}
|
||||
void setEntryFolder(const QString &entryFolder)
|
||||
{
|
||||
this->entryFolder = entryFolder;
|
||||
}
|
||||
|
||||
private:
|
||||
void timerEvent(QTimerEvent *event) override;
|
||||
void readEntries();
|
||||
void readValue();
|
||||
void readMapValue();
|
||||
void readPasswordValue();
|
||||
void writeValue();
|
||||
|
||||
private Q_SLOTS:
|
||||
void walletOpened(bool);
|
||||
|
||||
public:
|
||||
QString walletName;
|
||||
Wallet *theWallet = nullptr;
|
||||
Mode mode;
|
||||
bool verbose = false;
|
||||
QString entryName;
|
||||
QString entryFolder;
|
||||
};
|
||||
@@ -0,0 +1,178 @@
|
||||
configure_file(config-kwalletd.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/config-kwalletd.h )
|
||||
|
||||
include(CheckSymbolExists)
|
||||
|
||||
check_symbol_exists(explicit_bzero "string.h" KWALLETD_HAVE_EXPLICIT_BZERO)
|
||||
check_symbol_exists(RtlSecureZeroMemory "windows.h" KWALLETD_HAVE_RTLSECUREZEROMEMORY)
|
||||
|
||||
find_package(Qt6 ${REQUIRED_QT_VERSION} CONFIG REQUIRED Gui)
|
||||
|
||||
find_package(KF6ColorScheme ${KF_DEP_VERSION} REQUIRED)
|
||||
find_package(KF6Config ${KF_DEP_VERSION} REQUIRED)
|
||||
find_package(KF6CoreAddons ${KF_DEP_VERSION} REQUIRED)
|
||||
find_package(KF6DBusAddons ${KF_DEP_VERSION} REQUIRED)
|
||||
find_package(KF6Notifications ${KF_DEP_VERSION} REQUIRED)
|
||||
find_package(KF6WidgetsAddons ${KF_DEP_VERSION} REQUIRED)
|
||||
find_package(KF6WindowSystem ${KF_DEP_VERSION} REQUIRED)
|
||||
find_package(KF6Crash ${KF_DEP_VERSION} REQUIRED)
|
||||
|
||||
########### find needed packages ######
|
||||
find_package(Gpgmepp 1.7.0) # provided by GpgME
|
||||
|
||||
if (Gpgmepp_FOUND)
|
||||
message("GPG support enabled")
|
||||
add_definitions(-DHAVE_GPGMEPP)
|
||||
add_definitions(-DBOOST_NO_EXCEPTIONS)
|
||||
include_directories(${GPGME_INCLUDES})
|
||||
endif(Gpgmepp_FOUND)
|
||||
|
||||
find_package(Qca-qt6 REQUIRED 2.3.1)
|
||||
|
||||
include_directories(${CMAKE_CURRENT_BINARY_DIR})
|
||||
########### build backends #########
|
||||
add_subdirectory(backend)
|
||||
add_subdirectory(autotests)
|
||||
|
||||
########### kwalletd ###############
|
||||
|
||||
add_executable(kwalletd6)
|
||||
|
||||
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/backend)
|
||||
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/../../api/KWallet)
|
||||
include_directories(${CMAKE_CURRENT_BINARY_DIR}/../../api/KWallet)
|
||||
|
||||
remove_definitions(-DQT_NO_CAST_FROM_ASCII)
|
||||
|
||||
ecm_setup_version(${KF_VERSION} VARIABLE_PREFIX KWALLETD
|
||||
VERSION_HEADER "${CMAKE_CURRENT_BINARY_DIR}/kwalletd_version.h"
|
||||
PACKAGE_VERSION_FILE "${CMAKE_CURRENT_BINARY_DIR}/KF6WalletConfigVersion.cmake"
|
||||
SOVERSION 6)
|
||||
|
||||
target_sources(kwalletd6 PRIVATE
|
||||
main.cpp
|
||||
kbetterthankdialog.cpp
|
||||
kwalletd.cpp
|
||||
kwalletwizard.cpp
|
||||
ktimeout.cpp
|
||||
kwalletsessionstore.cpp
|
||||
kwalletfreedesktopservice.cpp
|
||||
kwalletfreedesktopsession.cpp
|
||||
kwalletfreedesktopcollection.cpp
|
||||
kwalletfreedesktopitem.cpp
|
||||
kwalletfreedesktopprompt.cpp
|
||||
kwalletfreedesktopattributes.cpp
|
||||
|
||||
kwalletportalsecrets.cpp
|
||||
)
|
||||
ecm_qt_declare_logging_category(kwalletd6
|
||||
HEADER kwalletd_debug.h
|
||||
IDENTIFIER KWALLETD_LOG
|
||||
CATEGORY_NAME kf.wallet.kwalletd
|
||||
OLD_CATEGORY_NAMES kf5.kwallet.kwalletd
|
||||
DESCRIPTION "kwalletd"
|
||||
EXPORT KWALLET
|
||||
)
|
||||
|
||||
ki18n_wrap_ui(kwalletd6
|
||||
kbetterthankdialogbase.ui
|
||||
kwalletwizardpageexplanation.ui
|
||||
kwalletwizardpageintro.ui
|
||||
kwalletwizardpageoptions.ui
|
||||
kwalletwizardpagepassword.ui
|
||||
)
|
||||
|
||||
if (Gpgmepp_FOUND)
|
||||
target_sources(kwalletd6 PRIVATE
|
||||
knewwalletdialog.cpp
|
||||
)
|
||||
ki18n_wrap_ui(kwalletd6
|
||||
kwalletwizardpagepasswordgpg.ui
|
||||
kwalletwizardpagegpgkey.ui
|
||||
knewwalletdialogintro.ui
|
||||
knewwalletdialoggpg.ui
|
||||
)
|
||||
endif(Gpgmepp_FOUND)
|
||||
|
||||
if (NOT EXCLUDE_DEPRECATED_BEFORE_AND_AT STREQUAL "CURRENT" AND
|
||||
EXCLUDE_DEPRECATED_BEFORE_AND_AT VERSION_LESS 5.72.0)
|
||||
set(kwallet_xml ${CMAKE_SOURCE_DIR}/src/api/KWallet/org.kde.KWallet.xml)
|
||||
else()
|
||||
# copy of org.kde.KWallet.xml, but with all deprecated API removed
|
||||
set(kwallet_xml ${CMAKE_SOURCE_DIR}/src/api/KWallet/org.kde.KWallet.nodeprecated.xml)
|
||||
endif()
|
||||
set(fdo_service_xml ${CMAKE_SOURCE_DIR}/src/api/KWallet/org.freedesktop.Secrets.Service.xml)
|
||||
set(fdo_session_xml ${CMAKE_SOURCE_DIR}/src/api/KWallet/org.freedesktop.Secrets.Session.xml)
|
||||
set(fdo_collection_xml ${CMAKE_SOURCE_DIR}/src/api/KWallet/org.freedesktop.Secrets.Collection.xml)
|
||||
set(fdo_item_xml ${CMAKE_SOURCE_DIR}/src/api/KWallet/org.freedesktop.Secrets.Item.xml)
|
||||
set(fdo_prompt_xml ${CMAKE_SOURCE_DIR}/src/api/KWallet/org.freedesktop.Secrets.Prompt.xml)
|
||||
set(fdo_portal_secret_xml ${CMAKE_SOURCE_DIR}/src/api/KWallet/org.freedesktop.impl.portal.Secret.xml)
|
||||
|
||||
set(kwalletd_dbus_SRCS)
|
||||
qt_add_dbus_adaptor(kwalletd_dbus_SRCS ${kwallet_xml} kwalletd.h KWalletD kwalletadaptor KWalletAdaptor)
|
||||
qt_add_dbus_adaptor(kwalletd_dbus_SRCS ${fdo_service_xml} kwalletfreedesktopservice.h KWalletFreedesktopService
|
||||
kwalletfreedesktopserviceadaptor KWalletFreedesktopServiceAdaptor)
|
||||
qt_add_dbus_adaptor(kwalletd_dbus_SRCS ${fdo_session_xml} kwalletfreedesktopsession.h KWalletFreedesktopSession
|
||||
kwalletfreedesktopsessionadaptor KWalletFreedesktopSessionAdaptor)
|
||||
qt_add_dbus_adaptor(kwalletd_dbus_SRCS ${fdo_collection_xml} kwalletfreedesktopcollection.h KWalletFreedesktopCollection
|
||||
kwalletfreedesktopcollectionadaptor KWalletFreedesktopCollectionAdaptor)
|
||||
qt_add_dbus_adaptor(kwalletd_dbus_SRCS ${fdo_item_xml} kwalletfreedesktopitem.h KWalletFreedesktopItem
|
||||
kwalletfreedesktopitemadaptor KWalletFreedesktopItemAdaptor)
|
||||
qt_add_dbus_adaptor(kwalletd_dbus_SRCS ${fdo_prompt_xml} kwalletfreedesktopprompt.h KWalletFreedesktopPrompt
|
||||
kwalletfreedesktoppromptadaptor KWalletFreedesktopPromptAdaptor)
|
||||
qt_add_dbus_adaptor(kwalletd_dbus_SRCS ${fdo_portal_secret_xml} kwalletportalsecrets.h KWalletPortalSecrets
|
||||
kwalletportalsecretsadaptor KWalletPortalSecretsAdaptor)
|
||||
|
||||
target_sources(kwalletd6 PRIVATE
|
||||
${kwalletd_dbus_SRCS}
|
||||
)
|
||||
|
||||
if(WIN32)
|
||||
configure_file(org.kde.kwalletd5.service.win.in
|
||||
${CMAKE_CURRENT_BINARY_DIR}/org.kde.kwalletd5.service)
|
||||
configure_file(org.kde.kwalletd6.service.win.in
|
||||
${CMAKE_CURRENT_BINARY_DIR}/org.kde.kwalletd6.service)
|
||||
else()
|
||||
configure_file(org.kde.kwalletd5.service.in
|
||||
${CMAKE_CURRENT_BINARY_DIR}/org.kde.kwalletd5.service)
|
||||
configure_file(org.kde.kwalletd6.service.in
|
||||
${CMAKE_CURRENT_BINARY_DIR}/org.kde.kwalletd6.service)
|
||||
endif()
|
||||
|
||||
install(
|
||||
FILES
|
||||
${CMAKE_CURRENT_BINARY_DIR}/org.kde.kwalletd5.service
|
||||
${CMAKE_CURRENT_BINARY_DIR}/org.kde.kwalletd6.service
|
||||
DESTINATION ${KDE_INSTALL_DBUSSERVICEDIR}
|
||||
)
|
||||
|
||||
if (HAIKU)
|
||||
target_link_libraries(kwalletd6 network)
|
||||
endif ()
|
||||
|
||||
target_link_libraries(kwalletd6
|
||||
KF6WalletBackend
|
||||
KF6Wallet
|
||||
Qt6::Widgets
|
||||
KF6::I18n
|
||||
KF6::ColorScheme
|
||||
KF6::CoreAddons
|
||||
KF6::ConfigCore
|
||||
KF6::DBusAddons
|
||||
KF6::WidgetsAddons
|
||||
KF6::WindowSystem
|
||||
KF6::Notifications
|
||||
KF6::Crash
|
||||
${Qca_LIBRARY})
|
||||
if (Gpgmepp_FOUND)
|
||||
target_link_libraries(kwalletd6 Gpgmepp)
|
||||
kde_target_enable_exceptions(kwalletd6 PRIVATE)
|
||||
endif(Gpgmepp_FOUND)
|
||||
|
||||
ecm_mark_nongui_executable(kwalletd6)
|
||||
install(TARGETS kwalletd6 ${KF_INSTALL_TARGETS_DEFAULT_ARGS})
|
||||
|
||||
########### install files ###############
|
||||
install( FILES kwalletd6.notifyrc DESTINATION ${KDE_INSTALL_KNOTIFYRCDIR} )
|
||||
install( FILES org.kde.kwalletd6.desktop DESTINATION ${KDE_INSTALL_APPDIR} )
|
||||
install( FILES kwallet.portal DESTINATION ${KDE_INSTALL_DATADIR}/xdg-desktop-portal/portals)
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
#! /usr/bin/env bash
|
||||
$EXTRACTRC `find . -name \*.ui` >> rc.cpp || exit 11
|
||||
$XGETTEXT `find . -name "*.cpp" -o -name "*.cc" | grep -v "/tests"` -o $podir/kwalletd6.pot
|
||||
@@ -0,0 +1,19 @@
|
||||
This directory consists of one daemon: kwalletd, and one library, in backend.
|
||||
|
||||
KWallet::Backend is used inside kwalletd to manage the actual files and
|
||||
encryption.
|
||||
|
||||
KWallet::Wallet, used to represent wallet entries and to encapsulate communication
|
||||
to and from the wallet server kwalletd, is part of the public API and has been
|
||||
moved to kdeui.
|
||||
|
||||
|
||||
Application level:
|
||||
|
||||
KSystemTray notifier for wallet accesses
|
||||
|
||||
Konqueror plugin
|
||||
|
||||
KControl module
|
||||
|
||||
You can also read the paper at http://www.staikos.net/~staikos/papers/2003/
|
||||
@@ -0,0 +1,78 @@
|
||||
set( EXECUTABLE_OUTPUT_PATH ${CMAKE_CURRENT_BINARY_DIR} )
|
||||
|
||||
find_package(Qt6Test REQUIRED)
|
||||
find_package(KF6Config ${KF6_DEP_VERSION} REQUIRED)
|
||||
set(CMAKE_INCLUDE_CURRENT_DIR ON)
|
||||
set(CMAKE_AUTOMOC ON)
|
||||
|
||||
include(ECMAddTests)
|
||||
|
||||
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/..)
|
||||
include_directories(${CMAKE_CURRENT_BINARY_DIR}/..)
|
||||
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/../backend)
|
||||
include_directories(${CMAKE_CURRENT_BINARY_DIR}/../backend)
|
||||
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/../../../api/KWallet)
|
||||
include_directories(${CMAKE_CURRENT_BINARY_DIR}/../../../api/KWallet)
|
||||
|
||||
add_definitions(-DFDO_ENABLE_DUMMY_MESSAGE_CONNECTION)
|
||||
remove_definitions(-DQT_NO_CAST_FROM_ASCII)
|
||||
|
||||
if (NOT EXCLUDE_DEPRECATED_BEFORE_AND_AT STREQUAL "CURRENT" AND
|
||||
EXCLUDE_DEPRECATED_BEFORE_AND_AT VERSION_LESS 5.72.0)
|
||||
set(kwallet_xml ${CMAKE_SOURCE_DIR}/src/api/KWallet/org.kde.KWallet.xml)
|
||||
else()
|
||||
# copy of org.kde.KWallet.xml, but with all deprecated API removed
|
||||
set(kwallet_xml ${CMAKE_SOURCE_DIR}/src/api/KWallet/org.kde.KWallet.nodeprecated.xml)
|
||||
endif()
|
||||
set(fdo_service_xml ${CMAKE_SOURCE_DIR}/src/api/KWallet/org.freedesktop.Secrets.Service.xml)
|
||||
set(fdo_session_xml ${CMAKE_SOURCE_DIR}/src/api/KWallet/org.freedesktop.Secrets.Session.xml)
|
||||
set(fdo_collection_xml ${CMAKE_SOURCE_DIR}/src/api/KWallet/org.freedesktop.Secrets.Collection.xml)
|
||||
set(fdo_item_xml ${CMAKE_SOURCE_DIR}/src/api/KWallet/org.freedesktop.Secrets.Item.xml)
|
||||
set(fdo_prompt_xml ${CMAKE_SOURCE_DIR}/src/api/KWallet/org.freedesktop.Secrets.Prompt.xml)
|
||||
|
||||
set(TEST_SRC
|
||||
fdo_secrets_test.cpp
|
||||
../kwalletfreedesktopservice.cpp
|
||||
../kwalletfreedesktopitem.cpp
|
||||
../kwalletfreedesktopcollection.cpp
|
||||
../kwalletfreedesktopsession.cpp
|
||||
../kwalletfreedesktopprompt.cpp
|
||||
../kwalletfreedesktopattributes.cpp
|
||||
)
|
||||
|
||||
qt_add_dbus_adaptor( TEST_SRC ${kwallet_xml} ../kwalletd.h KWalletD kwalletadaptor KWalletAdaptor)
|
||||
qt_add_dbus_adaptor( TEST_SRC ${fdo_service_xml} ../kwalletfreedesktopservice.h KWalletFreedesktopService
|
||||
kwalletfreedesktopserviceadaptor KWalletFreedesktopServiceAdaptor)
|
||||
qt_add_dbus_adaptor( TEST_SRC ${fdo_session_xml} ../kwalletfreedesktopsession.h KWalletFreedesktopSession
|
||||
kwalletfreedesktopsessionadaptor KWalletFreedesktopSessionAdaptor)
|
||||
qt_add_dbus_adaptor( TEST_SRC ${fdo_collection_xml} ../kwalletfreedesktopcollection.h KWalletFreedesktopCollection
|
||||
kwalletfreedesktopcollectionadaptor KWalletFreedesktopCollectionAdaptor)
|
||||
qt_add_dbus_adaptor( TEST_SRC ${fdo_item_xml} ../kwalletfreedesktopitem.h KWalletFreedesktopItem
|
||||
kwalletfreedesktopitemadaptor KWalletFreedesktopItemAdaptor)
|
||||
qt_add_dbus_adaptor( TEST_SRC ${fdo_prompt_xml} ../kwalletfreedesktopprompt.h KWalletFreedesktopPrompt
|
||||
kwalletfreedesktoppromptadaptor KWalletFreedesktopPromptAdaptor)
|
||||
|
||||
ecm_add_test(
|
||||
${TEST_SRC}
|
||||
../kwalletfreedesktopservice.h
|
||||
../kwalletfreedesktopcollection.h
|
||||
../kwalletfreedesktopitem.h
|
||||
../kwalletfreedesktopsession.h
|
||||
../kwalletfreedesktopprompt.h
|
||||
../kwalletd.h
|
||||
../ktimeout.h
|
||||
kwalletfreedesktopserviceadaptor.cpp
|
||||
kwalletfreedesktopcollectionadaptor.cpp
|
||||
kwalletfreedesktopitemadaptor.cpp
|
||||
kwalletfreedesktopsessionadaptor.cpp
|
||||
kwalletfreedesktoppromptadaptor.cpp
|
||||
TEST_NAME fdo_secrets_test
|
||||
LINK_LIBRARIES
|
||||
KF6Wallet
|
||||
KF6WalletBackend
|
||||
Qt6::Widgets
|
||||
Qt6::Test
|
||||
KF6::DBusAddons
|
||||
KF6::ConfigCore
|
||||
${Qca_LIBRARY}
|
||||
)
|
||||
+497
@@ -0,0 +1,497 @@
|
||||
/*
|
||||
This file is part of the KDE libraries
|
||||
SPDX-FileCopyrightText: 2021 Slava Aseev <nullptrnine@basealt.ru>
|
||||
|
||||
SPDX-License-Identifier: LGPL-2.0-or-later
|
||||
*/
|
||||
#include "fdo_secrets_test.h"
|
||||
#include "mockkwalletd.cpp"
|
||||
// cannot be in mockkwalletd.cpp, as CMake's automoc does not look there
|
||||
#include "moc_ktimeout.cpp"
|
||||
#include "moc_kwalletd.cpp"
|
||||
#include "static_mock.hpp"
|
||||
|
||||
void FdoSecretsTest::initTestCase()
|
||||
{
|
||||
static QCA::Initializer init{};
|
||||
}
|
||||
|
||||
void FdoSecretsTest::serviceStaticFunctions()
|
||||
{
|
||||
auto labels = Testset<QString, FdoUniqueLabel>{
|
||||
{"label", {"label", -1}},
|
||||
{"label__0_", {"label", 0}},
|
||||
{"label___1_", {"label_", 1}},
|
||||
{"__0_label___200_", {"__0_label_", 200}},
|
||||
};
|
||||
|
||||
runTestset(FdoUniqueLabel::fromName, labels);
|
||||
runRevTestset(
|
||||
[](const FdoUniqueLabel &l) {
|
||||
return l.toName();
|
||||
},
|
||||
labels);
|
||||
|
||||
runTestset(KWalletFreedesktopService::wrapToCollectionPath,
|
||||
Testset<QString, QString>{
|
||||
{"/org/freedesktop/secrets/collection/abcd", "/org/freedesktop/secrets/collection/abcd"},
|
||||
{"/org/freedesktop/secrets/collection/abcd/2", "/org/freedesktop/secrets/collection/abcd"},
|
||||
{"/org/freedesktop/secrets/collection/abcd/2/2/3/4", "/org/freedesktop/secrets/collection/abcd"},
|
||||
});
|
||||
|
||||
QCOMPARE(KWalletFreedesktopService::nextPromptPath().path(), "/org/freedesktop/secrets/prompt/p0");
|
||||
QCOMPARE(KWalletFreedesktopService::nextPromptPath().path(), "/org/freedesktop/secrets/prompt/p1");
|
||||
}
|
||||
|
||||
void FdoSecretsTest::collectionStaticFunctions()
|
||||
{
|
||||
auto dirNameTestset = Testset<EntryLocation, FdoUniqueLabel>{
|
||||
{{FDO_SECRETS_DEFAULT_DIR, "entry1"}, {"entry1", -1}},
|
||||
{{FDO_SECRETS_DEFAULT_DIR, "entry__3_"}, {"entry", 3}},
|
||||
{{"Passwords", "password__"}, {"Passwords/password__", -1}},
|
||||
{{"Passwords__3_", "password__200_"}, {"Passwords__3_/password", 200}},
|
||||
{{"", "password"}, {"/password", -1}},
|
||||
{{"", "/"}, {"//", -1}},
|
||||
{{FDO_SECRETS_DEFAULT_DIR, "/"}, {"/", -1}},
|
||||
{{FDO_SECRETS_DEFAULT_DIR, "/__2_"}, {"/", 2}},
|
||||
{{"https:", "/foobar.org/"}, {"https://foobar.org/", -1}},
|
||||
{{"https:", "/foobar.org/__80_"}, {"https://foobar.org/", 80}},
|
||||
};
|
||||
|
||||
runTestset(
|
||||
[](const EntryLocation &l) {
|
||||
return l.toUniqueLabel();
|
||||
},
|
||||
dirNameTestset);
|
||||
runRevTestset(
|
||||
[](const FdoUniqueLabel &l) {
|
||||
return l.toEntryLocation();
|
||||
},
|
||||
dirNameTestset);
|
||||
}
|
||||
|
||||
void FdoSecretsTest::cleanup()
|
||||
{
|
||||
SET_FUNCTION_RESULT(KWalletD::wallets, QStringList());
|
||||
}
|
||||
|
||||
void FdoSecretsTest::precreatedWallets()
|
||||
{
|
||||
const QStringList wallets = {"wallet1", "wallet2", "wallet2__0_", "wallet2__1_"};
|
||||
SET_FUNCTION_RESULT(KWalletD::wallets, wallets);
|
||||
SET_FUNCTION_RESULT_OVERLOADED(KWalletD::isOpen, true, bool(KWalletD::*)(int));
|
||||
|
||||
std::unique_ptr<KWalletD> kwalletd{new KWalletD};
|
||||
std::unique_ptr<KWalletFreedesktopService> service{new KWalletFreedesktopService(kwalletd.get())};
|
||||
|
||||
QCOMPARE(wallets.size(), service->collections().size());
|
||||
for (const auto &walletName : wallets) {
|
||||
auto collection = service->getCollectionByWalletName(walletName);
|
||||
QVERIFY(collection);
|
||||
QVERIFY(collection->label() == "wallet1" || collection->label() == "wallet2");
|
||||
}
|
||||
|
||||
auto firstCollection = service->getCollectionByWalletName(wallets.front());
|
||||
auto &item1 = firstCollection->pushNewItem(FdoUniqueLabel{"item1", -1}, QDBusObjectPath(firstCollection->fdoObjectPath().path() + "/0"));
|
||||
QCOMPARE(item1.fdoObjectPath().path(), (firstCollection->fdoObjectPath().path() + "/0"));
|
||||
QCOMPARE(&item1, service->getItemByObjectPath(item1.fdoObjectPath()));
|
||||
}
|
||||
|
||||
void FdoSecretsTest::aliases()
|
||||
{
|
||||
std::unique_ptr<KWalletD> kwalletd{new KWalletD};
|
||||
std::unique_ptr<KWalletFreedesktopService> service{new KWalletFreedesktopService(kwalletd.get())};
|
||||
|
||||
service->createCollectionAlias("alias", "walletName");
|
||||
service->createCollectionAlias("alias2", "walletName");
|
||||
service->createCollectionAlias("alias3", "walletName300");
|
||||
service->updateCollectionAlias("alias3", "walletName");
|
||||
QSet<QString> checkAliases = {"alias", "alias2", "alias3"};
|
||||
const QStringList aliases = service->readAliasesFor("walletName");
|
||||
for (const auto &alias : aliases)
|
||||
checkAliases.remove(alias);
|
||||
QVERIFY(checkAliases.isEmpty());
|
||||
|
||||
service->removeAlias("alias");
|
||||
service->removeAlias("alias2");
|
||||
service->removeAlias("alias3");
|
||||
QVERIFY(service->readAliasesFor("walletName").isEmpty());
|
||||
}
|
||||
|
||||
struct SetupSessionT {
|
||||
QDBusObjectPath sessionPath;
|
||||
QCA::SymmetricKey symmetricKey;
|
||||
QByteArray error;
|
||||
};
|
||||
|
||||
#define SETUP_SESSION_VERIFY(cond) \
|
||||
do { \
|
||||
if (!(cond)) \
|
||||
return SetupSessionT{QDBusObjectPath(), QCA::SymmetricKey(), #cond}; \
|
||||
} while (false)
|
||||
|
||||
SetupSessionT setupSession(KWalletFreedesktopService *service)
|
||||
{
|
||||
SetupSessionT result;
|
||||
QCA::KeyGenerator keygen;
|
||||
auto dlGroup = QCA::DLGroup(keygen.createDLGroup(QCA::IETF_1024));
|
||||
if (dlGroup.isNull()) {
|
||||
result.error = "createDLGroup failed, maybe libqca-ossl is missing";
|
||||
return result;
|
||||
}
|
||||
|
||||
auto privateKey = QCA::PrivateKey(keygen.createDH(dlGroup));
|
||||
auto publicKey = QCA::PublicKey(privateKey);
|
||||
|
||||
auto connection = QDBusConnection::sessionBus();
|
||||
auto message = QDBusMessage::createSignal("dummy", "dummy", "dummy");
|
||||
|
||||
auto pubKeyBytes = publicKey.toDH().y().toArray().toByteArray();
|
||||
auto sessionPubKeyVariant = service->OpenSession("dh-ietf1024-sha256-aes128-cbc-pkcs7", QDBusVariant(pubKeyBytes), result.sessionPath);
|
||||
SETUP_SESSION_VERIFY(result.sessionPath.path() != "/");
|
||||
SETUP_SESSION_VERIFY(sessionPubKeyVariant.variant().canConvert<QByteArray>());
|
||||
|
||||
auto servicePublicKeyBytes = sessionPubKeyVariant.variant().toByteArray();
|
||||
SETUP_SESSION_VERIFY(!servicePublicKeyBytes.isEmpty());
|
||||
|
||||
auto servicePublicKey = QCA::DHPublicKey(dlGroup, QCA::BigInteger(QCA::SecureArray(servicePublicKeyBytes)));
|
||||
auto commonSecret = privateKey.deriveKey(servicePublicKey);
|
||||
result.symmetricKey = QCA::HKDF().makeKey(commonSecret, {}, {}, FDO_SECRETS_CIPHER_KEY_SIZE);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void FdoSecretsTest::items()
|
||||
{
|
||||
const QStringList wallets = {"wallet1"};
|
||||
const QStringList folders = {FDO_SECRETS_DEFAULT_DIR};
|
||||
const QStringList entries = {"item1", "item2", "item3"};
|
||||
SET_FUNCTION_RESULT(KWalletD::wallets, wallets);
|
||||
SET_FUNCTION_RESULT(KWalletD::folderList, folders);
|
||||
SET_FUNCTION_RESULT(KWalletD::entryList, entries);
|
||||
|
||||
SET_FUNCTION_IMPL(KWalletD::entryType, [](int, const QString &, const QString &key, const QString &) -> int {
|
||||
if (key == "item1")
|
||||
return KWallet::Wallet::Password;
|
||||
else if (key == "item2")
|
||||
return KWallet::Wallet::Map;
|
||||
else if (key == "item3")
|
||||
return KWallet::Wallet::Stream;
|
||||
|
||||
QTEST_ASSERT(false);
|
||||
return KWallet::Wallet::Unknown;
|
||||
});
|
||||
|
||||
QString _secretHolder1 = "It's a password";
|
||||
QByteArray _secretHolder2;
|
||||
QByteArray _secretHolder3;
|
||||
|
||||
{
|
||||
QByteArray a = "It's a";
|
||||
QString b = "stream";
|
||||
|
||||
QDataStream ds{&_secretHolder2, QIODevice::WriteOnly};
|
||||
ds << a << b;
|
||||
}
|
||||
|
||||
{
|
||||
StrStrMap map;
|
||||
map["it's a"] = "map";
|
||||
|
||||
QDataStream ds{&_secretHolder3, QIODevice::WriteOnly};
|
||||
ds << map;
|
||||
}
|
||||
|
||||
SET_FUNCTION_IMPL(KWalletD::readPassword, [&](int, const QString &, const QString &key, const QString &) -> QString {
|
||||
QTEST_ASSERT(key == "item1");
|
||||
return _secretHolder1;
|
||||
});
|
||||
|
||||
SET_FUNCTION_IMPL(KWalletD::readEntry, [&](int, const QString &, const QString &key, const QString &) -> QByteArray {
|
||||
QTEST_ASSERT(key == "item3" || key == "item2");
|
||||
if (key == "item2")
|
||||
return _secretHolder2;
|
||||
else
|
||||
return _secretHolder3;
|
||||
});
|
||||
|
||||
SET_FUNCTION_IMPL(KWalletD::writePassword, [&](int, const QString &, const QString &key, const QString &value, const QString &) -> int {
|
||||
QTEST_ASSERT(key == "item1");
|
||||
_secretHolder1 = value;
|
||||
return 0;
|
||||
});
|
||||
|
||||
using writeEntryT = int (KWalletD::*)(int, const QString &, const QString &, const QByteArray &, int, const QString &);
|
||||
SET_FUNCTION_IMPL_OVERLOADED(KWalletD::writeEntry,
|
||||
writeEntryT,
|
||||
[&](int, const QString &, const QString &key, const QByteArray &value, int, const QString &) -> int {
|
||||
QTEST_ASSERT(key == "item3" || key == "item2");
|
||||
if (key == "item2")
|
||||
_secretHolder2 = value;
|
||||
else
|
||||
_secretHolder3 = value;
|
||||
return 0;
|
||||
});
|
||||
|
||||
std::unique_ptr<KWalletD> kwalletd{new KWalletD};
|
||||
std::unique_ptr<KWalletFreedesktopService> service{new KWalletFreedesktopService(kwalletd.get())};
|
||||
|
||||
auto collection = service->getCollectionByWalletName("wallet1");
|
||||
QVERIFY(collection);
|
||||
|
||||
/* Write some attributes */
|
||||
{
|
||||
collection->itemAttributes().newItem({FDO_SECRETS_DEFAULT_DIR, "item1"});
|
||||
collection->itemAttributes().newItem({FDO_SECRETS_DEFAULT_DIR, "item2"});
|
||||
collection->itemAttributes().newItem({FDO_SECRETS_DEFAULT_DIR, "item3"});
|
||||
collection->itemAttributes().setParam({FDO_SECRETS_DEFAULT_DIR, "item3"}, FDO_KEY_CREATED, 100200300ULL);
|
||||
collection->itemAttributes().setParam({FDO_SECRETS_DEFAULT_DIR, "item3"}, FDO_KEY_MODIFIED, 100200301ULL);
|
||||
auto attribs = collection->itemAttributes().getAttributes({FDO_SECRETS_DEFAULT_DIR, "item3"});
|
||||
attribs["Attrib1"] = "value1";
|
||||
attribs["Attrib2"] = "value2";
|
||||
collection->itemAttributes().setAttributes({FDO_SECRETS_DEFAULT_DIR, "item3"}, attribs);
|
||||
}
|
||||
|
||||
/* Create collection */
|
||||
using OpenAsyncT = int (KWalletD::*)(const QString &, qlonglong, const QString &, bool, const QDBusConnection &, const QDBusMessage &);
|
||||
bool openAsyncCalled = false;
|
||||
SET_FUNCTION_IMPL_OVERLOADED(KWalletD::openAsync,
|
||||
OpenAsyncT,
|
||||
[&](const QString &, qlonglong, const QString &, bool, const QDBusConnection &, const QDBusMessage &) -> int {
|
||||
openAsyncCalled = true;
|
||||
return 0;
|
||||
});
|
||||
|
||||
QDBusObjectPath promptPath;
|
||||
service->Unlock({collection->fdoObjectPath()}, promptPath);
|
||||
auto prompt = service->getPromptByObjectPath(promptPath);
|
||||
QVERIFY(prompt);
|
||||
prompt->Prompt("wndid");
|
||||
Q_EMIT kwalletd->walletAsyncOpened(0, 0);
|
||||
SET_FUNCTION_RESULT_OVERLOADED(KWalletD::isOpen, true, bool(KWalletD::*)(int));
|
||||
QVERIFY(!collection->locked());
|
||||
|
||||
auto item1 = collection->findItemByEntryLocation({FDO_SECRETS_DEFAULT_DIR, "item1"});
|
||||
auto item2 = collection->findItemByEntryLocation({FDO_SECRETS_DEFAULT_DIR, "item2"});
|
||||
auto item3 = collection->findItemByEntryLocation({FDO_SECRETS_DEFAULT_DIR, "item3"});
|
||||
QVERIFY(item1 && item2 && item3);
|
||||
|
||||
auto message = QDBusMessage::createSignal("dummy", "dummy", "dummy");
|
||||
auto [sessionPath, symmetricKey, errorStr] = setupSession(service.get());
|
||||
QVERIFY2(errorStr.isEmpty(), errorStr.constData());
|
||||
|
||||
/* Check secrets */
|
||||
auto secret1 = item1->GetSecret(sessionPath);
|
||||
service->desecret(message, secret1);
|
||||
QCOMPARE(secret1.value.toByteArray(), "It's a password");
|
||||
// QCOMPARE(secret1.mimeType, "text/plain");
|
||||
|
||||
auto secret2 = item2->GetSecret(sessionPath);
|
||||
service->desecret(message, secret2);
|
||||
QByteArray secretBytes = secret2.value.toByteArray();
|
||||
QDataStream ds{secretBytes};
|
||||
QByteArray a;
|
||||
QString b;
|
||||
ds >> a >> b;
|
||||
|
||||
QCOMPARE(secret2.mimeType, "application/octet-stream");
|
||||
QCOMPARE(a, "It's a");
|
||||
QCOMPARE(b, "stream");
|
||||
|
||||
auto secret3 = item3->GetSecret(sessionPath);
|
||||
service->desecret(message, secret3);
|
||||
auto bytes3 = secret3.value.toByteArray();
|
||||
QDataStream ds2(bytes3);
|
||||
StrStrMap map3;
|
||||
ds2 >> map3;
|
||||
|
||||
QVERIFY(map3.find("it's a") != map3.end() && map3["it's a"] == "map");
|
||||
QCOMPARE(item3->created(), 100200300);
|
||||
QCOMPARE(item3->modified(), 100200301);
|
||||
QCOMPARE(item3->attributes()["Attrib1"], "value1");
|
||||
QCOMPARE(item3->attributes()["Attrib2"], "value2");
|
||||
|
||||
/* Set new secrets */
|
||||
secret1.value = QByteArray("It's a new password");
|
||||
secret1.mimeType = "text/plain";
|
||||
service->ensecret(message, secret1);
|
||||
item1->SetSecret(secret1);
|
||||
secret1 = item1->GetSecret(sessionPath);
|
||||
service->desecret(message, secret1);
|
||||
QCOMPARE(secret1.value.toByteArray(), "It's a new password");
|
||||
QCOMPARE(secret1.mimeType, "text/plain");
|
||||
|
||||
secret2.value = QByteArray("It's a new secret");
|
||||
secret2.mimeType = "application/octet-stream";
|
||||
service->ensecret(message, secret2);
|
||||
item2->SetSecret(secret2);
|
||||
auto attribs = item2->attributes();
|
||||
attribs["newAttrib"] = ")))";
|
||||
item2->setAttributes(attribs);
|
||||
|
||||
secret2 = item2->GetSecret(sessionPath);
|
||||
service->desecret(message, secret2);
|
||||
QCOMPARE(secret2.value.toByteArray(), "It's a new secret");
|
||||
QCOMPARE(item2->attributes()["newAttrib"], ")))");
|
||||
|
||||
/* Search items */
|
||||
attribs.clear();
|
||||
attribs["Attrib1"] = "value1";
|
||||
QList<QDBusObjectPath> lockedItems;
|
||||
auto unlockedItems = service->SearchItems(attribs, lockedItems);
|
||||
QCOMPARE(unlockedItems.size(), 1);
|
||||
QCOMPARE(unlockedItems.front(), item3->fdoObjectPath());
|
||||
}
|
||||
|
||||
void FdoSecretsTest::createLockUnlockCollection()
|
||||
{
|
||||
std::unique_ptr<KWalletD> kwalletd{new KWalletD};
|
||||
std::unique_ptr<KWalletFreedesktopService> service{new KWalletFreedesktopService(kwalletd.get())};
|
||||
|
||||
/* Create collection */
|
||||
using OpenAsyncT = int (KWalletD::*)(const QString &, qlonglong, const QString &, bool, const QDBusConnection &, const QDBusMessage &);
|
||||
bool openAsyncCalled = false;
|
||||
SET_FUNCTION_IMPL_OVERLOADED(KWalletD::openAsync,
|
||||
OpenAsyncT,
|
||||
[&](const QString &, qlonglong, const QString &, bool, const QDBusConnection &, const QDBusMessage &) -> int {
|
||||
openAsyncCalled = true;
|
||||
return 0;
|
||||
});
|
||||
|
||||
QVariantMap props;
|
||||
props["org.freedesktop.Secret.Collection.Label"] = QString("walletName");
|
||||
QDBusObjectPath promptPath;
|
||||
service->CreateCollection(props, "", promptPath);
|
||||
auto prompt = service->getPromptByObjectPath(promptPath);
|
||||
QVERIFY(prompt);
|
||||
prompt->Prompt("wndid");
|
||||
QVERIFY(openAsyncCalled);
|
||||
Q_EMIT kwalletd->walletAsyncOpened(0, 0);
|
||||
|
||||
auto createdCollection = service->getCollectionByWalletName("walletName");
|
||||
QVERIFY(createdCollection);
|
||||
QCOMPARE(createdCollection->label(), "walletName");
|
||||
|
||||
/* Check aliases */
|
||||
service->createCollectionAlias("alias", "walletName");
|
||||
service->createCollectionAlias("alias2", "walletName");
|
||||
service->createCollectionAlias("alias3", "walletName");
|
||||
|
||||
QCOMPARE(service->resolveIfAlias(QStringLiteral(FDO_ALIAS_PATH) + "alias"), createdCollection->fdoObjectPath().path());
|
||||
QCOMPARE(service->resolveIfAlias(QStringLiteral(FDO_ALIAS_PATH) + "alias2"), createdCollection->fdoObjectPath().path());
|
||||
QCOMPARE(service->resolveIfAlias(QStringLiteral(FDO_ALIAS_PATH) + "alias3"), createdCollection->fdoObjectPath().path());
|
||||
QCOMPARE(service->ReadAlias("alias"), createdCollection->fdoObjectPath());
|
||||
|
||||
service->removeAlias("alias");
|
||||
service->removeAlias("alias2");
|
||||
service->removeAlias("alias3");
|
||||
|
||||
/* Lock/Unlock */
|
||||
auto lockedObjects = service->Lock({createdCollection->fdoObjectPath()}, promptPath);
|
||||
QCOMPARE(lockedObjects.size(), 1);
|
||||
QCOMPARE(lockedObjects.front(), createdCollection->fdoObjectPath());
|
||||
SET_FUNCTION_RESULT_OVERLOADED(KWalletD::isOpen, false, bool(KWalletD::*)(int));
|
||||
QVERIFY(createdCollection->locked());
|
||||
|
||||
service->Unlock({createdCollection->fdoObjectPath()}, promptPath);
|
||||
prompt = service->getPromptByObjectPath(promptPath);
|
||||
QVERIFY(prompt);
|
||||
openAsyncCalled = false;
|
||||
prompt->Prompt("wndid");
|
||||
QVERIFY(openAsyncCalled);
|
||||
Q_EMIT kwalletd->walletAsyncOpened(0, 0);
|
||||
SET_FUNCTION_RESULT_OVERLOADED(KWalletD::isOpen, true, bool(KWalletD::*)(int));
|
||||
QVERIFY(!createdCollection->locked());
|
||||
}
|
||||
|
||||
void FdoSecretsTest::session()
|
||||
{
|
||||
std::unique_ptr<KWalletD> kwalletd{new KWalletD};
|
||||
std::unique_ptr<KWalletFreedesktopService> service{new KWalletFreedesktopService(kwalletd.get())};
|
||||
|
||||
auto message = QDBusMessage::createSignal("dummy", "dummy", "dummy");
|
||||
auto [sessionPath, symmetricKey, errorStr] = setupSession(service.get());
|
||||
|
||||
/* Generate secret */
|
||||
auto secret = FreedesktopSecret(sessionPath, QByteArray("It's a secret"), "text/plain");
|
||||
QVERIFY(service->ensecret(message, secret));
|
||||
|
||||
/* Try to decrypt by hand with symmetricKey */
|
||||
auto cipher = QCA::Cipher("aes128", QCA::Cipher::CBC, QCA::Cipher::PKCS7, QCA::Decode, symmetricKey, secret.parameters);
|
||||
QCA::SecureArray result;
|
||||
result.append(cipher.update(QCA::MemoryRegion(secret.value.toByteArray())));
|
||||
result.append(cipher.final());
|
||||
|
||||
QCOMPARE(QString::fromUtf8(result.toByteArray()), "It's a secret");
|
||||
|
||||
/* Try to decrypt by session */
|
||||
QVERIFY(service->desecret(message, secret));
|
||||
QCOMPARE(secret.value.toByteArray(), QByteArray("It's a secret"));
|
||||
}
|
||||
|
||||
void FdoSecretsTest::attributes()
|
||||
{
|
||||
KWalletFreedesktopAttributes attribs{"test"};
|
||||
|
||||
attribs.newItem({"dir", "name"});
|
||||
|
||||
attribs.setParam({"dir", "name"}, "param1", 0xff00ff00ff00ff00);
|
||||
attribs.setParam({"dir", "name"}, "param2", "string_param");
|
||||
|
||||
QCOMPARE(attribs.getULongLongParam({"dir", "name"}, "param1", 0), 0xff00ff00ff00ff00);
|
||||
QCOMPARE(attribs.getStringParam({"dir", "name"}, "param2", ""), "string_param");
|
||||
|
||||
attribs.renameLabel({"dir", "name"}, {"newdir", "newname"});
|
||||
|
||||
QCOMPARE(attribs.getULongLongParam({"newdir", "newname"}, "param1", 0), 0xff00ff00ff00ff00);
|
||||
QCOMPARE(attribs.getStringParam({"newdir", "newname"}, "param2", ""), "string_param");
|
||||
QCOMPARE(attribs.getULongLongParam({"dir", "name"}, "param1", 0xdef017), 0xdef017);
|
||||
QCOMPARE(attribs.getStringParam({"dir", "name"}, "param2", "default"), "default");
|
||||
|
||||
attribs.setParam({"newdir", "newname"}, "param1", 100200300ULL);
|
||||
attribs.setParam({"newdir", "newname"}, "param2", "another_string_param");
|
||||
|
||||
QCOMPARE(attribs.getULongLongParam({"newdir", "newname"}, "param1", 0), 100200300ULL);
|
||||
QCOMPARE(attribs.getStringParam({"newdir", "newname"}, "param2", ""), "another_string_param");
|
||||
|
||||
QVERIFY(attribs.getAttributes({"newdir", "newname"}).empty());
|
||||
|
||||
StrStrMap attribMap;
|
||||
attribMap["key1"] = "value1";
|
||||
attribMap["key2"] = "value2";
|
||||
|
||||
attribs.setAttributes({"newdir", "newname"}, attribMap);
|
||||
QCOMPARE(attribs.getAttributes({"newdir", "newname"}), attribMap);
|
||||
|
||||
attribs.setAttributes({"dir", "name"}, attribMap);
|
||||
/* Item not exists - expects empty attributes map */
|
||||
QVERIFY(attribs.getAttributes({"dir", "name"}).empty());
|
||||
|
||||
attribs.setParam({"dir1", "name1"}, "param1", "some_param");
|
||||
QCOMPARE(attribs.getStringParam({"dir1", "name1"}, "param1", "default"), "default");
|
||||
}
|
||||
|
||||
void FdoSecretsTest::walletNameEncodeDecode()
|
||||
{
|
||||
#define ENCODE_DECODE_CHECK(DECODED, ENCODED) \
|
||||
do { \
|
||||
auto encodedResult = KWallet::Backend::encodeWalletName(DECODED); \
|
||||
auto decodedResult = KWallet::Backend::decodeWalletName(ENCODED); \
|
||||
QCOMPARE(encodedResult, ENCODED); \
|
||||
QCOMPARE(decodedResult, DECODED); \
|
||||
} while (false)
|
||||
|
||||
ENCODE_DECODE_CHECK("/", ";2F");
|
||||
QString allowedChars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789^&'@{}[],$=!-#()%.+_\r\n\t\f\v ";
|
||||
ENCODE_DECODE_CHECK(allowedChars, allowedChars);
|
||||
ENCODE_DECODE_CHECK("a/b/c\\", "a;2Fb;2Fc;5C");
|
||||
ENCODE_DECODE_CHECK("/\\/", ";2F;5C;2F");
|
||||
ENCODE_DECODE_CHECK(";;;", ";3B;3B;3B");
|
||||
ENCODE_DECODE_CHECK(";3B", ";3B3B");
|
||||
|
||||
#undef ENCODE_DECODE_CHECK
|
||||
}
|
||||
|
||||
QTEST_GUILESS_MAIN(FdoSecretsTest)
|
||||
|
||||
#include "moc_fdo_secrets_test.cpp"
|
||||
+34
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
This file is part of the KDE libraries
|
||||
SPDX-FileCopyrightText: 2021 Slava Aseev <nullptrnine@basealt.ru>
|
||||
|
||||
SPDX-License-Identifier: LGPL-2.0-or-later
|
||||
*/
|
||||
|
||||
#ifndef FDOSECRETSTEST_H
|
||||
#define FDOSECRETSTEST_H
|
||||
|
||||
#include "../kwalletd.h"
|
||||
#include "testhelpers.hpp"
|
||||
|
||||
class FdoSecretsTest : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
private Q_SLOTS:
|
||||
void initTestCase();
|
||||
void cleanup();
|
||||
|
||||
void serviceStaticFunctions();
|
||||
void collectionStaticFunctions();
|
||||
|
||||
void precreatedWallets();
|
||||
void aliases();
|
||||
void createLockUnlockCollection();
|
||||
void items();
|
||||
void session();
|
||||
void attributes();
|
||||
void walletNameEncodeDecode();
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,150 @@
|
||||
/*
|
||||
This file is part of the KDE libraries
|
||||
SPDX-FileCopyrightText: 2022 Slava Aseev <nullptrnine@basealt.ru>
|
||||
|
||||
SPDX-License-Identifier: LGPL-2.0-or-later
|
||||
*/
|
||||
#include "static_mock.hpp"
|
||||
|
||||
#include "../kwalletd.h"
|
||||
#include "../kwalletfreedesktopcollection.h"
|
||||
#include "../kwalletfreedesktopitem.h"
|
||||
#include "../kwalletfreedesktopprompt.h"
|
||||
#include "../kwalletfreedesktopservice.h"
|
||||
#include "../kwalletfreedesktopsession.h"
|
||||
|
||||
KWalletD::KWalletD()
|
||||
: _syncTime(0)
|
||||
{
|
||||
}
|
||||
KWalletD::~KWalletD()
|
||||
{
|
||||
}
|
||||
|
||||
KWalletSessionStore::KWalletSessionStore()
|
||||
{
|
||||
}
|
||||
KWalletSessionStore::~KWalletSessionStore()
|
||||
{
|
||||
}
|
||||
|
||||
KTimeout::KTimeout(QObject *)
|
||||
{
|
||||
}
|
||||
KTimeout::~KTimeout()
|
||||
{
|
||||
}
|
||||
|
||||
MOCK_FUNCTION(KWalletD, encodeWalletName, 1, );
|
||||
MOCK_FUNCTION(KWalletD, decodeWalletName, 1, );
|
||||
|
||||
MOCK_FUNCTION(KTimeout, clear, 0, );
|
||||
MOCK_FUNCTION(KTimeout, resetTimer, 2, );
|
||||
MOCK_FUNCTION(KTimeout, removeTimer, 1, );
|
||||
MOCK_FUNCTION(KTimeout, addTimer, 2, );
|
||||
|
||||
void KTimeout::timerEvent(QTimerEvent *)
|
||||
{
|
||||
}
|
||||
|
||||
MOCK_FUNCTION(KWalletD, readEntry, 4, );
|
||||
MOCK_FUNCTION(KWalletD, readMap, 4, );
|
||||
MOCK_FUNCTION(KWalletD, readPassword, 4, );
|
||||
|
||||
MOCK_FUNCTION_RES(KWalletD, removeEntry, 4, 0, );
|
||||
MOCK_FUNCTION_RES(KWalletD, writeMap, 5, 0, );
|
||||
MOCK_FUNCTION_RES(KWalletD, writePassword, 5, 0, );
|
||||
|
||||
using OVWriteEntry_6 = int (KWalletD::*)(int, const QString &, const QString &, const QByteArray &, int, const QString &);
|
||||
MOCK_FUNCTION_OVERLOADED_RES(KWalletD, writeEntry, 6, 0, OVWriteEntry_6);
|
||||
|
||||
using OVWriteEntry_5 = int (KWalletD::*)(int, const QString &, const QString &, const QByteArray &, const QString &);
|
||||
MOCK_FUNCTION_OVERLOADED_RES(KWalletD, writeEntry, 5, 0, OVWriteEntry_5);
|
||||
|
||||
MOCK_FUNCTION(KWalletD, entryType, 4, );
|
||||
MOCK_FUNCTION_RES(KWalletD, renameEntry, 5, 0, );
|
||||
|
||||
MOCK_FUNCTION(KWalletD, isEnabled, 0, const);
|
||||
MOCK_FUNCTION(KWalletD, open, 3, );
|
||||
MOCK_FUNCTION(KWalletD, openPath, 3, );
|
||||
MOCK_FUNCTION(KWalletD, openPathAsync, 4, );
|
||||
|
||||
using OVOpenAsync4 = int (KWalletD::*)(const QString &, qlonglong, const QString &, bool);
|
||||
MOCK_FUNCTION_OVERLOADED(KWalletD, openAsync, 4, OVOpenAsync4);
|
||||
|
||||
using OVOpenAsync6 = int (KWalletD::*)(const QString &, qlonglong, const QString &, bool, const QDBusConnection &, const QDBusMessage &);
|
||||
MOCK_FUNCTION_OVERLOADED(KWalletD, openAsync, 6, OVOpenAsync6);
|
||||
|
||||
using OVClose4 = int (KWalletD::*)(int, bool, const QString &, const QDBusMessage &);
|
||||
MOCK_FUNCTION_OVERLOADED(KWalletD, close, 4, OVClose4);
|
||||
|
||||
using OVClose2 = int (KWalletD::*)(const QString &, bool);
|
||||
MOCK_FUNCTION_OVERLOADED(KWalletD, close, 2, OVClose2);
|
||||
|
||||
using OVClose3 = int (KWalletD::*)(int, bool, const QString &);
|
||||
MOCK_FUNCTION_OVERLOADED(KWalletD, close, 3, OVClose3);
|
||||
|
||||
MOCK_FUNCTION(KWalletD, deleteWallet, 1, );
|
||||
|
||||
MOCK_FUNCTION_OVERLOADED(KWalletD, isOpen, 1, bool (KWalletD::*)(const QString &));
|
||||
MOCK_FUNCTION_OVERLOADED(KWalletD, isOpen, 1, bool (KWalletD::*)(int));
|
||||
|
||||
MOCK_FUNCTION(KWalletD, users, 1, const);
|
||||
MOCK_FUNCTION(KWalletD, wallets, 0, const);
|
||||
MOCK_FUNCTION(KWalletD, folderList, 2, );
|
||||
MOCK_FUNCTION(KWalletD, hasFolder, 3, );
|
||||
MOCK_FUNCTION(KWalletD, createFolder, 3, );
|
||||
MOCK_FUNCTION(KWalletD, removeFolder, 3, );
|
||||
MOCK_FUNCTION(KWalletD, entryList, 3, );
|
||||
|
||||
#if KWALLET_BUILD_DEPRECATED_SINCE(5, 72)
|
||||
MOCK_FUNCTION(KWalletD, readEntryList, 4, );
|
||||
MOCK_FUNCTION(KWalletD, readMapList, 4, );
|
||||
MOCK_FUNCTION(KWalletD, readPasswordList, 4, );
|
||||
#endif
|
||||
|
||||
MOCK_FUNCTION(KWalletD, entriesList, 3, );
|
||||
MOCK_FUNCTION(KWalletD, mapList, 3, );
|
||||
MOCK_FUNCTION(KWalletD, passwordList, 3, );
|
||||
MOCK_FUNCTION(KWalletD, renameWallet, 2, );
|
||||
MOCK_FUNCTION(KWalletD, hasEntry, 4, );
|
||||
MOCK_FUNCTION(KWalletD, disconnectApplication, 2, );
|
||||
MOCK_FUNCTION(KWalletD, folderDoesNotExist, 2, );
|
||||
MOCK_FUNCTION(KWalletD, keyDoesNotExist, 3, );
|
||||
MOCK_FUNCTION(KWalletD, networkWallet, 0, );
|
||||
MOCK_FUNCTION(KWalletD, localWallet, 0, );
|
||||
MOCK_FUNCTION(KWalletD, pamOpen, 3, );
|
||||
MOCK_FUNCTION(KWalletD, sync, 2, );
|
||||
MOCK_FUNCTION(KWalletD, changePassword, 3, );
|
||||
MOCK_FUNCTION(KWalletD, reconfigure, 0, );
|
||||
MOCK_FUNCTION(KWalletD, closeAllWallets, 0, );
|
||||
MOCK_FUNCTION(KWalletD, screenSaverChanged, 1, );
|
||||
|
||||
void KWalletD::slotServiceOwnerChanged(const QString &, const QString &, const QString &)
|
||||
{
|
||||
}
|
||||
void KWalletD::emitWalletListDirty()
|
||||
{
|
||||
}
|
||||
void KWalletD::timedOutClose(int)
|
||||
{
|
||||
}
|
||||
void KWalletD::timedOutSync(int)
|
||||
{
|
||||
}
|
||||
void KWalletD::notifyFailures()
|
||||
{
|
||||
}
|
||||
void KWalletD::processTransactions()
|
||||
{
|
||||
}
|
||||
void KWalletD::activatePasswordDialog()
|
||||
{
|
||||
}
|
||||
|
||||
#include <QLoggingCategory>
|
||||
const QLoggingCategory &KWALLETD_LOG()
|
||||
{
|
||||
static const QLoggingCategory category("kf.wallet.kwalletd", QtFatalMsg);
|
||||
return category;
|
||||
}
|
||||
@@ -0,0 +1,312 @@
|
||||
/*
|
||||
This file is part of the KDE libraries
|
||||
SPDX-FileCopyrightText: 2021 Slava Aseev <nullptrnine@basealt.ru>
|
||||
|
||||
SPDX-License-Identifier: LGPL-2.0-or-later
|
||||
*/
|
||||
|
||||
#ifndef __STATIC_MOCK__H__
|
||||
#define __STATIC_MOCK__H__
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <functional>
|
||||
#include <tuple>
|
||||
|
||||
/*
|
||||
* Details
|
||||
*/
|
||||
|
||||
#define COMPTIME_HASH(x) details::fnv1a64_hash<sizeof(x) - 2>(x)
|
||||
|
||||
namespace details
|
||||
{
|
||||
template<size_t I>
|
||||
constexpr uint64_t fnv1a64_hash(const char *str)
|
||||
{
|
||||
return (fnv1a64_hash<I - 1>(str) ^ static_cast<uint64_t>(str[I])) * 0x100000001b3;
|
||||
}
|
||||
|
||||
template<>
|
||||
constexpr uint64_t fnv1a64_hash<size_t(-1)>(const char *)
|
||||
{
|
||||
return 0xcbf29ce484222325;
|
||||
}
|
||||
|
||||
template<bool Enable, size_t N, typename... ArgsT>
|
||||
struct ElementType_ {
|
||||
using type = typename std::tuple_element<N, std::tuple<ArgsT...>>::type;
|
||||
};
|
||||
|
||||
template<size_t N, typename... ArgsT>
|
||||
struct ElementType_<false, N, ArgsT...> {
|
||||
using type = std::nullptr_t;
|
||||
};
|
||||
|
||||
template<size_t N, typename... ArgsT>
|
||||
struct ElementType : details::ElementType_<(N < sizeof...(ArgsT)), N, ArgsT...> {
|
||||
};
|
||||
|
||||
template<typename ReturnT, typename T, typename... ArgsT>
|
||||
struct FunctionTraitsImpl {
|
||||
using ReturnType = ReturnT;
|
||||
|
||||
template<size_t ArgNum>
|
||||
using ArgT = typename ElementType<ArgNum, ArgsT...>::type;
|
||||
|
||||
static constexpr size_t arity = sizeof...(ArgsT);
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct FunctionTraits {
|
||||
};
|
||||
|
||||
template<typename ReturnT, typename T, typename... ArgsT>
|
||||
struct FunctionTraits<ReturnT (T::*)(ArgsT...)> : FunctionTraitsImpl<ReturnT, T, ArgsT...> {
|
||||
};
|
||||
|
||||
template<typename ReturnT, typename T, typename... ArgsT>
|
||||
struct FunctionTraits<ReturnT (T::*)(ArgsT...) const> : FunctionTraitsImpl<ReturnT, T, ArgsT...> {
|
||||
};
|
||||
|
||||
template<typename ReturnT, typename... ArgsT>
|
||||
struct FunctionTraits<ReturnT (*)(ArgsT...)> : FunctionTraitsImpl<ReturnT, void, ArgsT...> {
|
||||
};
|
||||
|
||||
template<typename, uint64_t, typename T>
|
||||
static T &returnStaticStorage()
|
||||
{
|
||||
static T value;
|
||||
return value;
|
||||
}
|
||||
|
||||
template<typename MemberF, uint64_t NameHash, typename T>
|
||||
struct ReturnStaticStorageHelper {
|
||||
using TT = typename std::decay<T>::type;
|
||||
|
||||
static T get()
|
||||
{
|
||||
return returnStaticStorage<MemberF, NameHash, TT>();
|
||||
}
|
||||
template<typename V>
|
||||
static void setValue(V &&v)
|
||||
{
|
||||
returnStaticStorage<MemberF, NameHash, TT>() = std::forward<V>(v);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename MemberF, uint64_t NameHash>
|
||||
struct ReturnStaticStorageHelper<MemberF, NameHash, void> {
|
||||
static void get()
|
||||
{
|
||||
}
|
||||
template<typename V>
|
||||
static void setValue(V)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct DefaultCtorOrNullForVoid {
|
||||
using TT = typename std::decay<T>::type;
|
||||
static TT get()
|
||||
{
|
||||
return TT();
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct DefaultCtorOrNullForVoid<void> {
|
||||
static std::nullptr_t get()
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
};
|
||||
|
||||
template<typename MemberF, uint64_t NameHash, typename... ArgsT>
|
||||
struct FuncImplHelper {
|
||||
using RetT = typename FunctionTraits<MemberF>::ReturnType;
|
||||
|
||||
static typename FunctionTraits<MemberF>::ReturnType call(ArgsT... args)
|
||||
{
|
||||
if (func())
|
||||
return func()(args...);
|
||||
else
|
||||
return ReturnStaticStorageHelper<MemberF, NameHash, typename FunctionTraits<MemberF>::ReturnType>::get();
|
||||
}
|
||||
|
||||
static std::function<RetT(ArgsT...)> &func()
|
||||
{
|
||||
static std::function<RetT(ArgsT...)> holder;
|
||||
return holder;
|
||||
}
|
||||
};
|
||||
|
||||
template<typename MemberF, uint64_t NameHash, size_t I = 0, typename... ArgsT>
|
||||
struct FuncImpl : std::conditional<(I < FunctionTraits<MemberF>::arity),
|
||||
FuncImpl<MemberF, NameHash, I + 1, ArgsT..., typename FunctionTraits<MemberF>::template ArgT<I>>,
|
||||
FuncImplHelper<MemberF, NameHash, ArgsT...>>::type {
|
||||
};
|
||||
|
||||
} // namespace details
|
||||
|
||||
#define MM_MEMBER_TRAITS(NAME) details::FunctionTraits<decltype(&NAME)>
|
||||
|
||||
#define MM_MEMBER_ARG_0(NAME)
|
||||
#define MM_MEMBER_ARG_1(NAME) typename details::FunctionTraits<NAME>::ArgT<0> _0
|
||||
#define MM_MEMBER_ARG_2(NAME) MM_MEMBER_ARG_1(NAME), typename details::FunctionTraits<NAME>::ArgT<1> _1
|
||||
#define MM_MEMBER_ARG_3(NAME) MM_MEMBER_ARG_2(NAME), typename details::FunctionTraits<NAME>::ArgT<2> _2
|
||||
#define MM_MEMBER_ARG_4(NAME) MM_MEMBER_ARG_3(NAME), typename details::FunctionTraits<NAME>::ArgT<3> _3
|
||||
#define MM_MEMBER_ARG_5(NAME) MM_MEMBER_ARG_4(NAME), typename details::FunctionTraits<NAME>::ArgT<4> _4
|
||||
#define MM_MEMBER_ARG_6(NAME) MM_MEMBER_ARG_5(NAME), typename details::FunctionTraits<NAME>::ArgT<5> _5
|
||||
#define MM_MEMBER_ARG_7(NAME) MM_MEMBER_ARG_6(NAME), typename details::FunctionTraits<NAME>::ArgT<6> _6
|
||||
|
||||
#define MM_MEMBER_ARGNAME_0(NAME)
|
||||
#define MM_MEMBER_ARGNAME_1(NAME) _0
|
||||
#define MM_MEMBER_ARGNAME_2(NAME) MM_MEMBER_ARGNAME_1(NAME), _1
|
||||
#define MM_MEMBER_ARGNAME_3(NAME) MM_MEMBER_ARGNAME_2(NAME), _2
|
||||
#define MM_MEMBER_ARGNAME_4(NAME) MM_MEMBER_ARGNAME_3(NAME), _3
|
||||
#define MM_MEMBER_ARGNAME_5(NAME) MM_MEMBER_ARGNAME_4(NAME), _4
|
||||
#define MM_MEMBER_ARGNAME_6(NAME) MM_MEMBER_ARGNAME_5(NAME), _5
|
||||
#define MM_MEMBER_ARGNAME_7(NAME) MM_MEMBER_ARGNAME_6(NAME), _6
|
||||
|
||||
#define MM_LINE_NAME(prefix) MM_JOIN_NAME(prefix, __LINE__)
|
||||
#define MM_JOIN_NAME(NAME, LINE) MM_JOIN_NAME_1(NAME, LINE)
|
||||
#define MM_JOIN_NAME_1(NAME, LINE) NAME##LINE
|
||||
|
||||
#define MOCK_FUNCTION_RES_RAW_TYPE(CLASS, NAME, TYPE, ARGS_COUNT, INIT_VALUE, ...) \
|
||||
details::FunctionTraits<TYPE>::ReturnType CLASS::NAME(MM_MEMBER_ARG_##ARGS_COUNT(TYPE)) __VA_ARGS__ \
|
||||
{ \
|
||||
return details::FuncImpl<TYPE, COMPTIME_HASH(#CLASS "::" #NAME)>::call(MM_MEMBER_ARGNAME_##ARGS_COUNT(TYPE)); \
|
||||
} \
|
||||
static int MM_LINE_NAME(_init_res_##CLASS##NAME##ARGS_COUNT) = []() { \
|
||||
details::ReturnStaticStorageHelper<TYPE, COMPTIME_HASH(#CLASS "::" #NAME), details::FunctionTraits<TYPE>::ReturnType>::setValue(INIT_VALUE); \
|
||||
return 0; \
|
||||
}()
|
||||
|
||||
/*
|
||||
* Interface
|
||||
*/
|
||||
|
||||
/*
|
||||
* Defines implementation for the function with specified return value
|
||||
*
|
||||
* CLASS - the class name
|
||||
* NAME - the function name
|
||||
* ARGS_COUNT - the count of function arguments
|
||||
* INIT_VALUE - the new result of the function
|
||||
* ... - the optional const qualifier (must be empty if member function is non-const)
|
||||
*/
|
||||
#define MOCK_FUNCTION_RES(CLASS, NAME, ARGS_COUNT, INIT_VALUE, ...) \
|
||||
MOCK_FUNCTION_RES_RAW_TYPE(CLASS, NAME, decltype(&CLASS::NAME), ARGS_COUNT, INIT_VALUE, __VA_ARGS__)
|
||||
|
||||
/*
|
||||
* Defines implementation for the function with default-constructed return value
|
||||
*
|
||||
* CLASS - the class name
|
||||
* NAME - the function name
|
||||
* ARGS_COUNT - the count of function arguments
|
||||
* ... - the optional const qualifier (must be empty if member function is non-const)
|
||||
*/
|
||||
#define MOCK_FUNCTION(CLASS, NAME, ARGS_COUNT, ...) \
|
||||
MOCK_FUNCTION_RES(CLASS, \
|
||||
NAME, \
|
||||
ARGS_COUNT, \
|
||||
details::DefaultCtorOrNullForVoid<details::FunctionTraits<decltype(&CLASS::NAME)>::ReturnType>::get(), \
|
||||
__VA_ARGS__)
|
||||
|
||||
/*
|
||||
* Defines implementation for the overloaded function with specified return value
|
||||
*
|
||||
* CLASS - the class name
|
||||
* NAME - the function name
|
||||
* ARGS_COUNT - the count of function arguments
|
||||
* INIT_VALUE - the new result of the function
|
||||
* ... - the signature of the overloaded function
|
||||
*/
|
||||
#define MOCK_FUNCTION_OVERLOADED_RES(CLASS, NAME, ARGS_COUNT, INIT_VALUE, ...) \
|
||||
MOCK_FUNCTION_RES_RAW_TYPE(CLASS, NAME, decltype((__VA_ARGS__) & CLASS::NAME), ARGS_COUNT, INIT_VALUE, )
|
||||
|
||||
/*
|
||||
* Defines implementation for the overloaded const member function with specified return value
|
||||
*
|
||||
* CLASS - the class name
|
||||
* NAME - the function name
|
||||
* ARGS_COUNT - the count of function arguments
|
||||
* INIT_VALUE - the new result of the function
|
||||
* ... - the signature of the overloaded function
|
||||
*/
|
||||
#define MOCK_FUNCTION_OVERLOADED_RES_CONST(CLASS, NAME, ARGS_COUNT, INIT_VALUE, ...) \
|
||||
MOCK_FUNCTION_RES_RAW_TYPE(CLASS, NAME, decltype((__VA_ARGS__) & CLASS::NAME), ARGS_COUNT, INIT_VALUE, const)
|
||||
|
||||
/*
|
||||
* Defines implementation for the overloaded function with default-constructed return value
|
||||
*
|
||||
* CLASS - the class name
|
||||
* NAME - the function name
|
||||
* ARGS_COUNT - the count of function arguments
|
||||
* ... - the signature of the overloaded function
|
||||
*/
|
||||
#define MOCK_FUNCTION_OVERLOADED(CLASS, NAME, ARGS_COUNT, ...) \
|
||||
MOCK_FUNCTION_OVERLOADED_RES(CLASS, \
|
||||
NAME, \
|
||||
ARGS_COUNT, \
|
||||
details::DefaultCtorOrNullForVoid<details::FunctionTraits<decltype((__VA_ARGS__) & CLASS::NAME)>::ReturnType>::get(), \
|
||||
__VA_ARGS__)
|
||||
|
||||
/*
|
||||
* Defines implementation for the overloaded const member function with default-constructed return value
|
||||
*
|
||||
* CLASS - the class name
|
||||
* NAME - the function name
|
||||
* ARGS_COUNT - the count of function arguments
|
||||
* ... - the signature of the overloaded function
|
||||
*/
|
||||
#define MOCK_FUNCTION_OVERLOADED_CONST(CLASS, NAME, ARGS_COUNT, ...) \
|
||||
MOCK_FUNCTION_OVERLOADED_RES_CONST(CLASS, \
|
||||
NAME, \
|
||||
ARGS_COUNT, \
|
||||
details::DefaultCtorOrNullForVoid<details::FunctionTraits<decltype((__VA_ARGS__) & CLASS::NAME)>::ReturnType>::get(), \
|
||||
__VA_ARGS__)
|
||||
|
||||
/*
|
||||
* Sets return value for the specified function
|
||||
*
|
||||
* FULL_NAME - the full name of the function (e.g. SomeClass::functionName)
|
||||
* ... - the value to be returned (or arguments to constructor)
|
||||
*/
|
||||
#define SET_FUNCTION_RESULT(FULL_NAME, ...) \
|
||||
details::ReturnStaticStorageHelper<decltype(&FULL_NAME), COMPTIME_HASH(#FULL_NAME), details::FunctionTraits<decltype(&FULL_NAME)>::ReturnType>::setValue( \
|
||||
__VA_ARGS__)
|
||||
|
||||
/*
|
||||
* Sets return value for the specified overloaded function
|
||||
*
|
||||
* FULL_NAME - the full name of the function (e.g. SomeClass::functionName)
|
||||
* VALUE - the value to be returned
|
||||
* ... - the signature of the overloaded function
|
||||
*/
|
||||
#define SET_FUNCTION_RESULT_OVERLOADED(FULL_NAME, VALUE, ...) \
|
||||
details::ReturnStaticStorageHelper<decltype((__VA_ARGS__) & FULL_NAME), \
|
||||
COMPTIME_HASH(#FULL_NAME), \
|
||||
details::FunctionTraits<decltype((__VA_ARGS__) & FULL_NAME)>::ReturnType>::setValue(VALUE)
|
||||
|
||||
/*
|
||||
* Sets implementation for the specified function
|
||||
*
|
||||
* FULL_NAME - the full name of the function (e.g. SomeClass::functionName)
|
||||
* ... - the lambda or function for implementation
|
||||
*/
|
||||
#define SET_FUNCTION_IMPL(FULL_NAME, ...) details::FuncImpl<decltype(&FULL_NAME), COMPTIME_HASH(#FULL_NAME)>::func() = __VA_ARGS__
|
||||
|
||||
/*
|
||||
* Sets implementation for the specified overloaded function
|
||||
*
|
||||
* FULL_NAME - the full name of the function (e.g. SomeClass::functionName)
|
||||
* FUNC_TYPE - the signature of the overloaded function (must be alias if it contains commas)
|
||||
* ... - the lambda or function for implementation
|
||||
*/
|
||||
#define SET_FUNCTION_IMPL_OVERLOADED(FULL_NAME, FUNC_TYPE, ...) \
|
||||
details::FuncImpl<decltype((FUNC_TYPE) & FULL_NAME), COMPTIME_HASH(#FULL_NAME)>::func() = __VA_ARGS__
|
||||
|
||||
#endif // __STATIC_MOCK__H__
|
||||
@@ -0,0 +1,106 @@
|
||||
/*
|
||||
This file is part of the KDE libraries
|
||||
SPDX-FileCopyrightText: 2021 Slava Aseev <nullptrnine@basealt.ru>
|
||||
|
||||
SPDX-License-Identifier: LGPL-2.0-or-later
|
||||
*/
|
||||
#ifndef __TESTHELPERS_HPP__
|
||||
#define __TESTHELPERS_HPP__
|
||||
|
||||
#include <../kwalletfreedesktopservice.h>
|
||||
#include <QTest>
|
||||
#include <string>
|
||||
#include <tuple>
|
||||
#include <vector>
|
||||
|
||||
template<typename InputT, typename OutputT>
|
||||
using Testset = std::vector<std::pair<InputT, OutputT>>;
|
||||
|
||||
template<typename T, typename Enable = void>
|
||||
struct EasyFormater {
|
||||
std::string operator()(const T &v) const
|
||||
{
|
||||
return std::string(v.toStdString());
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct EasyFormater<T, typename std::enable_if<std::is_integral<T>::value || std::is_floating_point<T>::value>::type> {
|
||||
std::string operator()(T v) const
|
||||
{
|
||||
return std::to_string(v);
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct EasyFormater<FdoUniqueLabel> {
|
||||
std::string operator()(const FdoUniqueLabel &v) const
|
||||
{
|
||||
return "{" + v.label.toStdString() + ", " + std::to_string(v.copyId) + "}";
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct EasyFormater<EntryLocation> {
|
||||
std::string operator()(const EntryLocation &v) const
|
||||
{
|
||||
return "{" + v.folder.toStdString() + ", " + v.key.toStdString() + "}";
|
||||
}
|
||||
};
|
||||
|
||||
template<bool Reverse>
|
||||
struct TestsetCmpHelper {
|
||||
template<typename F, typename T>
|
||||
bool cmp(F &&function, const T &pair)
|
||||
{
|
||||
return function(pair.first) == pair.second;
|
||||
}
|
||||
template<typename F, typename T>
|
||||
std::string format(F &&function, const T &pair)
|
||||
{
|
||||
using RetT = decltype(function(pair.first));
|
||||
return EasyFormater<typename T::first_type>()(pair.first) + " (evaluates to " + EasyFormater<RetT>()(function(pair.first)) + ") not equal with "
|
||||
+ EasyFormater<typename T::second_type>()(pair.second);
|
||||
}
|
||||
};
|
||||
template<>
|
||||
struct TestsetCmpHelper<true> {
|
||||
template<typename F, typename T>
|
||||
bool cmp(F &&function, const T &pair)
|
||||
{
|
||||
return function(pair.second) == pair.first;
|
||||
}
|
||||
template<typename F, typename T>
|
||||
std::string format(F &&function, const T &pair)
|
||||
{
|
||||
using RetT = decltype(function(pair.second));
|
||||
return EasyFormater<typename T::second_type>()(pair.second) + " (evaluates to " + EasyFormater<RetT>()(function(pair.second)) + ") not equal with "
|
||||
+ EasyFormater<typename T::first_type>()(pair.first);
|
||||
}
|
||||
};
|
||||
|
||||
template<bool Reverse, typename F, typename I, typename O>
|
||||
void runTestsetTmpl(F &&function, const Testset<I, O> &labelMap)
|
||||
{
|
||||
for (auto &pair : labelMap) {
|
||||
bool ok = TestsetCmpHelper<Reverse>().cmp(function, pair);
|
||||
if (!ok) {
|
||||
std::string str = TestsetCmpHelper<Reverse>().format(function, pair);
|
||||
QVERIFY2(ok, str.c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template<typename F, typename I, typename O>
|
||||
void runTestset(F &&function, const Testset<I, O> &labelMap)
|
||||
{
|
||||
return runTestsetTmpl<false>(std::forward<F>(function), labelMap);
|
||||
}
|
||||
|
||||
template<typename F, typename I, typename O>
|
||||
void runRevTestset(F &&function, const Testset<I, O> &labelMap)
|
||||
{
|
||||
return runTestsetTmpl<true>(std::forward<F>(function), labelMap);
|
||||
}
|
||||
|
||||
#endif // __TESTHELPERS_HPP__
|
||||
@@ -0,0 +1,88 @@
|
||||
include(CheckIncludeFiles)
|
||||
include(GenerateExportHeader)
|
||||
|
||||
########### Configure checks for kwalletbackend ###############
|
||||
|
||||
check_include_files(stdint.h HAVE_STDINT_H)
|
||||
check_include_files(sys/bitypes.h HAVE_SYS_BITYPES_H)
|
||||
if (Gpgmepp_FOUND)
|
||||
add_definitions(-DHAVE_GPGMEPP)
|
||||
add_definitions(-DBOOST_NO_EXCEPTIONS)
|
||||
endif(Gpgmepp_FOUND)
|
||||
|
||||
configure_file (config-kwalletbackend.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/config-kwalletbackend.h )
|
||||
|
||||
########### kwalletbackend ###############
|
||||
find_package(Qt6 ${REQUIRED_QT_VERSION} CONFIG REQUIRED Widgets DBus)
|
||||
find_package(KF6CoreAddons ${KF_DEP_VERSION} REQUIRED)
|
||||
find_package(KF6I18n ${KF_DEP_VERSION} REQUIRED)
|
||||
find_package(KF6Notifications ${KF_DEP_VERSION} REQUIRED)
|
||||
find_package(KF6WidgetsAddons ${KF_DEP_VERSION} REQUIRED)
|
||||
find_package(KF6Config ${KF_DEP_VERSION} REQUIRED)
|
||||
|
||||
find_package(LibGcrypt 1.5.0 REQUIRED)
|
||||
set_package_properties(LibGcrypt PROPERTIES
|
||||
TYPE REQUIRED
|
||||
PURPOSE "kwalletd needs libgcrypt to perform PBKDF2-SHA512 hashing"
|
||||
)
|
||||
find_package(Qca-qt6 REQUIRED 2.3.1)
|
||||
|
||||
ecm_setup_version(${KF_VERSION} VARIABLE_PREFIX KWALLETBACKEND SOVERSION 6)
|
||||
|
||||
add_library(KF6WalletBackend SHARED)
|
||||
|
||||
set_target_properties(KF6WalletBackend PROPERTIES
|
||||
VERSION ${KWALLETBACKEND_VERSION}
|
||||
SOVERSION ${KWALLETBACKEND_SOVERSION}
|
||||
)
|
||||
|
||||
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/../../../api/KWallet)
|
||||
include_directories(${CMAKE_CURRENT_BINARY_DIR}/../../../api/KWallet)
|
||||
include_directories(${LIBGCRYPT_INCLUDE_DIRS})
|
||||
|
||||
remove_definitions(-DQT_NO_CAST_FROM_ASCII)
|
||||
|
||||
target_sources(KF6WalletBackend PRIVATE
|
||||
blockcipher.cc
|
||||
blowfish.cc
|
||||
cbc.cc
|
||||
sha1.cc
|
||||
kwalletentry.cc
|
||||
kwalletbackend.cc
|
||||
backendpersisthandler.cpp
|
||||
)
|
||||
ecm_qt_declare_logging_category(KF6WalletBackend
|
||||
HEADER kwalletbackend_debug.h
|
||||
IDENTIFIER KWALLETBACKEND_LOG
|
||||
CATEGORY_NAME kf.wallet.backend
|
||||
OLD_CATEGORY_NAMES kf5.kwallet.kwalletbackend
|
||||
DESCRIPTION "kwalletbackend"
|
||||
EXPORT KWALLET
|
||||
)
|
||||
|
||||
|
||||
generate_export_header(KF6WalletBackend
|
||||
BASE_NAME kwalletbackend
|
||||
)
|
||||
|
||||
target_link_libraries(KF6WalletBackend
|
||||
Qt6::Widgets
|
||||
KF6::WidgetsAddons
|
||||
KF6::CoreAddons
|
||||
KF6::Notifications
|
||||
KF6::I18n
|
||||
${LIBGCRYPT_LIBRARIES}
|
||||
${Qca_LIBRARY}
|
||||
)
|
||||
if(Gpgmepp_FOUND)
|
||||
target_link_libraries(KF6WalletBackend Gpgmepp)
|
||||
endif(Gpgmepp_FOUND)
|
||||
|
||||
# link with advapi32 on windows
|
||||
if(WIN32 AND NOT WINCE)
|
||||
target_link_libraries(KF6WalletBackend advapi32)
|
||||
endif(WIN32 AND NOT WINCE)
|
||||
|
||||
install(TARGETS KF6WalletBackend ${KF_INSTALL_TARGETS_DEFAULT_ARGS} LIBRARY NAMELINK_SKIP)
|
||||
|
||||
add_subdirectory(tests)
|
||||
+763
@@ -0,0 +1,763 @@
|
||||
/*
|
||||
This file is part of the KDE project
|
||||
SPDX-FileCopyrightText: 2013 Valentin Rusu <kde@rusu.info>
|
||||
|
||||
SPDX-License-Identifier: LGPL-2.0-only
|
||||
*/
|
||||
|
||||
#include "backendpersisthandler.h"
|
||||
#include "kwalletbackend_debug.h"
|
||||
|
||||
#include <KLocalizedString>
|
||||
#include <KMessageBox>
|
||||
#include <QCryptographicHash>
|
||||
#include <QFile>
|
||||
#include <QIODevice>
|
||||
#include <QSaveFile>
|
||||
#include <assert.h>
|
||||
#ifdef HAVE_GPGMEPP
|
||||
#include <gpgme++/context.h>
|
||||
#include <gpgme++/data.h>
|
||||
#include <gpgme++/decryptionresult.h>
|
||||
#include <gpgme++/encryptionresult.h>
|
||||
#include <gpgme++/key.h>
|
||||
#include <gpgme++/keylistresult.h>
|
||||
#endif
|
||||
#include "blowfish.h"
|
||||
#include "cbc.h"
|
||||
#include "kwalletbackend.h"
|
||||
#include "sha1.h"
|
||||
|
||||
#ifdef Q_OS_WIN
|
||||
#include <windows.h> // Must be included before wincrypt.h
|
||||
|
||||
#include <wincrypt.h>
|
||||
#endif
|
||||
|
||||
#define KWALLET_CIPHER_BLOWFISH_ECB 0 // this was the old KWALLET_CIPHER_BLOWFISH_CBC
|
||||
#define KWALLET_CIPHER_3DES_CBC 1 // unsupported
|
||||
#define KWALLET_CIPHER_GPG 2
|
||||
#define KWALLET_CIPHER_BLOWFISH_CBC 3
|
||||
|
||||
#define KWALLET_HASH_SHA1 0
|
||||
#define KWALLET_HASH_MD5 1 // unsupported
|
||||
#define KWALLET_HASH_PBKDF2_SHA512 2 // used when using kwallet with pam or since 4.13 version
|
||||
|
||||
namespace KWallet
|
||||
{
|
||||
typedef char Digest[16];
|
||||
|
||||
static int getRandomBlock(QByteArray &randBlock)
|
||||
{
|
||||
#ifdef Q_OS_WIN // krazy:exclude=cpp
|
||||
|
||||
// Use windows crypto API to get randomness on win32
|
||||
// HACK: this should be done using qca
|
||||
HCRYPTPROV hProv;
|
||||
|
||||
if (!CryptAcquireContext(&hProv, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT | CRYPT_SILENT)) {
|
||||
return -1; // couldn't get random data
|
||||
}
|
||||
|
||||
if (!CryptGenRandom(hProv, static_cast<DWORD>(randBlock.size()), (BYTE *)randBlock.data())) {
|
||||
return -3; // read error
|
||||
}
|
||||
|
||||
// release the crypto context
|
||||
CryptReleaseContext(hProv, 0);
|
||||
|
||||
return randBlock.size();
|
||||
|
||||
#else
|
||||
|
||||
// First try /dev/urandom
|
||||
if (QFile::exists(QStringLiteral("/dev/urandom"))) {
|
||||
QFile devrand(QStringLiteral("/dev/urandom"));
|
||||
if (devrand.open(QIODevice::ReadOnly)) {
|
||||
int rc = devrand.read(randBlock.data(), randBlock.size());
|
||||
|
||||
if (rc != randBlock.size()) {
|
||||
return -3; // not enough data read
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
// If that failed, try /dev/random
|
||||
// FIXME: open in noblocking mode!
|
||||
if (QFile::exists(QStringLiteral("/dev/random"))) {
|
||||
QFile devrand(QStringLiteral("/dev/random"));
|
||||
if (devrand.open(QIODevice::ReadOnly)) {
|
||||
int rc = 0;
|
||||
int cnt = 0;
|
||||
|
||||
do {
|
||||
int rc2 = devrand.read(randBlock.data() + rc, randBlock.size());
|
||||
|
||||
if (rc2 < 0) {
|
||||
return -3; // read error
|
||||
}
|
||||
|
||||
rc += rc2;
|
||||
cnt++;
|
||||
if (cnt > randBlock.size()) {
|
||||
return -4; // reading forever?!
|
||||
}
|
||||
} while (rc < randBlock.size());
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
// EGD method
|
||||
QString randFilename = QString::fromLocal8Bit(qgetenv("RANDFILE"));
|
||||
if (!randFilename.isEmpty()) {
|
||||
if (QFile::exists(randFilename)) {
|
||||
QFile devrand(randFilename);
|
||||
if (devrand.open(QIODevice::ReadOnly)) {
|
||||
int rc = devrand.read(randBlock.data(), randBlock.size());
|
||||
if (rc != randBlock.size()) {
|
||||
return -3; // not enough data read
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Couldn't get any random data!!
|
||||
return -1;
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
BackendPersistHandler *BackendPersistHandler::getPersistHandler(BackendCipherType cipherType)
|
||||
{
|
||||
switch (cipherType) {
|
||||
case BACKEND_CIPHER_BLOWFISH:
|
||||
return new BlowfishPersistHandler;
|
||||
#ifdef HAVE_GPGMEPP
|
||||
case BACKEND_CIPHER_GPG:
|
||||
return new GpgPersistHandler;
|
||||
#endif // HAVE_GPGMEPP
|
||||
default:
|
||||
Q_ASSERT(0);
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
BackendPersistHandler *BackendPersistHandler::getPersistHandler(char magicBuf[12])
|
||||
{
|
||||
if ((magicBuf[2] == KWALLET_CIPHER_BLOWFISH_ECB || magicBuf[2] == KWALLET_CIPHER_BLOWFISH_CBC)
|
||||
&& (magicBuf[3] == KWALLET_HASH_SHA1 || magicBuf[3] == KWALLET_HASH_PBKDF2_SHA512)) {
|
||||
bool useECBforReading = magicBuf[2] == KWALLET_CIPHER_BLOWFISH_ECB;
|
||||
if (useECBforReading) {
|
||||
qCDebug(KWALLETBACKEND_LOG) << "this wallet uses ECB encryption. It'll be converted to CBC on next save.";
|
||||
}
|
||||
return new BlowfishPersistHandler(useECBforReading);
|
||||
}
|
||||
#ifdef HAVE_GPGMEPP
|
||||
if (magicBuf[2] == KWALLET_CIPHER_GPG && magicBuf[3] == 0) {
|
||||
return new GpgPersistHandler;
|
||||
}
|
||||
#endif // HAVE_GPGMEPP
|
||||
return nullptr; // unknown cipher or hash
|
||||
}
|
||||
|
||||
int BlowfishPersistHandler::write(Backend *wb, QSaveFile &sf, QByteArray &version, WId)
|
||||
{
|
||||
assert(wb->_cipherType == BACKEND_CIPHER_BLOWFISH);
|
||||
|
||||
if (_useECBforReading) {
|
||||
qCDebug(KWALLETBACKEND_LOG) << "This wallet used ECB and is now saved using CBC";
|
||||
_useECBforReading = false;
|
||||
}
|
||||
|
||||
version[2] = KWALLET_CIPHER_BLOWFISH_CBC;
|
||||
if (!wb->_useNewHash) {
|
||||
version[3] = KWALLET_HASH_SHA1;
|
||||
} else {
|
||||
version[3] = KWALLET_HASH_PBKDF2_SHA512; // Since 4.13 we always use PBKDF2_SHA512
|
||||
}
|
||||
|
||||
if (sf.write(version) != 4) {
|
||||
sf.cancelWriting();
|
||||
return -4; // write error
|
||||
}
|
||||
|
||||
// Holds the hashes we write out
|
||||
QByteArray hashes;
|
||||
QDataStream hashStream(&hashes, QIODevice::WriteOnly);
|
||||
QCryptographicHash md5(QCryptographicHash::Md5);
|
||||
hashStream << static_cast<quint32>(wb->_entries.count());
|
||||
|
||||
// Holds decrypted data prior to encryption
|
||||
QByteArray decrypted;
|
||||
|
||||
// FIXME: we should estimate the amount of data we will write in each
|
||||
// buffer and resize them approximately in order to avoid extra
|
||||
// resizes.
|
||||
|
||||
// populate decrypted
|
||||
QDataStream dStream(&decrypted, QIODevice::WriteOnly);
|
||||
for (Backend::FolderMap::ConstIterator i = wb->_entries.constBegin(); i != wb->_entries.constEnd(); ++i) {
|
||||
dStream << i.key();
|
||||
dStream << static_cast<quint32>(i.value().count());
|
||||
|
||||
md5.reset();
|
||||
md5.addData(i.key().toUtf8());
|
||||
hashStream.writeRawData(md5.result().constData(), 16);
|
||||
hashStream << static_cast<quint32>(i.value().count());
|
||||
|
||||
for (Backend::EntryMap::ConstIterator j = i.value().constBegin(); j != i.value().constEnd(); ++j) {
|
||||
dStream << j.key();
|
||||
dStream << static_cast<qint32>(j.value()->type());
|
||||
dStream << j.value()->value();
|
||||
|
||||
md5.reset();
|
||||
md5.addData(j.key().toUtf8());
|
||||
hashStream.writeRawData(md5.result().constData(), 16);
|
||||
}
|
||||
}
|
||||
|
||||
if (sf.write(hashes) != hashes.size()) {
|
||||
sf.cancelWriting();
|
||||
return -4; // write error
|
||||
}
|
||||
|
||||
// calculate the hash of the file
|
||||
SHA1 sha;
|
||||
BlowFish _bf;
|
||||
CipherBlockChain bf(&_bf);
|
||||
|
||||
sha.process(decrypted.data(), decrypted.size());
|
||||
|
||||
// prepend and append the random data
|
||||
QByteArray wholeFile;
|
||||
long blksz = bf.blockSize();
|
||||
long newsize = decrypted.size() + blksz + // encrypted block
|
||||
4 + // file size
|
||||
20; // size of the SHA hash
|
||||
|
||||
int delta = (blksz - (newsize % blksz));
|
||||
newsize += delta;
|
||||
wholeFile.resize(newsize);
|
||||
|
||||
QByteArray randBlock;
|
||||
randBlock.resize(blksz + delta);
|
||||
if (getRandomBlock(randBlock) < 0) {
|
||||
sha.reset();
|
||||
decrypted.fill(0);
|
||||
sf.cancelWriting();
|
||||
return -3; // Fatal error: can't get random
|
||||
}
|
||||
|
||||
for (int i = 0; i < blksz; i++) {
|
||||
wholeFile[i] = randBlock[i];
|
||||
}
|
||||
|
||||
for (int i = 0; i < 4; i++) {
|
||||
wholeFile[(int)(i + blksz)] = (decrypted.size() >> 8 * (3 - i)) & 0xff;
|
||||
}
|
||||
|
||||
for (int i = 0; i < decrypted.size(); i++) {
|
||||
wholeFile[(int)(i + blksz + 4)] = decrypted[i];
|
||||
}
|
||||
|
||||
for (int i = 0; i < delta; i++) {
|
||||
wholeFile[(int)(i + blksz + 4 + decrypted.size())] = randBlock[(int)(i + blksz)];
|
||||
}
|
||||
|
||||
const char *hash = (const char *)sha.hash();
|
||||
for (int i = 0; i < 20; i++) {
|
||||
wholeFile[(int)(newsize - 20 + i)] = hash[i];
|
||||
}
|
||||
|
||||
sha.reset();
|
||||
decrypted.fill(0);
|
||||
|
||||
// encrypt the data
|
||||
if (!bf.setKey(wb->_passhash.data(), wb->_passhash.size() * 8)) {
|
||||
wholeFile.fill(0);
|
||||
sf.cancelWriting();
|
||||
return -2; // encrypt error
|
||||
}
|
||||
|
||||
int rc = bf.encrypt(wholeFile.data(), wholeFile.size());
|
||||
if (rc < 0) {
|
||||
wholeFile.fill(0);
|
||||
sf.cancelWriting();
|
||||
return -2; // encrypt error
|
||||
}
|
||||
|
||||
// write the file
|
||||
auto written = sf.write(wholeFile);
|
||||
if (written != wholeFile.size()) {
|
||||
wholeFile.fill(0);
|
||||
sf.cancelWriting();
|
||||
return -4; // write error
|
||||
}
|
||||
if (!sf.commit()) {
|
||||
qCDebug(KWALLETBACKEND_LOG) << "WARNING: wallet sync to disk failed! QSaveFile status was " << sf.errorString();
|
||||
wholeFile.fill(0);
|
||||
return -4; // write error
|
||||
}
|
||||
|
||||
wholeFile.fill(0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int BlowfishPersistHandler::read(Backend *wb, QFile &db, WId)
|
||||
{
|
||||
wb->_cipherType = BACKEND_CIPHER_BLOWFISH;
|
||||
wb->_hashes.clear();
|
||||
// Read in the hashes
|
||||
QDataStream hds(&db);
|
||||
quint32 n;
|
||||
hds >> n;
|
||||
if (n > 0xffff) { // sanity check
|
||||
return -43;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < n; ++i) {
|
||||
Digest d;
|
||||
Digest d2; // judgment day
|
||||
MD5Digest ba;
|
||||
QMap<MD5Digest, QList<MD5Digest>>::iterator it;
|
||||
quint32 fsz;
|
||||
if (hds.atEnd()) {
|
||||
return -43;
|
||||
}
|
||||
hds.readRawData(d, 16);
|
||||
hds >> fsz;
|
||||
ba = MD5Digest(reinterpret_cast<char *>(d));
|
||||
it = wb->_hashes.insert(ba, QList<MD5Digest>());
|
||||
for (size_t j = 0; j < fsz; ++j) {
|
||||
hds.readRawData(d2, 16);
|
||||
ba = MD5Digest(d2);
|
||||
(*it).append(ba);
|
||||
}
|
||||
}
|
||||
|
||||
// Read in the rest of the file.
|
||||
QByteArray encrypted = db.readAll();
|
||||
assert(encrypted.size() < db.size());
|
||||
|
||||
BlowFish _bf;
|
||||
CipherBlockChain bf(&_bf, _useECBforReading);
|
||||
int blksz = bf.blockSize();
|
||||
if ((encrypted.size() % blksz) != 0) {
|
||||
return -5; // invalid file structure
|
||||
}
|
||||
|
||||
bf.setKey((void *)wb->_passhash.data(), wb->_passhash.size() * 8);
|
||||
|
||||
if (!encrypted.data()) {
|
||||
wb->_passhash.fill(0);
|
||||
encrypted.fill(0);
|
||||
return -7; // file structure error
|
||||
}
|
||||
|
||||
int rc = bf.decrypt(encrypted.data(), encrypted.size());
|
||||
if (rc < 0) {
|
||||
wb->_passhash.fill(0);
|
||||
encrypted.fill(0);
|
||||
return -6; // decrypt error
|
||||
}
|
||||
|
||||
const char *t = encrypted.data();
|
||||
|
||||
// strip the leading data
|
||||
t += blksz; // one block of random data
|
||||
|
||||
// strip the file size off
|
||||
long fsize = 0;
|
||||
|
||||
fsize |= (long(*t) << 24) & 0xff000000;
|
||||
t++;
|
||||
fsize |= (long(*t) << 16) & 0x00ff0000;
|
||||
t++;
|
||||
fsize |= (long(*t) << 8) & 0x0000ff00;
|
||||
t++;
|
||||
fsize |= long(*t) & 0x000000ff;
|
||||
t++;
|
||||
|
||||
if (fsize < 0 || fsize > long(encrypted.size()) - blksz - 4) {
|
||||
qCDebug(KWALLETBACKEND_LOG) << "fsize: " << fsize << " encrypted.size(): " << encrypted.size() << " blksz: " << blksz;
|
||||
encrypted.fill(0);
|
||||
return -9; // file structure error.
|
||||
}
|
||||
|
||||
// compute the hash ourself
|
||||
SHA1 sha;
|
||||
sha.process(t, fsize);
|
||||
const char *testhash = (const char *)sha.hash();
|
||||
|
||||
// compare hashes
|
||||
int sz = encrypted.size();
|
||||
for (int i = 0; i < 20; i++) {
|
||||
if (testhash[i] != encrypted[sz - 20 + i]) {
|
||||
encrypted.fill(0);
|
||||
sha.reset();
|
||||
return -8; // hash error.
|
||||
}
|
||||
}
|
||||
|
||||
sha.reset();
|
||||
|
||||
// chop off the leading blksz+4 bytes
|
||||
QByteArray tmpenc(encrypted.data() + blksz + 4, fsize);
|
||||
encrypted = tmpenc;
|
||||
tmpenc.fill(0);
|
||||
|
||||
// Load the data structures up
|
||||
QDataStream eStream(encrypted);
|
||||
|
||||
while (!eStream.atEnd()) {
|
||||
QString folder;
|
||||
quint32 n;
|
||||
|
||||
eStream >> folder;
|
||||
eStream >> n;
|
||||
|
||||
// Force initialisation
|
||||
wb->_entries[folder].clear();
|
||||
|
||||
for (size_t i = 0; i < n; ++i) {
|
||||
QString key;
|
||||
KWallet::Wallet::EntryType et = KWallet::Wallet::Unknown;
|
||||
Entry *e = new Entry;
|
||||
eStream >> key;
|
||||
qint32 x = 0; // necessary to read properly
|
||||
eStream >> x;
|
||||
et = static_cast<KWallet::Wallet::EntryType>(x);
|
||||
|
||||
switch (et) {
|
||||
case KWallet::Wallet::Password:
|
||||
case KWallet::Wallet::Stream:
|
||||
case KWallet::Wallet::Map:
|
||||
break;
|
||||
default: // Unknown entry
|
||||
delete e;
|
||||
continue;
|
||||
}
|
||||
|
||||
QByteArray a;
|
||||
eStream >> a;
|
||||
e->setValue(a);
|
||||
e->setType(et);
|
||||
e->setKey(key);
|
||||
wb->_entries[folder][key] = e;
|
||||
}
|
||||
}
|
||||
|
||||
wb->_open = true;
|
||||
encrypted.fill(0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef HAVE_GPGMEPP
|
||||
GpgME::Error initGpgME()
|
||||
{
|
||||
GpgME::Error err;
|
||||
static bool alreadyInitialized = false;
|
||||
if (!alreadyInitialized) {
|
||||
GpgME::initializeLibrary();
|
||||
err = GpgME::checkEngine(GpgME::OpenPGP);
|
||||
if (err) {
|
||||
qCDebug(KWALLETBACKEND_LOG) << "OpenPGP not supported!";
|
||||
}
|
||||
alreadyInitialized = true;
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
int GpgPersistHandler::write(Backend *wb, QSaveFile &sf, QByteArray &version, WId w)
|
||||
{
|
||||
version[2] = KWALLET_CIPHER_GPG;
|
||||
version[3] = 0;
|
||||
if (sf.write(version) != 4) {
|
||||
sf.cancelWriting();
|
||||
return -4; // write error
|
||||
}
|
||||
|
||||
GpgME::Error err = initGpgME();
|
||||
if (err) {
|
||||
qCDebug(KWALLETBACKEND_LOG) << "initGpgME returned " << err.code();
|
||||
KMessageBox::errorWId(w,
|
||||
i18n("<qt>Error when attempting to initialize OpenPGP while attempting to save the wallet <b>%1</b>. Error code is <b>%2</b>. "
|
||||
"Please fix your system configuration, then try again.</qt>",
|
||||
wb->_name.toHtmlEscaped(),
|
||||
err.code()));
|
||||
sf.cancelWriting();
|
||||
return -5;
|
||||
}
|
||||
|
||||
std::shared_ptr<GpgME::Context> ctx(GpgME::Context::createForProtocol(GpgME::OpenPGP));
|
||||
if (!ctx) {
|
||||
qCDebug(KWALLETBACKEND_LOG) << "Cannot setup OpenPGP context!";
|
||||
KMessageBox::errorWId(w,
|
||||
i18n("<qt>Error when attempting to initialize OpenPGP while attempting to save the wallet <b>%1</b>. Please fix your system "
|
||||
"configuration, then try again.</qt>"),
|
||||
wb->_name.toHtmlEscaped());
|
||||
return -6;
|
||||
}
|
||||
|
||||
assert(wb->_cipherType == BACKEND_CIPHER_GPG);
|
||||
|
||||
QByteArray hashes;
|
||||
QDataStream hashStream(&hashes, QIODevice::WriteOnly);
|
||||
QCryptographicHash md5(QCryptographicHash::Md5);
|
||||
hashStream << static_cast<quint32>(wb->_entries.count());
|
||||
|
||||
QByteArray values;
|
||||
QDataStream valueStream(&values, QIODevice::WriteOnly);
|
||||
Backend::FolderMap::ConstIterator i = wb->_entries.constBegin();
|
||||
Backend::FolderMap::ConstIterator ie = wb->_entries.constEnd();
|
||||
for (; i != ie; ++i) {
|
||||
valueStream << i.key();
|
||||
valueStream << static_cast<quint32>(i.value().count());
|
||||
|
||||
md5.reset();
|
||||
md5.addData(i.key().toUtf8());
|
||||
hashStream.writeRawData(md5.result().constData(), 16);
|
||||
hashStream << static_cast<quint32>(i.value().count());
|
||||
|
||||
Backend::EntryMap::ConstIterator j = i.value().constBegin();
|
||||
Backend::EntryMap::ConstIterator je = i.value().constEnd();
|
||||
for (; j != je; ++j) {
|
||||
valueStream << j.key();
|
||||
valueStream << static_cast<qint32>(j.value()->type());
|
||||
valueStream << j.value()->value();
|
||||
|
||||
md5.reset();
|
||||
md5.addData(j.key().toUtf8());
|
||||
hashStream.writeRawData(md5.result().constData(), 16);
|
||||
}
|
||||
}
|
||||
|
||||
QByteArray dataBuffer;
|
||||
QDataStream dataStream(&dataBuffer, QIODevice::WriteOnly);
|
||||
QString keyID(wb->_gpgKey.keyID());
|
||||
dataStream << keyID;
|
||||
dataStream << hashes;
|
||||
dataStream << values;
|
||||
|
||||
GpgME::Data decryptedData(dataBuffer.data(), size_t(dataBuffer.size()), false);
|
||||
GpgME::Data encryptedData;
|
||||
std::vector<GpgME::Key> keys;
|
||||
keys.push_back(wb->_gpgKey);
|
||||
const GpgME::EncryptionResult res = ctx->encrypt(keys, decryptedData, encryptedData, GpgME::Context::None);
|
||||
if (res.error()) {
|
||||
const int gpgerr = res.error().code();
|
||||
KMessageBox::errorWId(w,
|
||||
i18n("<qt>Encryption error while attempting to save the wallet <b>%1</b>. Error code is <b>%2 (%3)</b>. Please fix your system "
|
||||
"configuration, then try again. This error may occur if you are not using a full trust GPG key. Please ensure you have the "
|
||||
"secret key for the key you are using.</qt>",
|
||||
wb->_name.toHtmlEscaped(),
|
||||
gpgerr,
|
||||
res.error().asString()));
|
||||
qCDebug(KWALLETBACKEND_LOG) << "GpgME encryption error: " << gpgerr;
|
||||
sf.cancelWriting();
|
||||
return -7;
|
||||
}
|
||||
|
||||
char buffer[4096];
|
||||
ssize_t bytes = 0;
|
||||
encryptedData.seek(0, SEEK_SET);
|
||||
while ((bytes = encryptedData.read(buffer, sizeof(buffer) / sizeof(buffer[0]))) > 0) {
|
||||
if (sf.write(buffer, bytes) != bytes) {
|
||||
KMessageBox::errorWId(w,
|
||||
i18n("<qt>File handling error while attempting to save the wallet <b>%1</b>. Error was <b>%2</b>. Please fix your system "
|
||||
"configuration, then try again.</qt>",
|
||||
wb->_name.toHtmlEscaped(),
|
||||
sf.errorString()));
|
||||
sf.cancelWriting();
|
||||
return -4; // write error
|
||||
}
|
||||
}
|
||||
|
||||
if (!sf.commit()) {
|
||||
qCDebug(KWALLETBACKEND_LOG) << "WARNING: wallet sync to disk failed! QSaveFile status was " << sf.errorString();
|
||||
return -4; // write error
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int GpgPersistHandler::read(Backend *wb, QFile &sf, WId w)
|
||||
{
|
||||
GpgME::Error err = initGpgME();
|
||||
if (err) {
|
||||
KMessageBox::errorWId(w,
|
||||
i18n("<qt>Error when attempting to initialize OpenPGP while attempting to open the wallet <b>%1</b>. Error code is <b>%2</b>. "
|
||||
"Please fix your system configuration, then try again.</qt>",
|
||||
wb->_name.toHtmlEscaped(),
|
||||
err.code()));
|
||||
return -1;
|
||||
}
|
||||
|
||||
wb->_cipherType = BACKEND_CIPHER_GPG;
|
||||
wb->_hashes.clear();
|
||||
|
||||
// the remainder of the file is GPG encrypted. Let's decrypt it
|
||||
GpgME::Data encryptedData;
|
||||
char buffer[4096];
|
||||
ssize_t bytes = 0;
|
||||
while ((bytes = sf.read(buffer, sizeof(buffer) / sizeof(buffer[0])))) {
|
||||
encryptedData.write(buffer, bytes);
|
||||
}
|
||||
|
||||
retry_label:
|
||||
std::shared_ptr<GpgME::Context> ctx(GpgME::Context::createForProtocol(GpgME::OpenPGP));
|
||||
if (nullptr == ctx) {
|
||||
KMessageBox::errorWId(w,
|
||||
i18n("<qt>Error when attempting to initialize OpenPGP while attempting to open the wallet <b>%1</b>. Please fix your system "
|
||||
"configuration, then try again.</qt>",
|
||||
wb->_name.toHtmlEscaped()));
|
||||
qCDebug(KWALLETBACKEND_LOG) << "Cannot setup OpenPGP context!";
|
||||
return -1;
|
||||
}
|
||||
|
||||
GpgME::Data decryptedData;
|
||||
encryptedData.seek(0, SEEK_SET);
|
||||
GpgME::DecryptionResult res = ctx->decrypt(encryptedData, decryptedData);
|
||||
if (res.error()) {
|
||||
qCDebug(KWALLETBACKEND_LOG) << "Error decrypting message: " << res.error().asString() << ", code " << res.error().code() << ", source "
|
||||
<< res.error().source();
|
||||
KGuiItem btnRetry(i18n("Retry"));
|
||||
// FIXME the logic here should be a little more elaborate; a dialog box should be used with "retry", "cancel", but also "troubleshoot" with options to
|
||||
// show card status and to kill scdaemon
|
||||
int userChoice =
|
||||
KMessageBox::warningTwoActionsWId(w,
|
||||
i18n("<qt>Error when attempting to decrypt the wallet <b>%1</b> using GPG. If you're using a SmartCard, "
|
||||
"please ensure it's inserted then try again.<br><br>GPG error was <b>%2</b></qt>",
|
||||
wb->_name.toHtmlEscaped(),
|
||||
res.error().asString()),
|
||||
i18n("kwalletd GPG backend"),
|
||||
btnRetry,
|
||||
KStandardGuiItem::cancel());
|
||||
if (userChoice == KMessageBox::PrimaryAction) {
|
||||
decryptedData.seek(0, SEEK_SET);
|
||||
goto retry_label;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
decryptedData.seek(0, SEEK_SET);
|
||||
QByteArray dataBuffer;
|
||||
while ((bytes = decryptedData.read(buffer, sizeof(buffer) / sizeof(buffer[0])))) {
|
||||
dataBuffer.append(buffer, bytes);
|
||||
}
|
||||
|
||||
// load the wallet from the decrypted data
|
||||
QDataStream dataStream(dataBuffer);
|
||||
QString keyID;
|
||||
QByteArray hashes;
|
||||
QByteArray values;
|
||||
dataStream >> keyID;
|
||||
dataStream >> hashes;
|
||||
dataStream >> values;
|
||||
|
||||
// locate the GPG key having the ID found inside the file. This will be needed later, when writing changes to disk.
|
||||
QDataStream fileStream(&sf);
|
||||
fileStream.setDevice(nullptr);
|
||||
qCDebug(KWALLETBACKEND_LOG) << "This wallet was encrypted using GPG key with ID " << keyID;
|
||||
|
||||
ctx->setKeyListMode(GpgME::KeyListMode::Local);
|
||||
err = ctx->startKeyListing();
|
||||
while (!err) {
|
||||
GpgME::Key k = ctx->nextKey(err);
|
||||
if (err) {
|
||||
break;
|
||||
}
|
||||
if (keyID == k.keyID()) {
|
||||
qCDebug(KWALLETBACKEND_LOG) << "The key was found.";
|
||||
wb->_gpgKey = k;
|
||||
break;
|
||||
}
|
||||
}
|
||||
ctx->endKeyListing();
|
||||
if (wb->_gpgKey.isNull()) {
|
||||
KMessageBox::errorWId(w,
|
||||
i18n("<qt>Error when attempting to open the wallet <b>%1</b>. The wallet was encrypted using the GPG Key ID <b>%2</b> but this "
|
||||
"key was not found on your system.</qt>",
|
||||
wb->_name.toHtmlEscaped(),
|
||||
keyID));
|
||||
return -1;
|
||||
}
|
||||
|
||||
QDataStream hashStream(hashes);
|
||||
QDataStream valueStream(values);
|
||||
|
||||
quint32 hashCount;
|
||||
hashStream >> hashCount;
|
||||
if (hashCount > 0xFFFF) {
|
||||
return -43;
|
||||
}
|
||||
|
||||
quint32 folderCount = hashCount;
|
||||
while (hashCount--) {
|
||||
Digest d;
|
||||
hashStream.readRawData(d, 16);
|
||||
|
||||
quint32 folderSize;
|
||||
hashStream >> folderSize;
|
||||
|
||||
MD5Digest ba = MD5Digest(reinterpret_cast<char *>(d));
|
||||
QMap<MD5Digest, QList<MD5Digest>>::iterator it = wb->_hashes.insert(ba, QList<MD5Digest>());
|
||||
while (folderSize--) {
|
||||
Digest d2;
|
||||
hashStream.readRawData(d2, 16);
|
||||
ba = MD5Digest(d2);
|
||||
(*it).append(ba);
|
||||
}
|
||||
}
|
||||
|
||||
while (folderCount--) {
|
||||
QString folder;
|
||||
valueStream >> folder;
|
||||
|
||||
quint32 entryCount;
|
||||
valueStream >> entryCount;
|
||||
|
||||
wb->_entries[folder].clear();
|
||||
|
||||
while (entryCount--) {
|
||||
KWallet::Wallet::EntryType et = KWallet::Wallet::Unknown;
|
||||
Entry *e = new Entry;
|
||||
|
||||
QString key;
|
||||
valueStream >> key;
|
||||
|
||||
qint32 x = 0; // necessary to read properly
|
||||
valueStream >> x;
|
||||
et = static_cast<KWallet::Wallet::EntryType>(x);
|
||||
|
||||
switch (et) {
|
||||
case KWallet::Wallet::Password:
|
||||
case KWallet::Wallet::Stream:
|
||||
case KWallet::Wallet::Map:
|
||||
break;
|
||||
default: // Unknown entry
|
||||
delete e;
|
||||
continue;
|
||||
}
|
||||
|
||||
QByteArray a;
|
||||
valueStream >> a;
|
||||
e->setValue(a);
|
||||
e->setType(et);
|
||||
e->setKey(key);
|
||||
wb->_entries[folder][key] = e;
|
||||
}
|
||||
}
|
||||
|
||||
wb->_open = true;
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif // HAVE_GPGMEPP
|
||||
|
||||
} // namespace
|
||||
+90
@@ -0,0 +1,90 @@
|
||||
/*
|
||||
This file is part of the KDE project
|
||||
SPDX-FileCopyrightText: 2013 Valentin Rusu <kde@rusu.info>
|
||||
|
||||
SPDX-License-Identifier: LGPL-2.0-only
|
||||
*/
|
||||
|
||||
#ifndef BACKENDPERSISTHANDLER_H
|
||||
#define BACKENDPERSISTHANDLER_H
|
||||
|
||||
#define KWMAGIC_LEN 12
|
||||
|
||||
#include <qwindowdefs.h>
|
||||
|
||||
class QFile;
|
||||
class QSaveFile;
|
||||
namespace KWallet
|
||||
{
|
||||
class Backend;
|
||||
|
||||
enum BackendCipherType {
|
||||
BACKEND_CIPHER_UNKNOWN, /// this is used by freshly allocated wallets
|
||||
BACKEND_CIPHER_BLOWFISH, /// use the legacy blowfish cipher type
|
||||
#ifdef HAVE_GPGMEPP
|
||||
BACKEND_CIPHER_GPG, /// use GPG backend to encrypt wallet contents
|
||||
#endif // HAVE_GPGMEPP
|
||||
};
|
||||
|
||||
class BackendPersistHandler
|
||||
{
|
||||
protected:
|
||||
BackendPersistHandler()
|
||||
{
|
||||
}
|
||||
|
||||
public:
|
||||
virtual ~BackendPersistHandler()
|
||||
{
|
||||
}
|
||||
/**
|
||||
* This is a factory method used to get an instance of the backend suitable
|
||||
* for reading/writing using the given cipher type
|
||||
*
|
||||
* @param cipherType indication of the backend that should be returned
|
||||
* @return a pointer to an instance of the requested handler type. No need to delete this pointer, it's lifetime is taken care of by this factory
|
||||
*/
|
||||
static BackendPersistHandler *getPersistHandler(BackendCipherType cipherType);
|
||||
static BackendPersistHandler *getPersistHandler(char magicBuf[KWMAGIC_LEN]);
|
||||
|
||||
virtual int write(Backend *wb, QSaveFile &sf, QByteArray &version, WId w) = 0;
|
||||
virtual int read(Backend *wb, QFile &sf, WId w) = 0;
|
||||
};
|
||||
|
||||
class BlowfishPersistHandler : public BackendPersistHandler
|
||||
{
|
||||
public:
|
||||
explicit BlowfishPersistHandler(bool useECBforReading = false)
|
||||
: _useECBforReading(useECBforReading)
|
||||
{
|
||||
}
|
||||
~BlowfishPersistHandler() override
|
||||
{
|
||||
}
|
||||
|
||||
int write(Backend *wb, QSaveFile &sf, QByteArray &version, WId w) override;
|
||||
int read(Backend *wb, QFile &sf, WId w) override;
|
||||
|
||||
private:
|
||||
bool _useECBforReading;
|
||||
};
|
||||
|
||||
#ifdef HAVE_GPGMEPP
|
||||
class GpgPersistHandler : public BackendPersistHandler
|
||||
{
|
||||
public:
|
||||
GpgPersistHandler()
|
||||
{
|
||||
}
|
||||
~GpgPersistHandler() override
|
||||
{
|
||||
}
|
||||
|
||||
int write(Backend *wb, QSaveFile &sf, QByteArray &version, WId w) override;
|
||||
int read(Backend *wb, QFile &sf, WId w) override;
|
||||
};
|
||||
#endif // HAVE_GPGMEPP
|
||||
|
||||
} // namespace
|
||||
|
||||
#endif // BACKENDPERSISTHANDLER_H
|
||||
@@ -0,0 +1,23 @@
|
||||
/*
|
||||
This file is part of the KDE project
|
||||
SPDX-FileCopyrightText: 2001 George Staikos <staikos@kde.org>
|
||||
|
||||
SPDX-License-Identifier: LGPL-2.0-or-later
|
||||
*/
|
||||
|
||||
#include "blockcipher.h"
|
||||
|
||||
BlockCipher::BlockCipher()
|
||||
{
|
||||
_blksz = -1;
|
||||
}
|
||||
|
||||
BlockCipher::~BlockCipher()
|
||||
{
|
||||
}
|
||||
|
||||
int BlockCipher::blockSize() const
|
||||
{
|
||||
return _blksz;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
This file is part of the KDE project
|
||||
SPDX-FileCopyrightText: 2001 George Staikos <staikos@kde.org>
|
||||
|
||||
SPDX-License-Identifier: LGPL-2.0-or-later
|
||||
*/
|
||||
|
||||
#ifndef BLOCKCIPHER_H
|
||||
#define BLOCKCIPHER_H
|
||||
|
||||
#include "kwalletbackend_export.h"
|
||||
|
||||
/* @internal
|
||||
*/
|
||||
class KWALLETBACKEND_EXPORT BlockCipher
|
||||
{
|
||||
public:
|
||||
BlockCipher();
|
||||
virtual ~BlockCipher();
|
||||
|
||||
/*
|
||||
* Return the current blocksize in bytes.
|
||||
*/
|
||||
int blockSize() const;
|
||||
|
||||
/*
|
||||
* Set the encryption key to key. Return true on success.
|
||||
*/
|
||||
virtual bool setKey(void *key, int bitlength) = 0;
|
||||
|
||||
/*
|
||||
* Get the required (or if it's variable, then the maximum) key
|
||||
* length for this cipher in bits.
|
||||
*/
|
||||
virtual int keyLen() const = 0;
|
||||
|
||||
/*
|
||||
* True if the key is of a variable length. In this case,
|
||||
* getKeyLen() will return the maximum length.
|
||||
*/
|
||||
virtual bool variableKeyLen() const = 0;
|
||||
|
||||
/*
|
||||
* True if all settings are good and we are ready to encrypt.
|
||||
*/
|
||||
virtual bool readyToGo() const = 0;
|
||||
|
||||
/*
|
||||
* Encrypt the block. Returns the number of bytes successfully
|
||||
* encrypted. Can return -1 on error.
|
||||
*/
|
||||
virtual int encrypt(void *block, int len) = 0;
|
||||
|
||||
/*
|
||||
* Decrypt the block. Returns as does encrypt();
|
||||
*/
|
||||
virtual int decrypt(void *block, int len) = 0;
|
||||
|
||||
protected:
|
||||
int _blksz;
|
||||
int _keylen; // in bits
|
||||
};
|
||||
|
||||
#endif // BLOCKCIPHER_H
|
||||
@@ -0,0 +1,255 @@
|
||||
/*
|
||||
This file is part of the KDE project
|
||||
SPDX-FileCopyrightText: 2001 George Staikos <staikos@kde.org>
|
||||
|
||||
SPDX-License-Identifier: LGPL-2.0-or-later
|
||||
*/
|
||||
|
||||
// FIXME: should we unroll some loops? Optimization can be done here.
|
||||
|
||||
/* Implementation of 16 rounds blowfish as described in:
|
||||
* _Applied_Cryptography_ (c) Bruce Schneier, 1996.
|
||||
*/
|
||||
|
||||
#include "blowfish.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "blowfishtables.h"
|
||||
|
||||
// DO NOT INCLUDE THIS. IT BREAKS KWALLET.
|
||||
// We need to live with -Wundef until someone really figures out the problem.
|
||||
//#include <QtCore/qglobal.h> // for Q_BYTE_ORDER and friends
|
||||
// Workaround for -Wundef
|
||||
#define Q_BIG_ENDIAN 1
|
||||
#define Q_BYTE_ORDER Q_BIG_ENDIAN
|
||||
|
||||
BlowFish::BlowFish()
|
||||
{
|
||||
_blksz = 8;
|
||||
m_key = nullptr;
|
||||
m_initialized = false;
|
||||
}
|
||||
|
||||
bool BlowFish::init()
|
||||
{
|
||||
// Initialize the sboxes
|
||||
for (int i = 0; i < 256; i++) {
|
||||
m_S[0][i] = ks0[i];
|
||||
m_S[1][i] = ks1[i];
|
||||
m_S[2][i] = ks2[i];
|
||||
m_S[3][i] = ks3[i];
|
||||
}
|
||||
|
||||
uint32_t datal = 0;
|
||||
uint32_t datar = 0;
|
||||
uint32_t data = 0;
|
||||
int j = 0;
|
||||
|
||||
// Update the sboxes and pbox.
|
||||
for (int i = 0; i < 18; i++) {
|
||||
data = 0;
|
||||
for (int k = 0; k < 4; ++k) {
|
||||
data = (data << 8) | ((unsigned char *)m_key)[j++];
|
||||
if (j >= m_keylen / 8) {
|
||||
j = 0;
|
||||
}
|
||||
}
|
||||
m_P[i] = P[i] ^ data;
|
||||
}
|
||||
|
||||
for (int i = 0; i < 18; i += 2) {
|
||||
encipher(&datal, &datar);
|
||||
m_P[i] = datal;
|
||||
m_P[i + 1] = datar;
|
||||
}
|
||||
|
||||
for (int j = 0; j < 4; j++) {
|
||||
for (int i = 0; i < 256; i += 2) {
|
||||
encipher(&datal, &datar);
|
||||
m_S[j][i] = datal;
|
||||
m_S[j][i + 1] = datar;
|
||||
}
|
||||
}
|
||||
|
||||
// Nice code from gpg's implementation...
|
||||
// check to see if the key is weak and return error if so
|
||||
for (int i = 0; i < 255; i++) {
|
||||
for (int j = i + 1; j < 256; j++) {
|
||||
if ((m_S[0][i] == m_S[0][j]) || (m_S[1][i] == m_S[1][j]) ||
|
||||
(m_S[2][i] == m_S[2][j]) || (m_S[3][i] == m_S[3][j])) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
m_initialized = true;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
BlowFish::~BlowFish()
|
||||
{
|
||||
delete[](unsigned char *)m_key;
|
||||
m_key = nullptr;
|
||||
}
|
||||
|
||||
int BlowFish::keyLen() const
|
||||
{
|
||||
return 448;
|
||||
}
|
||||
|
||||
bool BlowFish::variableKeyLen() const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
bool BlowFish::readyToGo() const
|
||||
{
|
||||
return m_initialized;
|
||||
}
|
||||
|
||||
bool BlowFish::setKey(void *key, int bitlength)
|
||||
{
|
||||
if (bitlength <= 0 || bitlength > 448 || bitlength % 8 != 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
delete[](unsigned char *)m_key;
|
||||
|
||||
m_key = new unsigned char[bitlength / 8];
|
||||
memcpy(m_key, key, bitlength / 8);
|
||||
m_keylen = bitlength;
|
||||
|
||||
return init();
|
||||
}
|
||||
// clang-format off
|
||||
#if Q_BYTE_ORDER == Q_BIG_ENDIAN
|
||||
#define shuffle(x) do { \
|
||||
uint32_t r = x; \
|
||||
x = (r & 0xff000000) >> 24; \
|
||||
x |= (r & 0x00ff0000) >> 8; \
|
||||
x |= (r & 0x0000ff00) << 8; \
|
||||
x |= (r & 0x000000ff) << 24; \
|
||||
} while (0)
|
||||
#endif
|
||||
// clang-format on
|
||||
|
||||
int BlowFish::encrypt(void *block, int len)
|
||||
{
|
||||
uint32_t *d = (uint32_t *)block;
|
||||
|
||||
if (!m_initialized || len % _blksz != 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (int i = 0; i < len / _blksz; i++) {
|
||||
#if Q_BYTE_ORDER == Q_BIG_ENDIAN
|
||||
shuffle(*d);
|
||||
shuffle(*(d + 1));
|
||||
#endif
|
||||
encipher(d, d + 1);
|
||||
#if Q_BYTE_ORDER == Q_BIG_ENDIAN
|
||||
shuffle(*d);
|
||||
shuffle(*(d + 1));
|
||||
#endif
|
||||
d += 2;
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
int BlowFish::decrypt(void *block, int len)
|
||||
{
|
||||
uint32_t *d = (uint32_t *)block;
|
||||
|
||||
if (!m_initialized || len % _blksz != 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (int i = 0; i < len / _blksz; i++) {
|
||||
#if Q_BYTE_ORDER == Q_BIG_ENDIAN
|
||||
shuffle(*d);
|
||||
shuffle(*(d + 1));
|
||||
#endif
|
||||
decipher(d, d + 1);
|
||||
#if Q_BYTE_ORDER == Q_BIG_ENDIAN
|
||||
shuffle(*d);
|
||||
shuffle(*(d + 1));
|
||||
#endif
|
||||
d += 2;
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
uint32_t BlowFish::F(uint32_t x)
|
||||
{
|
||||
unsigned short a;
|
||||
unsigned short b;
|
||||
unsigned short c;
|
||||
unsigned short d;
|
||||
uint32_t y;
|
||||
|
||||
d = x & 0x000000ff;
|
||||
x >>= 8;
|
||||
c = x & 0x000000ff;
|
||||
x >>= 8;
|
||||
b = x & 0x000000ff;
|
||||
x >>= 8;
|
||||
a = x & 0x000000ff;
|
||||
|
||||
y = m_S[0][a] + m_S[1][b];
|
||||
y ^= m_S[2][c];
|
||||
y += m_S[3][d];
|
||||
|
||||
return y;
|
||||
}
|
||||
|
||||
void BlowFish::encipher(uint32_t *xl, uint32_t *xr)
|
||||
{
|
||||
uint32_t Xl = *xl;
|
||||
uint32_t Xr = *xr;
|
||||
uint32_t temp;
|
||||
|
||||
for (int i = 0; i < 16; ++i) {
|
||||
Xl ^= m_P[i];
|
||||
Xr ^= F(Xl);
|
||||
// Exchange
|
||||
temp = Xl; Xl = Xr; Xr = temp;
|
||||
}
|
||||
|
||||
// Exchange
|
||||
temp = Xl; Xl = Xr; Xr = temp;
|
||||
|
||||
Xr ^= m_P[16];
|
||||
Xl ^= m_P[17];
|
||||
|
||||
*xl = Xl;
|
||||
*xr = Xr;
|
||||
}
|
||||
|
||||
void BlowFish::decipher(uint32_t *xl, uint32_t *xr)
|
||||
{
|
||||
uint32_t Xl = *xl;
|
||||
uint32_t Xr = *xr;
|
||||
uint32_t temp;
|
||||
|
||||
for (int i = 17; i > 1; --i) {
|
||||
Xl ^= m_P[i];
|
||||
Xr ^= F(Xl);
|
||||
// Exchange
|
||||
temp = Xl; Xl = Xr; Xr = temp;
|
||||
}
|
||||
|
||||
// Exchange
|
||||
temp = Xl; Xl = Xr; Xr = temp;
|
||||
|
||||
Xr ^= m_P[1];
|
||||
Xl ^= m_P[0];
|
||||
|
||||
*xl = Xl;
|
||||
*xr = Xr;
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
This file is part of the KDE project
|
||||
SPDX-FileCopyrightText: 2001 George Staikos <staikos@kde.org>
|
||||
|
||||
SPDX-License-Identifier: LGPL-2.0-or-later
|
||||
*/
|
||||
|
||||
#ifndef _BLOWFISH_H
|
||||
#define _BLOWFISH_H
|
||||
|
||||
#include <config-kwalletbackend.h>
|
||||
|
||||
#if HAVE_STDINT_H
|
||||
#include <stdint.h>
|
||||
#endif
|
||||
#include <sys/types.h>
|
||||
#if HAVE_SYS_BITYPES_H
|
||||
#include <sys/bitypes.h> /* For uintXX_t on Tru64 */
|
||||
#endif
|
||||
|
||||
#include "blockcipher.h"
|
||||
#include "kwalletbackend_export.h"
|
||||
|
||||
/* @internal
|
||||
*/
|
||||
class KWALLETBACKEND_EXPORT BlowFish : public BlockCipher
|
||||
{
|
||||
public:
|
||||
BlowFish();
|
||||
~BlowFish() override;
|
||||
|
||||
bool setKey(void *key, int bitlength) override;
|
||||
|
||||
int keyLen() const override;
|
||||
|
||||
bool variableKeyLen() const override;
|
||||
|
||||
bool readyToGo() const override;
|
||||
|
||||
int encrypt(void *block, int len) override;
|
||||
|
||||
int decrypt(void *block, int len) override;
|
||||
|
||||
private:
|
||||
uint32_t m_S[4][256];
|
||||
uint32_t m_P[18];
|
||||
|
||||
void *m_key;
|
||||
int m_keylen; // in bits
|
||||
|
||||
bool m_initialized;
|
||||
|
||||
bool init();
|
||||
uint32_t F(uint32_t x);
|
||||
void encipher(uint32_t *xl, uint32_t *xr);
|
||||
void decipher(uint32_t *xl, uint32_t *xr);
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,120 @@
|
||||
/*
|
||||
This file is part of the KDE project
|
||||
SPDX-FileCopyrightText: 2001 George Staikos <staikos@kde.org>
|
||||
|
||||
SPDX-License-Identifier: LGPL-2.0-or-later
|
||||
*/
|
||||
|
||||
// This is also from _Applied_Cryptography_. See blowfish.cc for more details.
|
||||
|
||||
#ifndef BLOWFISHTABLES_H
|
||||
#define BLOWFISHTABLES_H
|
||||
|
||||
const unsigned long ks0[256] = {
|
||||
0xd1310ba6, 0x98dfb5ac, 0x2ffd72db, 0xd01adfb7, 0xb8e1afed, 0x6a267e96, 0xba7c9045, 0xf12c7f99, 0x24a19947, 0xb3916cf7, 0x0801f2e2, 0x858efc16, 0x636920d8,
|
||||
0x71574e69, 0xa458fea3, 0xf4933d7e, 0x0d95748f, 0x728eb658, 0x718bcd58, 0x82154aee, 0x7b54a41d, 0xc25a59b5, 0x9c30d539, 0x2af26013, 0xc5d1b023, 0x286085f0,
|
||||
0xca417918, 0xb8db38ef, 0x8e79dcb0, 0x603a180e, 0x6c9e0e8b, 0xb01e8a3e, 0xd71577c1, 0xbd314b27, 0x78af2fda, 0x55605c60, 0xe65525f3, 0xaa55ab94, 0x57489862,
|
||||
0x63e81440, 0x55ca396a, 0x2aab10b6, 0xb4cc5c34, 0x1141e8ce, 0xa15486af, 0x7c72e993, 0xb3ee1411, 0x636fbc2a, 0x2ba9c55d, 0x741831f6, 0xce5c3e16, 0x9b87931e,
|
||||
0xafd6ba33, 0x6c24cf5c, 0x7a325381, 0x28958677, 0x3b8f4898, 0x6b4bb9af, 0xc4bfe81b, 0x66282193, 0x61d809cc, 0xfb21a991, 0x487cac60, 0x5dec8032, 0xef845d5d,
|
||||
0xe98575b1, 0xdc262302, 0xeb651b88, 0x23893e81, 0xd396acc5, 0x0f6d6ff3, 0x83f44239, 0x2e0b4482, 0xa4842004, 0x69c8f04a, 0x9e1f9b5e, 0x21c66842, 0xf6e96c9a,
|
||||
0x670c9c61, 0xabd388f0, 0x6a51a0d2, 0xd8542f68, 0x960fa728, 0xab5133a3, 0x6eef0b6c, 0x137a3be4, 0xba3bf050, 0x7efb2a98, 0xa1f1651d, 0x39af0176, 0x66ca593e,
|
||||
0x82430e88, 0x8cee8619, 0x456f9fb4, 0x7d84a5c3, 0x3b8b5ebe, 0xe06f75d8, 0x85c12073, 0x401a449f, 0x56c16aa6, 0x4ed3aa62, 0x363f7706, 0x1bfedf72, 0x429b023d,
|
||||
0x37d0d724, 0xd00a1248, 0xdb0fead3, 0x49f1c09b, 0x075372c9, 0x80991b7b, 0x25d479d8, 0xf6e8def7, 0xe3fe501a, 0xb6794c3b, 0x976ce0bd, 0x04c006ba, 0xc1a94fb6,
|
||||
0x409f60c4, 0x5e5c9ec2, 0x196a2463, 0x68fb6faf, 0x3e6c53b5, 0x1339b2eb, 0x3b52ec6f, 0x6dfc511f, 0x9b30952c, 0xcc814544, 0xaf5ebd09, 0xbee3d004, 0xde334afd,
|
||||
0x660f2807, 0x192e4bb3, 0xc0cba857, 0x45c8740f, 0xd20b5f39, 0xb9d3fbdb, 0x5579c0bd, 0x1a60320a, 0xd6a100c6, 0x402c7279, 0x679f25fe, 0xfb1fa3cc, 0x8ea5e9f8,
|
||||
0xdb3222f8, 0x3c7516df, 0xfd616b15, 0x2f501ec8, 0xad0552ab, 0x323db5fa, 0xfd238760, 0x53317b48, 0x3e00df82, 0x9e5c57bb, 0xca6f8ca0, 0x1a87562e, 0xdf1769db,
|
||||
0xd542a8f6, 0x287effc3, 0xac6732c6, 0x8c4f5573, 0x695b27b0, 0xbbca58c8, 0xe1ffa35d, 0xb8f011a0, 0x10fa3d98, 0xfd2183b8, 0x4afcb56c, 0x2dd1d35b, 0x9a53e479,
|
||||
0xb6f84565, 0xd28e49bc, 0x4bfb9790, 0xe1ddf2da, 0xa4cb7e33, 0x62fb1341, 0xcee4c6e8, 0xef20cada, 0x36774c01, 0xd07e9efe, 0x2bf11fb4, 0x95dbda4d, 0xae909198,
|
||||
0xeaad8e71, 0x6b93d5a0, 0xd08ed1d0, 0xafc725e0, 0x8e3c5b2f, 0x8e7594b7, 0x8ff6e2fb, 0xf2122b64, 0x8888b812, 0x900df01c, 0x4fad5ea0, 0x688fc31c, 0xd1cff191,
|
||||
0xb3a8c1ad, 0x2f2f2218, 0xbe0e1777, 0xea752dfe, 0x8b021fa1, 0xe5a0cc0f, 0xb56f74e8, 0x18acf3d6, 0xce89e299, 0xb4a84fe0, 0xfd13e0b7, 0x7cc43b81, 0xd2ada8d9,
|
||||
0x165fa266, 0x80957705, 0x93cc7314, 0x211a1477, 0xe6ad2065, 0x77b5fa86, 0xc75442f5, 0xfb9d35cf, 0xebcdaf0c, 0x7b3e89a0, 0xd6411bd3, 0xae1e7e49, 0x00250e2d,
|
||||
0x2071b35e, 0x226800bb, 0x57b8e0af, 0x2464369b, 0xf009b91e, 0x5563911d, 0x59dfa6aa, 0x78c14389, 0xd95a537f, 0x207d5ba2, 0x02e5b9c5, 0x83260376, 0x6295cfa9,
|
||||
0x11c81968, 0x4e734a41, 0xb3472dca, 0x7b14a94a, 0x1b510052, 0x9a532915, 0xd60f573f, 0xbc9bc6e4, 0x2b60a476, 0x81e67400, 0x08ba6fb5, 0x571be91f, 0xf296ec6b,
|
||||
0x2a0dd915, 0xb6636521, 0xe7b9f9b6, 0xff34052e, 0xc5855664, 0x53b02d5d, 0xa99f8fa1, 0x08ba4799, 0x6e85076a};
|
||||
|
||||
const unsigned long ks1[256] = {
|
||||
0x4b7a70e9, 0xb5b32944, 0xdb75092e, 0xc4192623, 0xad6ea6b0, 0x49a7df7d, 0x9cee60b8, 0x8fedb266, 0xecaa8c71, 0x699a17ff, 0x5664526c, 0xc2b19ee1, 0x193602a5,
|
||||
0x75094c29, 0xa0591340, 0xe4183a3e, 0x3f54989a, 0x5b429d65, 0x6b8fe4d6, 0x99f73fd6, 0xa1d29c07, 0xefe830f5, 0x4d2d38e6, 0xf0255dc1, 0x4cdd2086, 0x8470eb26,
|
||||
0x6382e9c6, 0x021ecc5e, 0x09686b3f, 0x3ebaefc9, 0x3c971814, 0x6b6a70a1, 0x687f3584, 0x52a0e286, 0xb79c5305, 0xaa500737, 0x3e07841c, 0x7fdeae5c, 0x8e7d44ec,
|
||||
0x5716f2b8, 0xb03ada37, 0xf0500c0d, 0xf01c1f04, 0x0200b3ff, 0xae0cf51a, 0x3cb574b2, 0x25837a58, 0xdc0921bd, 0xd19113f9, 0x7ca92ff6, 0x94324773, 0x22f54701,
|
||||
0x3ae5e581, 0x37c2dadc, 0xc8b57634, 0x9af3dda7, 0xa9446146, 0x0fd0030e, 0xecc8c73e, 0xa4751e41, 0xe238cd99, 0x3bea0e2f, 0x3280bba1, 0x183eb331, 0x4e548b38,
|
||||
0x4f6db908, 0x6f420d03, 0xf60a04bf, 0x2cb81290, 0x24977c79, 0x5679b072, 0xbcaf89af, 0xde9a771f, 0xd9930810, 0xb38bae12, 0xdccf3f2e, 0x5512721f, 0x2e6b7124,
|
||||
0x501adde6, 0x9f84cd87, 0x7a584718, 0x7408da17, 0xbc9f9abc, 0xe94b7d8c, 0xec7aec3a, 0xdb851dfa, 0x63094366, 0xc464c3d2, 0xef1c1847, 0x3215d908, 0xdd433b37,
|
||||
0x24c2ba16, 0x12a14d43, 0x2a65c451, 0x50940002, 0x133ae4dd, 0x71dff89e, 0x10314e55, 0x81ac77d6, 0x5f11199b, 0x043556f1, 0xd7a3c76b, 0x3c11183b, 0x5924a509,
|
||||
0xf28fe6ed, 0x97f1fbfa, 0x9ebabf2c, 0x1e153c6e, 0x86e34570, 0xeae96fb1, 0x860e5e0a, 0x5a3e2ab3, 0x771fe71c, 0x4e3d06fa, 0x2965dcb9, 0x99e71d0f, 0x803e89d6,
|
||||
0x5266c825, 0x2e4cc978, 0x9c10b36a, 0xc6150eba, 0x94e2ea78, 0xa5fc3c53, 0x1e0a2df4, 0xf2f74ea7, 0x361d2b3d, 0x1939260f, 0x19c27960, 0x5223a708, 0xf71312b6,
|
||||
0xebadfe6e, 0xeac31f66, 0xe3bc4595, 0xa67bc883, 0xb17f37d1, 0x018cff28, 0xc332ddef, 0xbe6c5aa5, 0x65582185, 0x68ab9802, 0xeecea50f, 0xdb2f953b, 0x2aef7dad,
|
||||
0x5b6e2f84, 0x1521b628, 0x29076170, 0xecdd4775, 0x619f1510, 0x13cca830, 0xeb61bd96, 0x0334fe1e, 0xaa0363cf, 0xb5735c90, 0x4c70a239, 0xd59e9e0b, 0xcbaade14,
|
||||
0xeecc86bc, 0x60622ca7, 0x9cab5cab, 0xb2f3846e, 0x648b1eaf, 0x19bdf0ca, 0xa02369b9, 0x655abb50, 0x40685a32, 0x3c2ab4b3, 0x319ee9d5, 0xc021b8f7, 0x9b540b19,
|
||||
0x875fa099, 0x95f7997e, 0x623d7da8, 0xf837889a, 0x97e32d77, 0x11ed935f, 0x16681281, 0x0e358829, 0xc7e61fd6, 0x96dedfa1, 0x7858ba99, 0x57f584a5, 0x1b227263,
|
||||
0x9b83c3ff, 0x1ac24696, 0xcdb30aeb, 0x532e3054, 0x8fd948e4, 0x6dbc3128, 0x58ebf2ef, 0x34c6ffea, 0xfe28ed61, 0xee7c3c73, 0x5d4a14d9, 0xe864b7e3, 0x42105d14,
|
||||
0x203e13e0, 0x45eee2b6, 0xa3aaabea, 0xdb6c4f15, 0xfacb4fd0, 0xc742f442, 0xef6abbb5, 0x654f3b1d, 0x41cd2105, 0xd81e799e, 0x86854dc7, 0xe44b476a, 0x3d816250,
|
||||
0xcf62a1f2, 0x5b8d2646, 0xfc8883a0, 0xc1c7b6a3, 0x7f1524c3, 0x69cb7492, 0x47848a0b, 0x5692b285, 0x095bbf00, 0xad19489d, 0x1462b174, 0x23820e00, 0x58428d2a,
|
||||
0x0c55f5ea, 0x1dadf43e, 0x233f7061, 0x3372f092, 0x8d937e41, 0xd65fecf1, 0x6c223bdb, 0x7cde3759, 0xcbee7460, 0x4085f2a7, 0xce77326e, 0xa6078084, 0x19f8509e,
|
||||
0xe8efd855, 0x61d99735, 0xa969a7aa, 0xc50c06c2, 0x5a04abfc, 0x800bcadc, 0x9e447a2e, 0xc3453484, 0xfdd56705, 0x0e1e9ec9, 0xdb73dbd3, 0x105588cd, 0x675fda79,
|
||||
0xe3674340, 0xc5c43465, 0x713e38d8, 0x3d28f89e, 0xf16dff20, 0x153e21e7, 0x8fb03d4a, 0xe6e39f2b, 0xdb83adf7};
|
||||
|
||||
const unsigned long ks2[256] = {
|
||||
0xe93d5a68, 0x948140f7, 0xf64c261c, 0x94692934, 0x411520f7, 0x7602d4f7, 0xbcf46b2e, 0xd4a20068, 0xd4082471, 0x3320f46a, 0x43b7d4b7, 0x500061af, 0x1e39f62e,
|
||||
0x97244546, 0x14214f74, 0xbf8b8840, 0x4d95fc1d, 0x96b591af, 0x70f4ddd3, 0x66a02f45, 0xbfbc09ec, 0x03bd9785, 0x7fac6dd0, 0x31cb8504, 0x96eb27b3, 0x55fd3941,
|
||||
0xda2547e6, 0xabca0a9a, 0x28507825, 0x530429f4, 0x0a2c86da, 0xe9b66dfb, 0x68dc1462, 0xd7486900, 0x680ec0a4, 0x27a18dee, 0x4f3ffea2, 0xe887ad8c, 0xb58ce006,
|
||||
0x7af4d6b6, 0xaace1e7c, 0xd3375fec, 0xce78a399, 0x406b2a42, 0x20fe9e35, 0xd9f385b9, 0xee39d7ab, 0x3b124e8b, 0x1dc9faf7, 0x4b6d1856, 0x26a36631, 0xeae397b2,
|
||||
0x3a6efa74, 0xdd5b4332, 0x6841e7f7, 0xca7820fb, 0xfb0af54e, 0xd8feb397, 0x454056ac, 0xba489527, 0x55533a3a, 0x20838d87, 0xfe6ba9b7, 0xd096954b, 0x55a867bc,
|
||||
0xa1159a58, 0xcca92963, 0x99e1db33, 0xa62a4a56, 0x3f3125f9, 0x5ef47e1c, 0x9029317c, 0xfdf8e802, 0x04272f70, 0x80bb155c, 0x05282ce3, 0x95c11548, 0xe4c66d22,
|
||||
0x48c1133f, 0xc70f86dc, 0x07f9c9ee, 0x41041f0f, 0x404779a4, 0x5d886e17, 0x325f51eb, 0xd59bc0d1, 0xf2bcc18f, 0x41113564, 0x257b7834, 0x602a9c60, 0xdff8e8a3,
|
||||
0x1f636c1b, 0x0e12b4c2, 0x02e1329e, 0xaf664fd1, 0xcad18115, 0x6b2395e0, 0x333e92e1, 0x3b240b62, 0xeebeb922, 0x85b2a20e, 0xe6ba0d99, 0xde720c8c, 0x2da2f728,
|
||||
0xd0127845, 0x95b794fd, 0x647d0862, 0xe7ccf5f0, 0x5449a36f, 0x877d48fa, 0xc39dfd27, 0xf33e8d1e, 0x0a476341, 0x992eff74, 0x3a6f6eab, 0xf4f8fd37, 0xa812dc60,
|
||||
0xa1ebddf8, 0x991be14c, 0xdb6e6b0d, 0xc67b5510, 0x6d672c37, 0x2765d43b, 0xdcd0e804, 0xf1290dc7, 0xcc00ffa3, 0xb5390f92, 0x690fed0b, 0x667b9ffb, 0xcedb7d9c,
|
||||
0xa091cf0b, 0xd9155ea3, 0xbb132f88, 0x515bad24, 0x7b9479bf, 0x763bd6eb, 0x37392eb3, 0xcc115979, 0x8026e297, 0xf42e312d, 0x6842ada7, 0xc66a2b3b, 0x12754ccc,
|
||||
0x782ef11c, 0x6a124237, 0xb79251e7, 0x06a1bbe6, 0x4bfb6350, 0x1a6b1018, 0x11caedfa, 0x3d25bdd8, 0xe2e1c3c9, 0x44421659, 0x0a121386, 0xd90cec6e, 0xd5abea2a,
|
||||
0x64af674e, 0xda86a85f, 0xbebfe988, 0x64e4c3fe, 0x9dbc8057, 0xf0f7c086, 0x60787bf8, 0x6003604d, 0xd1fd8346, 0xf6381fb0, 0x7745ae04, 0xd736fccc, 0x83426b33,
|
||||
0xf01eab71, 0xb0804187, 0x3c005e5f, 0x77a057be, 0xbde8ae24, 0x55464299, 0xbf582e61, 0x4e58f48f, 0xf2ddfda2, 0xf474ef38, 0x8789bdc2, 0x5366f9c3, 0xc8b38e74,
|
||||
0xb475f255, 0x46fcd9b9, 0x7aeb2661, 0x8b1ddf84, 0x846a0e79, 0x915f95e2, 0x466e598e, 0x20b45770, 0x8cd55591, 0xc902de4c, 0xb90bace1, 0xbb8205d0, 0x11a86248,
|
||||
0x7574a99e, 0xb77f19b6, 0xe0a9dc09, 0x662d09a1, 0xc4324633, 0xe85a1f02, 0x09f0be8c, 0x4a99a025, 0x1d6efe10, 0x1ab93d1d, 0x0ba5a4df, 0xa186f20f, 0x2868f169,
|
||||
0xdcb7da83, 0x573906fe, 0xa1e2ce9b, 0x4fcd7f52, 0x50115e01, 0xa70683fa, 0xa002b5c4, 0x0de6d027, 0x9af88c27, 0x773f8641, 0xc3604c06, 0x61a806b5, 0xf0177a28,
|
||||
0xc0f586e0, 0x006058aa, 0x30dc7d62, 0x11e69ed7, 0x2338ea63, 0x53c2dd94, 0xc2c21634, 0xbbcbee56, 0x90bcb6de, 0xebfc7da1, 0xce591d76, 0x6f05e409, 0x4b7c0188,
|
||||
0x39720a3d, 0x7c927c24, 0x86e3725f, 0x724d9db9, 0x1ac15bb4, 0xd39eb8fc, 0xed545578, 0x08fca5b5, 0xd83d7cd3, 0x4dad0fc4, 0x1e50ef5e, 0xb161e6f8, 0xa28514d9,
|
||||
0x6c51133c, 0x6fd5c7e7, 0x56e14ec4, 0x362abfce, 0xddc6c837, 0xd79a3234, 0x92638212, 0x670efa8e, 0x406000e0};
|
||||
|
||||
const unsigned long ks3[256] = {
|
||||
0x3a39ce37, 0xd3faf5cf, 0xabc27737, 0x5ac52d1b, 0x5cb0679e, 0x4fa33742, 0xd3822740, 0x99bc9bbe, 0xd5118e9d, 0xbf0f7315, 0xd62d1c7e, 0xc700c47b, 0xb78c1b6b,
|
||||
0x21a19045, 0xb26eb1be, 0x6a366eb4, 0x5748ab2f, 0xbc946e79, 0xc6a376d2, 0x6549c2c8, 0x530ff8ee, 0x468dde7d, 0xd5730a1d, 0x4cd04dc6, 0x2939bbdb, 0xa9ba4650,
|
||||
0xac9526e8, 0xbe5ee304, 0xa1fad5f0, 0x6a2d519a, 0x63ef8ce2, 0x9a86ee22, 0xc089c2b8, 0x43242ef6, 0xa51e03aa, 0x9cf2d0a4, 0x83c061ba, 0x9be96a4d, 0x8fe51550,
|
||||
0xba645bd6, 0x2826a2f9, 0xa73a3ae1, 0x4ba99586, 0xef5562e9, 0xc72fefd3, 0xf752f7da, 0x3f046f69, 0x77fa0a59, 0x80e4a915, 0x87b08601, 0x9b09e6ad, 0x3b3ee593,
|
||||
0xe990fd5a, 0x9e34d797, 0x2cf0b7d9, 0x022b8b51, 0x96d5ac3a, 0x017da67d, 0xd1cf3ed6, 0x7c7d2d28, 0x1f9f25cf, 0xadf2b89b, 0x5ad6b472, 0x5a88f54c, 0xe029ac71,
|
||||
0xe019a5e6, 0x47b0acfd, 0xed93fa9b, 0xe8d3c48d, 0x283b57cc, 0xf8d56629, 0x79132e28, 0x785f0191, 0xed756055, 0xf7960e44, 0xe3d35e8c, 0x15056dd4, 0x88f46dba,
|
||||
0x03a16125, 0x0564f0bd, 0xc3eb9e15, 0x3c9057a2, 0x97271aec, 0xa93a072a, 0x1b3f6d9b, 0x1e6321f5, 0xf59c66fb, 0x26dcf319, 0x7533d928, 0xb155fdf5, 0x03563482,
|
||||
0x8aba3cbb, 0x28517711, 0xc20ad9f8, 0xabcc5167, 0xccad925f, 0x4de81751, 0x3830dc8e, 0x379d5862, 0x9320f991, 0xea7a90c2, 0xfb3e7bce, 0x5121ce64, 0x774fbe32,
|
||||
0xa8b6e37e, 0xc3293d46, 0x48de5369, 0x6413e680, 0xa2ae0810, 0xdd6db224, 0x69852dfd, 0x09072166, 0xb39a460a, 0x6445c0dd, 0x586cdecf, 0x1c20c8ae, 0x5bbef7dd,
|
||||
0x1b588d40, 0xccd2017f, 0x6bb4e3bb, 0xdda26a7e, 0x3a59ff45, 0x3e350a44, 0xbcb4cdd5, 0x72eacea8, 0xfa6484bb, 0x8d6612ae, 0xbf3c6f47, 0xd29be463, 0x542f5d9e,
|
||||
0xaec2771b, 0xf64e6370, 0x740e0d8d, 0xe75b1357, 0xf8721671, 0xaf537d5d, 0x4040cb08, 0x4eb4e2cc, 0x34d2466a, 0x0115af84, 0xe1b00428, 0x95983a1d, 0x06b89fb4,
|
||||
0xce6ea048, 0x6f3f3b82, 0x3520ab82, 0x011a1d4b, 0x277227f8, 0x611560b1, 0xe7933fdc, 0xbb3a792b, 0x344525bd, 0xa08839e1, 0x51ce794b, 0x2f32c9b7, 0xa01fbac9,
|
||||
0xe01cc87e, 0xbcc7d1f6, 0xcf0111c3, 0xa1e8aac7, 0x1a908749, 0xd44fbd9a, 0xd0dadecb, 0xd50ada38, 0x0339c32a, 0xc6913667, 0x8df9317c, 0xe0b12b4f, 0xf79e59b7,
|
||||
0x43f5bb3a, 0xf2d519ff, 0x27d9459c, 0xbf97222c, 0x15e6fc2a, 0x0f91fc71, 0x9b941525, 0xfae59361, 0xceb69ceb, 0xc2a86459, 0x12baa8d1, 0xb6c1075e, 0xe3056a0c,
|
||||
0x10d25065, 0xcb03a442, 0xe0ec6e0e, 0x1698db3b, 0x4c98a0be, 0x3278e964, 0x9f1f9532, 0xe0d392df, 0xd3a0342b, 0x8971f21e, 0x1b0a7441, 0x4ba3348c, 0xc5be7120,
|
||||
0xc37632d8, 0xdf359f8d, 0x9b992f2e, 0xe60b6f47, 0x0fe3f11d, 0xe54cda54, 0x1edad891, 0xce6279cf, 0xcd3e7e6f, 0x1618b166, 0xfd2c1d05, 0x848fd2c5, 0xf6fb2299,
|
||||
0xf523f357, 0xa6327623, 0x93a83531, 0x56cccd02, 0xacf08162, 0x5a75ebb5, 0x6e163697, 0x88d273cc, 0xde966292, 0x81b949d0, 0x4c50901b, 0x71c65614, 0xe6c6c7bd,
|
||||
0x327a140a, 0x45e1d006, 0xc3f27b9a, 0xc9aa53fd, 0x62a80f00, 0xbb25bfe2, 0x35bdd2f6, 0x71126905, 0xb2040222, 0xb6cbcf7c, 0xcd769c2b, 0x53113ec0, 0x1640e3d3,
|
||||
0x38abbd60, 0x2547adf0, 0xba38209c, 0xf746ce76, 0x77afa1c5, 0x20756060, 0x85cbfe4e, 0x8ae88dd8, 0x7aaaf9b0, 0x4cf9aa7e, 0x1948c25c, 0x02fb8a8c, 0x01c36ae4,
|
||||
0xd6ebe1f9, 0x90d4f869, 0xa65cdea0, 0x3f09252d, 0xc208e69f, 0xb74e6132, 0xce77e25b, 0x578fdfe3, 0x3ac372e6};
|
||||
|
||||
const unsigned long P[18] = {0x243f6a88,
|
||||
0x85a308d3,
|
||||
0x13198a2e,
|
||||
0x03707344,
|
||||
0xa4093822,
|
||||
0x299f31d0,
|
||||
0x082efa98,
|
||||
0xec4e6c89,
|
||||
0x452821e6,
|
||||
0x38d01377,
|
||||
0xbe5466cf,
|
||||
0x34e90c6c,
|
||||
0xc0ac29b7,
|
||||
0xc97c50dd,
|
||||
0x3f84d5b5,
|
||||
0xb5470917,
|
||||
0x9216d5d9,
|
||||
0x8979fb1b};
|
||||
|
||||
#endif // BLOWFISHTABLES_H
|
||||
@@ -0,0 +1,200 @@
|
||||
/*
|
||||
This file is part of the KDE project
|
||||
SPDX-FileCopyrightText: 2001 George Staikos <staikos@kde.org>
|
||||
|
||||
SPDX-License-Identifier: LGPL-2.0-or-later
|
||||
*/
|
||||
|
||||
#include "cbc.h"
|
||||
#include "kwalletbackend_debug.h"
|
||||
#include <string.h>
|
||||
|
||||
CipherBlockChain::CipherBlockChain(BlockCipher *cipher, bool useECBforReading) :
|
||||
_cipher(cipher)
|
||||
, _useECBforReading(useECBforReading)
|
||||
{
|
||||
_next = nullptr;
|
||||
_register = nullptr;
|
||||
_len = -1;
|
||||
_reader = _writer = 0L;
|
||||
if (cipher) {
|
||||
_blksz = cipher->blockSize();
|
||||
}
|
||||
}
|
||||
|
||||
CipherBlockChain::~CipherBlockChain()
|
||||
{
|
||||
delete[](char *)_register;
|
||||
_register = nullptr;
|
||||
delete[](char *)_next;
|
||||
_next = nullptr;
|
||||
}
|
||||
|
||||
bool CipherBlockChain::setKey(void *key, int bitlength)
|
||||
{
|
||||
if (_cipher) {
|
||||
return _cipher->setKey(key, bitlength);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
int CipherBlockChain::keyLen() const
|
||||
{
|
||||
if (_cipher) {
|
||||
return _cipher->keyLen();
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
bool CipherBlockChain::variableKeyLen() const
|
||||
{
|
||||
if (_cipher) {
|
||||
return _cipher->variableKeyLen();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CipherBlockChain::readyToGo() const
|
||||
{
|
||||
if (_cipher) {
|
||||
return _cipher->readyToGo();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void CipherBlockChain::initRegister() {
|
||||
if (_register == nullptr) {
|
||||
size_t registerLen = _cipher->blockSize();
|
||||
_register = new unsigned char[registerLen];
|
||||
_len = registerLen;
|
||||
}
|
||||
memset(_register, 0, _len);
|
||||
}
|
||||
|
||||
int CipherBlockChain::encrypt(void *block, int len)
|
||||
{
|
||||
if (_cipher && !_reader) {
|
||||
int rc;
|
||||
|
||||
_writer |= 1;
|
||||
|
||||
initRegister();
|
||||
|
||||
if ((len % _len) >0) {
|
||||
qCDebug(KWALLETBACKEND_LOG) << "Block length given encrypt (" << len << ") is not a multiple of " << _len;
|
||||
return -1;
|
||||
}
|
||||
|
||||
char *elemBlock = static_cast<char*>(block);
|
||||
for (int b = 0; b < len/_len; b++) {
|
||||
|
||||
// This might be optimizable
|
||||
char *tb = static_cast<char*>(elemBlock);
|
||||
for (int i = 0; i < _len; i++) {
|
||||
*tb++ ^= ((char *)_register)[i];
|
||||
}
|
||||
|
||||
rc = _cipher->encrypt(elemBlock, _len);
|
||||
|
||||
if (rc != -1) {
|
||||
memcpy(_register, elemBlock, _len);
|
||||
}
|
||||
elemBlock += _len;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
// This is the old decrypt method, that was decrypting using ECB
|
||||
// instead of CBC
|
||||
int CipherBlockChain::decryptECB(void *block, int len) {
|
||||
if (_cipher && !_writer) {
|
||||
int rc;
|
||||
|
||||
_reader |= 1;
|
||||
|
||||
if (!_register) {
|
||||
_register = new unsigned char[len];
|
||||
_len = len;
|
||||
memset(_register, 0, len);
|
||||
} else if (len > _len) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!_next) {
|
||||
_next = new unsigned char[_len];
|
||||
}
|
||||
memcpy(_next, block, _len);
|
||||
|
||||
rc = _cipher->decrypt(block, len);
|
||||
|
||||
if (rc != -1) {
|
||||
// This might be optimizable
|
||||
char *tb = (char *)block;
|
||||
for (int i = 0; i < len; i++) {
|
||||
tb[i] ^= ((char *)_register)[i];
|
||||
}
|
||||
}
|
||||
|
||||
void *temp;
|
||||
temp = _next;
|
||||
_next = _register;
|
||||
_register = temp;
|
||||
|
||||
return rc;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
int CipherBlockChain::decrypt(void *block, int len)
|
||||
{
|
||||
if (_useECBforReading) {
|
||||
qCDebug(KWALLETBACKEND_LOG) << "decrypting using ECB!";
|
||||
return decryptECB(block, len);
|
||||
}
|
||||
|
||||
if (_cipher && !_writer) {
|
||||
int rc = 0;
|
||||
|
||||
_reader |= 1;
|
||||
|
||||
initRegister();
|
||||
|
||||
if ((len % _len) >0) {
|
||||
qCDebug(KWALLETBACKEND_LOG) << "Block length given for decrypt (" << len << ") is not a multiple of " << _len;
|
||||
return -1;
|
||||
}
|
||||
|
||||
char *elemBlock = static_cast<char*>(block);
|
||||
for (int b = 0; b < len/_len; b++) {
|
||||
if (_next == nullptr) {
|
||||
_next = new unsigned char[_len];
|
||||
}
|
||||
memcpy(_next, elemBlock, _len);
|
||||
|
||||
int bytesDecrypted = _cipher->decrypt(elemBlock, _len);
|
||||
|
||||
if (bytesDecrypted != -1) {
|
||||
rc += bytesDecrypted;
|
||||
// This might be optimizable
|
||||
char *tb = (char *)elemBlock;
|
||||
for (int i = 0; i < _len; i++) {
|
||||
*tb++ ^= ((char *)_register)[i];
|
||||
}
|
||||
}
|
||||
|
||||
void *temp;
|
||||
temp = _next;
|
||||
_next = _register;
|
||||
_register = temp;
|
||||
|
||||
elemBlock += _len;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
This file is part of the KDE project
|
||||
SPDX-FileCopyrightText: 2001 George Staikos <staikos@kde.org>
|
||||
|
||||
SPDX-License-Identifier: LGPL-2.0-or-later
|
||||
*/
|
||||
|
||||
#ifndef __CBC__KO__H
|
||||
#define __CBC__KO__H
|
||||
|
||||
#include "blockcipher.h"
|
||||
|
||||
/* @internal
|
||||
* Initialize this class with a pointer to a valid, uninitialized BlockCipher
|
||||
* and it will apply that cipher using CBC. You may want to make the
|
||||
* initial block a full block of random data. Do not change the block size
|
||||
* at any time!! You must pad it yourself. Also, you can only encrypt or
|
||||
* decrypt. You can't do both with a given instance. After you call one,
|
||||
* calls to the other will fail in this instance.
|
||||
*/
|
||||
|
||||
class CipherBlockChain : public BlockCipher
|
||||
{
|
||||
public:
|
||||
CipherBlockChain(BlockCipher *cipher, bool useECBforReading = false);
|
||||
~CipherBlockChain() override;
|
||||
|
||||
bool setKey(void *key, int bitlength) override;
|
||||
|
||||
int keyLen() const override;
|
||||
|
||||
bool variableKeyLen() const override;
|
||||
|
||||
bool readyToGo() const override;
|
||||
|
||||
int encrypt(void *block, int len) override;
|
||||
|
||||
int decrypt(void *block, int len) override;
|
||||
|
||||
private:
|
||||
void initRegister();
|
||||
int decryptECB(void *block, int len);
|
||||
|
||||
BlockCipher *_cipher;
|
||||
void *_register;
|
||||
void *_next;
|
||||
int _len;
|
||||
int _reader, _writer;
|
||||
bool _useECBforReading;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,133 @@
|
||||
/*
|
||||
This file is part of the KDE project
|
||||
SPDX-FileCopyrightText: 2001 George Staikos <staikos@kde.org>
|
||||
|
||||
SPDX-License-Identifier: LGPL-2.0-or-later
|
||||
*/
|
||||
|
||||
#include "cbc.h"
|
||||
#include <string.h>
|
||||
|
||||
CipherBlockChain::CipherBlockChain(BlockCipher *cipher) : _cipher(cipher)
|
||||
{
|
||||
_next = 0L;
|
||||
_register = 0L;
|
||||
_len = -1;
|
||||
_reader = _writer = 0L;
|
||||
if (cipher) {
|
||||
_blksz = cipher->blockSize();
|
||||
}
|
||||
}
|
||||
|
||||
CipherBlockChain::~CipherBlockChain()
|
||||
{
|
||||
delete[](char *)_register;
|
||||
_register = 0L;
|
||||
delete[](char *)_next;
|
||||
_next = 0L;
|
||||
}
|
||||
|
||||
bool CipherBlockChain::setKey(void *key, int bitlength)
|
||||
{
|
||||
if (_cipher) {
|
||||
return _cipher->setKey(key, bitlength);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
int CipherBlockChain::keyLen() const
|
||||
{
|
||||
if (_cipher) {
|
||||
return _cipher->keyLen();
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
bool CipherBlockChain::variableKeyLen() const
|
||||
{
|
||||
if (_cipher) {
|
||||
return _cipher->variableKeyLen();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CipherBlockChain::readyToGo() const
|
||||
{
|
||||
if (_cipher) {
|
||||
return _cipher->readyToGo();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
int CipherBlockChain::encrypt(void *block, int len)
|
||||
{
|
||||
if (_cipher && !_reader) {
|
||||
int rc;
|
||||
|
||||
_writer |= 1;
|
||||
|
||||
if (!_register) {
|
||||
_register = new unsigned char[len];
|
||||
_len = len;
|
||||
memset(_register, 0, len);
|
||||
} else if (len > _len) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
// This might be optimizable
|
||||
char *tb = (char *)block;
|
||||
for (int i = 0; i < len; i++) {
|
||||
tb[i] ^= ((char *)_register)[i];
|
||||
}
|
||||
|
||||
rc = _cipher->encrypt(block, len);
|
||||
|
||||
if (rc != -1) {
|
||||
memcpy(_register, block, len);
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
int CipherBlockChain::decrypt(void *block, int len)
|
||||
{
|
||||
if (_cipher && !_writer) {
|
||||
int rc;
|
||||
|
||||
_reader |= 1;
|
||||
|
||||
if (!_register) {
|
||||
_register = new unsigned char[len];
|
||||
_len = len;
|
||||
memset(_register, 0, len);
|
||||
} else if (len > _len) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!_next) {
|
||||
_next = new unsigned char[_len];
|
||||
}
|
||||
memcpy(_next, block, _len);
|
||||
|
||||
rc = _cipher->decrypt(block, len);
|
||||
|
||||
if (rc != -1) {
|
||||
// This might be optimizable
|
||||
char *tb = (char *)block;
|
||||
for (int i = 0; i < len; i++) {
|
||||
tb[i] ^= ((char *)_register)[i];
|
||||
}
|
||||
}
|
||||
|
||||
void *temp;
|
||||
temp = _next;
|
||||
_next = _register;
|
||||
_register = temp;
|
||||
|
||||
return rc;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
#cmakedefine01 HAVE_STDINT_H
|
||||
|
||||
#cmakedefine01 HAVE_SYS_BITYPES_H
|
||||
@@ -0,0 +1,782 @@
|
||||
/*
|
||||
This file is part of the KDE project
|
||||
SPDX-FileCopyrightText: 2001-2004 George Staikos <staikos@kde.org>
|
||||
|
||||
SPDX-License-Identifier: LGPL-2.0-or-later
|
||||
*/
|
||||
|
||||
#include "kwalletbackend.h"
|
||||
#include "kwalletbackend_debug.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <QSaveFile>
|
||||
#ifdef HAVE_GPGMEPP
|
||||
#include <gpgme++/key.h>
|
||||
#endif
|
||||
#include <gcrypt.h>
|
||||
#include <KNotification>
|
||||
#include <KLocalizedString>
|
||||
|
||||
#include <QDir>
|
||||
#include <QFile>
|
||||
#include <QFileInfo>
|
||||
#include <QSaveFile>
|
||||
#include <QCryptographicHash>
|
||||
#include <QRegularExpression>
|
||||
#include <QStandardPaths>
|
||||
|
||||
#include "blowfish.h"
|
||||
#include "sha1.h"
|
||||
#include "cbc.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <cerrno>
|
||||
|
||||
// quick fix to get random numbers on win32
|
||||
#ifdef Q_OS_WIN //krazy:exclude=cpp
|
||||
#include <windows.h>
|
||||
#include <wincrypt.h>
|
||||
#endif
|
||||
|
||||
#define KWALLETSTORAGE_VERSION_MAJOR 0
|
||||
#define KWALLETSTORAGE_VERSION_MINOR 1
|
||||
|
||||
using namespace KWallet;
|
||||
|
||||
#define KWMAGIC "KWALLET\n\r\0\r\n"
|
||||
|
||||
static const QByteArray walletAllowedChars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789^&'@{}[],$=!-#()%.+_\r\n\t\f\v ";
|
||||
|
||||
/* The encoding works if the name contains at least one unsupported character.
|
||||
* Names that were allowed prior to the Secret Service API patch remain intact.
|
||||
*/
|
||||
QString Backend::encodeWalletName(const QString &name) {
|
||||
/* Use a semicolon as "percent" because it does not conflict with already allowed characters for wallet names
|
||||
* and is allowed for file names
|
||||
*/
|
||||
return QString::fromUtf8(name.toUtf8().toPercentEncoding(walletAllowedChars, {}, ';'));
|
||||
}
|
||||
|
||||
QString Backend::decodeWalletName(const QString &encodedName) {
|
||||
return QString::fromUtf8(QByteArray::fromPercentEncoding(encodedName.toUtf8(), ';'));
|
||||
}
|
||||
|
||||
class Backend::BackendPrivate
|
||||
{
|
||||
};
|
||||
|
||||
// static void initKWalletDir()
|
||||
// {
|
||||
// KGlobal::dirs()->addResourceType("kwallet", 0, "share/apps/kwallet");
|
||||
// }
|
||||
|
||||
Backend::Backend(const QString &name, bool isPath)
|
||||
: d(nullptr),
|
||||
_name(name),
|
||||
_cipherType(KWallet::BACKEND_CIPHER_UNKNOWN)
|
||||
{
|
||||
// initKWalletDir();
|
||||
if (isPath) {
|
||||
_path = name;
|
||||
} else {
|
||||
_path = getSaveLocation() + '/' + encodeWalletName(_name) + ".kwl";
|
||||
}
|
||||
|
||||
_open = false;
|
||||
}
|
||||
|
||||
Backend::~Backend()
|
||||
{
|
||||
if (_open) {
|
||||
close();
|
||||
}
|
||||
delete d;
|
||||
}
|
||||
|
||||
QString Backend::getSaveLocation()
|
||||
{
|
||||
QString writeLocation = QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation) + QLatin1String("/kwalletd");
|
||||
QDir writeDir(writeLocation);
|
||||
if (!writeDir.exists()) {
|
||||
if (!writeDir.mkpath(writeLocation)) {
|
||||
qFatal("Cannot create wallet save location!");
|
||||
}
|
||||
}
|
||||
|
||||
// qCDebug(KWALLETBACKEND_LOG) << "Using saveLocation " + writeLocation;
|
||||
return writeLocation;
|
||||
}
|
||||
|
||||
void Backend::setCipherType(BackendCipherType ct)
|
||||
{
|
||||
// changing cipher type on already initialed wallets is not permitted
|
||||
assert(_cipherType == KWallet::BACKEND_CIPHER_UNKNOWN);
|
||||
_cipherType = ct;
|
||||
}
|
||||
|
||||
static int password2PBKDF2_SHA512(const QByteArray &password, QByteArray &hash, const QByteArray &salt)
|
||||
{
|
||||
if (!gcry_check_version("1.5.0")) {
|
||||
qCWarning(KWALLETBACKEND_LOG) << "libcrypt version is too old";
|
||||
return GPG_ERR_USER_2;
|
||||
}
|
||||
|
||||
gcry_error_t error;
|
||||
bool static gcry_secmem_init = false;
|
||||
if (!gcry_secmem_init) {
|
||||
error = gcry_control(GCRYCTL_INIT_SECMEM, 32768, 0);
|
||||
if (error != 0) {
|
||||
qCWarning(KWALLETBACKEND_LOG) << "Can't get secure memory:" << error;
|
||||
return error;
|
||||
}
|
||||
gcry_secmem_init = true;
|
||||
}
|
||||
|
||||
gcry_control(GCRYCTL_INITIALIZATION_FINISHED, 0);
|
||||
|
||||
error = gcry_kdf_derive(password.constData(), password.size(),
|
||||
GCRY_KDF_PBKDF2, GCRY_MD_SHA512,
|
||||
salt.data(), salt.size(),
|
||||
PBKDF2_SHA512_ITERATIONS, PBKDF2_SHA512_KEYSIZE, hash.data());
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
// this should be SHA-512 for release probably
|
||||
static int password2hash(const QByteArray &password, QByteArray &hash)
|
||||
{
|
||||
SHA1 sha;
|
||||
int shasz = sha.size() / 8;
|
||||
|
||||
assert(shasz >= 20);
|
||||
|
||||
QByteArray block1(shasz, 0);
|
||||
|
||||
sha.process(password.data(), qMin(password.size(), 16));
|
||||
|
||||
// To make brute force take longer
|
||||
for (int i = 0; i < 2000; i++) {
|
||||
memcpy(block1.data(), sha.hash(), shasz);
|
||||
sha.reset();
|
||||
sha.process(block1.data(), shasz);
|
||||
}
|
||||
|
||||
sha.reset();
|
||||
|
||||
if (password.size() > 16) {
|
||||
sha.process(password.data() + 16, qMin(password.size() - 16, 16));
|
||||
QByteArray block2(shasz, 0);
|
||||
// To make brute force take longer
|
||||
for (int i = 0; i < 2000; i++) {
|
||||
memcpy(block2.data(), sha.hash(), shasz);
|
||||
sha.reset();
|
||||
sha.process(block2.data(), shasz);
|
||||
}
|
||||
|
||||
sha.reset();
|
||||
|
||||
if (password.size() > 32) {
|
||||
sha.process(password.data() + 32, qMin(password.size() - 32, 16));
|
||||
|
||||
QByteArray block3(shasz, 0);
|
||||
// To make brute force take longer
|
||||
for (int i = 0; i < 2000; i++) {
|
||||
memcpy(block3.data(), sha.hash(), shasz);
|
||||
sha.reset();
|
||||
sha.process(block3.data(), shasz);
|
||||
}
|
||||
|
||||
sha.reset();
|
||||
|
||||
if (password.size() > 48) {
|
||||
sha.process(password.data() + 48, password.size() - 48);
|
||||
|
||||
QByteArray block4(shasz, 0);
|
||||
// To make brute force take longer
|
||||
for (int i = 0; i < 2000; i++) {
|
||||
memcpy(block4.data(), sha.hash(), shasz);
|
||||
sha.reset();
|
||||
sha.process(block4.data(), shasz);
|
||||
}
|
||||
|
||||
sha.reset();
|
||||
// split 14/14/14/14
|
||||
hash.resize(56);
|
||||
memcpy(hash.data(), block1.data(), 14);
|
||||
memcpy(hash.data() + 14, block2.data(), 14);
|
||||
memcpy(hash.data() + 28, block3.data(), 14);
|
||||
memcpy(hash.data() + 42, block4.data(), 14);
|
||||
block4.fill(0);
|
||||
} else {
|
||||
// split 20/20/16
|
||||
hash.resize(56);
|
||||
memcpy(hash.data(), block1.data(), 20);
|
||||
memcpy(hash.data() + 20, block2.data(), 20);
|
||||
memcpy(hash.data() + 40, block3.data(), 16);
|
||||
}
|
||||
block3.fill(0);
|
||||
} else {
|
||||
// split 20/20
|
||||
hash.resize(40);
|
||||
memcpy(hash.data(), block1.data(), 20);
|
||||
memcpy(hash.data() + 20, block2.data(), 20);
|
||||
}
|
||||
block2.fill(0);
|
||||
} else {
|
||||
// entirely block1
|
||||
hash.resize(20);
|
||||
memcpy(hash.data(), block1.data(), 20);
|
||||
}
|
||||
|
||||
block1.fill(0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int Backend::deref()
|
||||
{
|
||||
if (--_ref < 0) {
|
||||
qCDebug(KWALLETBACKEND_LOG) << "refCount negative!";
|
||||
_ref = 0;
|
||||
}
|
||||
return _ref;
|
||||
}
|
||||
|
||||
bool Backend::exists(const QString &wallet)
|
||||
{
|
||||
QString saveLocation = getSaveLocation();
|
||||
QString path = saveLocation + '/' + encodeWalletName(wallet) + QLatin1String(".kwl");
|
||||
// Note: 60 bytes is presently the minimum size of a wallet file.
|
||||
// Anything smaller is junk.
|
||||
return QFile::exists(path) && QFileInfo(path).size() >= 60;
|
||||
}
|
||||
|
||||
QString Backend::openRCToString(int rc)
|
||||
{
|
||||
switch (rc) {
|
||||
case -255:
|
||||
return i18n("Already open.");
|
||||
case -2:
|
||||
return i18n("Error opening file.");
|
||||
case -3:
|
||||
return i18n("Not a wallet file.");
|
||||
case -4:
|
||||
return i18n("Unsupported file format revision.");
|
||||
case -41:
|
||||
return QStringLiteral("Unknown cipher or hash"); //FIXME: use i18n after string freeze
|
||||
case -42:
|
||||
return i18n("Unknown encryption scheme.");
|
||||
case -43:
|
||||
return i18n("Corrupt file?");
|
||||
case -8:
|
||||
return i18n("Error validating wallet integrity. Possibly corrupted.");
|
||||
case -5:
|
||||
case -7:
|
||||
case -9:
|
||||
return i18n("Read error - possibly incorrect password.");
|
||||
case -6:
|
||||
return i18n("Decryption error.");
|
||||
default:
|
||||
return QString();
|
||||
}
|
||||
}
|
||||
|
||||
int Backend::open(const QByteArray &password, WId w)
|
||||
{
|
||||
if (_open) {
|
||||
return -255; // already open
|
||||
}
|
||||
|
||||
setPassword(password);
|
||||
return openInternal(w);
|
||||
}
|
||||
|
||||
#ifdef HAVE_GPGMEPP
|
||||
int Backend::open(const GpgME::Key &key)
|
||||
{
|
||||
if (_open) {
|
||||
return -255; // already open
|
||||
}
|
||||
_gpgKey = key;
|
||||
return openInternal();
|
||||
}
|
||||
#endif // HAVE_GPGMEPP
|
||||
|
||||
int Backend::openPreHashed(const QByteArray &passwordHash)
|
||||
{
|
||||
if (_open) {
|
||||
return -255; // already open
|
||||
}
|
||||
|
||||
// check the password hash for correct size (currently fixed)
|
||||
if (passwordHash.size() != 20 && passwordHash.size() != 40 &&
|
||||
passwordHash.size() != 56) {
|
||||
return -42; // unsupported encryption scheme
|
||||
}
|
||||
|
||||
_passhash = passwordHash;
|
||||
_newPassHash = passwordHash;
|
||||
_useNewHash = true;//Only new hash is supported
|
||||
|
||||
return openInternal();
|
||||
}
|
||||
|
||||
int Backend::openInternal(WId w)
|
||||
{
|
||||
// No wallet existed. Let's create it.
|
||||
// Note: 60 bytes is presently the minimum size of a wallet file.
|
||||
// Anything smaller is junk and should be deleted.
|
||||
if (!QFile::exists(_path) || QFileInfo(_path).size() < 60) {
|
||||
QFile newfile(_path);
|
||||
if (!newfile.open(QIODevice::ReadWrite)) {
|
||||
return -2; // error opening file
|
||||
}
|
||||
newfile.close();
|
||||
_open = true;
|
||||
if (sync(w) != 0) {
|
||||
return -2;
|
||||
}
|
||||
}
|
||||
|
||||
QFile db(_path);
|
||||
|
||||
if (!db.open(QIODevice::ReadOnly)) {
|
||||
return -2; // error opening file
|
||||
}
|
||||
|
||||
char magicBuf[KWMAGIC_LEN];
|
||||
db.read(magicBuf, KWMAGIC_LEN);
|
||||
if (memcmp(magicBuf, KWMAGIC, KWMAGIC_LEN) != 0) {
|
||||
return -3; // bad magic
|
||||
}
|
||||
|
||||
db.read(magicBuf, 4);
|
||||
|
||||
// First byte is major version, second byte is minor version
|
||||
if (magicBuf[0] != KWALLETSTORAGE_VERSION_MAJOR) {
|
||||
return -4; // unknown version
|
||||
}
|
||||
|
||||
//0 has been the MINOR version until 4.13, from that point we use it to upgrade the hash
|
||||
if (magicBuf[1] == 1) {
|
||||
qCDebug(KWALLETBACKEND_LOG) << "Wallet new enough, using new hash";
|
||||
swapToNewHash();
|
||||
} else if (magicBuf[1] != 0) {
|
||||
qCDebug(KWALLETBACKEND_LOG) << "Wallet is old, sad panda :(";
|
||||
return -4; // unknown version
|
||||
}
|
||||
|
||||
BackendPersistHandler *phandler = BackendPersistHandler::getPersistHandler(magicBuf);
|
||||
if (nullptr == phandler) {
|
||||
return -41; // unknown cipher or hash
|
||||
}
|
||||
int result = phandler->read(this, db, w);
|
||||
delete phandler;
|
||||
return result;
|
||||
}
|
||||
|
||||
void Backend::swapToNewHash()
|
||||
{
|
||||
//Runtime error happened and we can't use the new hash
|
||||
if (!_useNewHash) {
|
||||
qCDebug(KWALLETBACKEND_LOG) << "Runtime error on the new hash";
|
||||
return;
|
||||
}
|
||||
_passhash.fill(0);//Making sure the old passhash is not around in memory
|
||||
_passhash = _newPassHash;//Use the new hash, means the wallet is modern enough
|
||||
}
|
||||
|
||||
QByteArray Backend::createAndSaveSalt(const QString &path) const
|
||||
{
|
||||
QFile saltFile(path);
|
||||
saltFile.remove();
|
||||
|
||||
if (!saltFile.open(QIODevice::WriteOnly)) {
|
||||
return QByteArray();
|
||||
}
|
||||
saltFile.setPermissions(QFile::ReadUser | QFile::WriteUser);
|
||||
|
||||
char *randomData = (char *) gcry_random_bytes(PBKDF2_SHA512_SALTSIZE, GCRY_STRONG_RANDOM);
|
||||
QByteArray salt(randomData, PBKDF2_SHA512_SALTSIZE);
|
||||
free(randomData);
|
||||
|
||||
if (saltFile.write(salt) != PBKDF2_SHA512_SALTSIZE) {
|
||||
return QByteArray();
|
||||
}
|
||||
|
||||
saltFile.close();
|
||||
|
||||
return salt;
|
||||
}
|
||||
|
||||
int Backend::sync(WId w)
|
||||
{
|
||||
if (!_open) {
|
||||
return -255; // not open yet
|
||||
}
|
||||
|
||||
if (!QFile::exists(_path)) {
|
||||
return -3; // File does not exist
|
||||
}
|
||||
|
||||
QSaveFile sf(_path);
|
||||
|
||||
if (!sf.open(QIODevice::WriteOnly | QIODevice::Unbuffered)) {
|
||||
return -1; // error opening file
|
||||
}
|
||||
sf.setPermissions(QFile::ReadUser | QFile::WriteUser);
|
||||
|
||||
if (sf.write(KWMAGIC, KWMAGIC_LEN) != KWMAGIC_LEN) {
|
||||
sf.cancelWriting();
|
||||
return -4; // write error
|
||||
}
|
||||
|
||||
// Write the version number
|
||||
QByteArray version(4, 0);
|
||||
version[0] = KWALLETSTORAGE_VERSION_MAJOR;
|
||||
if (_useNewHash) {
|
||||
version[1] = KWALLETSTORAGE_VERSION_MINOR;
|
||||
//Use the sync to update the hash to PBKDF2_SHA512
|
||||
swapToNewHash();
|
||||
} else {
|
||||
version[1] = 0; //was KWALLETSTORAGE_VERSION_MINOR before the new hash
|
||||
}
|
||||
|
||||
BackendPersistHandler *phandler = BackendPersistHandler::getPersistHandler(_cipherType);
|
||||
if (nullptr == phandler) {
|
||||
return -4; // write error
|
||||
}
|
||||
int rc = phandler->write(this, sf, version, w);
|
||||
if (rc < 0) {
|
||||
// Oops! wallet file sync filed! Display a notification about that
|
||||
// TODO: change kwalletd status flags, when status flags will be implemented
|
||||
KNotification *notification = new KNotification(QStringLiteral("syncFailed"));
|
||||
notification->setText(i18n("Failed to sync wallet <b>%1</b> to disk. Error codes are:\nRC <b>%2</b>\nSF <b>%3</b>. Please file a BUG report using this information to bugs.kde.org", _name, rc, sf.errorString()));
|
||||
notification->sendEvent();
|
||||
}
|
||||
delete phandler;
|
||||
return rc;
|
||||
}
|
||||
|
||||
int Backend::closeInternal(bool save)
|
||||
{
|
||||
// save if requested
|
||||
if (save) {
|
||||
int rc = sync(0);
|
||||
if (rc != 0) {
|
||||
return rc;
|
||||
}
|
||||
}
|
||||
|
||||
// do the actual close
|
||||
for (FolderMap::ConstIterator i = _entries.constBegin(); i != _entries.constEnd(); ++i) {
|
||||
for (EntryMap::ConstIterator j = i.value().constBegin(); j != i.value().constEnd(); ++j) {
|
||||
delete j.value();
|
||||
}
|
||||
}
|
||||
_entries.clear();
|
||||
_open = false;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int Backend::close(bool save)
|
||||
{
|
||||
int rc = closeInternal(save);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
// empty the password hash
|
||||
_passhash.fill(0);
|
||||
_newPassHash.fill(0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
const QString &Backend::walletName() const
|
||||
{
|
||||
return _name;
|
||||
}
|
||||
|
||||
int Backend::renameWallet(const QString &newName, bool isPath)
|
||||
{
|
||||
QString newPath;
|
||||
const auto saveLocation = getSaveLocation();
|
||||
|
||||
if (isPath) {
|
||||
newPath = newName;
|
||||
} else {
|
||||
newPath = saveLocation + QChar::fromLatin1('/') + encodeWalletName(newName) + QStringLiteral(".kwl");
|
||||
}
|
||||
|
||||
if (newPath == _path) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (QFile::exists(newPath)) {
|
||||
return -EEXIST;
|
||||
}
|
||||
|
||||
int rc = closeInternal(true);
|
||||
if (rc) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
QFile::rename(_path, newPath);
|
||||
QFile::rename(saveLocation + QChar::fromLatin1('/') + encodeWalletName(_name) + QStringLiteral(".salt"),
|
||||
saveLocation + QChar::fromLatin1('/') + encodeWalletName(newName) + QStringLiteral(".salt"));
|
||||
|
||||
_name = newName;
|
||||
_path = newPath;
|
||||
|
||||
rc = openInternal();
|
||||
if (rc) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool Backend::isOpen() const
|
||||
{
|
||||
return _open;
|
||||
}
|
||||
|
||||
QStringList Backend::folderList() const
|
||||
{
|
||||
return _entries.keys();
|
||||
}
|
||||
|
||||
QStringList Backend::entryList() const
|
||||
{
|
||||
return _entries[_folder].keys();
|
||||
}
|
||||
|
||||
Entry *Backend::readEntry(const QString &key)
|
||||
{
|
||||
Entry *rc = nullptr;
|
||||
|
||||
if (_open && hasEntry(key)) {
|
||||
rc = _entries[_folder][key];
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
#if KWALLET_BUILD_DEPRECATED_SINCE(5, 72)
|
||||
QList<Entry *> Backend::readEntryList(const QString &key)
|
||||
{
|
||||
QList<Entry *> rc;
|
||||
|
||||
if (!_open) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
// HACK: see Wallet::WalletPrivate::forEachItemThatMatches()
|
||||
const QString pattern = QRegularExpression::wildcardToRegularExpression(key).replace(
|
||||
QLatin1String("[^/]"), QLatin1String("."));
|
||||
const QRegularExpression re(pattern);
|
||||
|
||||
const EntryMap &map = _entries[_folder];
|
||||
for (EntryMap::ConstIterator i = map.begin(); i != map.end(); ++i) {
|
||||
if (re.match(i.key()).hasMatch()) {
|
||||
rc.append(i.value());
|
||||
}
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
#endif
|
||||
|
||||
QList<Entry *> Backend::entriesList() const
|
||||
{
|
||||
if (!_open) {
|
||||
return QList<Entry *>();
|
||||
}
|
||||
const EntryMap &map = _entries[_folder];
|
||||
|
||||
return map.values();
|
||||
}
|
||||
|
||||
|
||||
bool Backend::createFolder(const QString &f)
|
||||
{
|
||||
if (_entries.contains(f)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
_entries.insert(f, EntryMap());
|
||||
|
||||
QCryptographicHash folderMd5(QCryptographicHash::Md5);
|
||||
folderMd5.addData(f.toUtf8());
|
||||
_hashes.insert(MD5Digest(folderMd5.result()), QList<MD5Digest>());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int Backend::renameEntry(const QString &oldName, const QString &newName)
|
||||
{
|
||||
EntryMap &emap = _entries[_folder];
|
||||
EntryMap::Iterator oi = emap.find(oldName);
|
||||
EntryMap::Iterator ni = emap.find(newName);
|
||||
|
||||
if (oi != emap.end() && ni == emap.end()) {
|
||||
Entry *e = oi.value();
|
||||
emap.erase(oi);
|
||||
emap[newName] = e;
|
||||
|
||||
QCryptographicHash folderMd5(QCryptographicHash::Md5);
|
||||
folderMd5.addData(_folder.toUtf8());
|
||||
|
||||
HashMap::iterator i = _hashes.find(MD5Digest(folderMd5.result()));
|
||||
if (i != _hashes.end()) {
|
||||
QCryptographicHash oldMd5(QCryptographicHash::Md5);
|
||||
QCryptographicHash newMd5(QCryptographicHash::Md5);
|
||||
oldMd5.addData(oldName.toUtf8());
|
||||
newMd5.addData(newName.toUtf8());
|
||||
i.value().removeAll(MD5Digest(oldMd5.result()));
|
||||
i.value().append(MD5Digest(newMd5.result()));
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
void Backend::writeEntry(Entry *e)
|
||||
{
|
||||
if (!_open) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!hasEntry(e->key())) {
|
||||
_entries[_folder][e->key()] = new Entry;
|
||||
}
|
||||
_entries[_folder][e->key()]->copy(e);
|
||||
|
||||
QCryptographicHash folderMd5(QCryptographicHash::Md5);
|
||||
folderMd5.addData(_folder.toUtf8());
|
||||
|
||||
HashMap::iterator i = _hashes.find(MD5Digest(folderMd5.result()));
|
||||
if (i != _hashes.end()) {
|
||||
QCryptographicHash md5(QCryptographicHash::Md5);
|
||||
md5.addData(e->key().toUtf8());
|
||||
i.value().append(MD5Digest(md5.result()));
|
||||
}
|
||||
}
|
||||
|
||||
bool Backend::hasEntry(const QString &key) const
|
||||
{
|
||||
return _entries.contains(_folder) && _entries[_folder].contains(key);
|
||||
}
|
||||
|
||||
bool Backend::removeEntry(const QString &key)
|
||||
{
|
||||
if (!_open) {
|
||||
return false;
|
||||
}
|
||||
|
||||
FolderMap::Iterator fi = _entries.find(_folder);
|
||||
EntryMap::Iterator ei = fi.value().find(key);
|
||||
|
||||
if (fi != _entries.end() && ei != fi.value().end()) {
|
||||
delete ei.value();
|
||||
fi.value().erase(ei);
|
||||
QCryptographicHash folderMd5(QCryptographicHash::Md5);
|
||||
folderMd5.addData(_folder.toUtf8());
|
||||
|
||||
HashMap::iterator i = _hashes.find(MD5Digest(folderMd5.result()));
|
||||
if (i != _hashes.end()) {
|
||||
QCryptographicHash md5(QCryptographicHash::Md5);
|
||||
md5.addData(key.toUtf8());
|
||||
i.value().removeAll(MD5Digest(md5.result()));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Backend::removeFolder(const QString &f)
|
||||
{
|
||||
if (!_open) {
|
||||
return false;
|
||||
}
|
||||
|
||||
FolderMap::Iterator fi = _entries.find(f);
|
||||
|
||||
if (fi != _entries.end()) {
|
||||
if (_folder == f) {
|
||||
_folder.clear();
|
||||
}
|
||||
|
||||
for (EntryMap::Iterator ei = fi.value().begin(); ei != fi.value().end(); ++ei) {
|
||||
delete ei.value();
|
||||
}
|
||||
|
||||
_entries.erase(fi);
|
||||
|
||||
QCryptographicHash folderMd5(QCryptographicHash::Md5);
|
||||
folderMd5.addData(f.toUtf8());
|
||||
_hashes.remove(MD5Digest(folderMd5.result()));
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Backend::folderDoesNotExist(const QString &folder) const
|
||||
{
|
||||
QCryptographicHash md5(QCryptographicHash::Md5);
|
||||
md5.addData(folder.toUtf8());
|
||||
return !_hashes.contains(MD5Digest(md5.result()));
|
||||
}
|
||||
|
||||
bool Backend::entryDoesNotExist(const QString &folder, const QString &entry) const
|
||||
{
|
||||
QCryptographicHash md5(QCryptographicHash::Md5);
|
||||
md5.addData(folder.toUtf8());
|
||||
HashMap::const_iterator i = _hashes.find(MD5Digest(md5.result()));
|
||||
if (i != _hashes.end()) {
|
||||
md5.reset();
|
||||
md5.addData(entry.toUtf8());
|
||||
return !i.value().contains(MD5Digest(md5.result()));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void Backend::setPassword(const QByteArray &password)
|
||||
{
|
||||
_passhash.fill(0); // empty just in case
|
||||
BlowFish _bf;
|
||||
CipherBlockChain bf(&_bf);
|
||||
_passhash.resize(bf.keyLen() / 8);
|
||||
_newPassHash.resize(bf.keyLen() / 8);
|
||||
_newPassHash.fill(0);
|
||||
|
||||
password2hash(password, _passhash);
|
||||
|
||||
QByteArray salt;
|
||||
QFile saltFile(getSaveLocation() + '/' + encodeWalletName(_name) + ".salt");
|
||||
if (!saltFile.exists() || saltFile.size() == 0) {
|
||||
salt = createAndSaveSalt(saltFile.fileName());
|
||||
} else {
|
||||
if (!saltFile.open(QIODevice::ReadOnly)) {
|
||||
salt = createAndSaveSalt(saltFile.fileName());
|
||||
} else {
|
||||
salt = saltFile.readAll();
|
||||
}
|
||||
}
|
||||
|
||||
if (!salt.isEmpty() && password2PBKDF2_SHA512(password, _newPassHash, salt) == 0) {
|
||||
qCDebug(KWALLETBACKEND_LOG) << "Setting useNewHash to true";
|
||||
_useNewHash = true;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef HAVE_GPGMEPP
|
||||
const GpgME::Key &Backend::gpgKey() const
|
||||
{
|
||||
return _gpgKey;
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,234 @@
|
||||
/*
|
||||
This file is part of the KDE project
|
||||
SPDX-FileCopyrightText: 2001-2004 George Staikos <staikos@kde.org>
|
||||
|
||||
SPDX-License-Identifier: LGPL-2.0-or-later
|
||||
*/
|
||||
|
||||
#ifndef _KWALLETBACKEND_H
|
||||
#define _KWALLETBACKEND_H
|
||||
|
||||
#include "backendpersisthandler.h"
|
||||
#include "kwalletbackend_export.h"
|
||||
#include "kwalletentry.h"
|
||||
#include <QMap>
|
||||
#include <QString>
|
||||
#include <QStringList>
|
||||
|
||||
#ifdef HAVE_GPGMEPP
|
||||
#include <gpgme++/key.h>
|
||||
#endif // HAVE_GPGMEPP
|
||||
|
||||
#define PBKDF2_SHA512_KEYSIZE 56
|
||||
#define PBKDF2_SHA512_SALTSIZE 56
|
||||
#define PBKDF2_SHA512_ITERATIONS 50000
|
||||
|
||||
namespace KWallet
|
||||
{
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
class MD5Digest : public QByteArray
|
||||
{
|
||||
public:
|
||||
MD5Digest()
|
||||
: QByteArray(16, 0)
|
||||
{
|
||||
}
|
||||
MD5Digest(const char *data)
|
||||
: QByteArray(data, 16)
|
||||
{
|
||||
}
|
||||
MD5Digest(const QByteArray &digest)
|
||||
: QByteArray(digest)
|
||||
{
|
||||
}
|
||||
virtual ~MD5Digest()
|
||||
{
|
||||
}
|
||||
|
||||
int operator<(const MD5Digest &r) const
|
||||
{
|
||||
int i = 0;
|
||||
char x, y;
|
||||
for (; i < 16; ++i) {
|
||||
x = at(i);
|
||||
y = r.at(i);
|
||||
if (x != y) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (i < 16 && x < y) {
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
|
||||
/* @internal
|
||||
*/
|
||||
class KWALLETBACKEND_EXPORT Backend
|
||||
{
|
||||
public:
|
||||
explicit Backend(const QString &name = QStringLiteral("kdewallet"), bool isPath = false);
|
||||
~Backend();
|
||||
|
||||
// Open and unlock the wallet.
|
||||
// If opening succeeds, the password's hash will be remembered.
|
||||
// If opening fails, the password's hash will be cleared.
|
||||
int open(const QByteArray &password, WId w = 0);
|
||||
#ifdef HAVE_GPGMEPP
|
||||
int open(const GpgME::Key &key);
|
||||
#endif
|
||||
|
||||
// Open and unlock the wallet using a pre-hashed password.
|
||||
// If opening succeeds, the password's hash will be remembered.
|
||||
// If opening fails, the password's hash will be cleared.
|
||||
int openPreHashed(const QByteArray &passwordHash);
|
||||
|
||||
// Close the wallet, losing any changes.
|
||||
// if save is true, the wallet is saved prior to closing it.
|
||||
int close(bool save = false);
|
||||
|
||||
// Write the wallet to disk
|
||||
int sync(WId w);
|
||||
|
||||
// Returns true if the current wallet is open.
|
||||
bool isOpen() const;
|
||||
|
||||
// Returns the current wallet name.
|
||||
const QString &walletName() const;
|
||||
|
||||
// Rename the wallet
|
||||
int renameWallet(const QString &newName, bool isPath = false);
|
||||
|
||||
// The list of folders.
|
||||
QStringList folderList() const;
|
||||
|
||||
// Force creation of a folder.
|
||||
bool createFolder(const QString &f);
|
||||
|
||||
// Change the folder.
|
||||
void setFolder(const QString &f)
|
||||
{
|
||||
_folder = f;
|
||||
}
|
||||
|
||||
// Current folder. If empty, it's the global folder.
|
||||
const QString &folder() const
|
||||
{
|
||||
return _folder;
|
||||
}
|
||||
|
||||
// Does it have this folder?
|
||||
bool hasFolder(const QString &f) const
|
||||
{
|
||||
return _entries.contains(f);
|
||||
}
|
||||
|
||||
// Look up an entry. Returns null if it doesn't exist.
|
||||
Entry *readEntry(const QString &key);
|
||||
|
||||
#if KWALLET_BUILD_DEPRECATED_SINCE(5, 72)
|
||||
// Look up a list of entries. Supports wildcards.
|
||||
// You delete the list.
|
||||
// Deprecated since 5.72, use entriesList()
|
||||
QList<Entry *> readEntryList(const QString &key);
|
||||
#endif
|
||||
|
||||
// Get a list of all the entries in the current folder.
|
||||
// @since 5.72
|
||||
QList<Entry *> entriesList() const;
|
||||
|
||||
// Store an entry.
|
||||
void writeEntry(Entry *e);
|
||||
|
||||
// Does this folder contain this entry?
|
||||
bool hasEntry(const QString &key) const;
|
||||
|
||||
// Returns true if the entry was removed
|
||||
bool removeEntry(const QString &key);
|
||||
|
||||
// Returns true if the folder was removed
|
||||
bool removeFolder(const QString &f);
|
||||
|
||||
// The list of entries in this folder.
|
||||
QStringList entryList() const;
|
||||
|
||||
// Rename an entry in this folder.
|
||||
int renameEntry(const QString &oldName, const QString &newName);
|
||||
|
||||
// Set the password used for opening/closing the wallet.
|
||||
// This does not sync the wallet to disk!
|
||||
void setPassword(const QByteArray &password);
|
||||
|
||||
int ref()
|
||||
{
|
||||
return ++_ref;
|
||||
}
|
||||
|
||||
int deref();
|
||||
|
||||
int refCount() const
|
||||
{
|
||||
return _ref;
|
||||
}
|
||||
|
||||
static bool exists(const QString &wallet);
|
||||
|
||||
bool folderDoesNotExist(const QString &folder) const;
|
||||
|
||||
bool entryDoesNotExist(const QString &folder, const QString &entry) const;
|
||||
|
||||
static QString openRCToString(int rc);
|
||||
|
||||
void setCipherType(BackendCipherType ct);
|
||||
BackendCipherType cipherType() const
|
||||
{
|
||||
return _cipherType;
|
||||
}
|
||||
#ifdef HAVE_GPGMEPP
|
||||
const GpgME::Key &gpgKey() const;
|
||||
#endif
|
||||
|
||||
static QString getSaveLocation();
|
||||
static QString encodeWalletName(const QString &name);
|
||||
static QString decodeWalletName(const QString &encodedName);
|
||||
|
||||
private:
|
||||
Q_DISABLE_COPY(Backend)
|
||||
class BackendPrivate;
|
||||
BackendPrivate *const d;
|
||||
QString _name;
|
||||
QString _path;
|
||||
bool _open;
|
||||
bool _useNewHash = false;
|
||||
QString _folder;
|
||||
int _ref = 0;
|
||||
// Map Folder->Entries
|
||||
typedef QMap<QString, Entry *> EntryMap;
|
||||
typedef QMap<QString, EntryMap> FolderMap;
|
||||
FolderMap _entries;
|
||||
typedef QMap<MD5Digest, QList<MD5Digest>> HashMap;
|
||||
HashMap _hashes;
|
||||
QByteArray _passhash; // password hash used for saving the wallet
|
||||
QByteArray _newPassHash; // Modern hash using KWALLET_HASH_PBKDF2_SHA512
|
||||
BackendCipherType _cipherType; // the kind of encryption used for this wallet
|
||||
|
||||
#ifdef HAVE_GPGMEPP
|
||||
GpgME::Key _gpgKey;
|
||||
#endif
|
||||
friend class BlowfishPersistHandler;
|
||||
friend class GpgPersistHandler;
|
||||
|
||||
// open the wallet with the password already set. This is
|
||||
// called internally by both open and openPreHashed.
|
||||
int openInternal(WId w = 0);
|
||||
int closeInternal(bool save);
|
||||
void swapToNewHash();
|
||||
QByteArray createAndSaveSalt(const QString &path) const;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,78 @@
|
||||
/*
|
||||
This file is part of the KDE project
|
||||
SPDX-FileCopyrightText: 2001-2003 George Staikos <staikos@kde.org>
|
||||
|
||||
SPDX-License-Identifier: LGPL-2.0-or-later
|
||||
*/
|
||||
|
||||
#include "kwalletentry.h"
|
||||
|
||||
using namespace KWallet;
|
||||
#include <QDataStream>
|
||||
#include <QIODevice>
|
||||
|
||||
Entry::Entry()
|
||||
{
|
||||
}
|
||||
|
||||
Entry::~Entry()
|
||||
{
|
||||
_value.fill(0);
|
||||
}
|
||||
|
||||
const QString &Entry::key() const
|
||||
{
|
||||
return _key;
|
||||
}
|
||||
|
||||
const QByteArray &Entry::value() const
|
||||
{
|
||||
return _value;
|
||||
}
|
||||
|
||||
QString Entry::password() const
|
||||
{
|
||||
QString x;
|
||||
QDataStream qds(_value);
|
||||
qds >> x;
|
||||
return x;
|
||||
}
|
||||
|
||||
void Entry::setValue(const QByteArray &val)
|
||||
{
|
||||
// do a direct copy from one into the other without
|
||||
// temporary variables
|
||||
_value.fill(0);
|
||||
_value = val;
|
||||
}
|
||||
|
||||
void Entry::setValue(const QString &val)
|
||||
{
|
||||
_value.fill(0);
|
||||
QDataStream qds(&_value, QIODevice::WriteOnly);
|
||||
qds << val;
|
||||
}
|
||||
|
||||
void Entry::setKey(const QString &key)
|
||||
{
|
||||
_key = key;
|
||||
}
|
||||
|
||||
Wallet::EntryType Entry::type() const
|
||||
{
|
||||
return _type;
|
||||
}
|
||||
|
||||
void Entry::setType(Wallet::EntryType type)
|
||||
{
|
||||
_type = type;
|
||||
}
|
||||
|
||||
void Entry::copy(const Entry *x)
|
||||
{
|
||||
_type = x->_type;
|
||||
_key = x->_key;
|
||||
_value.fill(0);
|
||||
_value = x->_value;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
This file is part of the KDE project
|
||||
SPDX-FileCopyrightText: 2001-2003 George Staikos <staikos@kde.org>
|
||||
|
||||
SPDX-License-Identifier: LGPL-2.0-or-later
|
||||
*/
|
||||
|
||||
#ifndef _KWALLETENTRY_H
|
||||
#define _KWALLETENTRY_H
|
||||
|
||||
#include <QString>
|
||||
|
||||
#include <kwallet.h>
|
||||
|
||||
#include "kwalletbackend_export.h"
|
||||
|
||||
namespace KWallet
|
||||
{
|
||||
/* @internal
|
||||
*/
|
||||
class KWALLETBACKEND_EXPORT Entry
|
||||
{
|
||||
public:
|
||||
Entry();
|
||||
~Entry();
|
||||
|
||||
const QString &key() const;
|
||||
const QByteArray &value() const;
|
||||
QString password() const;
|
||||
const QByteArray &map() const
|
||||
{
|
||||
return value();
|
||||
}
|
||||
|
||||
void setValue(const QByteArray &val);
|
||||
void setValue(const QString &val);
|
||||
void setKey(const QString &key);
|
||||
|
||||
Wallet::EntryType type() const;
|
||||
void setType(Wallet::EntryType type);
|
||||
|
||||
void copy(const Entry *x);
|
||||
|
||||
private:
|
||||
QString _key;
|
||||
QByteArray _value;
|
||||
Wallet::EntryType _type;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,341 @@
|
||||
/*
|
||||
This file is part of the KDE project
|
||||
SPDX-FileCopyrightText: 2001 George Staikos <staikos@kde.org>
|
||||
|
||||
Based heavily on SHA1 code from GPG 1.0.3:
|
||||
SPDX-FileCopyrightText: 1998 FSF
|
||||
|
||||
SPDX-License-Identifier: LGPL-2.0-or-later
|
||||
*/
|
||||
|
||||
#include "sha1.h"
|
||||
|
||||
#include <config-kwalletbackend.h>
|
||||
|
||||
// DO NOT INCLUDE THIS. IT BREAKS KWALLET.
|
||||
// We need to live with -Wundef until someone really figures out the problem.
|
||||
//#include <QtCore/qglobal.h> // for Q_BYTE_ORDER and friends
|
||||
// Workaround for -Wundef
|
||||
#define Q_BIG_ENDIAN 1
|
||||
#define Q_BYTE_ORDER Q_BIG_ENDIAN
|
||||
|
||||
#include <sys/types.h>
|
||||
#if HAVE_SYS_BITYPES_H
|
||||
#include <sys/bitypes.h> /* For uintXX_t on Tru64 */
|
||||
#endif
|
||||
#if HAVE_STDINT_H
|
||||
#include <stdint.h>
|
||||
#endif
|
||||
|
||||
#include <string.h>
|
||||
|
||||
// clang-format off
|
||||
// FIXME: this can be optimized to one instruction on most cpus.
|
||||
#define rol(x,y) ((x << y) | (x >> (32-y)))
|
||||
|
||||
#define K1 0x5a827999L
|
||||
#define K2 0x6ed9eba1L
|
||||
#define K3 0x8f1bbcdcL
|
||||
#define K4 0xca62c1d6L
|
||||
#define F1(x,y,z) ( z ^ ( x & ( y ^ z ) ) )
|
||||
#define F2(x,y,z) ( x ^ y ^ z )
|
||||
#define F3(x,y,z) ( ( x & y ) | ( z & ( x | y ) ) )
|
||||
#define F4(x,y,z) ( x ^ y ^ z )
|
||||
|
||||
#define M(i) ( tm = x[i&0x0f] ^ x[(i-14)&0x0f] \
|
||||
^ x[(i-8)&0x0f] ^ x[(i-3)&0x0f] \
|
||||
, (x[i&0x0f] = (tm << 1) | (tm >> 31)))
|
||||
|
||||
#define R(a,b,c,d,e,f,k,m) do { e += rol(a, 5) \
|
||||
+ f(b, c, d) \
|
||||
+ k \
|
||||
+ m; \
|
||||
b = rol(b, 30); \
|
||||
} while(0)
|
||||
// clang-format on
|
||||
|
||||
SHA1::SHA1()
|
||||
{
|
||||
_hashlen = 160;
|
||||
_init = false;
|
||||
reset();
|
||||
}
|
||||
|
||||
int SHA1::reset()
|
||||
{
|
||||
_h0 = 0x67452301;
|
||||
_h1 = 0xefcdab89;
|
||||
_h2 = 0x98badcfe;
|
||||
_h3 = 0x10325476;
|
||||
_h4 = 0xc3d2e1f0;
|
||||
_nblocks = 0;
|
||||
_count = 0;
|
||||
memset(_buf, 0, 56); // clear the buffer
|
||||
|
||||
_init = true;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int SHA1::size() const
|
||||
{
|
||||
return _hashlen;
|
||||
}
|
||||
|
||||
SHA1::~SHA1()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void SHA1::transform(void *data)
|
||||
{
|
||||
unsigned int a;
|
||||
unsigned int b;
|
||||
unsigned int c;
|
||||
unsigned int d;
|
||||
unsigned int e;
|
||||
unsigned int tm;
|
||||
unsigned int x[16];
|
||||
unsigned char *_data = (unsigned char *)data;
|
||||
|
||||
a = _h0;
|
||||
b = _h1;
|
||||
c = _h2;
|
||||
d = _h3;
|
||||
e = _h4;
|
||||
|
||||
#if Q_BYTE_ORDER == Q_BIG_ENDIAN
|
||||
memcpy(x, _data, 64);
|
||||
#else
|
||||
int i;
|
||||
unsigned char *p2;
|
||||
for (i = 0, p2 = (unsigned char *)x;
|
||||
i < 16; i++, p2 += 4) {
|
||||
p2[3] = *_data++;
|
||||
p2[2] = *_data++;
|
||||
p2[1] = *_data++;
|
||||
p2[0] = *_data++;
|
||||
}
|
||||
#endif
|
||||
|
||||
R(a, b, c, d, e, F1, K1, x[ 0]);
|
||||
R(e, a, b, c, d, F1, K1, x[ 1]);
|
||||
R(d, e, a, b, c, F1, K1, x[ 2]);
|
||||
R(c, d, e, a, b, F1, K1, x[ 3]);
|
||||
R(b, c, d, e, a, F1, K1, x[ 4]);
|
||||
R(a, b, c, d, e, F1, K1, x[ 5]);
|
||||
R(e, a, b, c, d, F1, K1, x[ 6]);
|
||||
R(d, e, a, b, c, F1, K1, x[ 7]);
|
||||
R(c, d, e, a, b, F1, K1, x[ 8]);
|
||||
R(b, c, d, e, a, F1, K1, x[ 9]);
|
||||
R(a, b, c, d, e, F1, K1, x[10]);
|
||||
R(e, a, b, c, d, F1, K1, x[11]);
|
||||
R(d, e, a, b, c, F1, K1, x[12]);
|
||||
R(c, d, e, a, b, F1, K1, x[13]);
|
||||
R(b, c, d, e, a, F1, K1, x[14]);
|
||||
R(a, b, c, d, e, F1, K1, x[15]);
|
||||
R(e, a, b, c, d, F1, K1, M(16));
|
||||
R(d, e, a, b, c, F1, K1, M(17));
|
||||
R(c, d, e, a, b, F1, K1, M(18));
|
||||
R(b, c, d, e, a, F1, K1, M(19));
|
||||
R(a, b, c, d, e, F2, K2, M(20));
|
||||
R(e, a, b, c, d, F2, K2, M(21));
|
||||
R(d, e, a, b, c, F2, K2, M(22));
|
||||
R(c, d, e, a, b, F2, K2, M(23));
|
||||
R(b, c, d, e, a, F2, K2, M(24));
|
||||
R(a, b, c, d, e, F2, K2, M(25));
|
||||
R(e, a, b, c, d, F2, K2, M(26));
|
||||
R(d, e, a, b, c, F2, K2, M(27));
|
||||
R(c, d, e, a, b, F2, K2, M(28));
|
||||
R(b, c, d, e, a, F2, K2, M(29));
|
||||
R(a, b, c, d, e, F2, K2, M(30));
|
||||
R(e, a, b, c, d, F2, K2, M(31));
|
||||
R(d, e, a, b, c, F2, K2, M(32));
|
||||
R(c, d, e, a, b, F2, K2, M(33));
|
||||
R(b, c, d, e, a, F2, K2, M(34));
|
||||
R(a, b, c, d, e, F2, K2, M(35));
|
||||
R(e, a, b, c, d, F2, K2, M(36));
|
||||
R(d, e, a, b, c, F2, K2, M(37));
|
||||
R(c, d, e, a, b, F2, K2, M(38));
|
||||
R(b, c, d, e, a, F2, K2, M(39));
|
||||
R(a, b, c, d, e, F3, K3, M(40));
|
||||
R(e, a, b, c, d, F3, K3, M(41));
|
||||
R(d, e, a, b, c, F3, K3, M(42));
|
||||
R(c, d, e, a, b, F3, K3, M(43));
|
||||
R(b, c, d, e, a, F3, K3, M(44));
|
||||
R(a, b, c, d, e, F3, K3, M(45));
|
||||
R(e, a, b, c, d, F3, K3, M(46));
|
||||
R(d, e, a, b, c, F3, K3, M(47));
|
||||
R(c, d, e, a, b, F3, K3, M(48));
|
||||
R(b, c, d, e, a, F3, K3, M(49));
|
||||
R(a, b, c, d, e, F3, K3, M(50));
|
||||
R(e, a, b, c, d, F3, K3, M(51));
|
||||
R(d, e, a, b, c, F3, K3, M(52));
|
||||
R(c, d, e, a, b, F3, K3, M(53));
|
||||
R(b, c, d, e, a, F3, K3, M(54));
|
||||
R(a, b, c, d, e, F3, K3, M(55));
|
||||
R(e, a, b, c, d, F3, K3, M(56));
|
||||
R(d, e, a, b, c, F3, K3, M(57));
|
||||
R(c, d, e, a, b, F3, K3, M(58));
|
||||
R(b, c, d, e, a, F3, K3, M(59));
|
||||
R(a, b, c, d, e, F4, K4, M(60));
|
||||
R(e, a, b, c, d, F4, K4, M(61));
|
||||
R(d, e, a, b, c, F4, K4, M(62));
|
||||
R(c, d, e, a, b, F4, K4, M(63));
|
||||
R(b, c, d, e, a, F4, K4, M(64));
|
||||
R(a, b, c, d, e, F4, K4, M(65));
|
||||
R(e, a, b, c, d, F4, K4, M(66));
|
||||
R(d, e, a, b, c, F4, K4, M(67));
|
||||
R(c, d, e, a, b, F4, K4, M(68));
|
||||
R(b, c, d, e, a, F4, K4, M(69));
|
||||
R(a, b, c, d, e, F4, K4, M(70));
|
||||
R(e, a, b, c, d, F4, K4, M(71));
|
||||
R(d, e, a, b, c, F4, K4, M(72));
|
||||
R(c, d, e, a, b, F4, K4, M(73));
|
||||
R(b, c, d, e, a, F4, K4, M(74));
|
||||
R(a, b, c, d, e, F4, K4, M(75));
|
||||
R(e, a, b, c, d, F4, K4, M(76));
|
||||
R(d, e, a, b, c, F4, K4, M(77));
|
||||
R(c, d, e, a, b, F4, K4, M(78));
|
||||
R(b, c, d, e, a, F4, K4, M(79));
|
||||
|
||||
_h0 += a;
|
||||
_h1 += b;
|
||||
_h2 += c;
|
||||
_h3 += d;
|
||||
_h4 += e;
|
||||
|
||||
}
|
||||
|
||||
bool SHA1::readyToGo() const
|
||||
{
|
||||
return _init;
|
||||
}
|
||||
|
||||
int SHA1::process(const void *block, int len)
|
||||
{
|
||||
if (!_init) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
unsigned char *_block = (unsigned char *)block;
|
||||
|
||||
int cnt = 0;
|
||||
// Flush the buffer before proceeding
|
||||
if (_count == 64) {
|
||||
transform(_buf);
|
||||
_count = 0;
|
||||
_nblocks++;
|
||||
}
|
||||
|
||||
if (!_block) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (_count) {
|
||||
for (; len && _count < 64; --len, ++cnt) {
|
||||
_buf[_count++] = *_block++;
|
||||
}
|
||||
process(nullptr, 0); // flush the buffer if necessary
|
||||
if (!len) {
|
||||
return cnt;
|
||||
}
|
||||
}
|
||||
|
||||
while (len >= 64) {
|
||||
transform(_block);
|
||||
_count = 0;
|
||||
_nblocks++;
|
||||
len -= 64;
|
||||
cnt += 64;
|
||||
_block += 64;
|
||||
}
|
||||
|
||||
for (; len && _count < 64; --len, ++cnt) {
|
||||
_buf[_count++] = *_block++;
|
||||
}
|
||||
|
||||
return cnt;
|
||||
}
|
||||
|
||||
const unsigned char *SHA1::hash()
|
||||
{
|
||||
unsigned int t;
|
||||
unsigned int msb;
|
||||
unsigned int lsb;
|
||||
unsigned char *p;
|
||||
|
||||
if (!_init) {
|
||||
return (unsigned char *)_buf;
|
||||
}
|
||||
|
||||
process(nullptr, 0);
|
||||
|
||||
msb = 0;
|
||||
t = _nblocks;
|
||||
|
||||
if ((lsb = t << 6) < t) {
|
||||
msb++;
|
||||
}
|
||||
|
||||
msb += t >> 26;
|
||||
t = lsb;
|
||||
|
||||
if ((lsb = t + _count) < t) {
|
||||
msb++;
|
||||
}
|
||||
|
||||
t = lsb;
|
||||
|
||||
if ((lsb = t << 3) < t) {
|
||||
msb++;
|
||||
}
|
||||
|
||||
msb += t >> 29;
|
||||
|
||||
_buf[_count++] = 0x80;
|
||||
|
||||
if (_count < 56) {
|
||||
while (_count < 56) {
|
||||
_buf[_count++] = 0;
|
||||
}
|
||||
} else {
|
||||
while (_count < 64) {
|
||||
_buf[_count++] = 0;
|
||||
}
|
||||
process(nullptr, 0);
|
||||
memset(_buf, 0, 56);
|
||||
}
|
||||
|
||||
_buf[56] = msb >> 24;
|
||||
_buf[57] = msb >> 16;
|
||||
_buf[58] = msb >> 8;
|
||||
_buf[59] = msb;
|
||||
_buf[60] = lsb >> 24;
|
||||
_buf[61] = lsb >> 16;
|
||||
_buf[62] = lsb >> 8;
|
||||
_buf[63] = lsb;
|
||||
|
||||
transform(_buf);
|
||||
|
||||
p = _buf;
|
||||
// clang-format off
|
||||
#if Q_BYTE_ORDER == Q_BIG_ENDIAN
|
||||
#define X(a) do { *(uint32_t *)p = _h##a; p += 4; } while (0)
|
||||
#else
|
||||
#define X(a) do { *p++ = _h##a >> 24; *p++ = _h##a >> 16; \
|
||||
*p++ = _h##a >> 8; *p++ = _h##a; } while (0)
|
||||
#endif
|
||||
// clang-format on
|
||||
|
||||
X(0);
|
||||
X(1);
|
||||
X(2);
|
||||
X(3);
|
||||
X(4);
|
||||
|
||||
#undef X
|
||||
|
||||
_init = false;
|
||||
|
||||
return (unsigned char *)_buf;
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
This file is part of the KDE project
|
||||
SPDX-FileCopyrightText: 2001 George Staikos <staikos@kde.org>
|
||||
|
||||
Based heavily on SHA1 code from GPG 1.0.3:
|
||||
SPDX-FileCopyrightText: 1998 FSF
|
||||
|
||||
SPDX-License-Identifier: LGPL-2.0-or-later
|
||||
*/
|
||||
|
||||
#ifndef __sha1__ko__h
|
||||
#define __sha1__ko__h
|
||||
|
||||
#include "kwalletbackend_export.h"
|
||||
|
||||
/* @internal
|
||||
*/
|
||||
class KWALLETBACKEND_EXPORT SHA1
|
||||
{
|
||||
public:
|
||||
SHA1();
|
||||
~SHA1();
|
||||
|
||||
/*
|
||||
* The number of bits in the hash generated.
|
||||
*/
|
||||
int size() const;
|
||||
|
||||
/*
|
||||
* True if all settings are good and we are ready to hash.
|
||||
*/
|
||||
bool readyToGo() const;
|
||||
|
||||
/*
|
||||
* Process a block of data for the hash function.
|
||||
*/
|
||||
int process(const void *block, int len);
|
||||
|
||||
/*
|
||||
* Return the digest as a 20 byte array reference.
|
||||
* Calling this makes readyToGo() == false.
|
||||
*/
|
||||
const unsigned char *hash();
|
||||
|
||||
/*
|
||||
* Reset the digest so a new one can be calculated.
|
||||
*/
|
||||
int reset();
|
||||
|
||||
protected:
|
||||
int _hashlen;
|
||||
bool _init;
|
||||
|
||||
long _h0, _h1, _h2, _h3, _h4;
|
||||
long _nblocks;
|
||||
int _count;
|
||||
unsigned char _buf[64];
|
||||
void transform(void *data);
|
||||
};
|
||||
|
||||
#endif
|
||||
+22
@@ -0,0 +1,22 @@
|
||||
set( EXECUTABLE_OUTPUT_PATH ${CMAKE_CURRENT_BINARY_DIR} )
|
||||
|
||||
include_directories(
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/..
|
||||
${CMAKE_CURRENT_BINARY_DIR}/..
|
||||
)
|
||||
|
||||
include(ECMMarkAsTest)
|
||||
|
||||
macro(kwallet_executable_tests)
|
||||
foreach(_testname ${ARGN})
|
||||
add_executable(${_testname} ${_testname}.cpp)
|
||||
ecm_mark_as_test(${_testname})
|
||||
target_link_libraries(${_testname} Qt6::Widgets KF6WalletBackend)
|
||||
endforeach(_testname)
|
||||
endmacro()
|
||||
|
||||
kwallet_executable_tests(
|
||||
backendtest
|
||||
testbf
|
||||
testsha
|
||||
)
|
||||
+43
@@ -0,0 +1,43 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <QApplication>
|
||||
#include <QString>
|
||||
|
||||
#include "kwalletbackend.h"
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
QApplication a(argc, argv);
|
||||
a.setApplicationName(QStringLiteral("backendtest"));
|
||||
|
||||
KWallet::Backend be(QStringLiteral("ktestwallet"));
|
||||
printf("KWalletBackend constructed\n");
|
||||
|
||||
QByteArray apass("apassword", 9);
|
||||
QByteArray bpass("bpassword", 9);
|
||||
|
||||
printf("Passwords initialised.\n");
|
||||
be.setPassword(apass);
|
||||
int rc = be.close(true);
|
||||
|
||||
printf("be.close(true) returned %d (should be -255)\n", rc);
|
||||
|
||||
rc = be.open(bpass);
|
||||
|
||||
printf("be.open(bpass) returned %d (should be 0 or 1)\n", rc);
|
||||
|
||||
rc = be.close(true);
|
||||
|
||||
printf("be.close(true) returned %d (should be 0)\n", rc);
|
||||
|
||||
rc = be.open(apass);
|
||||
|
||||
printf("be.open(apass) returned %d (should be negative)\n", rc);
|
||||
|
||||
rc = be.open(bpass);
|
||||
|
||||
printf("be.open(bpass) returned %d (should be 0)\n", rc);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
#include "blowfish.h"
|
||||
#include "cbc.h"
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
int main()
|
||||
{
|
||||
BlockCipher *bf;
|
||||
char data[] = "This is a test.";
|
||||
const char expect[] = "\x3f\x3c\x2d\xae\x8c\x7\x84\xf2\xa7\x6d\x28\xbd\xd\xb\xb8\x79";
|
||||
char key[] = "testkey";
|
||||
unsigned long et[] = {0x11223344};
|
||||
|
||||
printf("%d: 0x11 == %d and 0x44 == %d\n", ((unsigned char *)et)[0], 0x11, 0x44);
|
||||
bf = new BlowFish();
|
||||
// bf = new CipherBlockChain(new BlowFish());
|
||||
|
||||
bf->setKey((void *)key, 7 * 8);
|
||||
|
||||
if (!bf->readyToGo()) {
|
||||
printf("Error: not ready to go!\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
printf("About to encrypt...\n");
|
||||
fflush(stdout);
|
||||
if (-1 == bf->encrypt((void *)data, 16)) {
|
||||
printf("Error: encrypt failed!\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
printf("Encryption done. data[] is now: ");
|
||||
for (int i = 0; i < 16; i++) {
|
||||
printf("0x%x ", data[i] & 0xff);
|
||||
if ((data[i] & 0xff) != (expect[i] & 0xff)) {
|
||||
printf("Error. This byte failed the comparison. It should have been 0x%x.\n", expect[i] & 0xff);
|
||||
break;
|
||||
}
|
||||
}
|
||||
printf("\n");
|
||||
|
||||
delete bf;
|
||||
bf = new BlowFish();
|
||||
// bf = new CipherBlockChain(new BlowFish());
|
||||
bf->setKey((void *)key, 7 * 8);
|
||||
|
||||
printf("About to decrypt...\n");
|
||||
fflush(stdout);
|
||||
if (-1 == bf->decrypt((void *)data, 16)) {
|
||||
printf("Error: decrypt failed!\n");
|
||||
return -1;
|
||||
}
|
||||
// bf->decrypt((void *)(data+8), 8);
|
||||
|
||||
printf("All done! Result... data[] = \"%s\"\n", data);
|
||||
if (strcmp(data, "This is a test.")) {
|
||||
printf("ERROR. Decryption failed.\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
delete bf;
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
#include "sha1.h"
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
int main()
|
||||
{
|
||||
SHA1 *sha1;
|
||||
unsigned char data[] = "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq";
|
||||
unsigned long et[] = {0x11223344};
|
||||
int rc;
|
||||
|
||||
printf("%d: 0x11 == %d and 0x44 == %d\n", ((unsigned char *)et)[0], 0x11, 0x44);
|
||||
sha1 = new SHA1();
|
||||
|
||||
if (!sha1->readyToGo()) {
|
||||
printf("Error: not ready to go!\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
printf("About to process [%s]\n", data);
|
||||
rc = sha1->process(data, strlen((char *)data));
|
||||
|
||||
if (rc != strlen((char *)data)) {
|
||||
printf("Error processing the data. rc=%d\n", rc);
|
||||
} else {
|
||||
printf("Done.\n");
|
||||
}
|
||||
|
||||
const unsigned char *res = sha1->hash();
|
||||
|
||||
if (res) {
|
||||
for (int i = 0; i < 20; i++) {
|
||||
printf("%.2X", *res++);
|
||||
if (i > 0 && (i - 1) % 2 == 0) {
|
||||
printf(" ");
|
||||
}
|
||||
}
|
||||
printf("\n");
|
||||
} else {
|
||||
printf("Error - getHash() returned NULL!\n");
|
||||
}
|
||||
|
||||
delete sha1;
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
#cmakedefine01 WITH_X11
|
||||
@@ -0,0 +1,69 @@
|
||||
/*
|
||||
This file is part of the KDE libraries
|
||||
SPDX-FileCopyrightText: 2004 George Staikos <staikos@kde.org>
|
||||
|
||||
SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
*/
|
||||
|
||||
#include "kbetterthankdialog.h"
|
||||
#include <QIcon>
|
||||
|
||||
KBetterThanKDialog::KBetterThanKDialog(QWidget *parent)
|
||||
: QDialog(parent)
|
||||
{
|
||||
setupUi(this);
|
||||
connect(_allowOnce, &QPushButton::clicked, this, &KBetterThanKDialog::allowOnceClicked);
|
||||
connect(_allowAlways, &QPushButton::clicked, this, &KBetterThanKDialog::allowAlwaysClicked);
|
||||
connect(_deny, &QPushButton::clicked, this, &KBetterThanKDialog::denyClicked);
|
||||
connect(_denyForever, &QPushButton::clicked, this, &KBetterThanKDialog::denyForeverClicked);
|
||||
|
||||
init();
|
||||
}
|
||||
|
||||
void KBetterThanKDialog::init()
|
||||
{
|
||||
_allowOnce->setIcon(QIcon::fromTheme(QStringLiteral("dialog-ok")));
|
||||
_allowAlways->setIcon(QIcon::fromTheme(QStringLiteral("dialog-ok")));
|
||||
_deny->setIcon(QIcon::fromTheme(QStringLiteral("dialog-cancel")));
|
||||
_denyForever->setIcon(QIcon::fromTheme(QStringLiteral("dialog-cancel")));
|
||||
|
||||
_allowOnce->setFocus();
|
||||
}
|
||||
|
||||
void KBetterThanKDialog::setLabel(const QString &label)
|
||||
{
|
||||
_label->setText(label);
|
||||
}
|
||||
|
||||
void KBetterThanKDialog::accept()
|
||||
{
|
||||
setResult(0);
|
||||
}
|
||||
|
||||
void KBetterThanKDialog::reject()
|
||||
{
|
||||
QDialog::reject();
|
||||
setResult(2);
|
||||
}
|
||||
|
||||
void KBetterThanKDialog::allowOnceClicked()
|
||||
{
|
||||
done(0);
|
||||
}
|
||||
|
||||
void KBetterThanKDialog::allowAlwaysClicked()
|
||||
{
|
||||
done(1);
|
||||
}
|
||||
|
||||
void KBetterThanKDialog::denyClicked()
|
||||
{
|
||||
done(2);
|
||||
}
|
||||
|
||||
void KBetterThanKDialog::denyForeverClicked()
|
||||
{
|
||||
done(3);
|
||||
}
|
||||
|
||||
#include "moc_kbetterthankdialog.cpp"
|
||||
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
This file is part of the KDE libraries
|
||||
SPDX-FileCopyrightText: 2004 George Staikos <staikos@kde.org>
|
||||
|
||||
SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
*/
|
||||
|
||||
#ifndef KBETTERTHANKDIALOG_H
|
||||
#define KBETTERTHANKDIALOG_H
|
||||
|
||||
#include <QDialog>
|
||||
|
||||
#include "ui_kbetterthankdialogbase.h"
|
||||
|
||||
class KBetterThanKDialog : public QDialog, private Ui_KBetterThanKDialogBase
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit KBetterThanKDialog(QWidget *parent = nullptr);
|
||||
|
||||
void init();
|
||||
void setLabel(const QString &label);
|
||||
|
||||
protected Q_SLOTS:
|
||||
void accept() override;
|
||||
void reject() override;
|
||||
|
||||
private Q_SLOTS:
|
||||
void allowOnceClicked();
|
||||
void allowAlwaysClicked();
|
||||
void denyClicked();
|
||||
void denyForeverClicked();
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,100 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>KBetterThanKDialogBase</class>
|
||||
<widget class="QDialog" name="KBetterThanKDialogBase">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>479</width>
|
||||
<height>109</height>
|
||||
</rect>
|
||||
</property>
|
||||
<layout class="QGridLayout">
|
||||
<property name="margin">
|
||||
<number>11</number>
|
||||
</property>
|
||||
<property name="spacing">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<item row="0" column="0" colspan="3">
|
||||
<widget class="QLabel" name="_label"/>
|
||||
</item>
|
||||
<item row="1" column="2">
|
||||
<spacer>
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeType">
|
||||
<enum>QSizePolicy::Expanding</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>41</width>
|
||||
<height>21</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<layout class="QHBoxLayout">
|
||||
<property name="spacing">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<property name="margin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QPushButton" name="_allowOnce">
|
||||
<property name="text">
|
||||
<string>Allow &Once</string>
|
||||
</property>
|
||||
<property name="default">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="_allowAlways">
|
||||
<property name="text">
|
||||
<string>Allow &Always</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="_deny">
|
||||
<property name="text">
|
||||
<string>&Deny</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="_denyForever">
|
||||
<property name="text">
|
||||
<string>Deny &Forever</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<spacer>
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeType">
|
||||
<enum>QSizePolicy::Expanding</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>61</width>
|
||||
<height>21</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||
@@ -0,0 +1,185 @@
|
||||
/*
|
||||
This file is part of the KDE project
|
||||
SPDX-FileCopyrightText: 2013 Valentin Rusu <kde@rusu.info>
|
||||
|
||||
SPDX-License-Identifier: LGPL-2.0-only
|
||||
*/
|
||||
|
||||
#include "knewwalletdialog.h"
|
||||
#include "kwalletd_debug.h"
|
||||
#include <KLocalizedString>
|
||||
#include <KMessageBox>
|
||||
#include <QTableWidget>
|
||||
#include <QTableWidgetItem>
|
||||
#include <gpgme++/context.h>
|
||||
#include <gpgme++/key.h>
|
||||
#include <gpgme++/keylistresult.h>
|
||||
|
||||
Q_DECLARE_METATYPE(GpgME::Key)
|
||||
|
||||
namespace KWallet
|
||||
{
|
||||
KNewWalletDialog::KNewWalletDialog(const QString &appName, const QString &walletName, QWidget *parent)
|
||||
: QWizard(parent)
|
||||
{
|
||||
setOption(HaveFinishButtonOnEarlyPages);
|
||||
_intro = new KNewWalletDialogIntro(appName, walletName, this);
|
||||
_introId = addPage(_intro);
|
||||
|
||||
_gpg = new KNewWalletDialogGpg(this);
|
||||
_gpgId = addPage(_gpg);
|
||||
}
|
||||
|
||||
bool KNewWalletDialog::isBlowfish() const
|
||||
{
|
||||
return _intro->isBlowfish();
|
||||
}
|
||||
|
||||
GpgME::Key KNewWalletDialog::gpgKey() const
|
||||
{
|
||||
QVariant varKey = field(QStringLiteral("key"));
|
||||
return varKey.value<GpgME::Key>();
|
||||
}
|
||||
|
||||
KNewWalletDialogIntro::KNewWalletDialogIntro(const QString &appName, const QString &walletName, QWidget *parent)
|
||||
: QWizardPage(parent)
|
||||
{
|
||||
_ui.setupUi(this);
|
||||
if (appName.isEmpty()) {
|
||||
_ui.labelIntro->setText(
|
||||
i18n("<qt>KDE has requested to create a new wallet named '<b>%1</b>'. This is used to store sensitive data in a secure fashion. Please choose the "
|
||||
"new wallet's type below or click cancel to deny the application's request.</qt>",
|
||||
walletName.toHtmlEscaped()));
|
||||
} else {
|
||||
_ui.labelIntro->setText(
|
||||
i18n("<qt>The application '<b>%1</b>' has requested to create a new wallet named '<b>%2</b>'. This is used to store sensitive data in a secure "
|
||||
"fashion. Please choose the new wallet's type below or click cancel to deny the application's request.</qt>",
|
||||
appName.toHtmlEscaped(),
|
||||
walletName.toHtmlEscaped()));
|
||||
}
|
||||
}
|
||||
|
||||
void KNewWalletDialogIntro::onBlowfishToggled(bool blowfish)
|
||||
{
|
||||
setFinalPage(blowfish);
|
||||
}
|
||||
|
||||
bool KNewWalletDialogIntro::isBlowfish() const
|
||||
{
|
||||
return _ui.radioBlowfish->isChecked();
|
||||
}
|
||||
|
||||
int KNewWalletDialogIntro::nextId() const
|
||||
{
|
||||
if (isBlowfish()) {
|
||||
return -1;
|
||||
} else {
|
||||
return qobject_cast<const KNewWalletDialog *>(wizard())->gpgId();
|
||||
}
|
||||
}
|
||||
|
||||
KNewWalletDialogGpg::KNewWalletDialogGpg(QWidget *parent)
|
||||
: QWizardPage(parent)
|
||||
{
|
||||
_ui.setupUi(this);
|
||||
}
|
||||
|
||||
struct AddKeyToList {
|
||||
QTableWidget *_list;
|
||||
int _row;
|
||||
AddKeyToList(QTableWidget *list)
|
||||
: _list(list)
|
||||
, _row(0)
|
||||
{
|
||||
}
|
||||
void operator()(const GpgME::Key &k)
|
||||
{
|
||||
GpgME::UserID uid = k.userID(0);
|
||||
QString name(uid.name());
|
||||
if (uid.comment()) {
|
||||
name = QStringLiteral("%1 (%2)").arg(name, uid.comment());
|
||||
}
|
||||
_list->setItem(_row, 0, new QTableWidgetItem(name));
|
||||
_list->setItem(_row, 1, new QTableWidgetItem(uid.email()));
|
||||
_list->setItem(_row, 2, new QTableWidgetItem(k.shortKeyID()));
|
||||
QVariant varKey;
|
||||
varKey.setValue(k);
|
||||
_list->item(_row, 0)->setData(Qt::UserRole, varKey);
|
||||
++_row;
|
||||
}
|
||||
};
|
||||
|
||||
void KNewWalletDialogGpg::initializePage()
|
||||
{
|
||||
if (_alreadyInitialized) {
|
||||
return;
|
||||
}
|
||||
|
||||
registerField(QStringLiteral("key"), this);
|
||||
|
||||
GpgME::initializeLibrary();
|
||||
GpgME::Error err = GpgME::checkEngine(GpgME::OpenPGP);
|
||||
if (err) {
|
||||
qCDebug(KWALLETD_LOG) << "OpenPGP not supported on your system!";
|
||||
KMessageBox::error(this,
|
||||
i18n("The GpgME library failed to initialize for the OpenPGP protocol. Please check your system's configuration then try again."));
|
||||
Q_EMIT completeChanged();
|
||||
return;
|
||||
}
|
||||
std::shared_ptr<GpgME::Context> _ctx(GpgME::Context::createForProtocol(GpgME::OpenPGP));
|
||||
if (!_ctx) {
|
||||
KMessageBox::error(this,
|
||||
i18n("The GpgME library failed to initialize for the OpenPGP protocol. Please check your system's configuration then try again."));
|
||||
Q_EMIT completeChanged();
|
||||
return;
|
||||
}
|
||||
_ctx->setKeyListMode(GpgME::Local);
|
||||
|
||||
std::vector<GpgME::Key> keys;
|
||||
err = _ctx->startKeyListing();
|
||||
while (!err) {
|
||||
GpgME::Key k = _ctx->nextKey(err);
|
||||
if (err) {
|
||||
break;
|
||||
}
|
||||
if (!k.isInvalid() && k.canEncrypt() && (k.ownerTrust() == GpgME::Key::Ultimate)) {
|
||||
keys.push_back(k);
|
||||
}
|
||||
}
|
||||
_ctx->endKeyListing();
|
||||
|
||||
if (keys.size() == 0) {
|
||||
KMessageBox::error(this,
|
||||
i18n("Seems that your system has no keys suitable for encryption. Please set-up at least one encryption key, then try again."));
|
||||
Q_EMIT completeChanged();
|
||||
return;
|
||||
}
|
||||
|
||||
_ui.listCertificates->setRowCount(keys.size());
|
||||
std::for_each(keys.begin(), keys.end(), AddKeyToList(_ui.listCertificates));
|
||||
_ui.listCertificates->resizeColumnsToContents();
|
||||
_ui.listCertificates->setCurrentCell(0, 0);
|
||||
|
||||
_alreadyInitialized = true;
|
||||
}
|
||||
|
||||
void KNewWalletDialogGpg::onItemSelectionChanged()
|
||||
{
|
||||
_complete = _ui.listCertificates->currentRow() >= 0;
|
||||
QVariant varKey = _ui.listCertificates->item(_ui.listCertificates->currentRow(), 0)->data(Qt::UserRole);
|
||||
setField(QStringLiteral("key"), varKey);
|
||||
Q_EMIT completeChanged();
|
||||
}
|
||||
|
||||
bool KNewWalletDialogGpg::isComplete() const
|
||||
{
|
||||
return _complete;
|
||||
}
|
||||
|
||||
bool KNewWalletDialogGpg::validateCurrentPage()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
#include "moc_knewwalletdialog.cpp"
|
||||
@@ -0,0 +1,79 @@
|
||||
/*
|
||||
This file is part of the KDE project
|
||||
SPDX-FileCopyrightText: 2013 Valentin Rusu <kde@rusu.info>
|
||||
|
||||
SPDX-License-Identifier: LGPL-2.0-only
|
||||
*/
|
||||
|
||||
#ifndef KNEWWALLETDIALOG_H
|
||||
#define KNEWWALLETDIALOG_H
|
||||
|
||||
#include <QWizard>
|
||||
|
||||
#include "ui_knewwalletdialoggpg.h"
|
||||
#include "ui_knewwalletdialogintro.h"
|
||||
|
||||
namespace GpgME
|
||||
{
|
||||
class Key;
|
||||
}
|
||||
|
||||
namespace KWallet
|
||||
{
|
||||
class KNewWalletDialogIntro;
|
||||
class KNewWalletDialogGpg;
|
||||
|
||||
class KNewWalletDialog : public QWizard
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
KNewWalletDialog(const QString &appName, const QString &walletName, QWidget *parent = nullptr);
|
||||
|
||||
bool isBlowfish() const;
|
||||
int gpgId() const
|
||||
{
|
||||
return _gpgId;
|
||||
}
|
||||
GpgME::Key gpgKey() const;
|
||||
|
||||
private:
|
||||
KNewWalletDialogIntro *_intro = nullptr;
|
||||
int _introId = 0;
|
||||
KNewWalletDialogGpg *_gpg = nullptr;
|
||||
int _gpgId = 0;
|
||||
};
|
||||
|
||||
class KNewWalletDialogIntro : public QWizardPage
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
KNewWalletDialogIntro(const QString &appName, const QString &walletName, QWidget *parent = nullptr);
|
||||
bool isBlowfish() const;
|
||||
int nextId() const override;
|
||||
protected Q_SLOTS:
|
||||
void onBlowfishToggled(bool);
|
||||
|
||||
private:
|
||||
Ui_KNewWalletDialogIntro _ui;
|
||||
};
|
||||
|
||||
class KNewWalletDialogGpg : public QWizardPage
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit KNewWalletDialogGpg(QWidget *parent = nullptr);
|
||||
void initializePage() override;
|
||||
bool isComplete() const override;
|
||||
virtual bool validateCurrentPage();
|
||||
protected Q_SLOTS:
|
||||
void onItemSelectionChanged();
|
||||
|
||||
private:
|
||||
bool _alreadyInitialized = false;
|
||||
Ui_KNewWalletDialogGpg _ui;
|
||||
bool _complete = false;
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
#endif // KNEWWALLETDIALOG_H
|
||||
@@ -0,0 +1,98 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>KNewWalletDialogGpg</class>
|
||||
<widget class="QWidget" name="KNewWalletDialogGpg">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>400</width>
|
||||
<height>300</height>
|
||||
</rect>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
<string>Please select the signing key from the list below:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="label_2">
|
||||
<property name="text">
|
||||
<string><html><head/><body><p><span style=" font-weight:600;">NOTE:</span> this list shows only &quot;ultimate-level&quot; trusted keys</p></body></html></string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QTableWidget" name="listCertificates">
|
||||
<property name="showDropIndicator" stdset="0">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="dragDropOverwriteMode">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="selectionBehavior">
|
||||
<enum>QAbstractItemView::SelectRows</enum>
|
||||
</property>
|
||||
<property name="showGrid">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="columnCount">
|
||||
<number>3</number>
|
||||
</property>
|
||||
<attribute name="horizontalHeaderCascadingSectionResizes">
|
||||
<bool>true</bool>
|
||||
</attribute>
|
||||
<attribute name="horizontalHeaderShowSortIndicator" stdset="0">
|
||||
<bool>true</bool>
|
||||
</attribute>
|
||||
<attribute name="verticalHeaderVisible">
|
||||
<bool>false</bool>
|
||||
</attribute>
|
||||
<attribute name="verticalHeaderHighlightSections">
|
||||
<bool>false</bool>
|
||||
</attribute>
|
||||
<column>
|
||||
<property name="text">
|
||||
<string>Name</string>
|
||||
</property>
|
||||
</column>
|
||||
<column>
|
||||
<property name="text">
|
||||
<string>E-Mail</string>
|
||||
</property>
|
||||
</column>
|
||||
<column>
|
||||
<property name="text">
|
||||
<string>Key-ID</string>
|
||||
</property>
|
||||
</column>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections>
|
||||
<connection>
|
||||
<sender>listCertificates</sender>
|
||||
<signal>itemSelectionChanged()</signal>
|
||||
<receiver>KNewWalletDialogGpg</receiver>
|
||||
<slot>onItemSelectionChanged()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>48</x>
|
||||
<y>89</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>0</x>
|
||||
<y>81</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
</connections>
|
||||
<slots>
|
||||
<slot>onItemSelectionChanged()</slot>
|
||||
</slots>
|
||||
</ui>
|
||||
@@ -0,0 +1,128 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>KNewWalletDialogIntro</class>
|
||||
<widget class="QWidget" name="KNewWalletDialogIntro">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>341</width>
|
||||
<height>190</height>
|
||||
</rect>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||
<item>
|
||||
<widget class="KTitleWidget" name="ktitlewidget">
|
||||
<property name="comment">
|
||||
<string>The KDE Wallet System</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="labelIntro">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string><html><head/><body><p>The application '<span style=" font-weight:600;">%1</span>' has requested to open the KDE wallet. This is used to store sensitive data in a secure fashion. Please choose the new wallet's type below or click cancel to deny the application's request.</p></body></html></string>
|
||||
</property>
|
||||
<property name="textFormat">
|
||||
<enum>Qt::RichText</enum>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignVCenter</set>
|
||||
</property>
|
||||
<property name="wordWrap">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="margin">
|
||||
<number>12</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<spacer name="horizontalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<widget class="QRadioButton" name="radioBlowfish">
|
||||
<property name="text">
|
||||
<string>Classic, blowfish encrypted file</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QRadioButton" name="radioGpg">
|
||||
<property name="text">
|
||||
<string>Use GPG encryption, for better protection</string>
|
||||
</property>
|
||||
<property name="checked">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer_2">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<customwidgets>
|
||||
<customwidget>
|
||||
<class>KTitleWidget</class>
|
||||
<extends>QWidget</extends>
|
||||
<header>ktitlewidget.h</header>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
<resources/>
|
||||
<connections>
|
||||
<connection>
|
||||
<sender>radioBlowfish</sender>
|
||||
<signal>toggled(bool)</signal>
|
||||
<receiver>KNewWalletDialogIntro</receiver>
|
||||
<slot>onBlowfishToggled(bool)</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>31</x>
|
||||
<y>144</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>2</x>
|
||||
<y>138</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
</connections>
|
||||
<slots>
|
||||
<slot>onBlowfishToggled(bool)</slot>
|
||||
</slots>
|
||||
</ui>
|
||||
@@ -0,0 +1,65 @@
|
||||
/*
|
||||
This file is part of the KDE libraries
|
||||
SPDX-FileCopyrightText: 2003 George Staikos <staikos@kde.org>
|
||||
|
||||
SPDX-License-Identifier: LGPL-2.0-or-later
|
||||
*/
|
||||
|
||||
#include "ktimeout.h"
|
||||
#include <QTimerEvent>
|
||||
|
||||
KTimeout::KTimeout(QObject *parent)
|
||||
: QObject(parent)
|
||||
{
|
||||
}
|
||||
|
||||
KTimeout::~KTimeout()
|
||||
{
|
||||
}
|
||||
|
||||
void KTimeout::clear()
|
||||
{
|
||||
for (int timerId : std::as_const(_timers)) {
|
||||
killTimer(timerId);
|
||||
}
|
||||
_timers.clear();
|
||||
}
|
||||
|
||||
void KTimeout::removeTimer(int id)
|
||||
{
|
||||
const int timerId = _timers.value(id, 0);
|
||||
if (timerId != 0) {
|
||||
killTimer(timerId);
|
||||
}
|
||||
_timers.remove(id);
|
||||
}
|
||||
|
||||
void KTimeout::addTimer(int id, int timeout)
|
||||
{
|
||||
if (_timers.contains(id)) {
|
||||
return;
|
||||
}
|
||||
_timers.insert(id, startTimer(timeout));
|
||||
}
|
||||
|
||||
void KTimeout::resetTimer(int id, int timeout)
|
||||
{
|
||||
int timerId = _timers.value(id, 0);
|
||||
if (timerId != 0) {
|
||||
killTimer(timerId);
|
||||
_timers.insert(id, startTimer(timeout));
|
||||
}
|
||||
}
|
||||
|
||||
void KTimeout::timerEvent(QTimerEvent *ev)
|
||||
{
|
||||
QHash<int, int>::const_iterator it = _timers.constBegin();
|
||||
for (; it != _timers.constEnd(); ++it) {
|
||||
if (it.value() == ev->timerId()) {
|
||||
Q_EMIT timedOut(it.key());
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#include "moc_ktimeout.cpp"
|
||||
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
This file is part of the KDE libraries
|
||||
SPDX-FileCopyrightText: 2003 George Staikos <staikos@kde.org>
|
||||
|
||||
SPDX-License-Identifier: LGPL-2.0-or-later
|
||||
*/
|
||||
|
||||
#ifndef _KTIMEOUT_H_
|
||||
#define _KTIMEOUT_H_
|
||||
|
||||
#include <QHash>
|
||||
#include <QObject>
|
||||
|
||||
// @internal
|
||||
class KTimeout : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit KTimeout(QObject *parent = nullptr);
|
||||
~KTimeout() override;
|
||||
|
||||
Q_SIGNALS:
|
||||
void timedOut(int id);
|
||||
|
||||
public Q_SLOTS:
|
||||
void resetTimer(int id, int timeout);
|
||||
void addTimer(int id, int timeout);
|
||||
void removeTimer(int id);
|
||||
void clear();
|
||||
|
||||
protected:
|
||||
void timerEvent(QTimerEvent *) override;
|
||||
|
||||
private:
|
||||
QHash<int /*id*/, int /*timerId*/> _timers;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,4 @@
|
||||
[portal]
|
||||
DBusName=org.freedesktop.impl.portal.desktop.kwallet
|
||||
Interfaces=org.freedesktop.impl.portal.Secret;
|
||||
UseIn=kde
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,271 @@
|
||||
/*
|
||||
This file is part of the KDE libraries
|
||||
SPDX-FileCopyrightText: 2002-2004 George Staikos <staikos@kde.org>
|
||||
SPDX-FileCopyrightText: 2008 Michael Leupold <lemma@confuego.org>
|
||||
|
||||
SPDX-License-Identifier: LGPL-2.0-or-later
|
||||
*/
|
||||
|
||||
#ifndef _KWALLETD_H_
|
||||
#define _KWALLETD_H_
|
||||
|
||||
#include "kwalletbackend.h"
|
||||
#include <QDBusConnection>
|
||||
#include <QDBusContext>
|
||||
#include <QDBusServiceWatcher>
|
||||
#include <QHash>
|
||||
#include <QPointer>
|
||||
#include <QString>
|
||||
|
||||
#include "ktimeout.h"
|
||||
#include "kwalletsessionstore.h"
|
||||
|
||||
class KDirWatch;
|
||||
class KTimeout;
|
||||
|
||||
// @Private
|
||||
class KWalletTransaction;
|
||||
class KWalletSessionStore;
|
||||
class KWalletFreedesktopService;
|
||||
|
||||
class KWalletD : public QObject, protected QDBusContext
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
KWalletD();
|
||||
~KWalletD() override;
|
||||
|
||||
static QString encodeWalletName(const QString &name);
|
||||
static QString decodeWalletName(const QString &mangledName);
|
||||
|
||||
int nextTransactionId() const;
|
||||
int
|
||||
openAsync(const QString &wallet, qlonglong wId, const QString &appid, bool handleSession, const QDBusConnection &connection, const QDBusMessage &message);
|
||||
// Close and lock the wallet
|
||||
// Accepts "message" for working from other QDBusContexts
|
||||
int close(int handle, bool force, const QString &appid, const QDBusMessage &message);
|
||||
public Q_SLOTS:
|
||||
|
||||
// Is the wallet enabled? If not, all open() calls fail.
|
||||
bool isEnabled() const;
|
||||
|
||||
// Open and unlock the wallet
|
||||
int open(const QString &wallet, qlonglong wId, const QString &appid);
|
||||
|
||||
// Open and unlock the wallet with this path
|
||||
int openPath(const QString &path, qlonglong wId, const QString &appid);
|
||||
|
||||
// Open the wallet asynchronously
|
||||
int openAsync(const QString &wallet, qlonglong wId, const QString &appid, bool handleSession);
|
||||
|
||||
// Open and unlock the wallet with this path asynchronously
|
||||
int openPathAsync(const QString &path, qlonglong wId, const QString &appid, bool handleSession);
|
||||
|
||||
// Close and lock the wallet
|
||||
// If force = true, will close it for all users. Behave. This
|
||||
// can break applications, and is generally intended for use by
|
||||
// the wallet manager app only.
|
||||
int close(const QString &wallet, bool force);
|
||||
int close(int handle, bool force, const QString &appid);
|
||||
|
||||
// Save to disk but leave open
|
||||
Q_NOREPLY void sync(int handle, const QString &appid);
|
||||
|
||||
// Physically deletes the wallet from disk.
|
||||
int deleteWallet(const QString &wallet);
|
||||
|
||||
// Returns true if the wallet is open
|
||||
bool isOpen(const QString &wallet);
|
||||
bool isOpen(int handle);
|
||||
|
||||
// List the users of this wallet
|
||||
QStringList users(const QString &wallet) const;
|
||||
|
||||
// Change the password of this wallet
|
||||
void changePassword(const QString &wallet, qlonglong wId, const QString &appid);
|
||||
|
||||
// A list of all wallets
|
||||
QStringList wallets() const;
|
||||
|
||||
// A list of all folders in this wallet
|
||||
QStringList folderList(int handle, const QString &appid);
|
||||
|
||||
// Does this wallet have this folder?
|
||||
bool hasFolder(int handle, const QString &folder, const QString &appid);
|
||||
|
||||
// Create this folder
|
||||
bool createFolder(int handle, const QString &folder, const QString &appid);
|
||||
|
||||
// Remove this folder
|
||||
bool removeFolder(int handle, const QString &folder, const QString &appid);
|
||||
|
||||
// List of entries in this folder
|
||||
QStringList entryList(int handle, const QString &folder, const QString &appid);
|
||||
|
||||
// Read an entry. If the entry does not exist, it just
|
||||
// returns an empty result. It is your responsibility to check
|
||||
// hasEntry() first.
|
||||
QByteArray readEntry(int handle, const QString &folder, const QString &key, const QString &appid);
|
||||
QByteArray readMap(int handle, const QString &folder, const QString &key, const QString &appid);
|
||||
QString readPassword(int handle, const QString &folder, const QString &key, const QString &appid);
|
||||
|
||||
#if KWALLET_BUILD_DEPRECATED_SINCE(5, 72)
|
||||
// use entriesList()
|
||||
QVariantMap readEntryList(int handle, const QString &folder, const QString &key, const QString &appid);
|
||||
#endif
|
||||
|
||||
#if KWALLET_BUILD_DEPRECATED_SINCE(5, 72)
|
||||
// use mapList()
|
||||
QVariantMap readMapList(int handle, const QString &folder, const QString &key, const QString &appid);
|
||||
#endif
|
||||
|
||||
#if KWALLET_BUILD_DEPRECATED_SINCE(5, 72)
|
||||
// use passwordList()
|
||||
QVariantMap readPasswordList(int handle, const QString &folder, const QString &key, const QString &appid);
|
||||
#endif
|
||||
|
||||
QVariantMap entriesList(int handle, const QString &folder, const QString &appid);
|
||||
QVariantMap mapList(int handle, const QString &folder, const QString &appid);
|
||||
QVariantMap passwordList(int handle, const QString &folder, const QString &appid);
|
||||
|
||||
// Rename an entry. rc=0 on success.
|
||||
int renameEntry(int handle, const QString &folder, const QString &oldName, const QString &newName, const QString &appid);
|
||||
// Rename the wallet
|
||||
int renameWallet(const QString &oldName, const QString &newName);
|
||||
|
||||
// Write an entry. rc=0 on success.
|
||||
int writeEntry(int handle, const QString &folder, const QString &key, const QByteArray &value, int entryType, const QString &appid);
|
||||
int writeEntry(int handle, const QString &folder, const QString &key, const QByteArray &value, const QString &appid);
|
||||
int writeMap(int handle, const QString &folder, const QString &key, const QByteArray &value, const QString &appid);
|
||||
int writePassword(int handle, const QString &folder, const QString &key, const QString &value, const QString &appid);
|
||||
|
||||
// Does the entry exist?
|
||||
bool hasEntry(int handle, const QString &folder, const QString &key, const QString &appid);
|
||||
|
||||
// What type is the entry?
|
||||
int entryType(int handle, const QString &folder, const QString &key, const QString &appid);
|
||||
|
||||
// Remove an entry. rc=0 on success.
|
||||
int removeEntry(int handle, const QString &folder, const QString &key, const QString &appid);
|
||||
|
||||
// Disconnect an app from a wallet
|
||||
bool disconnectApplication(const QString &wallet, const QString &application);
|
||||
|
||||
void reconfigure();
|
||||
|
||||
// Determine
|
||||
bool folderDoesNotExist(const QString &wallet, const QString &folder);
|
||||
bool keyDoesNotExist(const QString &wallet, const QString &folder, const QString &key);
|
||||
|
||||
void closeAllWallets();
|
||||
|
||||
QString networkWallet();
|
||||
|
||||
QString localWallet();
|
||||
|
||||
void screenSaverChanged(bool);
|
||||
|
||||
// Open a wallet using a pre-hashed password. This is only useful in cooperation
|
||||
// with the kwallet PAM module. It's also less secure than manually entering the
|
||||
// password as the password hash is transmitted using D-Bus.
|
||||
int pamOpen(const QString &wallet, const QByteArray &passwordHash, int sessionTimeout);
|
||||
|
||||
Q_SIGNALS:
|
||||
void walletAsyncOpened(int id, int handle); // used to notify KWallet::Wallet
|
||||
void walletListDirty();
|
||||
void walletCreated(const QString &wallet);
|
||||
void walletOpened(const QString &wallet);
|
||||
void walletDeleted(const QString &wallet);
|
||||
void walletClosed(const QString &wallet); // clazy:exclude=overloaded-signal
|
||||
|
||||
// TODO KF6 remove this signal, replaced by walletClosedId(int)
|
||||
void walletClosed(int handle); // clazy:exclude=overloaded-signal
|
||||
|
||||
// since 5.81
|
||||
void walletClosedId(int handle);
|
||||
|
||||
void allWalletsClosed();
|
||||
void folderListUpdated(const QString &wallet);
|
||||
void folderUpdated(const QString &, const QString &);
|
||||
void entryUpdated(const QString &, const QString &, const QString &);
|
||||
void entryRenamed(const QString &, const QString &, const QString &, const QString &);
|
||||
void entryDeleted(const QString &, const QString &, const QString &);
|
||||
void applicationDisconnected(const QString &wallet, const QString &application);
|
||||
|
||||
private Q_SLOTS:
|
||||
void slotServiceOwnerChanged(const QString &name, const QString &oldOwner, const QString &newOwner);
|
||||
void emitWalletListDirty();
|
||||
void timedOutClose(int handle);
|
||||
void timedOutSync(int handle);
|
||||
void notifyFailures();
|
||||
void processTransactions();
|
||||
void activatePasswordDialog();
|
||||
#ifdef Q_WS_X11
|
||||
void connectToScreenSaver();
|
||||
#endif
|
||||
|
||||
private:
|
||||
// Internal - open a wallet
|
||||
int internalOpen(const QString &appid, const QString &wallet, bool isPath, WId w, bool modal, const QString &service);
|
||||
// Internal - close this wallet.
|
||||
int internalClose(KWallet::Backend *const w, const int handle, const bool force, const bool saveBeforeClose = true);
|
||||
|
||||
bool isAuthorizedApp(const QString &appid, const QString &wallet, WId w);
|
||||
// This also validates the handle. May return NULL.
|
||||
KWallet::Backend *getWallet(const QString &appid, int handle);
|
||||
// Generate a new unique handle.
|
||||
int generateHandle();
|
||||
// Emit signals about closing wallets
|
||||
void doCloseSignals(int, const QString &);
|
||||
void emitFolderUpdated(const QString &, const QString &);
|
||||
void emitEntryUpdated(const QString &, const QString &, const QString &);
|
||||
void emitEntryRenamed(const QString &, const QString &, const QString &, const QString &);
|
||||
void emitEntryDeleted(const QString &, const QString &, const QString &);
|
||||
// Implicitly allow access for this application
|
||||
bool implicitAllow(const QString &wallet, const QString &app);
|
||||
bool implicitDeny(const QString &wallet, const QString &app);
|
||||
|
||||
void doTransactionChangePassword(const QString &appid, const QString &wallet, qlonglong wId);
|
||||
void doTransactionOpenCancelled(const QString &appid, const QString &wallet, const QString &service);
|
||||
int doTransactionOpen(const QString &appid, const QString &wallet, bool isPath, qlonglong wId, bool modal, const QString &service);
|
||||
void initiateSync(int handle);
|
||||
|
||||
void setupDialog(QWidget *dialog, WId wId, const QString &appid, bool modal);
|
||||
void checkActiveDialog();
|
||||
|
||||
QPair<int, KWallet::Backend *> findWallet(const QString &walletName) const;
|
||||
|
||||
typedef QHash<int, KWallet::Backend *> Wallets;
|
||||
Wallets _wallets;
|
||||
KDirWatch *_dw;
|
||||
int _failed;
|
||||
|
||||
// configuration values
|
||||
bool _leaveOpen, _closeIdle, _launchManager, _enabled;
|
||||
bool _openPrompt, _firstUse, _showingFailureNotify;
|
||||
int _idleTime;
|
||||
QMap<QString, QStringList> _implicitAllowMap, _implicitDenyMap;
|
||||
KTimeout _closeTimers;
|
||||
KTimeout _syncTimers;
|
||||
const int _syncTime;
|
||||
static bool _processing;
|
||||
|
||||
KWalletTransaction *_curtrans; // current transaction
|
||||
QList<KWalletTransaction *> _transactions;
|
||||
QPointer<QWidget> activeDialog;
|
||||
|
||||
#ifdef Q_WS_X11
|
||||
QDBusInterface *screensaver;
|
||||
#endif
|
||||
|
||||
// sessions
|
||||
KWalletSessionStore _sessions;
|
||||
QDBusServiceWatcher _serviceWatcher;
|
||||
|
||||
std::unique_ptr<KWalletFreedesktopService> _fdoService;
|
||||
|
||||
bool _useGpg;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,329 @@
|
||||
[Global]
|
||||
IconName=kwalletmanager
|
||||
Comment=KDE Wallet
|
||||
Comment[ar]=محفظة كِيدِي
|
||||
Comment[ast]=KDE Wallet
|
||||
Comment[az]=KDE Cüzdanı
|
||||
Comment[bg]=Портфейл на KDE
|
||||
Comment[ca]=Cartera de KDE
|
||||
Comment[ca@valencia]=Cartera de KDE
|
||||
Comment[cs]=Úschovna KDE
|
||||
Comment[da]=KDE tegnebog
|
||||
Comment[de]=KDE-Passwortspeicher
|
||||
Comment[el]=Πορτοφόλι του KDE
|
||||
Comment[en_GB]=KDE Wallet
|
||||
Comment[eo]=KDE Trezorejo
|
||||
Comment[es]=Cartera de KDE
|
||||
Comment[eu]=KDE Zorroa
|
||||
Comment[fi]=KDE Wallet
|
||||
Comment[fr]=Portefeuille de KDE
|
||||
Comment[gl]=KDE Wallet.
|
||||
Comment[he]=ארנק KDE
|
||||
Comment[hu]=KDE Wallet
|
||||
Comment[ia]=KDE Wallet (Portafolio de KDE)
|
||||
Comment[is]=KDE Wallet
|
||||
Comment[it]=Portafoglio di KDE
|
||||
Comment[ka]=KDE-ის საფულე
|
||||
Comment[ko]=KDE 지갑
|
||||
Comment[lt]=KDE slaptažodinė
|
||||
Comment[lv]=KDE maks
|
||||
Comment[nl]=KDE Portefeuillebeheer
|
||||
Comment[nn]=KDE-lommebok
|
||||
Comment[pa]=KDE ਵਾਲਟ
|
||||
Comment[pl]=Portfel KDE
|
||||
Comment[pt]=Carteira do KDE
|
||||
Comment[pt_BR]=Carteira do KDE
|
||||
Comment[ro]=Portofel KDE
|
||||
Comment[ru]=Бумажник
|
||||
Comment[sa]=केडीई बटुआ
|
||||
Comment[sk]=KDE Wallet
|
||||
Comment[sl]=KDE Wallet
|
||||
Comment[sv]=KDE-plånbok
|
||||
Comment[tr]=KDE Cüzdan
|
||||
Comment[uk]=Торбинка KDE
|
||||
Comment[vi]=Ví KDE
|
||||
Comment[x-test]=xxKDE Walletxx
|
||||
Comment[zh_CN]=KDE 密码库
|
||||
Comment[zh_TW]=KDE 錢包
|
||||
Name=KDE Wallet
|
||||
Name[ar]=محفظة كِيدِي
|
||||
Name[ast]=KDE Wallet
|
||||
Name[az]=KDE Cüzdanı
|
||||
Name[bg]=Портфейл на KDE
|
||||
Name[ca]=Cartera de KDE
|
||||
Name[ca@valencia]=Cartera de KDE
|
||||
Name[cs]=Úschovna KDE
|
||||
Name[da]=KDE tegnebog
|
||||
Name[de]=KDE-Passwortspeicher
|
||||
Name[el]=Πορτοφόλι του KDE
|
||||
Name[en_GB]=KDE Wallet
|
||||
Name[eo]=KDE Trezorejo
|
||||
Name[es]=Cartera de KDE
|
||||
Name[eu]=KDE Zorroa
|
||||
Name[fi]=KDE Wallet
|
||||
Name[fr]=Portefeuille de KDE
|
||||
Name[gl]=KDE Wallet
|
||||
Name[he]=ארנק KDE
|
||||
Name[hu]=KDE Wallet
|
||||
Name[ia]=KDE Wallet (Portafolio de KDE)
|
||||
Name[is]=KDE Wallet
|
||||
Name[it]=Portafoglio di KDE
|
||||
Name[ka]=KDE-ის საფულე
|
||||
Name[ko]=KDE 지갑
|
||||
Name[lt]=KDE slaptažodinė
|
||||
Name[lv]=KDE maks
|
||||
Name[nl]=KDE Portefeuillebeheer
|
||||
Name[nn]=KDE-lommebok
|
||||
Name[pa]=KDE ਵਾਲਟ
|
||||
Name[pl]=Portfel KDE
|
||||
Name[pt]=Carteira do KDE
|
||||
Name[pt_BR]=Carteira do KDE
|
||||
Name[ro]=Portofel KDE
|
||||
Name[ru]=Бумажник
|
||||
Name[sa]=केडीई बटुआ
|
||||
Name[sk]=KDE Wallet
|
||||
Name[sl]=KDE Wallet
|
||||
Name[sv]=KDE-plånbok
|
||||
Name[tr]=KDE Cüzdan
|
||||
Name[uk]=Торбинка KDE
|
||||
Name[vi]=Ví KDE
|
||||
Name[x-test]=xxKDE Walletxx
|
||||
Name[zh_CN]=KDE 密码库
|
||||
Name[zh_TW]=KDE 錢包
|
||||
|
||||
[Event/needsPassword]
|
||||
Name=Needs Password
|
||||
Name[ar]=يحتاج كلمة السر
|
||||
Name[az]=Şifrə tələb olunur
|
||||
Name[bg]=Изисква парола
|
||||
Name[ca]=Cal una contrasenya
|
||||
Name[ca@valencia]=Cal una contrasenya
|
||||
Name[cs]=Je třeba heslo
|
||||
Name[da]=Kræver adgangskode
|
||||
Name[de]=Passwort erforderlich
|
||||
Name[el]=Απαιτείται κωδικός πρόσβασης
|
||||
Name[en_GB]=Needs Password
|
||||
Name[eo]=Postulas Pasvorton
|
||||
Name[es]=Necesita contraseña
|
||||
Name[eu]=Pasahitza behar du
|
||||
Name[fi]=Salasana vaaditaan
|
||||
Name[fr]=Nécessite un mot de passe
|
||||
Name[gl]=Precisa dun contrasinal
|
||||
Name[he]=צריך סיסמה
|
||||
Name[hu]=Jelszó megadása szükséges
|
||||
Name[ia]=Il necessita de un contrasigno
|
||||
Name[is]=Þarf lykilorð
|
||||
Name[it]=Richiede password
|
||||
Name[ka]=სჭირდება პაროლი
|
||||
Name[ko]=암호 필요함
|
||||
Name[lt]=Reikalauja slaptažodžio
|
||||
Name[lv]=Nepieciešama parole
|
||||
Name[nl]=Wachtwoord nodig
|
||||
Name[nn]=Passord er påkravd
|
||||
Name[pa]=ਪਾਸਵਰਡ ਚਾਹੀਦਾ ਹੈ
|
||||
Name[pl]=Potrzebuje hasła
|
||||
Name[pt]=Necessita de Senha
|
||||
Name[pt_BR]=Necessita senha
|
||||
Name[ro]=Necesită parolă
|
||||
Name[ru]=Требуется пароль
|
||||
Name[sa]=Password आवश्यकम्
|
||||
Name[sk]=Vyžaduje heslo
|
||||
Name[sl]=Potrebno je geslo
|
||||
Name[sv]=Kräver lösenord
|
||||
Name[tr]=Parola Gerektirir
|
||||
Name[uk]=Потрібен пароль
|
||||
Name[vi]=Cần mật khẩu
|
||||
Name[x-test]=xxNeeds Passwordxx
|
||||
Name[zh_CN]=需要密码
|
||||
Name[zh_TW]=需要密碼
|
||||
Comment=The KDE Wallet Daemon requests a password
|
||||
Comment[ar]=«عفريت محفظة كِيدِي» يطلب كلمة سر
|
||||
Comment[az]=KDE Cüzdan şifrə tələb edir
|
||||
Comment[bg]=Услугата Портфейл на KDE изисква парола
|
||||
Comment[bn]=কে.ডি.ই. ওয়ালেট ডিমন একটি পাসওয়ার্ড চাইছে
|
||||
Comment[bs]=KDE‑ov demon novčanika zahtjeva lozinku
|
||||
Comment[ca]=El dimoni de carteres de KDE demana una contrasenya
|
||||
Comment[ca@valencia]=El dimoni de carteres de KDE demana una contrasenya
|
||||
Comment[cs]=Démon úschovny KDE požaduje heslo
|
||||
Comment[csb]=Demóna KDE Wallet żądô parolë
|
||||
Comment[da]=Dæmonen for KDE's tegnebog anmoder om en adgangskode
|
||||
Comment[de]=Der Passwortspeicher benötigt ein Passwort
|
||||
Comment[el]=Ο δαίμονας πορτοφολιού του KDE απαιτεί έναν κωδικό πρόσβασης
|
||||
Comment[en_GB]=The KDE Wallet Dæmon requests a password
|
||||
Comment[eo]=La trezoreja demono de KDE postulas pasvorton
|
||||
Comment[es]=El demonio de la cartera de KDE requiere una contraseña
|
||||
Comment[et]=KDE turvalaeka deemon nõuab parooli
|
||||
Comment[eu]=KDEren zorroaren daemon-ak pasahitza eskatzen du
|
||||
Comment[fa]=شبح Wallte کیدیای رمزعبوری را درخواست میکند
|
||||
Comment[fi]=KDE:n Lompakkotaustaprosessi pyytää salasanaa
|
||||
Comment[fr]=Le démon du portefeuille de KDE demande un mot de passe
|
||||
Comment[fy]=The KDE slûf daemon fereasket in wachtwurd
|
||||
Comment[ga]=Tá Deamhan Sparáin KDE ag iarraidh focal faire
|
||||
Comment[gd]=Tha an daemon aig Sporan KDE ag iarraidh facal-faire
|
||||
Comment[gl]=O Servizo de carteiras de KDE pide un contrasinal.
|
||||
Comment[gu]=KDE વોલેટ ડેમને પાસવર્ડની માંગ કરી છે
|
||||
Comment[he]=סוכן ארנק KDE מבקש סיסמה
|
||||
Comment[hi]=केडीई वॉलेट डेमॉन एक पासवर्ड का अनुरोध करता है
|
||||
Comment[hr]=KDE-ov novčanik daemon zahtijeva zaporku
|
||||
Comment[hu]=A KDE jelszótároló szolgáltatás jelszót kér
|
||||
Comment[ia]=Le Demone KDE Wallet exige un contrasigno
|
||||
Comment[id]=Daemon Wallet KDE meminta sandi
|
||||
Comment[is]=KDE Wallet-miðlarinn biður um lykilorð
|
||||
Comment[it]=Il demone dei portafogli di KDE richiede una password
|
||||
Comment[ja]=KDE ウォレットデーモンがパスワードを要求しています
|
||||
Comment[ka]=KDE-ის საფულის დემონი პაროლს ითხოვს
|
||||
Comment[kk]=KDE әмиян қызметі паролін қажет етеді
|
||||
Comment[km]=ដេមិនកាបូបរបស់ KDE ស្នើពាក្យសម្ងាត់
|
||||
Comment[kn]=ಕೆಡಿಇ ವಾಲೆಟ್ ಡೀಮನ್ ಗುಪ್ತಪದಕ್ಕಾಗಿ ಮನವಿ ಸಲ್ಲಿಸುತ್ತದೆ
|
||||
Comment[ko]=KDE 지갑 데몬에서 암호를 물어봅니다
|
||||
Comment[lt]=KDE slaptažodinių tarnyba reikalauja slaptažodžio
|
||||
Comment[lv]=KDE maka dēmons pieprasa paroli
|
||||
Comment[mai]=KDE वालेट डेमान एकटा कूटशब्दकेँ आग्रह करैत अछि
|
||||
Comment[mk]=KDE даемонот за паричник побарува лозинка
|
||||
Comment[ml]=കെഡിയിലെ വാലറ്റ് നിരന്തരപ്രവൃത്തി ഒരു അടയാളവാക്കു് ചോദിയ്ക്കുന്നു
|
||||
Comment[mr]=केडीई पाकीट डीमनने गुप्तशब्दाची मागणी केली आहे.
|
||||
Comment[nb]=KDEs lommeboknisse ber om et passord
|
||||
Comment[nds]=De KDE-Knipp-Dämoon bruukt en Passwoort
|
||||
Comment[nl]=De KDE-portefeuille-daemon vereist een wachtwoord
|
||||
Comment[nn]=Lommeboktenesta i KDE treng eit passord
|
||||
Comment[pa]=KDE ਵਾਲਟ ਡੈਮਨ ਨੇ ਪਾਸਵਰਡ ਦੀ ਮੰਗ ਕੀਤੀ ਹੈ
|
||||
Comment[pl]=Usługa Portfela KDE wymaga hasła
|
||||
Comment[pt]=O Servidor da Carteira do KDE está a pedir uma senha
|
||||
Comment[pt_BR]=O servidor de carteiras do KDE está solicitando uma senha
|
||||
Comment[ro]=Demonul de portofel KDE cere o parolă
|
||||
Comment[ru]=Бумажник KDE запрашивает пароль
|
||||
Comment[sa]=KDE Wallet Daemon गुप्तशब्दं याचते
|
||||
Comment[si]=The KDE පසුම්බි ඩීමනය මුරපදයක් ඉල්ලයි
|
||||
Comment[sk]=Démon KDE Wallet vyžaduje heslo
|
||||
Comment[sl]=Ozadnji program KDE-jeve Listnice zahteva geslo
|
||||
Comment[sr]=КДЕ‑ов демон новчаника захтева лозинку
|
||||
Comment[sr@ijekavian]=КДЕ‑ов демон новчаника захтијева лозинку
|
||||
Comment[sr@ijekavianlatin]=KDE‑ov demon novčanika zahtijeva lozinku
|
||||
Comment[sr@latin]=KDE‑ov demon novčanika zahteva lozinku
|
||||
Comment[sv]=KDE-plånboksdemonen begär ett lösenord
|
||||
Comment[tg]=Низоми дохилии ҳамёнҳои KDE ниҳонвожаеро дархост мекунад
|
||||
Comment[th]=บริการกระเป๋าคุมข้อมูลของ KDE ร้องขอรหัสผ่าน
|
||||
Comment[tr]=KDE Cüzdan Ardalan Süreci bir parola istiyor
|
||||
Comment[ug]=KDE ھەميان نازارەتچىسى ئىم سورايدۇ
|
||||
Comment[uk]=Фонова служба торбинок KDE надіслала запит на пароль
|
||||
Comment[vi]=Trình nền Ví KDE yêu cầu một mật khẩu
|
||||
Comment[wa]=Li démon poite-manoye di KDE dimande on scret
|
||||
Comment[x-test]=xxThe KDE Wallet Daemon requests a passwordxx
|
||||
Comment[zh_CN]=KDE 密码库守护程序请求密码
|
||||
Comment[zh_TW]=KDE 錢包守護程式需要密碼
|
||||
Action=Popup
|
||||
|
||||
[Event/syncFailed]
|
||||
Name=Sync Failed
|
||||
Name[ar]=فشلت المزامنة
|
||||
Name[az]=Eyniləşdirilmə Xətası
|
||||
Name[bg]=Неуспешно синхронизиране
|
||||
Name[bs]=Sinhronizacija neuspjela
|
||||
Name[ca]=Ha fallat la sincronització
|
||||
Name[ca@valencia]=No s'ha pogut sincronitzar
|
||||
Name[cs]=Synchronizace selhala
|
||||
Name[da]=Synkronisering mislykkedes
|
||||
Name[de]=Abgleich fehlgeschlagen
|
||||
Name[el]=Αποτυχία συγχρονισμού
|
||||
Name[en_GB]=Sync Failed
|
||||
Name[eo]=Sinkronigo Malsukcesis
|
||||
Name[es]=Sincronización fallida
|
||||
Name[et]=Sünkroonimine nurjus
|
||||
Name[eu]=Sinkronizatzeak huts egin du
|
||||
Name[fi]=Synkronointi epäonnistui
|
||||
Name[fr]=Échec de la synchronisation
|
||||
Name[gd]=Dh'fhàillig leis an sioncronachadh
|
||||
Name[gl]=Fallou a sincronización
|
||||
Name[he]=הסנכרון נכשל
|
||||
Name[hu]=A szinkronizálás meghiúsult
|
||||
Name[ia]=Il falleva synchronisar
|
||||
Name[id]=Sinkronisasi Gagal
|
||||
Name[is]=Samstilling mistókst
|
||||
Name[it]=Sincronizzazione non riuscita
|
||||
Name[ka]=სინქრონიზაცია ჩავარდა
|
||||
Name[kk]=Қадамдастыру жаңылды
|
||||
Name[ko]=동기화 실패
|
||||
Name[lt]=Sinchronizavimas nepavyko
|
||||
Name[lv]=Sinhronizēšana neizdevās
|
||||
Name[nb]=Synkronisering mislyktes
|
||||
Name[nds]=Synkroniseren is fehlslaan
|
||||
Name[nl]=Synchronisatie mislukt
|
||||
Name[nn]=Feil ved synkronisering
|
||||
Name[pa]=ਸਿੰਕ ਫੇਲ੍ਹ ਹੈ
|
||||
Name[pl]=Nieudana synchronizacja
|
||||
Name[pt]=A Sincronização Falhou
|
||||
Name[pt_BR]=Falha na sincronização
|
||||
Name[ro]=Sincronizare eșuată
|
||||
Name[ru]=Ошибка синхронизации бумажника
|
||||
Name[sa]=समन्वयनं विफलम्
|
||||
Name[sk]=Synchronizácia zlyhala
|
||||
Name[sl]=Uskladitev spodletela
|
||||
Name[sr]=Синхронизација пропала
|
||||
Name[sr@ijekavian]=Синхронизација пропала
|
||||
Name[sr@ijekavianlatin]=Sinhronizacija propala
|
||||
Name[sr@latin]=Sinhronizacija propala
|
||||
Name[sv]=Synkronisering misslyckades
|
||||
Name[tg]=Ҳамоҳангсозӣ қатъ шуд
|
||||
Name[tr]=Eşitleme Başarısız
|
||||
Name[uk]=Спроба синхронізації зазнала невдачі
|
||||
Name[vi]=Đồng bộ hoá thất bại
|
||||
Name[x-test]=xxSync Failedxx
|
||||
Name[zh_CN]=同步失败
|
||||
Name[zh_TW]=同步失敗
|
||||
Comment=KDE Wallet System failed to sync a wallet file to disk
|
||||
Comment[ar]=فشل نظام «محفظة كِيدِي» في مزامنة ملف المحفظة مع القرص
|
||||
Comment[az]=KDE Cüzdan Sistemi diskdə ona uyğun faylları saxlaya bilmədi
|
||||
Comment[bg]=Грешка при синхронизиране на портфейл файла на диска
|
||||
Comment[bs]=KDE Wallet Sistem nije uspio da sinhronizuje datoteku novčanika na disk
|
||||
Comment[ca]=El sistema de carteres de KDE ha fallat en sincronitzar un fitxer de cartera al disc
|
||||
Comment[ca@valencia]=El sistema de carteres de KDE ha fallat en sincronitzar un fitxer de cartera amb el disc
|
||||
Comment[cs]=Systému úschovny pro KDE selhala synchronizace úschovny na disk
|
||||
Comment[da]=KDE's tegnebogsystem kunne ikke synkronisere en tegnebogsfil til disken
|
||||
Comment[de]=Abgleich des KDE-Passwortspeicher mit einer Passwortspeicherdatei auf der Festplatte ist fehlgeschlagen.
|
||||
Comment[el]=Το σύστημα πορτοφολιού του KDE απέτυχε να συγχρονίσει ενός πορτοφολιού στον δίσκο
|
||||
Comment[en_GB]=KDE Wallet System failed to sync a wallet file to disk
|
||||
Comment[eo]=KDE trezoreja sistemo malsukcesis sinkronigi trezordoesieron al disko
|
||||
Comment[es]=El sistema de carteras de KDE ha fallado al sincronizar un archivo de cartera con el disco
|
||||
Comment[et]=KDE turvalaekasüsteem ei suutnud sünkroonida turvalaekafaili kettale
|
||||
Comment[eu]=KDE zorro-sistemak ezin izan du zorro bat diskora sinkronizatu
|
||||
Comment[fi]=KDE:n lompakkojärjestelmä ei onnistunut tallentamaan lompakkotiedostoa levylle
|
||||
Comment[fr]=Le système du portefeuille de KDE n'a pas réussi à synchroniser un fichier de portefeuille sur le disque
|
||||
Comment[gd]=Cha deach le siostam sporan KDE faidhle sporain a shioncronachadh ris an diosga
|
||||
Comment[gl]=O sistema de carteiras de KDE non puido sincronizar un ficheiro de carteira co disco.
|
||||
Comment[he]=מערכת הארנק של KDE נכשלה בסנכרון קובץ הארנק לכונן
|
||||
Comment[hu]=A KDE jelszókezelő rendszer nem tudta szinkronizálni a jelszófájlt a lemezre
|
||||
Comment[ia]=Le sistema de portafolio de KDE (KDE Wallet System) falleva synchronisar un file de portafolio con le disco
|
||||
Comment[id]=Sistem Wallet KDE gagal sinkronisasi file wallet ke cakram
|
||||
Comment[is]=KDE Wallet-kerfið náði ekki að samstilla veskisskrá á disk
|
||||
Comment[it]=Il sistema di portafogli di KDE non è riuscito a sincronizzare il file del portafogli sul disco
|
||||
Comment[ka]=KDE-ის საფულის სისტემის დისკთან სინქრონიზაციის შეცდომა
|
||||
Comment[kk]=KDE әмиян жүйесінің дискідегі әмиян файлымен қадамдастыру жаңылысы
|
||||
Comment[ko]=KDE 지갑 시스템과 디스크의 지갑 상태를 동기화할 수 없음
|
||||
Comment[lt]=KDE slaptažodinių sistemai nepavyko sinchronizuoti slaptažodinės failo į diską
|
||||
Comment[lv]=KDE maka sistēmai neizdevās sinhronizēt maka datni diskā
|
||||
Comment[nb]=KDE Wallet System klarte ikke å synkronisere en lommebokfil til disk
|
||||
Comment[nds]=Binnen KDE sien Knippsystem lett sik en Knipp nich mit de Datei op de Fastplaat synkroniseren
|
||||
Comment[nl]=Het lukte het KDE portefeuillesysteem niet om een portefeuillebestand naar schijf te synchroniseren
|
||||
Comment[nn]=Lommeboktenesta klarte ikkje synkronisera lommebokfila til disken
|
||||
Comment[pa]=ਕੇਡੀਈ ਵਾਲਟ ਸਿਸਟਮ ਵਾਲਟ ਫਾਇਲ ਨੂੰ ਡਿਸਕ ਉੱਤੇ ਸਿੰਕ ਕਰਨ ਲਈ ਫੇਲ੍ਹ ਹੈ
|
||||
Comment[pl]=Synchronizacja pliku portfela na dysku przez System portfela KDE zakończyła się niepowodzeniem
|
||||
Comment[pt]=O sistema da Carteira do KDE não conseguiu sincronizar um ficheiro da carteira para o disco
|
||||
Comment[pt_BR]=O Sistema da Carteiras do KDE não conseguiu sincronizar um arquivo de carteira com o disco
|
||||
Comment[ro]=Sistemul de portofele KDE nu a putut sincroniza fișierul unui portofel cu discul
|
||||
Comment[ru]=Не удалось сохранить бумажник в соответствующий ему файл на диске
|
||||
Comment[sa]=KDE Wallet System एकं बटुकसञ्चिकां डिस्कं प्रति समन्वययितुं असफलम् अभवत्
|
||||
Comment[sk]=Systému KDE peňaženky sa nepodarilo synchronizovať súbor peňaženky na disk
|
||||
Comment[sl]=Sistem listnic za KDE ni uspel uskladiti datoteke z listnico na disku
|
||||
Comment[sr]=К‑новчаник не може да синхронизује фајл новчаника на диск
|
||||
Comment[sr@ijekavian]=К‑новчаник не може да синхронизује фајл новчаника на диск
|
||||
Comment[sr@ijekavianlatin]=K‑novčanik ne može da sinhronizuje fajl novčanika na disk
|
||||
Comment[sr@latin]=K‑novčanik ne može da sinhronizuje fajl novčanika na disk
|
||||
Comment[sv]=KDE:s plånbokssystem misslyckades synkronisera en plånboksfil till disk
|
||||
Comment[tg]=Низоми ҳамёнҳои KDE ҳангоми ҳамоҳангсозии файли ҳамён бо диск қатъ шуд
|
||||
Comment[tr]=KDE Cüzdan Sistemi diske bir cüzdan dosyası eşitlerken başarısız oldu
|
||||
Comment[uk]=Система торбинок KDE не змогла синхронізувати дані файла торбинок з диском
|
||||
Comment[vi]=Hệ thống Ví KDE thất bại trong việc đồng bộ hoá một tệp ví vào đĩa
|
||||
Comment[x-test]=xxKDE Wallet System failed to sync a wallet file to diskxx
|
||||
Comment[zh_CN]=KDE 密码库系统无法将密码库文件同步到磁盘
|
||||
Comment[zh_TW]=KDE 錢包系統在將錢包檔同步到磁碟時失敗
|
||||
Action=Popup
|
||||
@@ -0,0 +1,17 @@
|
||||
/*
|
||||
This file is part of the KDE libraries
|
||||
SPDX-FileCopyrightText: 2022 Slava Aseev <nullptrnine@basealt.ru>
|
||||
|
||||
SPDX-License-Identifier: LGPL-2.0-or-later
|
||||
*/
|
||||
#include "kwalletdbuscontext.h"
|
||||
|
||||
const QDBusMessage &KWalletDBusContext::message() const
|
||||
{
|
||||
return QDBusContext::message();
|
||||
}
|
||||
|
||||
QDBusConnection KWalletDBusContext::connection() const
|
||||
{
|
||||
return QDBusContext::connection();
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
This file is part of the KDE libraries
|
||||
SPDX-FileCopyrightText: 2022 Slava Aseev <nullptrnine@basealt.ru>
|
||||
|
||||
SPDX-License-Identifier: LGPL-2.0-or-later
|
||||
*/
|
||||
#ifndef _KWALLETDBUSCONTEXT_H_
|
||||
#define _KWALLETDBUSCONTEXT_H_
|
||||
|
||||
#include "qdbuserror.h"
|
||||
#include <QDBusConnection>
|
||||
#include <QDBusContext>
|
||||
#include <QDBusMessage>
|
||||
|
||||
/* FDO_DBUS_CONTEXT macro will be replaced by KWalletDBusContextDummy during
|
||||
* preprocessing if FDO_ENABLE_DUMMY_MESSAGE_CONNECTION was defined,
|
||||
* otherwise we get QDBusContext.
|
||||
*
|
||||
* This is used for mocking QDBusContext in autotests.
|
||||
*
|
||||
* QDBusContext's connection() and message() member functions can't be called
|
||||
* without a real connection context (this cause segfault).
|
||||
* So we need to use KWalletDBusContextDummy in case some DBus-related
|
||||
* member functions may call connection()/message().
|
||||
*
|
||||
* This header defines FDO_DBUS_CONTEXT macro that should be used instead of
|
||||
* QDBusContext in all DBus-related which we want to use in autotests.
|
||||
*/
|
||||
|
||||
#ifdef FDO_ENABLE_DUMMY_MESSAGE_CONNECTION
|
||||
|
||||
class KWalletDBusContextDummy : public QDBusContext
|
||||
{
|
||||
public:
|
||||
const QDBusMessage &message()
|
||||
{
|
||||
static auto msg = QDBusMessage::createSignal(QStringLiteral("dummy"), QStringLiteral("dummy"), QStringLiteral("dummy"));
|
||||
return msg;
|
||||
}
|
||||
QDBusConnection connection() const
|
||||
{
|
||||
return QDBusConnection::sessionBus();
|
||||
}
|
||||
};
|
||||
|
||||
#define FDO_DBUS_CONTEXT KWalletDBusContextDummy
|
||||
|
||||
#else
|
||||
|
||||
#define FDO_DBUS_CONTEXT QDBusContext
|
||||
|
||||
#endif
|
||||
|
||||
#endif // _KWALLETDBUSCONTEXT_H_
|
||||
+341
@@ -0,0 +1,341 @@
|
||||
/*
|
||||
This file is part of the KDE libraries
|
||||
SPDX-FileCopyrightText: 2021 Slava Aseev <nullptrnine@basealt.ru>
|
||||
|
||||
SPDX-License-Identifier: LGPL-2.0-or-later
|
||||
*/
|
||||
#include "kwalletfreedesktopattributes.h"
|
||||
|
||||
#include "kwalletd.h"
|
||||
#include "kwalletd_debug.h"
|
||||
#include "kwalletfreedesktopcollection.h"
|
||||
#include <QDir>
|
||||
#include <QFile>
|
||||
#include <QJsonDocument>
|
||||
#include <QSaveFile>
|
||||
|
||||
KWalletFreedesktopAttributes::KWalletFreedesktopAttributes(const QString &walletName)
|
||||
{
|
||||
const QString writeLocation = QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation) + QLatin1String("/kwalletd");
|
||||
_path = writeLocation + QChar::fromLatin1('/') + KWalletD::encodeWalletName(walletName) + QStringLiteral("_attributes.json");
|
||||
|
||||
read();
|
||||
|
||||
if (!_params.contains(FDO_KEY_CREATED)) {
|
||||
const auto currentTime = QString::number(QDateTime::currentSecsSinceEpoch());
|
||||
_params[FDO_KEY_CREATED] = currentTime;
|
||||
_params[FDO_KEY_MODIFIED] = currentTime;
|
||||
}
|
||||
}
|
||||
|
||||
void KWalletFreedesktopAttributes::read()
|
||||
{
|
||||
QByteArray content;
|
||||
{
|
||||
QFile file(_path);
|
||||
file.open(QIODevice::ReadOnly | QIODevice::Text);
|
||||
if (!file.isOpen()) {
|
||||
qCDebug(KWALLETD_LOG) << "Can't read attributes file " << _path;
|
||||
return;
|
||||
}
|
||||
content = file.readAll();
|
||||
}
|
||||
|
||||
const auto jsonDoc = QJsonDocument::fromJson(content);
|
||||
if (jsonDoc.isObject()) {
|
||||
_params = jsonDoc.object();
|
||||
} else {
|
||||
qCWarning(KWALLETD_LOG) << "Can't read attributes: the root element must be an JSON-object: " << _path;
|
||||
_params = QJsonObject();
|
||||
}
|
||||
}
|
||||
|
||||
void KWalletFreedesktopAttributes::write()
|
||||
{
|
||||
if (_params.empty()) {
|
||||
QFile::remove(_path);
|
||||
return;
|
||||
}
|
||||
|
||||
updateLastModified();
|
||||
|
||||
QSaveFile sf(_path);
|
||||
if (!sf.open(QIODevice::WriteOnly | QIODevice::Unbuffered)) {
|
||||
qCWarning(KWALLETD_LOG) << "Can't write attributes file: " << _path;
|
||||
return;
|
||||
}
|
||||
sf.setPermissions(QSaveFile::ReadUser | QSaveFile::WriteUser);
|
||||
|
||||
const QJsonDocument saveDoc(_params);
|
||||
|
||||
const QByteArray jsonBytes = saveDoc.toJson();
|
||||
if (sf.write(jsonBytes) != jsonBytes.size()) {
|
||||
sf.cancelWriting();
|
||||
qCWarning(KWALLETD_LOG) << "Cannot write attributes file " << _path;
|
||||
return;
|
||||
}
|
||||
if (!sf.commit()) {
|
||||
qCWarning(KWALLETD_LOG) << "Cannot commit attributes file " << _path;
|
||||
}
|
||||
}
|
||||
|
||||
static QString entryLocationToStr(const EntryLocation &entryLocation)
|
||||
{
|
||||
return entryLocation.folder + QChar::fromLatin1('/') + entryLocation.key;
|
||||
}
|
||||
|
||||
static EntryLocation splitToEntryLocation(const QString &entryLocation)
|
||||
{
|
||||
const int slashPos = entryLocation.indexOf(QChar::fromLatin1('/'));
|
||||
if (slashPos == -1) {
|
||||
qCWarning(KWALLETD_LOG) << "Entry location '" << entryLocation << "' has no slash '/'";
|
||||
return {};
|
||||
} else {
|
||||
return {entryLocation.left(slashPos), entryLocation.right((entryLocation.size() - slashPos) - 1)};
|
||||
}
|
||||
}
|
||||
|
||||
void KWalletFreedesktopAttributes::remove(const EntryLocation &entryLocation)
|
||||
{
|
||||
_params.remove(entryLocationToStr(entryLocation));
|
||||
if (_params.empty()) {
|
||||
QFile::remove(_path);
|
||||
} else {
|
||||
write();
|
||||
}
|
||||
}
|
||||
|
||||
void KWalletFreedesktopAttributes::deleteFile()
|
||||
{
|
||||
QFile::remove(_path);
|
||||
}
|
||||
|
||||
void KWalletFreedesktopAttributes::renameLabel(const EntryLocation &oldLocation, const EntryLocation &newLocation)
|
||||
{
|
||||
const QString oldLoc = entryLocationToStr(oldLocation);
|
||||
|
||||
const auto found = _params.find(oldLoc);
|
||||
if (found == _params.end() || !found->isObject()) {
|
||||
qCWarning(KWALLETD_LOG) << "Can't rename label (!?)";
|
||||
return;
|
||||
}
|
||||
const auto obj = found->toObject();
|
||||
_params.erase(found);
|
||||
_params.insert(entryLocationToStr(newLocation), obj);
|
||||
|
||||
write();
|
||||
}
|
||||
|
||||
void KWalletFreedesktopAttributes::renameWallet(const QString &newName)
|
||||
{
|
||||
const QString writeLocation = QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation) + QLatin1String("/kwalletd");
|
||||
const QString newPath = writeLocation + QChar::fromLatin1('/') + newName + QStringLiteral("_attributes.json");
|
||||
|
||||
QFile::rename(_path, newPath);
|
||||
_path = newPath;
|
||||
}
|
||||
|
||||
void KWalletFreedesktopAttributes::newItem(const EntryLocation &entryLocation)
|
||||
{
|
||||
_params[entryLocationToStr(entryLocation)] = QJsonObject();
|
||||
}
|
||||
|
||||
QList<EntryLocation> KWalletFreedesktopAttributes::matchAttributes(const StrStrMap &attributes) const
|
||||
{
|
||||
QList<EntryLocation> items;
|
||||
|
||||
for (auto i = _params.constBegin(); i != _params.constEnd(); ++i) {
|
||||
if (!i->isObject()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
bool match = true;
|
||||
const auto itemParams = i->toObject();
|
||||
const auto foundItemAttribs = itemParams.find(QStringLiteral("attributes"));
|
||||
if (foundItemAttribs == itemParams.end() || !foundItemAttribs->isObject()) {
|
||||
continue;
|
||||
}
|
||||
const auto itemAttribs = foundItemAttribs->toObject();
|
||||
|
||||
for (auto i = attributes.constBegin(); i != attributes.constEnd(); ++i) {
|
||||
const auto foundKey = itemAttribs.find(i.key());
|
||||
if (foundKey == itemAttribs.end() || !foundKey->isString() || foundKey->toString() != i.value()) {
|
||||
match = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (match) {
|
||||
items += splitToEntryLocation(i.key());
|
||||
}
|
||||
}
|
||||
|
||||
return items;
|
||||
}
|
||||
|
||||
void KWalletFreedesktopAttributes::setAttributes(const EntryLocation &entryLocation, const StrStrMap &attributes)
|
||||
{
|
||||
QJsonObject jsonAttrs;
|
||||
for (auto i = attributes.constBegin(); i != attributes.constEnd(); ++i) {
|
||||
jsonAttrs.insert(i.key(), i.value());
|
||||
}
|
||||
|
||||
const QString strLocation = entryLocationToStr(entryLocation);
|
||||
|
||||
const auto foundParams = _params.find(strLocation);
|
||||
QJsonObject params;
|
||||
if (foundParams != _params.end() && foundParams->isObject()) {
|
||||
params = foundParams->toObject();
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
|
||||
if (jsonAttrs.empty()) {
|
||||
params.remove(QStringLiteral("attributes"));
|
||||
} else {
|
||||
params[QStringLiteral("attributes")] = jsonAttrs;
|
||||
}
|
||||
|
||||
_params[strLocation] = params;
|
||||
|
||||
write();
|
||||
}
|
||||
|
||||
StrStrMap KWalletFreedesktopAttributes::getAttributes(const EntryLocation &entryLocation) const
|
||||
{
|
||||
const auto foundObj = _params.find(entryLocationToStr(entryLocation));
|
||||
if (foundObj == _params.end() || !foundObj->isObject()) {
|
||||
return StrStrMap();
|
||||
}
|
||||
const auto jsonParams = foundObj->toObject();
|
||||
|
||||
const auto foundAttrs = jsonParams.find(QStringLiteral("attributes"));
|
||||
if (foundAttrs == jsonParams.end() || !foundAttrs->isObject()) {
|
||||
return StrStrMap();
|
||||
}
|
||||
const auto jsonAttrs = foundAttrs->toObject();
|
||||
|
||||
StrStrMap itemAttrs;
|
||||
|
||||
for (auto i = jsonAttrs.constBegin(); i != jsonAttrs.constEnd(); ++i) {
|
||||
if (i.value().isString()) {
|
||||
itemAttrs.insert(i.key(), i.value().toString());
|
||||
}
|
||||
}
|
||||
|
||||
return itemAttrs;
|
||||
}
|
||||
|
||||
QString KWalletFreedesktopAttributes::getStringParam(const EntryLocation &entryLocation, const QString ¶mName, const QString &defaultParam) const
|
||||
{
|
||||
const auto foundParams = _params.find(entryLocationToStr(entryLocation));
|
||||
if (foundParams == _params.end() || !foundParams->isObject()) {
|
||||
return defaultParam;
|
||||
}
|
||||
const auto params = foundParams->toObject();
|
||||
|
||||
const auto foundParam = params.find(paramName);
|
||||
if (foundParam == params.end() || !foundParam->isString()) {
|
||||
return defaultParam;
|
||||
}
|
||||
|
||||
return foundParam->toString();
|
||||
}
|
||||
|
||||
qulonglong KWalletFreedesktopAttributes::getULongLongParam(const EntryLocation &entryLocation, const QString ¶mName, qulonglong defaultParam) const
|
||||
{
|
||||
const auto str = getStringParam(entryLocation, paramName, QString::number(defaultParam));
|
||||
bool ok = false;
|
||||
const auto result = str.toULongLong(&ok);
|
||||
return ok ? result : defaultParam;
|
||||
}
|
||||
|
||||
void KWalletFreedesktopAttributes::setParam(const EntryLocation &entryLocation, const QString ¶mName, const QString ¶m)
|
||||
{
|
||||
const auto entryLoc = entryLocationToStr(entryLocation);
|
||||
const auto foundParams = _params.find(entryLoc);
|
||||
if (foundParams == _params.end() || !foundParams->isObject()) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto params = foundParams->toObject();
|
||||
|
||||
params[paramName] = param;
|
||||
_params[entryLoc] = params;
|
||||
|
||||
write();
|
||||
}
|
||||
|
||||
void KWalletFreedesktopAttributes::setParam(const EntryLocation &entryLocation, const QString ¶mName, qulonglong param)
|
||||
{
|
||||
setParam(entryLocation, paramName, QString::number(param));
|
||||
}
|
||||
|
||||
void KWalletFreedesktopAttributes::remove(const FdoUniqueLabel &itemUniqLabel)
|
||||
{
|
||||
remove(itemUniqLabel.toEntryLocation());
|
||||
}
|
||||
|
||||
void KWalletFreedesktopAttributes::setAttributes(const FdoUniqueLabel &itemUniqLabel, const StrStrMap &attributes)
|
||||
{
|
||||
setAttributes(itemUniqLabel.toEntryLocation(), attributes);
|
||||
}
|
||||
|
||||
StrStrMap KWalletFreedesktopAttributes::getAttributes(const FdoUniqueLabel &itemUniqLabel) const
|
||||
{
|
||||
return getAttributes(itemUniqLabel.toEntryLocation());
|
||||
}
|
||||
|
||||
QString KWalletFreedesktopAttributes::getStringParam(const FdoUniqueLabel &itemUniqLabel, const QString ¶mName, const QString &defaultParam) const
|
||||
{
|
||||
return getStringParam(itemUniqLabel.toEntryLocation(), paramName, defaultParam);
|
||||
}
|
||||
|
||||
qulonglong KWalletFreedesktopAttributes::getULongLongParam(const FdoUniqueLabel &itemUniqLabel, const QString ¶mName, qulonglong defaultParam) const
|
||||
{
|
||||
return getULongLongParam(itemUniqLabel.toEntryLocation(), paramName, defaultParam);
|
||||
}
|
||||
|
||||
void KWalletFreedesktopAttributes::setParam(const FdoUniqueLabel &itemUniqLabel, const QString ¶mName, const QString ¶m)
|
||||
{
|
||||
setParam(itemUniqLabel.toEntryLocation(), paramName, param);
|
||||
}
|
||||
|
||||
void KWalletFreedesktopAttributes::setParam(const FdoUniqueLabel &itemUniqLabel, const QString ¶mName, qulonglong param)
|
||||
{
|
||||
setParam(itemUniqLabel.toEntryLocation(), paramName, param);
|
||||
}
|
||||
|
||||
QList<EntryLocation> KWalletFreedesktopAttributes::listItems() const
|
||||
{
|
||||
QList<EntryLocation> items;
|
||||
for (auto i = _params.constBegin(); i != _params.constEnd(); ++i) {
|
||||
if (i->isObject()) {
|
||||
items.push_back(splitToEntryLocation(i.key()));
|
||||
}
|
||||
}
|
||||
return items;
|
||||
}
|
||||
|
||||
qulonglong KWalletFreedesktopAttributes::lastModified() const
|
||||
{
|
||||
auto found = _params.constFind(FDO_KEY_MODIFIED);
|
||||
if (found == _params.constEnd()) {
|
||||
return 0;
|
||||
}
|
||||
return found->toString().toULongLong();
|
||||
}
|
||||
|
||||
qulonglong KWalletFreedesktopAttributes::birthTime() const
|
||||
{
|
||||
auto found = _params.constFind(FDO_KEY_CREATED);
|
||||
if (found == _params.constEnd()) {
|
||||
return 0;
|
||||
}
|
||||
return found->toString().toULongLong();
|
||||
}
|
||||
|
||||
void KWalletFreedesktopAttributes::updateLastModified()
|
||||
{
|
||||
_params[FDO_KEY_MODIFIED] = QString::number(QDateTime::currentSecsSinceEpoch());
|
||||
}
|
||||
+57
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
This file is part of the KDE libraries
|
||||
SPDX-FileCopyrightText: 2021 Slava Aseev <nullptrnine@basealt.ru>
|
||||
|
||||
SPDX-License-Identifier: LGPL-2.0-or-later
|
||||
*/
|
||||
#ifndef _KWALLETFREEDESKTOPATTRIBUTES_H_
|
||||
#define _KWALLETFREEDESKTOPATTRIBUTES_H_
|
||||
|
||||
#include "kwalletfreedesktopservice.h"
|
||||
#include <QJsonObject>
|
||||
|
||||
class KWalletFreedesktopAttributes : public QObject
|
||||
{
|
||||
public:
|
||||
KWalletFreedesktopAttributes(const QString &walletName);
|
||||
|
||||
void read();
|
||||
void write();
|
||||
void remove(const EntryLocation &entryLocation);
|
||||
void remove(const FdoUniqueLabel &itemUniqLabel);
|
||||
void renameLabel(const EntryLocation &oldLocation, const EntryLocation &newLocation);
|
||||
void deleteFile();
|
||||
void renameWallet(const QString &newName);
|
||||
void newItem(const EntryLocation &entryLocation);
|
||||
|
||||
QList<EntryLocation> matchAttributes(const StrStrMap &attributes) const;
|
||||
void setAttributes(const EntryLocation &entryLocation, const StrStrMap &attributes);
|
||||
StrStrMap getAttributes(const EntryLocation &entryLocation) const;
|
||||
|
||||
void setAttributes(const FdoUniqueLabel &itemUniqLabel, const StrStrMap &attributes);
|
||||
StrStrMap getAttributes(const FdoUniqueLabel &itemUniqLabel) const;
|
||||
|
||||
QString getStringParam(const EntryLocation &entryLocation, const QString ¶mName, const QString &defaultParam) const;
|
||||
qulonglong getULongLongParam(const EntryLocation &entryLocation, const QString ¶mName, qulonglong defaultParam) const;
|
||||
|
||||
QString getStringParam(const FdoUniqueLabel &itemUniqLabel, const QString ¶mName, const QString &defaultParam) const;
|
||||
qulonglong getULongLongParam(const FdoUniqueLabel &itemUniqLabel, const QString ¶mName, qulonglong defaultParam) const;
|
||||
|
||||
void setParam(const EntryLocation &entryLocation, const QString ¶mName, const QString ¶m);
|
||||
void setParam(const EntryLocation &entryLocation, const QString ¶mName, qulonglong param);
|
||||
|
||||
void setParam(const FdoUniqueLabel &itemUniqLabel, const QString ¶mName, const QString ¶m);
|
||||
void setParam(const FdoUniqueLabel &itemUniqLabel, const QString ¶mName, qulonglong param);
|
||||
|
||||
qulonglong lastModified() const;
|
||||
qulonglong birthTime() const;
|
||||
void updateLastModified();
|
||||
|
||||
QList<EntryLocation> listItems() const;
|
||||
|
||||
private:
|
||||
QString _path;
|
||||
QJsonObject _params;
|
||||
};
|
||||
|
||||
#endif
|
||||
+418
@@ -0,0 +1,418 @@
|
||||
/*
|
||||
This file is part of the KDE libraries
|
||||
SPDX-FileCopyrightText: 2021 Slava Aseev <nullptrnine@basealt.ru>
|
||||
|
||||
SPDX-License-Identifier: LGPL-2.0-or-later
|
||||
*/
|
||||
#include "kwalletfreedesktopcollection.h"
|
||||
|
||||
#include "kwalletd.h"
|
||||
#include "kwalletfreedesktopcollectionadaptor.h"
|
||||
#include "kwalletfreedesktopitem.h"
|
||||
|
||||
KWalletFreedesktopCollection::KWalletFreedesktopCollection(KWalletFreedesktopService *service,
|
||||
int handle,
|
||||
const QString &walletName,
|
||||
QDBusObjectPath objectPath)
|
||||
: m_service(service)
|
||||
, m_handle(handle)
|
||||
, m_uniqueLabel(FdoUniqueLabel::fromName(walletName))
|
||||
, m_objectPath(std::move(objectPath))
|
||||
, m_itemAttribs(walletName)
|
||||
{
|
||||
(void)new KWalletFreedesktopCollectionAdaptor(this);
|
||||
QDBusConnection::sessionBus().registerObject(fdoObjectPath().path(), this);
|
||||
|
||||
const QStringList aliases = fdoService()->readAliasesFor(walletName);
|
||||
for (const auto &alias : aliases) {
|
||||
QDBusConnection::sessionBus().registerObject(QStringLiteral(FDO_ALIAS_PATH) + alias, this);
|
||||
}
|
||||
|
||||
onWalletChangeState(handle);
|
||||
|
||||
/* Create items described in the attributes file */
|
||||
if (m_handle == -1) {
|
||||
const auto items = itemAttributes().listItems();
|
||||
for (const auto &entryLocation : items) {
|
||||
if (!findItemByEntryLocation(entryLocation)) {
|
||||
pushNewItem(entryLocation.toUniqueLabel(), nextItemPath());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
QDBusObjectPath KWalletFreedesktopCollection::nextItemPath()
|
||||
{
|
||||
return QDBusObjectPath(fdoObjectPath().path() + QChar::fromLatin1('/') + QString::number(m_itemCounter++));
|
||||
}
|
||||
|
||||
const QString &KWalletFreedesktopCollection::label() const
|
||||
{
|
||||
return m_uniqueLabel.label;
|
||||
}
|
||||
|
||||
void KWalletFreedesktopCollection::setLabel(const QString &newLabel)
|
||||
{
|
||||
if (newLabel == label()) {
|
||||
return;
|
||||
}
|
||||
|
||||
const auto oldName = m_uniqueLabel.toName();
|
||||
const auto newUniqLabel = fdoService()->makeUniqueCollectionLabel(newLabel);
|
||||
const auto newName = newUniqLabel.toName();
|
||||
|
||||
int rc = backend()->renameWallet(oldName, newName);
|
||||
if (rc == 0) {
|
||||
const QStringList aliases = fdoService()->readAliasesFor(walletName());
|
||||
m_uniqueLabel = newUniqLabel;
|
||||
const QString newName = walletName();
|
||||
for (const auto &alias : aliases) {
|
||||
fdoService()->updateCollectionAlias(alias, newName);
|
||||
}
|
||||
|
||||
itemAttributes().renameWallet(newName);
|
||||
}
|
||||
}
|
||||
|
||||
bool KWalletFreedesktopCollection::locked() const
|
||||
{
|
||||
return m_handle < 0 || !backend()->isOpen(m_handle);
|
||||
}
|
||||
|
||||
QList<QDBusObjectPath> KWalletFreedesktopCollection::items() const
|
||||
{
|
||||
QList<QDBusObjectPath> items;
|
||||
|
||||
for (const auto &item : m_items) {
|
||||
items.push_back(item.second->fdoObjectPath());
|
||||
}
|
||||
|
||||
return items;
|
||||
}
|
||||
|
||||
qulonglong KWalletFreedesktopCollection::created() const
|
||||
{
|
||||
return itemAttributes().birthTime();
|
||||
}
|
||||
|
||||
qulonglong KWalletFreedesktopCollection::modified() const
|
||||
{
|
||||
return itemAttributes().lastModified();
|
||||
}
|
||||
|
||||
QDBusObjectPath
|
||||
KWalletFreedesktopCollection::CreateItem(const PropertiesMap &properties, const FreedesktopSecret &secret, bool replace, QDBusObjectPath &prompt)
|
||||
{
|
||||
prompt = QDBusObjectPath("/");
|
||||
|
||||
if (m_handle == -1) {
|
||||
sendErrorReply(QStringLiteral("org.freedesktop.Secret.Error.IsLocked"),
|
||||
QStringLiteral("Collection ") + fdoObjectPath().path() + QStringLiteral(" is locked"));
|
||||
return QDBusObjectPath("/");
|
||||
}
|
||||
|
||||
const auto labelFound = properties.map.find(QStringLiteral("org.freedesktop.Secret.Item.Label"));
|
||||
if (labelFound == properties.map.end()) {
|
||||
sendErrorReply(QDBusError::ErrorType::InvalidArgs, QStringLiteral("Item label is missing (org.freedesktop.Secret.Item.Label)"));
|
||||
return QDBusObjectPath("/");
|
||||
}
|
||||
if (!labelFound->canConvert<QString>()) {
|
||||
sendErrorReply(QDBusError::ErrorType::InvalidArgs, QStringLiteral("Item label is not a string (org.freedesktop.Secret.Item.Label)"));
|
||||
return QDBusObjectPath("/");
|
||||
}
|
||||
|
||||
const QString fdoLabel = labelFound->toString();
|
||||
QString dir, label;
|
||||
QDBusObjectPath itemPath;
|
||||
|
||||
StrStrMap attribs;
|
||||
const auto attribsFound = properties.map.find(QStringLiteral("org.freedesktop.Secret.Item.Attributes"));
|
||||
if (attribsFound != properties.map.end() && attribsFound->canConvert<StrStrMap>()) {
|
||||
attribs = attribsFound->value<StrStrMap>();
|
||||
}
|
||||
|
||||
if (replace) {
|
||||
/* Try find item with same attributes */
|
||||
const auto matchedItems = itemAttributes().matchAttributes(attribs);
|
||||
|
||||
if (!matchedItems.empty()) {
|
||||
const auto &entryLoc = matchedItems.constFirst();
|
||||
const auto item = findItemByEntryLocation(entryLoc);
|
||||
if (item) {
|
||||
itemPath = item->fdoObjectPath();
|
||||
dir = entryLoc.folder;
|
||||
label = entryLoc.key;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (dir.isEmpty() && label.isEmpty()) {
|
||||
const auto entryLocation = makeUniqueEntryLocation(fdoLabel);
|
||||
dir = entryLocation.folder;
|
||||
label = entryLocation.key;
|
||||
itemPath = nextItemPath();
|
||||
}
|
||||
|
||||
if (label.isEmpty()) {
|
||||
sendErrorReply(QDBusError::ErrorType::InvalidArgs, QStringLiteral("Item label is invalid (org.freedesktop.Secret.Item.Label)"));
|
||||
return QDBusObjectPath("/");
|
||||
}
|
||||
|
||||
const qulonglong createTime = QDateTime::currentSecsSinceEpoch();
|
||||
const EntryLocation entryLoc{dir, label};
|
||||
itemAttributes().newItem(entryLoc);
|
||||
itemAttributes().setParam(entryLoc, FDO_KEY_MIME, secret.mimeType);
|
||||
itemAttributes().setParam(entryLoc, FDO_KEY_CREATED, createTime);
|
||||
itemAttributes().setParam(entryLoc, FDO_KEY_MODIFIED, createTime);
|
||||
itemAttributes().setAttributes(entryLoc, attribs);
|
||||
|
||||
pushNewItem(entryLoc.toUniqueLabel(), itemPath);
|
||||
|
||||
{
|
||||
auto decrypted = secret;
|
||||
if (!fdoService()->desecret(message(), decrypted)) {
|
||||
sendErrorReply(QDBusError::ErrorType::InvalidObjectPath, QStringLiteral("Can't find session ") + secret.session.path());
|
||||
return QDBusObjectPath("/");
|
||||
}
|
||||
|
||||
QString xdgSchema = QStringLiteral("org.kde.KWallet.Stream");
|
||||
const auto found = attribs.find(FDO_KEY_XDG_SCHEMA);
|
||||
if (found != attribs.end()) {
|
||||
xdgSchema = found.value();
|
||||
}
|
||||
|
||||
if (xdgSchema == QStringLiteral("org.kde.KWallet.Password") || secret.mimeType.startsWith(QStringLiteral("text/"))) {
|
||||
auto bytes = decrypted.value.toByteArray();
|
||||
auto str = QString::fromUtf8(bytes);
|
||||
backend()->writePassword(walletHandle(), dir, label, str, FDO_APPID);
|
||||
explicit_zero_mem(bytes.data(), bytes.size());
|
||||
explicit_zero_mem(str.data(), str.size() * sizeof(QChar));
|
||||
} else {
|
||||
auto bytes = decrypted.value.toByteArray();
|
||||
backend()->writeEntry(walletHandle(), dir, label, bytes, KWallet::Wallet::Stream, FDO_APPID);
|
||||
explicit_zero_mem(bytes.data(), bytes.size());
|
||||
}
|
||||
}
|
||||
|
||||
onItemCreated(itemPath);
|
||||
|
||||
return itemPath;
|
||||
}
|
||||
|
||||
QDBusObjectPath KWalletFreedesktopCollection::Delete()
|
||||
{
|
||||
const auto name = walletName();
|
||||
|
||||
const QStringList aliases = fdoService()->readAliasesFor(name);
|
||||
for (const QString &alias : aliases) {
|
||||
fdoService()->removeAlias(alias);
|
||||
}
|
||||
|
||||
backend()->deleteWallet(name);
|
||||
QDBusConnection::sessionBus().unregisterObject(fdoObjectPath().path());
|
||||
m_service->onCollectionDeleted(fdoObjectPath());
|
||||
|
||||
return QDBusObjectPath("/");
|
||||
}
|
||||
|
||||
QList<QDBusObjectPath> KWalletFreedesktopCollection::SearchItems(const StrStrMap &attributes)
|
||||
{
|
||||
QList<QDBusObjectPath> result;
|
||||
|
||||
for (const auto &entryLoc : m_itemAttribs.matchAttributes(attributes)) {
|
||||
auto *itm = findItemByEntryLocation(entryLoc);
|
||||
if (itm) {
|
||||
result.push_back(itm->fdoObjectPath());
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
int KWalletFreedesktopCollection::walletHandle() const
|
||||
{
|
||||
return m_handle;
|
||||
}
|
||||
|
||||
KWalletFreedesktopItem *KWalletFreedesktopCollection::getItemByObjectPath(const QString &objectPath) const
|
||||
{
|
||||
const auto found = m_items.find(objectPath);
|
||||
if (found != m_items.end()) {
|
||||
return found->second.get();
|
||||
} else {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
KWalletFreedesktopItem *KWalletFreedesktopCollection::findItemByEntryLocation(const EntryLocation &entryLocation) const
|
||||
{
|
||||
const auto uniqLabel = FdoUniqueLabel::fromEntryLocation(entryLocation);
|
||||
|
||||
for (const auto &itemPair : m_items) {
|
||||
auto *item = itemPair.second.get();
|
||||
if (item->uniqueLabel() == uniqLabel) {
|
||||
return item;
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
EntryLocation KWalletFreedesktopCollection::makeUniqueEntryLocation(const QString &label)
|
||||
{
|
||||
QString dir, name;
|
||||
|
||||
const int slashPos = label.indexOf(QChar::fromLatin1('/'));
|
||||
if (slashPos == -1 || slashPos == label.size() - 1) {
|
||||
dir = QStringLiteral(FDO_SECRETS_DEFAULT_DIR);
|
||||
name = label;
|
||||
} else {
|
||||
dir = label.left(slashPos);
|
||||
name = label.mid(slashPos + 1);
|
||||
}
|
||||
|
||||
int suffix = 0;
|
||||
QString resultName = name;
|
||||
while (backend()->hasEntry(m_handle, dir, resultName, FDO_APPID)) {
|
||||
resultName = FdoUniqueLabel::makeName(name, suffix++);
|
||||
}
|
||||
|
||||
return {dir, resultName};
|
||||
}
|
||||
|
||||
FdoUniqueLabel KWalletFreedesktopCollection::makeUniqueItemLabel(const QString &label)
|
||||
{
|
||||
return makeUniqueEntryLocation(label).toUniqueLabel();
|
||||
}
|
||||
|
||||
KWalletFreedesktopItem &KWalletFreedesktopCollection::pushNewItem(FdoUniqueLabel uniqLabel, const QDBusObjectPath &path)
|
||||
{
|
||||
m_items.erase(path.path());
|
||||
auto item = std::make_unique<KWalletFreedesktopItem>(this, std::move(uniqLabel), path);
|
||||
return *m_items.emplace(path.path(), std::move(item)).first->second;
|
||||
}
|
||||
|
||||
KWalletFreedesktopItem &KWalletFreedesktopCollection::pushNewItem(const QString &label, const QDBusObjectPath &path)
|
||||
{
|
||||
return pushNewItem(makeUniqueItemLabel(label), path);
|
||||
}
|
||||
|
||||
KWalletFreedesktopService *KWalletFreedesktopCollection::fdoService() const
|
||||
{
|
||||
return m_service;
|
||||
}
|
||||
|
||||
KWalletD *KWalletFreedesktopCollection::backend() const
|
||||
{
|
||||
return fdoService()->backend();
|
||||
}
|
||||
|
||||
QDBusObjectPath KWalletFreedesktopCollection::fdoObjectPath() const
|
||||
{
|
||||
return m_objectPath;
|
||||
}
|
||||
|
||||
const FdoUniqueLabel &KWalletFreedesktopCollection::uniqueLabel() const
|
||||
{
|
||||
return m_uniqueLabel;
|
||||
}
|
||||
|
||||
QString KWalletFreedesktopCollection::walletName() const
|
||||
{
|
||||
return m_uniqueLabel.toName();
|
||||
}
|
||||
|
||||
void KWalletFreedesktopCollection::onWalletChangeState(int handle)
|
||||
{
|
||||
if (handle == m_handle) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (handle >= 0 && m_handle >= 0) {
|
||||
m_handle = handle;
|
||||
return;
|
||||
}
|
||||
|
||||
m_handle = handle;
|
||||
|
||||
if (m_handle < 0 || !m_items.empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
const QStringList folderList = backend()->folderList(m_handle, FDO_APPID);
|
||||
for (const QString &folder : folderList) {
|
||||
const QStringList entries = backend()->entryList(m_handle, folder, FDO_APPID);
|
||||
|
||||
for (const auto &entry : entries) {
|
||||
const EntryLocation entryLoc{folder, entry};
|
||||
const auto itm = findItemByEntryLocation(entryLoc);
|
||||
if (!itm) {
|
||||
auto &newItem = pushNewItem(entryLoc.toUniqueLabel(), nextItemPath());
|
||||
Q_EMIT ItemChanged(newItem.fdoObjectPath());
|
||||
} else {
|
||||
Q_EMIT ItemChanged(itm->fdoObjectPath());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void KWalletFreedesktopCollection::onItemCreated(const QDBusObjectPath &item)
|
||||
{
|
||||
itemAttributes().updateLastModified();
|
||||
Q_EMIT ItemCreated(item);
|
||||
|
||||
QVariantMap props;
|
||||
props[QStringLiteral("Items")] = QVariant::fromValue(items());
|
||||
onPropertiesChanged(props);
|
||||
}
|
||||
|
||||
void KWalletFreedesktopCollection::onItemChanged(const QDBusObjectPath &item)
|
||||
{
|
||||
itemAttributes().updateLastModified();
|
||||
Q_EMIT ItemChanged(item);
|
||||
}
|
||||
|
||||
void KWalletFreedesktopCollection::onItemDeleted(const QDBusObjectPath &item)
|
||||
{
|
||||
itemAttributes().updateLastModified();
|
||||
const auto itemMapPos = m_items.find(item.path());
|
||||
if (itemMapPos == m_items.end()) {
|
||||
return;
|
||||
}
|
||||
auto *itemPtr = itemMapPos->second.get();
|
||||
|
||||
/* This can be called in the context of the item that is currently being
|
||||
* deleted. Therefore we should schedule deletion on the next event loop iteration
|
||||
*/
|
||||
itemPtr->setDeleted();
|
||||
itemPtr->deleteLater();
|
||||
itemMapPos->second.release();
|
||||
m_items.erase(itemMapPos);
|
||||
|
||||
Q_EMIT ItemDeleted(item);
|
||||
|
||||
QVariantMap props;
|
||||
props[QStringLiteral("Items")] = QVariant::fromValue(items());
|
||||
onPropertiesChanged(props);
|
||||
}
|
||||
|
||||
void KWalletFreedesktopCollection::onPropertiesChanged(const QVariantMap &properties)
|
||||
{
|
||||
auto msg = QDBusMessage::createSignal(fdoObjectPath().path(), QStringLiteral("org.freedesktop.DBus.Properties"), QStringLiteral("PropertiesChanged"));
|
||||
auto args = QVariantList();
|
||||
args << QStringLiteral("org.freedesktop.Secret.Collection") << properties << QStringList();
|
||||
msg.setArguments(args);
|
||||
QDBusConnection::sessionBus().send(msg);
|
||||
}
|
||||
|
||||
KWalletFreedesktopAttributes &KWalletFreedesktopCollection::itemAttributes()
|
||||
{
|
||||
return m_itemAttribs;
|
||||
}
|
||||
|
||||
const KWalletFreedesktopAttributes &KWalletFreedesktopCollection::itemAttributes() const
|
||||
{
|
||||
return m_itemAttribs;
|
||||
}
|
||||
|
||||
#include "moc_kwalletfreedesktopcollection.cpp"
|
||||
+104
@@ -0,0 +1,104 @@
|
||||
/*
|
||||
This file is part of the KDE libraries
|
||||
SPDX-FileCopyrightText: 2021 Slava Aseev <nullptrnine@basealt.ru>
|
||||
|
||||
SPDX-License-Identifier: LGPL-2.0-or-later
|
||||
*/
|
||||
#ifndef _KWALLETFREEDESKTOPCOLLECTION_H_
|
||||
#define _KWALLETFREEDESKTOPCOLLECTION_H_
|
||||
#include "kwalletfreedesktopattributes.h"
|
||||
#include "kwalletfreedesktopservice.h"
|
||||
|
||||
#define FDO_SECRETS_COLLECTION_PATH FDO_SECRETS_SERVICE_OBJECT "/collection/"
|
||||
#define FDO_SECRETS_DEFAULT_DIR "Secret Service"
|
||||
#define FDO_KEY_MODIFIED QStringLiteral("$fdo_modified")
|
||||
#define FDO_KEY_CREATED QStringLiteral("$fdo_created")
|
||||
#define FDO_KEY_MIME QStringLiteral("$fdo_mime_type")
|
||||
#define FDO_KEY_XDG_SCHEMA QStringLiteral("xdg:schema")
|
||||
|
||||
class KWalletFreedesktopItem;
|
||||
|
||||
class KWalletFreedesktopCollection : public QObject, protected QDBusContext
|
||||
{
|
||||
/* org.freedesktop.Secret.Collection properties */
|
||||
public:
|
||||
Q_PROPERTY(qulonglong Created READ created)
|
||||
qulonglong created() const;
|
||||
|
||||
Q_PROPERTY(qulonglong Modified READ modified)
|
||||
qulonglong modified() const;
|
||||
|
||||
Q_PROPERTY(QList<QDBusObjectPath> Items READ items)
|
||||
QList<QDBusObjectPath> items() const;
|
||||
|
||||
Q_PROPERTY(QString Label READ label WRITE setLabel)
|
||||
const QString &label() const;
|
||||
void setLabel(const QString &value);
|
||||
|
||||
Q_PROPERTY(bool Locked READ locked)
|
||||
bool locked() const;
|
||||
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
KWalletFreedesktopCollection(KWalletFreedesktopService *service, int handle, const QString &walletName, QDBusObjectPath objectPath);
|
||||
|
||||
KWalletFreedesktopCollection(const KWalletFreedesktopCollection &) = delete;
|
||||
KWalletFreedesktopCollection &operator=(const KWalletFreedesktopCollection &) = delete;
|
||||
|
||||
KWalletFreedesktopCollection(KWalletFreedesktopCollection &&) = delete;
|
||||
KWalletFreedesktopCollection &&operator=(KWalletFreedesktopCollection &&) = delete;
|
||||
|
||||
EntryLocation makeUniqueEntryLocation(const QString &label);
|
||||
FdoUniqueLabel makeUniqueItemLabel(const QString &label);
|
||||
|
||||
QDBusObjectPath nextItemPath();
|
||||
|
||||
KWalletFreedesktopService *fdoService() const;
|
||||
KWalletD *backend() const;
|
||||
QDBusObjectPath fdoObjectPath() const;
|
||||
const FdoUniqueLabel &uniqueLabel() const;
|
||||
QString walletName() const;
|
||||
int walletHandle() const;
|
||||
|
||||
KWalletFreedesktopItem *getItemByObjectPath(const QString &objectPath) const;
|
||||
KWalletFreedesktopItem *findItemByEntryLocation(const EntryLocation &entryLocation) const;
|
||||
KWalletFreedesktopItem &pushNewItem(FdoUniqueLabel label, const QDBusObjectPath &path);
|
||||
KWalletFreedesktopAttributes &itemAttributes();
|
||||
const KWalletFreedesktopAttributes &itemAttributes() const;
|
||||
|
||||
/* Emitters */
|
||||
void onWalletChangeState(int handle);
|
||||
void onItemCreated(const QDBusObjectPath &item);
|
||||
void onItemChanged(const QDBusObjectPath &item);
|
||||
void onItemDeleted(const QDBusObjectPath &item);
|
||||
void onPropertiesChanged(const QVariantMap &properties);
|
||||
|
||||
private:
|
||||
KWalletFreedesktopItem &pushNewItem(const QString &label, const QDBusObjectPath &path);
|
||||
|
||||
private:
|
||||
KWalletFreedesktopService *m_service;
|
||||
int m_handle;
|
||||
FdoUniqueLabel m_uniqueLabel;
|
||||
QDBusObjectPath m_objectPath;
|
||||
KWalletFreedesktopAttributes m_itemAttribs;
|
||||
std::map<QString, std::unique_ptr<KWalletFreedesktopItem>> m_items;
|
||||
uint64_t m_itemCounter = 0;
|
||||
|
||||
/* Freedesktop API */
|
||||
|
||||
/* org.freedesktop.Secret.Collection methods */
|
||||
public Q_SLOTS:
|
||||
QDBusObjectPath CreateItem(const PropertiesMap &properties, const FreedesktopSecret &secret, bool replace, QDBusObjectPath &prompt);
|
||||
QDBusObjectPath Delete();
|
||||
QList<QDBusObjectPath> SearchItems(const StrStrMap &attributes);
|
||||
|
||||
/* org.freedesktop.Secret.Service signals */
|
||||
Q_SIGNALS:
|
||||
void ItemChanged(const QDBusObjectPath &item);
|
||||
void ItemCreated(const QDBusObjectPath &item);
|
||||
void ItemDeleted(const QDBusObjectPath &item);
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,224 @@
|
||||
/*
|
||||
This file is part of the KDE libraries
|
||||
SPDX-FileCopyrightText: 2021 Slava Aseev <nullptrnine@basealt.ru>
|
||||
|
||||
SPDX-License-Identifier: LGPL-2.0-or-later
|
||||
*/
|
||||
#include "kwalletfreedesktopitem.h"
|
||||
|
||||
#include "kwalletd.h"
|
||||
#include "kwalletd_debug.h"
|
||||
#include "kwalletfreedesktopcollection.h"
|
||||
#include "kwalletfreedesktopitemadaptor.h"
|
||||
|
||||
KWalletFreedesktopItem::KWalletFreedesktopItem(KWalletFreedesktopCollection *collection, FdoUniqueLabel uniqLabel, QDBusObjectPath path)
|
||||
: m_collection(collection)
|
||||
, m_uniqueLabel(std::move(uniqLabel))
|
||||
, m_path(std::move(path))
|
||||
{
|
||||
(void)new KWalletFreedesktopItemAdaptor(this);
|
||||
QDBusConnection::sessionBus().registerObject(fdoObjectPath().path(), this);
|
||||
}
|
||||
|
||||
KWalletFreedesktopItem::~KWalletFreedesktopItem()
|
||||
{
|
||||
onPropertiesChanged(QVariantMap());
|
||||
|
||||
QDBusConnection::sessionBus().unregisterObject(fdoObjectPath().path());
|
||||
|
||||
if (!m_wasDeleted) {
|
||||
m_collection->onItemChanged(fdoObjectPath());
|
||||
}
|
||||
}
|
||||
|
||||
StrStrMap KWalletFreedesktopItem::attributes() const
|
||||
{
|
||||
return fdoCollection()->itemAttributes().getAttributes(m_uniqueLabel);
|
||||
}
|
||||
|
||||
void KWalletFreedesktopItem::setAttributes(const StrStrMap &value)
|
||||
{
|
||||
fdoCollection()->itemAttributes().setAttributes(m_uniqueLabel, value);
|
||||
}
|
||||
|
||||
qulonglong KWalletFreedesktopItem::created() const
|
||||
{
|
||||
return fdoCollection()->itemAttributes().getULongLongParam(m_uniqueLabel, FDO_KEY_CREATED, fdoCollection()->modified());
|
||||
}
|
||||
|
||||
qulonglong KWalletFreedesktopItem::modified() const
|
||||
{
|
||||
return fdoCollection()->itemAttributes().getULongLongParam(m_uniqueLabel, FDO_KEY_MODIFIED, fdoCollection()->modified());
|
||||
}
|
||||
|
||||
QString KWalletFreedesktopItem::label() const
|
||||
{
|
||||
return m_uniqueLabel.label;
|
||||
}
|
||||
|
||||
void KWalletFreedesktopItem::setLabel(const QString &value)
|
||||
{
|
||||
const auto entryLocation = m_uniqueLabel.toEntryLocation();
|
||||
m_uniqueLabel = fdoCollection()->makeUniqueItemLabel(value);
|
||||
const auto newEntryLocation = m_uniqueLabel.toEntryLocation();
|
||||
|
||||
if (newEntryLocation.folder != entryLocation.folder) {
|
||||
const auto data = backend()->readEntry(fdoCollection()->walletHandle(), entryLocation.folder, entryLocation.key, FDO_APPID);
|
||||
backend()->writeEntry(fdoCollection()->walletHandle(), newEntryLocation.folder, newEntryLocation.key, data, FDO_APPID);
|
||||
backend()->removeEntry(fdoCollection()->walletHandle(), entryLocation.folder, entryLocation.key, FDO_APPID);
|
||||
} else if (newEntryLocation.key != entryLocation.key) {
|
||||
backend()->renameEntry(fdoCollection()->walletHandle(), entryLocation.folder, entryLocation.key, newEntryLocation.key, FDO_APPID);
|
||||
}
|
||||
|
||||
fdoCollection()->itemAttributes().setParam(entryLocation, FDO_KEY_MODIFIED, static_cast<qulonglong>(QDateTime::currentSecsSinceEpoch()));
|
||||
fdoCollection()->itemAttributes().renameLabel(entryLocation, newEntryLocation);
|
||||
|
||||
fdoCollection()->onItemChanged(fdoObjectPath());
|
||||
}
|
||||
|
||||
bool KWalletFreedesktopItem::locked() const
|
||||
{
|
||||
return m_collection->locked();
|
||||
}
|
||||
|
||||
QString KWalletFreedesktopItem::type() const
|
||||
{
|
||||
const auto attribs = fdoCollection()->itemAttributes().getAttributes(m_uniqueLabel);
|
||||
const auto found = attribs.find(FDO_KEY_XDG_SCHEMA);
|
||||
if (found != attribs.end()) {
|
||||
return found.value();
|
||||
} else {
|
||||
return QStringLiteral("org.freedesktop.Secret.Generic");
|
||||
}
|
||||
}
|
||||
|
||||
void KWalletFreedesktopItem::setType(const QString &value)
|
||||
{
|
||||
auto attribs = fdoCollection()->itemAttributes().getAttributes(m_uniqueLabel);
|
||||
attribs[FDO_KEY_XDG_SCHEMA] = value;
|
||||
fdoCollection()->itemAttributes().setAttributes(m_uniqueLabel, attribs);
|
||||
}
|
||||
|
||||
QDBusObjectPath KWalletFreedesktopItem::Delete()
|
||||
{
|
||||
const auto entryLocation = m_uniqueLabel.toEntryLocation();
|
||||
|
||||
backend()->removeEntry(fdoCollection()->walletHandle(), entryLocation.folder, entryLocation.key, FDO_APPID);
|
||||
QDBusConnection::sessionBus().unregisterObject(fdoObjectPath().path());
|
||||
|
||||
m_collection->onItemDeleted(fdoObjectPath());
|
||||
|
||||
return QDBusObjectPath("/");
|
||||
}
|
||||
|
||||
FreedesktopSecret KWalletFreedesktopItem::getSecret(const QDBusConnection &connection, const QDBusMessage &message, const QDBusObjectPath &session)
|
||||
{
|
||||
const auto entryLocation = m_uniqueLabel.toEntryLocation();
|
||||
const auto mimeType = fdoCollection()->itemAttributes().getStringParam(entryLocation, FDO_KEY_MIME, QStringLiteral("application/octet-stream"));
|
||||
|
||||
FreedesktopSecret fdoSecret;
|
||||
|
||||
const auto entryType = backend()->entryType(fdoCollection()->walletHandle(), entryLocation.folder, entryLocation.key, FDO_APPID);
|
||||
if (entryType == KWallet::Wallet::Password) {
|
||||
auto password = backend()->readPassword(fdoCollection()->walletHandle(), entryLocation.folder, entryLocation.key, FDO_APPID);
|
||||
auto bytes = password.toUtf8();
|
||||
fdoSecret = FreedesktopSecret(session, bytes, mimeType);
|
||||
explicit_zero_mem(bytes.data(), bytes.size());
|
||||
explicit_zero_mem(password.data(), password.size() * sizeof(QChar));
|
||||
} else {
|
||||
auto bytes = backend()->readEntry(fdoCollection()->walletHandle(), entryLocation.folder, entryLocation.key, FDO_APPID);
|
||||
fdoSecret = FreedesktopSecret(session, bytes, mimeType);
|
||||
explicit_zero_mem(bytes.data(), bytes.size());
|
||||
}
|
||||
|
||||
if (!fdoService()->ensecret(message, fdoSecret)) {
|
||||
message.setDelayedReply(true);
|
||||
connection.send(message.createErrorReply(QDBusError::ErrorType::UnknownObject, QStringLiteral("Can't find session ") + session.path()));
|
||||
}
|
||||
|
||||
return fdoSecret;
|
||||
}
|
||||
|
||||
FreedesktopSecret KWalletFreedesktopItem::GetSecret(const QDBusObjectPath &session)
|
||||
{
|
||||
return getSecret(connection(), message(), session);
|
||||
}
|
||||
|
||||
void KWalletFreedesktopItem::SetSecret(const FreedesktopSecret &secret)
|
||||
{
|
||||
const auto entryLocation = m_uniqueLabel.toEntryLocation();
|
||||
|
||||
fdoCollection()->itemAttributes().setParam(entryLocation, FDO_KEY_MIME, secret.mimeType);
|
||||
fdoCollection()->itemAttributes().setParam(entryLocation, FDO_KEY_MODIFIED, static_cast<qulonglong>(QDateTime::currentSecsSinceEpoch()));
|
||||
|
||||
auto decrypted = secret;
|
||||
if (!fdoService()->desecret(message(), decrypted)) {
|
||||
sendErrorReply(QDBusError::ErrorType::UnknownObject, QStringLiteral("Can't find session ") + secret.session.path());
|
||||
return;
|
||||
}
|
||||
|
||||
QString xdgSchema = QStringLiteral("org.kde.KWallet.Stream");
|
||||
const auto attribs = fdoCollection()->itemAttributes().getAttributes(entryLocation);
|
||||
const auto found = attribs.find(FDO_KEY_XDG_SCHEMA);
|
||||
if (found != attribs.end()) {
|
||||
xdgSchema = found.value();
|
||||
}
|
||||
|
||||
if (xdgSchema == QStringLiteral("org.kde.KWallet.Password") || secret.mimeType.startsWith(QStringLiteral("text/"))) {
|
||||
auto bytes = decrypted.value.toByteArray();
|
||||
auto str = QString::fromUtf8(bytes);
|
||||
backend()->writePassword(fdoCollection()->walletHandle(), entryLocation.folder, entryLocation.key, str, FDO_APPID);
|
||||
explicit_zero_mem(bytes.data(), bytes.size());
|
||||
explicit_zero_mem(str.data(), str.size() * sizeof(QChar));
|
||||
} else {
|
||||
auto bytes = decrypted.value.toByteArray();
|
||||
backend()->writeEntry(fdoCollection()->walletHandle(), entryLocation.folder, entryLocation.key, bytes, KWallet::Wallet::Stream, FDO_APPID);
|
||||
}
|
||||
}
|
||||
|
||||
KWalletFreedesktopCollection *KWalletFreedesktopItem::fdoCollection() const
|
||||
{
|
||||
return m_collection;
|
||||
}
|
||||
|
||||
KWalletFreedesktopService *KWalletFreedesktopItem::fdoService() const
|
||||
{
|
||||
return fdoCollection()->fdoService();
|
||||
}
|
||||
|
||||
KWalletD *KWalletFreedesktopItem::backend() const
|
||||
{
|
||||
return fdoCollection()->fdoService()->backend();
|
||||
}
|
||||
|
||||
QDBusObjectPath KWalletFreedesktopItem::fdoObjectPath() const
|
||||
{
|
||||
return m_path;
|
||||
}
|
||||
|
||||
const FdoUniqueLabel &KWalletFreedesktopItem::uniqueLabel() const
|
||||
{
|
||||
return m_uniqueLabel;
|
||||
}
|
||||
|
||||
void KWalletFreedesktopItem::uniqueLabel(const FdoUniqueLabel &uniqueLabel)
|
||||
{
|
||||
m_uniqueLabel = uniqueLabel;
|
||||
}
|
||||
|
||||
void KWalletFreedesktopItem::setDeleted()
|
||||
{
|
||||
m_wasDeleted = true;
|
||||
fdoCollection()->itemAttributes().remove(m_uniqueLabel);
|
||||
}
|
||||
|
||||
void KWalletFreedesktopItem::onPropertiesChanged(const QVariantMap &properties)
|
||||
{
|
||||
auto msg = QDBusMessage::createSignal(fdoObjectPath().path(), QStringLiteral("org.freedesktop.DBus.Properties"), QStringLiteral("PropertiesChanged"));
|
||||
auto args = QVariantList();
|
||||
args << QStringLiteral("org.freedesktop.Secret.Item") << properties << QStringList();
|
||||
msg.setArguments(args);
|
||||
QDBusConnection::sessionBus().send(msg);
|
||||
}
|
||||
|
||||
#include "moc_kwalletfreedesktopitem.cpp"
|
||||
@@ -0,0 +1,87 @@
|
||||
/*
|
||||
This file is part of the KDE libraries
|
||||
SPDX-FileCopyrightText: 2021 Slava Aseev <nullptrnine@basealt.ru>
|
||||
|
||||
SPDX-License-Identifier: LGPL-2.0-or-later
|
||||
*/
|
||||
#ifndef _KWALLETFREEDESKTOPITEM_H_
|
||||
#define _KWALLETFREEDESKTOPITEM_H_
|
||||
#include "kwalletfreedesktopservice.h"
|
||||
|
||||
static inline constexpr auto FDO_SS_MAGICK = 0x4950414f44465353ULL;
|
||||
|
||||
class KWalletD;
|
||||
class KWalletFreedesktopCollection;
|
||||
|
||||
class KWalletFreedesktopItem : public QObject, protected FDO_DBUS_CONTEXT
|
||||
{
|
||||
/* org.freedesktop.Secret.Item properties */
|
||||
public:
|
||||
Q_PROPERTY(StrStrMap Attributes READ attributes WRITE setAttributes)
|
||||
StrStrMap attributes() const;
|
||||
void setAttributes(const StrStrMap &value);
|
||||
|
||||
Q_PROPERTY(qulonglong Created READ created)
|
||||
qulonglong created() const;
|
||||
|
||||
Q_PROPERTY(QString Label READ label WRITE setLabel)
|
||||
QString label() const;
|
||||
void setLabel(const QString &value);
|
||||
|
||||
Q_PROPERTY(bool Locked READ locked)
|
||||
bool locked() const;
|
||||
|
||||
Q_PROPERTY(qulonglong Modified READ modified)
|
||||
qulonglong modified() const;
|
||||
|
||||
Q_PROPERTY(QString Type READ type WRITE setType)
|
||||
QString type() const;
|
||||
void setType(const QString &value);
|
||||
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
KWalletFreedesktopItem(KWalletFreedesktopCollection *collection, FdoUniqueLabel uniqLabel, QDBusObjectPath path);
|
||||
~KWalletFreedesktopItem();
|
||||
|
||||
KWalletFreedesktopItem(const KWalletFreedesktopItem &) = delete;
|
||||
KWalletFreedesktopItem &operator=(const KWalletFreedesktopItem &) = delete;
|
||||
|
||||
KWalletFreedesktopItem(KWalletFreedesktopItem &&) = delete;
|
||||
KWalletFreedesktopItem &operator=(KWalletFreedesktopItem &&) = delete;
|
||||
|
||||
KWalletFreedesktopCollection *fdoCollection() const;
|
||||
KWalletFreedesktopService *fdoService() const;
|
||||
KWalletD *backend() const;
|
||||
QDBusObjectPath fdoObjectPath() const;
|
||||
const FdoUniqueLabel &uniqueLabel() const;
|
||||
void uniqueLabel(const FdoUniqueLabel &uniqLabel);
|
||||
|
||||
/*
|
||||
QVariantMap readMap() const;
|
||||
void writeMap(const QVariantMap &data);
|
||||
*/
|
||||
|
||||
FreedesktopSecret getSecret(const QDBusConnection &connection, const QDBusMessage &message, const QDBusObjectPath &session);
|
||||
void setDeleted();
|
||||
|
||||
/* Emitters */
|
||||
void onPropertiesChanged(const QVariantMap &properties);
|
||||
void enableFdoFormat();
|
||||
|
||||
private:
|
||||
KWalletFreedesktopCollection *m_collection;
|
||||
FdoUniqueLabel m_uniqueLabel;
|
||||
QDBusObjectPath m_path;
|
||||
bool m_wasDeleted = false;
|
||||
|
||||
/* Freedesktop API */
|
||||
|
||||
/* org.freedesktop.Secret.Item methods */
|
||||
public Q_SLOTS:
|
||||
QDBusObjectPath Delete();
|
||||
FreedesktopSecret GetSecret(const QDBusObjectPath &session);
|
||||
void SetSecret(const FreedesktopSecret &secret);
|
||||
};
|
||||
|
||||
#endif
|
||||
+133
@@ -0,0 +1,133 @@
|
||||
/*
|
||||
This file is part of the KDE libraries
|
||||
SPDX-FileCopyrightText: 2021 Slava Aseev <nullptrnine@basealt.ru>
|
||||
|
||||
SPDX-License-Identifier: LGPL-2.0-or-later
|
||||
*/
|
||||
#include "kwalletfreedesktopprompt.h"
|
||||
|
||||
#include "kwalletd.h"
|
||||
#include "kwalletfreedesktopcollection.h"
|
||||
#include "kwalletfreedesktoppromptadaptor.h"
|
||||
|
||||
KWalletFreedesktopPrompt::KWalletFreedesktopPrompt(KWalletFreedesktopService *service, QDBusObjectPath objectPath, PromptType type, QString responseBusName)
|
||||
: QObject(nullptr)
|
||||
, m_service(service)
|
||||
, m_objectPath(std::move(objectPath))
|
||||
, m_type(type)
|
||||
, m_responseBusName(std::move(responseBusName))
|
||||
{
|
||||
(void)new KWalletFreedesktopPromptAdaptor(this);
|
||||
}
|
||||
|
||||
KWalletFreedesktopService *KWalletFreedesktopPrompt::fdoService() const
|
||||
{
|
||||
return m_service;
|
||||
}
|
||||
|
||||
KWalletD *KWalletFreedesktopPrompt::backend() const
|
||||
{
|
||||
return fdoService()->backend();
|
||||
}
|
||||
|
||||
QDBusObjectPath KWalletFreedesktopPrompt::fdoObjectPath() const
|
||||
{
|
||||
return m_objectPath;
|
||||
}
|
||||
|
||||
void KWalletFreedesktopPrompt::Dismiss()
|
||||
{
|
||||
auto msg = QDBusMessage::createTargetedSignal(m_responseBusName,
|
||||
fdoObjectPath().path(),
|
||||
QStringLiteral("org.freedesktop.Secret.Prompt"),
|
||||
QStringLiteral("Completed"));
|
||||
QVariantList args;
|
||||
args << true << QVariant::fromValue(QDBusVariant(QVariant::fromValue(QList<QDBusObjectPath>())));
|
||||
msg.setArguments(args);
|
||||
QDBusConnection::sessionBus().send(msg);
|
||||
QDBusConnection::sessionBus().unregisterObject(fdoObjectPath().path());
|
||||
}
|
||||
|
||||
void KWalletFreedesktopPrompt::Prompt(const QString &window_id)
|
||||
{
|
||||
if (m_type != PromptType::Open && m_type != PromptType::Create) {
|
||||
return;
|
||||
}
|
||||
|
||||
const int wId = window_id.toInt();
|
||||
for (auto properties : std::as_const(m_propertiesList)) {
|
||||
/* When type is "PromptType::Open" the properties.label actually stores
|
||||
* the wallet name
|
||||
*/
|
||||
QString walletName = properties.collectionLabel;
|
||||
|
||||
if (m_type == PromptType::Create) {
|
||||
walletName = fdoService()->makeUniqueWalletName(properties.collectionLabel);
|
||||
properties.collectionLabel = walletName;
|
||||
}
|
||||
|
||||
if (!properties.alias.isEmpty()) {
|
||||
fdoService()->createCollectionAlias(properties.alias, walletName);
|
||||
}
|
||||
|
||||
const int tId = backend()->openAsync(walletName, wId, FDO_APPID, false, connection(), message());
|
||||
m_transactionIds.insert(tId);
|
||||
m_transactionIdToCollectionProperties.emplace(tId, std::move(properties));
|
||||
}
|
||||
}
|
||||
|
||||
void KWalletFreedesktopPrompt::walletAsyncOpened(int transactionId, int walletHandle)
|
||||
{
|
||||
const auto found = m_transactionIds.find(transactionId);
|
||||
|
||||
if (found != m_transactionIds.end()) {
|
||||
const auto propertiesPos = m_transactionIdToCollectionProperties.find(transactionId);
|
||||
if (walletHandle < 0 || propertiesPos == m_transactionIdToCollectionProperties.end()) {
|
||||
Dismiss();
|
||||
fdoService()->deletePrompt(fdoObjectPath().path());
|
||||
return;
|
||||
}
|
||||
m_transactionIds.remove(transactionId);
|
||||
|
||||
const QString &walletName = propertiesPos->second.collectionLabel;
|
||||
const auto collectionPath = fdoService()->promptUnlockCollection(walletName, walletHandle);
|
||||
m_result.push_back(propertiesPos->second.objectPath.path() == QStringLiteral("/") ? collectionPath : propertiesPos->second.objectPath);
|
||||
}
|
||||
|
||||
if (m_transactionIds.empty()) {
|
||||
/* At this point there is no remaining transactions, so we able to complete prompt */
|
||||
|
||||
auto msg = QDBusMessage::createTargetedSignal(m_responseBusName,
|
||||
fdoObjectPath().path(),
|
||||
QStringLiteral("org.freedesktop.Secret.Prompt"),
|
||||
QStringLiteral("Completed"));
|
||||
QVariantList args;
|
||||
args << false;
|
||||
|
||||
if (m_type == PromptType::Create && m_result.size() < 2) {
|
||||
/* Single object in dbus variant */
|
||||
args << QVariant::fromValue(QDBusVariant(QVariant::fromValue(m_result.empty() ? QDBusObjectPath("/") : m_result.front())));
|
||||
} else {
|
||||
/* Object array in dbus variant */
|
||||
args << QVariant::fromValue(QDBusVariant(QVariant::fromValue(m_result)));
|
||||
}
|
||||
|
||||
msg.setArguments(args);
|
||||
QDBusConnection::sessionBus().send(msg);
|
||||
|
||||
fdoService()->deletePrompt(fdoObjectPath().path());
|
||||
}
|
||||
}
|
||||
|
||||
void KWalletFreedesktopPrompt::subscribeForWalletAsyncOpened()
|
||||
{
|
||||
connect(backend(), &KWalletD::walletAsyncOpened, this, &KWalletFreedesktopPrompt::walletAsyncOpened);
|
||||
QDBusConnection::sessionBus().registerObject(fdoObjectPath().path(), this);
|
||||
}
|
||||
|
||||
void KWalletFreedesktopPrompt::appendProperties(const QString &label, const QDBusObjectPath &objectPath, const QString &alias)
|
||||
{
|
||||
m_propertiesList.push_back(CollectionProperties{label, objectPath, alias});
|
||||
}
|
||||
|
||||
#include "moc_kwalletfreedesktopprompt.cpp"
|
||||
@@ -0,0 +1,73 @@
|
||||
/*
|
||||
This file is part of the KDE libraries
|
||||
SPDX-FileCopyrightText: 2021 Slava Aseev <nullptrnine@basealt.ru>
|
||||
|
||||
SPDX-License-Identifier: LGPL-2.0-or-later
|
||||
*/
|
||||
#ifndef _KWALLETFREEDESKTOPPROMPT_H_
|
||||
#define _KWALLETFREEDESKTOPPROMPT_H_
|
||||
|
||||
#include "kwalletfreedesktopservice.h"
|
||||
|
||||
#define FDO_SECRET_SERVICE_PROMPT_PATH FDO_SECRETS_SERVICE_OBJECT "/prompt/"
|
||||
|
||||
class KWalletD;
|
||||
|
||||
enum class PromptType {
|
||||
Open,
|
||||
Create,
|
||||
};
|
||||
|
||||
class KWalletFreedesktopPrompt : public QObject, protected FDO_DBUS_CONTEXT
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
struct CollectionProperties {
|
||||
QString collectionLabel;
|
||||
QDBusObjectPath objectPath;
|
||||
QString alias;
|
||||
};
|
||||
|
||||
public:
|
||||
KWalletFreedesktopPrompt(KWalletFreedesktopService *service, QDBusObjectPath objectPath, PromptType type, QString responseBusName);
|
||||
|
||||
KWalletFreedesktopPrompt(const KWalletFreedesktopPrompt &) = delete;
|
||||
KWalletFreedesktopPrompt &operator=(const KWalletFreedesktopPrompt &) = delete;
|
||||
|
||||
KWalletFreedesktopPrompt(KWalletFreedesktopPrompt &&) = delete;
|
||||
KWalletFreedesktopPrompt &operator=(KWalletFreedesktopPrompt &&) = delete;
|
||||
|
||||
KWalletFreedesktopService *fdoService() const;
|
||||
KWalletD *backend() const;
|
||||
QDBusObjectPath fdoObjectPath() const;
|
||||
|
||||
void subscribeForWalletAsyncOpened();
|
||||
void appendProperties(const QString &label, const QDBusObjectPath &objectPath = QDBusObjectPath("/"), const QString &alias = {});
|
||||
|
||||
public Q_SLOTS:
|
||||
void walletAsyncOpened(int transactionId, int walletHandle);
|
||||
|
||||
private:
|
||||
KWalletFreedesktopService *m_service;
|
||||
QDBusObjectPath m_objectPath;
|
||||
PromptType m_type;
|
||||
QSet<int> m_transactionIds;
|
||||
QList<QDBusObjectPath> m_result;
|
||||
QList<CollectionProperties> m_propertiesList;
|
||||
std::map<int, CollectionProperties> m_transactionIdToCollectionProperties;
|
||||
QString m_responseBusName;
|
||||
|
||||
/* Freedesktop API */
|
||||
|
||||
/* org.freedesktop.Secret.Prompt methods */
|
||||
public Q_SLOTS:
|
||||
void Dismiss();
|
||||
void Prompt(const QString &window_id);
|
||||
|
||||
/* org.freedesktop.Secret.Prompt signals */
|
||||
Q_SIGNALS:
|
||||
/* Emitted manually now */
|
||||
void Completed(bool dismissed, const QDBusVariant &result);
|
||||
};
|
||||
|
||||
#endif
|
||||
+962
@@ -0,0 +1,962 @@
|
||||
/*
|
||||
This file is part of the KDE libraries
|
||||
SPDX-FileCopyrightText: 2021 Slava Aseev <nullptrnine@basealt.ru>
|
||||
|
||||
SPDX-License-Identifier: LGPL-2.0-or-later
|
||||
*/
|
||||
#include "kwalletfreedesktopservice.h"
|
||||
|
||||
#include "kwalletd.h"
|
||||
#include "kwalletd_debug.h"
|
||||
#include "kwalletfreedesktopcollection.h"
|
||||
#include "kwalletfreedesktopitem.h"
|
||||
#include "kwalletfreedesktopprompt.h"
|
||||
#include "kwalletfreedesktopserviceadaptor.h"
|
||||
#include "kwalletfreedesktopsession.h"
|
||||
#include <KConfigGroup>
|
||||
#include <QWidget>
|
||||
#include <string.h>
|
||||
|
||||
#ifdef Q_OS_WIN
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
[[maybe_unused]] int DBUS_SECRET_SERVICE_META_TYPE_REGISTER = []() {
|
||||
qDBusRegisterMetaType<StrStrMap>();
|
||||
qDBusRegisterMetaType<QMap<QString, QString>>();
|
||||
qDBusRegisterMetaType<FreedesktopSecret>();
|
||||
qDBusRegisterMetaType<FreedesktopSecretMap>();
|
||||
qDBusRegisterMetaType<PropertiesMap>();
|
||||
qDBusRegisterMetaType<QCA::SecureArray>();
|
||||
|
||||
return 0;
|
||||
}();
|
||||
|
||||
namespace
|
||||
{
|
||||
QString mangleInvalidObjectPathChars(const QString &str)
|
||||
{
|
||||
const auto utf8Str = str.toUtf8();
|
||||
static constexpr char hex[] = "0123456789abcdef";
|
||||
static_assert(sizeof(hex) == 17);
|
||||
|
||||
QString mangled;
|
||||
mangled.reserve(utf8Str.size());
|
||||
|
||||
for (const auto &c : utf8Str) {
|
||||
if ((c < 'A' || c > 'Z') && (c < 'a' || c > 'z') && (c < '0' || c > '9') && c != '_') {
|
||||
const auto cp = static_cast<quint8>(c);
|
||||
mangled.push_back(QChar::fromLatin1('_'));
|
||||
mangled.push_back(QChar::fromLatin1(hex[cp >> 4]));
|
||||
mangled.push_back(QChar::fromLatin1(hex[cp & 0x0f]));
|
||||
} else {
|
||||
mangled.push_back(QChar::fromLatin1(c));
|
||||
}
|
||||
}
|
||||
|
||||
return mangled;
|
||||
}
|
||||
}
|
||||
|
||||
#define LABEL_NUMBER_PREFIX "__"
|
||||
#define LABEL_NUMBER_POSTFIX "_"
|
||||
#define LABEL_NUMBER_REGEX "(^.*)" LABEL_NUMBER_PREFIX "(\\d+)" LABEL_NUMBER_POSTFIX "$"
|
||||
|
||||
EntryLocation EntryLocation::fromUniqueLabel(const FdoUniqueLabel &uniqLabel)
|
||||
{
|
||||
QString dir;
|
||||
QString name = uniqLabel.label;
|
||||
|
||||
const int slashPos = uniqLabel.label.indexOf(QChar::fromLatin1('/'));
|
||||
if (slashPos == -1 || slashPos == uniqLabel.label.size() - 1) {
|
||||
dir = QStringLiteral(FDO_SECRETS_DEFAULT_DIR);
|
||||
} else {
|
||||
dir = uniqLabel.label.left(slashPos);
|
||||
name = uniqLabel.label.right((uniqLabel.label.size() - dir.size()) - 1);
|
||||
}
|
||||
|
||||
return EntryLocation{dir, FdoUniqueLabel::makeName(name, uniqLabel.copyId)};
|
||||
}
|
||||
|
||||
FdoUniqueLabel EntryLocation::toUniqueLabel() const
|
||||
{
|
||||
return FdoUniqueLabel::fromEntryLocation(*this);
|
||||
}
|
||||
|
||||
FdoUniqueLabel FdoUniqueLabel::fromEntryLocation(const EntryLocation &entryLocation)
|
||||
{
|
||||
const auto uniqLabel = FdoUniqueLabel::fromName(entryLocation.key);
|
||||
|
||||
if (entryLocation.folder == QStringLiteral(FDO_SECRETS_DEFAULT_DIR)) {
|
||||
return uniqLabel;
|
||||
} else {
|
||||
return {entryLocation.folder + QChar::fromLatin1('/') + uniqLabel.label, uniqLabel.copyId};
|
||||
}
|
||||
}
|
||||
|
||||
FdoUniqueLabel FdoUniqueLabel::fromName(const QString &name)
|
||||
{
|
||||
static QRegularExpression regexp(QStringLiteral(LABEL_NUMBER_REGEX));
|
||||
|
||||
const auto match = regexp.match(name);
|
||||
if (match.hasMatch()) {
|
||||
const QString strNum = match.captured(2);
|
||||
bool ok = false;
|
||||
const int n = strNum.toInt(&ok);
|
||||
if (ok) {
|
||||
return FdoUniqueLabel{match.captured(1), n};
|
||||
}
|
||||
}
|
||||
return FdoUniqueLabel{name};
|
||||
}
|
||||
|
||||
QString FdoUniqueLabel::makeName(const QString &label, int n)
|
||||
{
|
||||
if (n == -1) {
|
||||
return label;
|
||||
} else {
|
||||
return label + QStringLiteral(LABEL_NUMBER_PREFIX) + QString::number(n) + QStringLiteral(LABEL_NUMBER_POSTFIX);
|
||||
}
|
||||
}
|
||||
|
||||
QString FdoUniqueLabel::toName() const
|
||||
{
|
||||
return makeName(label, copyId);
|
||||
}
|
||||
|
||||
EntryLocation FdoUniqueLabel::toEntryLocation() const
|
||||
{
|
||||
return EntryLocation::fromUniqueLabel(*this);
|
||||
}
|
||||
|
||||
QString KWalletFreedesktopService::wrapToCollectionPath(const QString &itemPath)
|
||||
{
|
||||
/* Take only /org/freedesktop/secrets/collection/collection_name */
|
||||
return itemPath.section(QChar::fromLatin1('/'), 0, 5);
|
||||
}
|
||||
|
||||
KWalletFreedesktopService::KWalletFreedesktopService(KWalletD *parent)
|
||||
: QObject(nullptr)
|
||||
, m_parent(parent)
|
||||
, m_kwalletrc(QStringLiteral("kwalletrc"))
|
||||
{
|
||||
(void)new KWalletFreedesktopServiceAdaptor(this);
|
||||
|
||||
/* register */
|
||||
QDBusConnection::sessionBus().registerService(QStringLiteral("org.freedesktop.secrets"));
|
||||
QDBusConnection::sessionBus().registerObject(QStringLiteral(FDO_SECRETS_SERVICE_OBJECT), this);
|
||||
|
||||
const KConfigGroup walletGroup(&m_kwalletrc, "Wallet");
|
||||
if (!parent || !walletGroup.readEntry("Enabled", true)) {
|
||||
return;
|
||||
}
|
||||
|
||||
connect(m_parent, static_cast<void (KWalletD::*)(const QString &)>(&KWalletD::walletClosed), this, &KWalletFreedesktopService::lockCollection);
|
||||
connect(m_parent, &KWalletD::entryUpdated, this, &KWalletFreedesktopService::entryUpdated);
|
||||
connect(m_parent, &KWalletD::entryDeleted, this, &KWalletFreedesktopService::entryDeleted);
|
||||
connect(m_parent, &KWalletD::entryRenamed, this, &KWalletFreedesktopService::entryRenamed);
|
||||
connect(m_parent, &KWalletD::walletDeleted, this, &KWalletFreedesktopService::walletDeleted);
|
||||
connect(m_parent, &KWalletD::walletCreated, this, &KWalletFreedesktopService::walletCreated);
|
||||
|
||||
const auto walletNames = backend()->wallets();
|
||||
|
||||
/* Build collections */
|
||||
for (const QString &walletName : walletNames) {
|
||||
const auto objectPath = makeUniqueObjectPath(walletName);
|
||||
auto collection = std::make_unique<KWalletFreedesktopCollection>(this, -1, walletName, objectPath);
|
||||
|
||||
m_collections.emplace(objectPath.path(), std::move(collection));
|
||||
}
|
||||
}
|
||||
|
||||
KWalletFreedesktopService::~KWalletFreedesktopService() = default;
|
||||
|
||||
QList<QDBusObjectPath> KWalletFreedesktopService::collections() const
|
||||
{
|
||||
QList<QDBusObjectPath> result;
|
||||
result.reserve(m_collections.size());
|
||||
|
||||
for (const auto &collectionPair : m_collections) {
|
||||
result.push_back(QDBusObjectPath(collectionPair.first));
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
QDBusObjectPath KWalletFreedesktopService::CreateCollection(const QVariantMap &properties, const QString &alias, QDBusObjectPath &prompt)
|
||||
{
|
||||
prompt.setPath(QStringLiteral("/"));
|
||||
|
||||
const auto labelIter = properties.find(QStringLiteral("org.freedesktop.Secret.Collection.Label"));
|
||||
if (labelIter == properties.end()) {
|
||||
sendErrorReply(QDBusError::ErrorType::InvalidArgs, QStringLiteral("Collection.Label property is missing"));
|
||||
return QDBusObjectPath("/");
|
||||
}
|
||||
if (!labelIter->canConvert<QString>()) {
|
||||
sendErrorReply(QDBusError::ErrorType::InvalidArgs, QStringLiteral("Type of Collection.Label property is invalid"));
|
||||
return QDBusObjectPath("/");
|
||||
}
|
||||
|
||||
prompt = nextPromptPath();
|
||||
auto fdoPromptPtr = std::make_unique<KWalletFreedesktopPrompt>(this, prompt, PromptType::Create, message().service());
|
||||
auto &fdoPrompt = *m_prompts.emplace(prompt.path(), std::move(fdoPromptPtr)).first->second;
|
||||
|
||||
fdoPrompt.appendProperties(labelIter->toString(), QDBusObjectPath("/"), alias);
|
||||
fdoPrompt.subscribeForWalletAsyncOpened();
|
||||
|
||||
return QDBusObjectPath("/");
|
||||
}
|
||||
|
||||
FreedesktopSecretMap KWalletFreedesktopService::GetSecrets(const QList<QDBusObjectPath> &items, const QDBusObjectPath &session)
|
||||
{
|
||||
FreedesktopSecretMap result;
|
||||
|
||||
for (const QDBusObjectPath &itemPath : items) {
|
||||
const auto item = getItemByObjectPath(itemPath);
|
||||
|
||||
if (item) {
|
||||
result.insert(itemPath, item->getSecret(connection(), message(), session));
|
||||
} else {
|
||||
sendErrorReply(QDBusError::ErrorType::InvalidArgs, QStringLiteral("Can't find item at path ") + itemPath.path());
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
QList<QDBusObjectPath> KWalletFreedesktopService::Lock(const QList<QDBusObjectPath> &objects, QDBusObjectPath &prompt)
|
||||
{
|
||||
prompt = QDBusObjectPath("/");
|
||||
QList<QDBusObjectPath> result;
|
||||
|
||||
/* Try find in active collections */
|
||||
for (const QDBusObjectPath &object : objects) {
|
||||
const QString collectionPath = wrapToCollectionPath(resolveIfAlias(object.path()));
|
||||
|
||||
const auto foundCollection = m_collections.find(collectionPath);
|
||||
if (foundCollection != m_collections.end()) {
|
||||
const int walletHandle = foundCollection->second->walletHandle();
|
||||
const int rc = m_parent->close(walletHandle, true, FDO_APPID, message());
|
||||
|
||||
if (rc == 0) {
|
||||
result.push_back(QDBusObjectPath(collectionPath));
|
||||
} else {
|
||||
sendErrorReply(QDBusError::ErrorType::InvalidArgs, QStringLiteral("Can't lock object at path ") + collectionPath);
|
||||
}
|
||||
} else {
|
||||
sendErrorReply(QDBusError::ErrorType::InvalidArgs, QStringLiteral("Collection at path ") + collectionPath + QStringLiteral(" does not exist"));
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
QDBusVariant KWalletFreedesktopService::OpenSession(const QString &algorithm, const QDBusVariant &input, QDBusObjectPath &result)
|
||||
{
|
||||
std::unique_ptr<KWalletFreedesktopSessionAlgorithm> sessionAlgorithm;
|
||||
if (algorithm == QStringLiteral("plain")) {
|
||||
sessionAlgorithm = createSessionAlgorithmPlain();
|
||||
} else if (algorithm == QStringLiteral("dh-ietf1024-sha256-aes128-cbc-pkcs7")) {
|
||||
if (!input.variant().canConvert<QByteArray>()) {
|
||||
sendErrorReply(QDBusError::ErrorType::InvalidArgs, QStringLiteral("Second input argument must be a byte array."));
|
||||
return {};
|
||||
}
|
||||
|
||||
sessionAlgorithm = createSessionAlgorithmDhAes(input.variant().toByteArray());
|
||||
} else {
|
||||
sendErrorReply(QDBusError::ErrorType::NotSupported,
|
||||
QStringLiteral("Algorithm ") + algorithm
|
||||
+ QStringLiteral(" is not supported. (only plain and dh-ietf1024-sha256-aes128-cbc-pkcs7 are supported)"));
|
||||
return {};
|
||||
}
|
||||
|
||||
if (!sessionAlgorithm) {
|
||||
// Creation of session algorithm failed, createSessionAlgorithm...() method should have sent an error reply.
|
||||
return {};
|
||||
}
|
||||
|
||||
const QString sessionPath = createSession(std::move(sessionAlgorithm));
|
||||
result.setPath(sessionPath);
|
||||
return QDBusVariant(QVariant(m_sessions[sessionPath]->negotiationOutput()));
|
||||
}
|
||||
|
||||
QDBusObjectPath KWalletFreedesktopService::ReadAlias(const QString &name)
|
||||
{
|
||||
QString walletName;
|
||||
|
||||
m_kwalletrc.reparseConfiguration();
|
||||
if (name == QStringLiteral("default")) {
|
||||
KConfigGroup cfg(&m_kwalletrc, "Wallet");
|
||||
walletName = defaultWalletName(cfg);
|
||||
|
||||
} else {
|
||||
KConfigGroup cfg(&m_kwalletrc, "org.freedesktop.secrets.aliases");
|
||||
walletName = cfg.readEntry(name, QString());
|
||||
}
|
||||
|
||||
if (!walletName.isEmpty()) {
|
||||
const auto *collection = getCollectionByWalletName(walletName);
|
||||
if (collection) {
|
||||
return collection->fdoObjectPath();
|
||||
}
|
||||
}
|
||||
|
||||
return QDBusObjectPath("/");
|
||||
}
|
||||
|
||||
QList<QDBusObjectPath> KWalletFreedesktopService::SearchItems(const StrStrMap &attributes, QList<QDBusObjectPath> &locked)
|
||||
{
|
||||
QList<QDBusObjectPath> unlocked;
|
||||
|
||||
for (const auto &collectionPair : m_collections) {
|
||||
auto &collection = *collectionPair.second;
|
||||
|
||||
if (collection.locked()) {
|
||||
locked += collection.SearchItems(attributes);
|
||||
} else {
|
||||
unlocked += collection.SearchItems(attributes);
|
||||
}
|
||||
}
|
||||
|
||||
return unlocked;
|
||||
}
|
||||
|
||||
void KWalletFreedesktopService::SetAlias(const QString &name, const QDBusObjectPath &collectionPath)
|
||||
{
|
||||
const auto foundCollection = m_collections.find(collectionPath.path());
|
||||
if (foundCollection == m_collections.end()) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto *collection = foundCollection->second.get();
|
||||
createCollectionAlias(name, collection);
|
||||
}
|
||||
|
||||
QString KWalletFreedesktopService::resolveIfAlias(QString alias)
|
||||
{
|
||||
if (alias.startsWith(QStringLiteral(FDO_ALIAS_PATH))) {
|
||||
const auto path = ReadAlias(alias.remove(0, QStringLiteral(FDO_ALIAS_PATH).size())).path();
|
||||
if (path != QStringLiteral("/")) {
|
||||
alias = path;
|
||||
} else {
|
||||
sendErrorReply(QDBusError::ErrorType::InvalidArgs, QStringLiteral("Alias ") + alias + QStringLiteral(" does not exist"));
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
if (!alias.startsWith(QStringLiteral(FDO_SECRETS_COLLECTION_PATH))) {
|
||||
sendErrorReply(QDBusError::ErrorType::InvalidArgs, QStringLiteral("Collection object path is invalid"));
|
||||
return {};
|
||||
}
|
||||
|
||||
return alias;
|
||||
}
|
||||
|
||||
struct UnlockedObject {
|
||||
QString walletName;
|
||||
QDBusObjectPath objectPath;
|
||||
};
|
||||
|
||||
QList<QDBusObjectPath> KWalletFreedesktopService::Unlock(const QList<QDBusObjectPath> &objects, QDBusObjectPath &prompt)
|
||||
{
|
||||
prompt = QDBusObjectPath("/");
|
||||
|
||||
QList<QDBusObjectPath> result;
|
||||
QList<UnlockedObject> needUnlock;
|
||||
|
||||
/* Try find in active collections */
|
||||
for (const QDBusObjectPath &object : objects) {
|
||||
const QString strPath = object.path();
|
||||
const QString collectionPath = wrapToCollectionPath(resolveIfAlias(strPath));
|
||||
|
||||
const auto foundCollection = m_collections.find(collectionPath);
|
||||
if (foundCollection != m_collections.end()) {
|
||||
if (foundCollection->second->locked()) {
|
||||
needUnlock.push_back({foundCollection->second->walletName(), QDBusObjectPath(strPath)});
|
||||
} else {
|
||||
result.push_back(QDBusObjectPath(strPath));
|
||||
}
|
||||
} else {
|
||||
sendErrorReply(QDBusError::ErrorType::InvalidObjectPath, QStringLiteral("Object ") + strPath + QStringLiteral(" does not exist"));
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
if (!needUnlock.empty()) {
|
||||
const auto promptPath = nextPromptPath();
|
||||
auto fdoPromptPtr = std::make_unique<KWalletFreedesktopPrompt>(this, promptPath, PromptType::Open, message().service());
|
||||
auto &fdoPrompt = *m_prompts.emplace(promptPath.path(), std::move(fdoPromptPtr)).first->second;
|
||||
|
||||
prompt = QDBusObjectPath(promptPath);
|
||||
|
||||
for (const auto &[walletName, objectPath] : std::as_const(needUnlock)) {
|
||||
fdoPrompt.appendProperties(walletName, objectPath);
|
||||
}
|
||||
|
||||
fdoPrompt.subscribeForWalletAsyncOpened();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
std::unique_ptr<KWalletFreedesktopSessionAlgorithm> KWalletFreedesktopService::createSessionAlgorithmPlain() const
|
||||
{
|
||||
return std::make_unique<KWalletFreedesktopSessionAlgorithmPlain>();
|
||||
}
|
||||
|
||||
std::unique_ptr<KWalletFreedesktopSessionAlgorithm> KWalletFreedesktopService::createSessionAlgorithmDhAes(const QByteArray &clientKey) const
|
||||
{
|
||||
if (clientKey.size() < FDO_DH_PUBLIC_KEY_SIZE) {
|
||||
sendErrorReply(QDBusError::ErrorType::InvalidArgs, QStringLiteral("Client public key size is invalid"));
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
QCA::KeyGenerator keygen;
|
||||
const auto dlGroup = QCA::DLGroup(keygen.createDLGroup(QCA::IETF_1024));
|
||||
if (dlGroup.isNull()) {
|
||||
sendErrorReply(QDBusError::ErrorType::InvalidArgs, QStringLiteral("createDLGroup failed: maybe libqca-ossl is missing"));
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto privateKey = QCA::PrivateKey(keygen.createDH(dlGroup));
|
||||
const auto publicKey = QCA::PublicKey(privateKey);
|
||||
const auto clientPublicKey = QCA::DHPublicKey(dlGroup, QCA::BigInteger(QCA::SecureArray(clientKey)));
|
||||
const auto commonSecret = privateKey.deriveKey(clientPublicKey);
|
||||
const auto symmetricKey = QCA::HKDF().makeKey(commonSecret, {}, {}, FDO_SECRETS_CIPHER_KEY_SIZE);
|
||||
|
||||
return std::make_unique<KWalletFreedesktopSessionAlgorithmDhAes>(publicKey, symmetricKey);
|
||||
}
|
||||
|
||||
QString KWalletFreedesktopService::createSession(std::unique_ptr<KWalletFreedesktopSessionAlgorithm> algorithm)
|
||||
{
|
||||
const QString sessionPath = QStringLiteral(FDO_SECRETS_SESSION_PATH) + QString::number(++m_session_counter);
|
||||
auto session = std::make_unique<KWalletFreedesktopSession>(this, std::move(algorithm), sessionPath, connection(), message());
|
||||
m_sessions[sessionPath] = std::move(session);
|
||||
return sessionPath;
|
||||
}
|
||||
|
||||
QString KWalletFreedesktopService::defaultWalletName(KConfigGroup &cfg)
|
||||
{
|
||||
auto walletName = cfg.readEntry("Default Wallet", "kdewallet");
|
||||
if (walletName.isEmpty()) {
|
||||
walletName = QStringLiteral("kdewallet");
|
||||
}
|
||||
return walletName;
|
||||
}
|
||||
|
||||
QDBusObjectPath KWalletFreedesktopService::promptUnlockCollection(const QString &walletName, int handle)
|
||||
{
|
||||
auto *collection = getCollectionByWalletName(walletName);
|
||||
QString objectPath;
|
||||
|
||||
if (collection) {
|
||||
collection->onWalletChangeState(handle);
|
||||
onCollectionChanged(collection->fdoObjectPath());
|
||||
objectPath = collection->fdoObjectPath().path();
|
||||
} else {
|
||||
const auto path = makeUniqueObjectPath(walletName);
|
||||
objectPath = path.path();
|
||||
auto newCollection = std::make_unique<KWalletFreedesktopCollection>(this, handle, walletName, path);
|
||||
m_collections[objectPath] = std::move(newCollection);
|
||||
onCollectionCreated(path);
|
||||
}
|
||||
|
||||
return QDBusObjectPath(objectPath);
|
||||
}
|
||||
|
||||
/* Triggered after KWalletD::walletClosed signal */
|
||||
void KWalletFreedesktopService::lockCollection(const QString &name)
|
||||
{
|
||||
auto *collection = getCollectionByWalletName(name);
|
||||
if (collection) {
|
||||
collection->onWalletChangeState(-1);
|
||||
onCollectionChanged(collection->fdoObjectPath());
|
||||
}
|
||||
}
|
||||
|
||||
/* Triggered after KWalletD::entryUpdated signal */
|
||||
void KWalletFreedesktopService::entryUpdated(const QString &walletName, const QString &folder, const QString &entryName)
|
||||
{
|
||||
auto *collection = getCollectionByWalletName(walletName);
|
||||
if (!collection) {
|
||||
return;
|
||||
}
|
||||
|
||||
const EntryLocation entryLocation{folder, entryName};
|
||||
const auto *item = collection->findItemByEntryLocation(entryLocation);
|
||||
if (item) {
|
||||
collection->onItemChanged(item->fdoObjectPath());
|
||||
} else {
|
||||
auto objectPath = collection->nextItemPath();
|
||||
collection->pushNewItem(entryLocation.toUniqueLabel(), objectPath);
|
||||
collection->onItemCreated(objectPath);
|
||||
}
|
||||
}
|
||||
|
||||
/* Triggered after KWalletD::entryDeleted signal */
|
||||
void KWalletFreedesktopService::entryDeleted(const QString &walletName, const QString &folder, const QString &entryName)
|
||||
{
|
||||
auto *collection = getCollectionByWalletName(walletName);
|
||||
if (!collection) {
|
||||
return;
|
||||
}
|
||||
|
||||
const auto *item = collection->findItemByEntryLocation({folder, entryName});
|
||||
if (item) {
|
||||
collection->onItemDeleted(item->fdoObjectPath());
|
||||
}
|
||||
}
|
||||
|
||||
/* Triggered after KWalletD::entryRenamed signal */
|
||||
void KWalletFreedesktopService::entryRenamed(const QString &walletName, const QString &folder, const QString &oldName, const QString &newName)
|
||||
{
|
||||
auto *collection = getCollectionByWalletName(walletName);
|
||||
if (!collection) {
|
||||
return;
|
||||
}
|
||||
|
||||
const EntryLocation oldLocation{folder, oldName};
|
||||
const EntryLocation newLocation{folder, newName};
|
||||
|
||||
auto *item = collection->findItemByEntryLocation(oldLocation);
|
||||
if (!item) {
|
||||
/* Warn if label not found and not yet renamed */
|
||||
if (!collection->findItemByEntryLocation(newLocation)) {
|
||||
qCWarning(KWALLETD_LOG) << "Cannot rename secret service label:" << FdoUniqueLabel::fromEntryLocation(oldLocation).label;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (item) {
|
||||
collection->itemAttributes().renameLabel(oldLocation, newLocation);
|
||||
item->uniqueLabel(newLocation.toUniqueLabel());
|
||||
collection->onItemChanged(item->fdoObjectPath());
|
||||
}
|
||||
}
|
||||
|
||||
/* Triggered after KWalletD::walletDeleted signal */
|
||||
void KWalletFreedesktopService::walletDeleted(const QString &walletName)
|
||||
{
|
||||
auto *collection = getCollectionByWalletName(walletName);
|
||||
if (collection) {
|
||||
collection->Delete();
|
||||
}
|
||||
}
|
||||
|
||||
/* Triggered after KWalletD::walletCreated signal */
|
||||
void KWalletFreedesktopService::walletCreated(const QString &walletName)
|
||||
{
|
||||
const auto objectPath = makeUniqueObjectPath(walletName);
|
||||
auto collection = std::make_unique<KWalletFreedesktopCollection>(this, -1, walletName, objectPath);
|
||||
m_collections.emplace(objectPath.path(), std::move(collection));
|
||||
onCollectionCreated(objectPath);
|
||||
}
|
||||
|
||||
bool KWalletFreedesktopService::desecret(const QDBusMessage &message, FreedesktopSecret &secret)
|
||||
{
|
||||
const auto foundSession = m_sessions.find(secret.session.path());
|
||||
|
||||
if (foundSession != m_sessions.end()) {
|
||||
const KWalletFreedesktopSession &session = *foundSession->second;
|
||||
return session.decrypt(message, secret);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool KWalletFreedesktopService::ensecret(const QDBusMessage &message, FreedesktopSecret &secret)
|
||||
{
|
||||
const auto foundSession = m_sessions.find(secret.session.path());
|
||||
|
||||
if (foundSession != m_sessions.end()) {
|
||||
const KWalletFreedesktopSession &session = *foundSession->second;
|
||||
return session.encrypt(message, secret);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
QDBusObjectPath KWalletFreedesktopService::nextPromptPath()
|
||||
{
|
||||
static uint64_t id = 0;
|
||||
return QDBusObjectPath(QStringLiteral(FDO_SECRET_SERVICE_PROMPT_PATH) + QStringLiteral("p") + QString::number(id++));
|
||||
}
|
||||
|
||||
QDBusArgument &operator<<(QDBusArgument &arg, const FreedesktopSecret &secret)
|
||||
{
|
||||
arg.beginStructure();
|
||||
arg << secret.session;
|
||||
arg << secret.parameters;
|
||||
arg << secret.value;
|
||||
arg << secret.mimeType;
|
||||
arg.endStructure();
|
||||
return arg;
|
||||
}
|
||||
|
||||
const QDBusArgument &operator>>(const QDBusArgument &arg, FreedesktopSecret &secret)
|
||||
{
|
||||
arg.beginStructure();
|
||||
arg >> secret.session;
|
||||
arg >> secret.parameters;
|
||||
arg >> secret.value;
|
||||
arg >> secret.mimeType;
|
||||
arg.endStructure();
|
||||
return arg;
|
||||
}
|
||||
|
||||
QDataStream &operator<<(QDataStream &stream, const QCA::SecureArray &value)
|
||||
{
|
||||
QByteArray bytes = value.toByteArray();
|
||||
stream << bytes;
|
||||
explicit_zero_mem(bytes.data(), bytes.size());
|
||||
return stream;
|
||||
}
|
||||
|
||||
QDataStream &operator>>(QDataStream &stream, QCA::SecureArray &value)
|
||||
{
|
||||
QByteArray bytes;
|
||||
stream >> bytes;
|
||||
value = QCA::SecureArray(bytes);
|
||||
explicit_zero_mem(bytes.data(), bytes.size());
|
||||
return stream;
|
||||
}
|
||||
|
||||
QDBusArgument &operator<<(QDBusArgument &arg, const QCA::SecureArray &value)
|
||||
{
|
||||
QByteArray bytes = value.toByteArray();
|
||||
arg << bytes;
|
||||
explicit_zero_mem(bytes.data(), bytes.size());
|
||||
return arg;
|
||||
}
|
||||
|
||||
const QDBusArgument &operator>>(const QDBusArgument &arg, QCA::SecureArray &buf)
|
||||
{
|
||||
QByteArray byteArray;
|
||||
arg >> byteArray;
|
||||
buf = QCA::SecureArray(byteArray);
|
||||
explicit_zero_mem(byteArray.data(), byteArray.size());
|
||||
return arg;
|
||||
}
|
||||
|
||||
KWalletD *KWalletFreedesktopService::backend() const
|
||||
{
|
||||
return m_parent;
|
||||
}
|
||||
|
||||
QDBusObjectPath KWalletFreedesktopService::fdoObjectPath() const
|
||||
{
|
||||
return QDBusObjectPath(FDO_SECRETS_SERVICE_OBJECT);
|
||||
}
|
||||
|
||||
KWalletFreedesktopItem *KWalletFreedesktopService::getItemByObjectPath(const QDBusObjectPath &path) const
|
||||
{
|
||||
const auto str = path.path();
|
||||
if (!str.startsWith(QStringLiteral(FDO_SECRETS_COLLECTION_PATH))) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const QString collectionPath = wrapToCollectionPath(str);
|
||||
const auto collectionPos = m_collections.find(collectionPath);
|
||||
if (collectionPos == m_collections.end()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const auto &collection = collectionPos->second;
|
||||
return collection->getItemByObjectPath(str);
|
||||
}
|
||||
|
||||
KWalletFreedesktopPrompt *KWalletFreedesktopService::getPromptByObjectPath(const QDBusObjectPath &path) const
|
||||
{
|
||||
const auto foundPrompt = m_prompts.find(path.path());
|
||||
if (foundPrompt != m_prompts.end()) {
|
||||
return foundPrompt->second.get();
|
||||
} else {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
FdoUniqueLabel KWalletFreedesktopService::makeUniqueCollectionLabel(const QString &label)
|
||||
{
|
||||
int n = -1;
|
||||
auto walletName = label;
|
||||
const QStringList wallets = backend()->wallets();
|
||||
|
||||
while (wallets.contains(walletName)) {
|
||||
walletName = FdoUniqueLabel::makeName(label, ++n);
|
||||
}
|
||||
|
||||
return {label, n};
|
||||
}
|
||||
|
||||
QString KWalletFreedesktopService::makeUniqueWalletName(const QString &labelPrefix)
|
||||
{
|
||||
return makeUniqueCollectionLabel(labelPrefix).toName();
|
||||
}
|
||||
|
||||
QDBusObjectPath KWalletFreedesktopService::makeUniqueObjectPath(const QString &walletName) const
|
||||
{
|
||||
auto mangled = mangleInvalidObjectPathChars(walletName);
|
||||
mangled.insert(0, QStringLiteral(FDO_SECRETS_COLLECTION_PATH));
|
||||
|
||||
QString result = mangled;
|
||||
int postfix = 0;
|
||||
while (m_collections.count(result)) {
|
||||
result = mangled + QString::number(postfix++);
|
||||
}
|
||||
|
||||
return QDBusObjectPath(result);
|
||||
}
|
||||
|
||||
QStringList KWalletFreedesktopService::readAliasesFor(const QString &walletName)
|
||||
{
|
||||
m_kwalletrc.reparseConfiguration();
|
||||
KConfigGroup cfg(&m_kwalletrc, "org.freedesktop.secrets.aliases");
|
||||
const auto map = cfg.entryMap();
|
||||
QStringList aliases;
|
||||
|
||||
for (auto i = map.begin(); i != map.end(); ++i) {
|
||||
if (i.value() == walletName) {
|
||||
aliases.push_back(i.key());
|
||||
}
|
||||
}
|
||||
|
||||
KConfigGroup cfgWallet(&m_kwalletrc, "Wallet");
|
||||
if (defaultWalletName(cfgWallet) == walletName) {
|
||||
aliases.push_back(QStringLiteral("default"));
|
||||
}
|
||||
|
||||
return aliases;
|
||||
}
|
||||
|
||||
void KWalletFreedesktopService::updateCollectionAlias(const QString &alias, const QString &walletName)
|
||||
{
|
||||
QString sectName = QStringLiteral("org.freedesktop.secrets.aliases");
|
||||
QString sectKey = alias;
|
||||
|
||||
if (alias == QStringLiteral("default")) {
|
||||
sectName = QStringLiteral("Wallet");
|
||||
sectKey = QStringLiteral("Default Wallet");
|
||||
}
|
||||
|
||||
KConfigGroup cfg(&m_kwalletrc, sectName);
|
||||
cfg.writeEntry(sectKey, walletName);
|
||||
m_kwalletrc.sync();
|
||||
}
|
||||
|
||||
void KWalletFreedesktopService::createCollectionAlias(const QString &alias, const QString &walletName)
|
||||
{
|
||||
QString sectName = QStringLiteral("org.freedesktop.secrets.aliases");
|
||||
QString sectKey = alias;
|
||||
|
||||
if (alias == QStringLiteral("default")) {
|
||||
sectName = QStringLiteral("Wallet");
|
||||
sectKey = QStringLiteral("Default Wallet");
|
||||
}
|
||||
|
||||
m_kwalletrc.reparseConfiguration();
|
||||
KConfigGroup cfg(&m_kwalletrc, sectName);
|
||||
|
||||
const QString prevWalletName = cfg.readEntry(sectKey, QString());
|
||||
if (!prevWalletName.isEmpty()) {
|
||||
const auto *prevCollection = getCollectionByWalletName(prevWalletName);
|
||||
if (prevCollection) {
|
||||
QDBusConnection::sessionBus().unregisterObject(QStringLiteral(FDO_ALIAS_PATH) + alias);
|
||||
}
|
||||
}
|
||||
|
||||
cfg.writeEntry(sectKey, walletName);
|
||||
m_kwalletrc.sync();
|
||||
|
||||
auto *collection = getCollectionByWalletName(walletName);
|
||||
if (collection) {
|
||||
QDBusConnection::sessionBus().registerObject(QStringLiteral(FDO_ALIAS_PATH) + alias, collection);
|
||||
}
|
||||
}
|
||||
|
||||
void KWalletFreedesktopService::createCollectionAlias(const QString &alias, KWalletFreedesktopCollection *collection)
|
||||
{
|
||||
QString sectName = QStringLiteral("org.freedesktop.secrets.aliases");
|
||||
QString sectKey = alias;
|
||||
|
||||
if (alias == QStringLiteral("default")) {
|
||||
sectName = QStringLiteral("Wallet");
|
||||
sectKey = QStringLiteral("Default Wallet");
|
||||
}
|
||||
|
||||
m_kwalletrc.reparseConfiguration();
|
||||
KConfigGroup cfg(&m_kwalletrc, sectName);
|
||||
|
||||
const QString prevWalletName = cfg.readEntry(sectKey, "");
|
||||
if (!prevWalletName.isEmpty()) {
|
||||
const auto *prevCollection = getCollectionByWalletName(prevWalletName);
|
||||
if (prevCollection) {
|
||||
QDBusConnection::sessionBus().unregisterObject(QStringLiteral(FDO_ALIAS_PATH) + alias);
|
||||
}
|
||||
}
|
||||
|
||||
cfg.writeEntry(sectKey, collection->walletName());
|
||||
m_kwalletrc.sync();
|
||||
QDBusConnection::sessionBus().registerObject(QStringLiteral(FDO_ALIAS_PATH) + alias, collection);
|
||||
}
|
||||
|
||||
void KWalletFreedesktopService::removeAlias(const QString &alias)
|
||||
{
|
||||
if (alias == QStringLiteral("default")) {
|
||||
return;
|
||||
}
|
||||
|
||||
KConfigGroup cfg(&m_kwalletrc, "org.freedesktop.secrets.aliases");
|
||||
cfg.deleteEntry(alias);
|
||||
m_kwalletrc.sync();
|
||||
QDBusConnection::sessionBus().unregisterObject(QStringLiteral(FDO_ALIAS_PATH) + alias);
|
||||
}
|
||||
|
||||
KWalletFreedesktopCollection *KWalletFreedesktopService::getCollectionByWalletName(const QString &walletName) const
|
||||
{
|
||||
for (const auto &collectionKeyValue : m_collections) {
|
||||
const auto collection = collectionKeyValue.second.get();
|
||||
if (collection->walletName() == walletName) {
|
||||
return collection;
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void KWalletFreedesktopService::deletePrompt(const QString &objectPath)
|
||||
{
|
||||
const auto foundPrompt = m_prompts.find(objectPath);
|
||||
if (foundPrompt == m_prompts.end()) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* This can be called in the context of the prompt that is currently being
|
||||
* deleted. Therefore, we should schedule deletion on the next event loop iteration
|
||||
*/
|
||||
foundPrompt->second->deleteLater();
|
||||
foundPrompt->second.release();
|
||||
m_prompts.erase(foundPrompt);
|
||||
}
|
||||
|
||||
void KWalletFreedesktopService::deleteSession(const QString &objectPath)
|
||||
{
|
||||
const auto foundSession = m_sessions.find(objectPath);
|
||||
if (foundSession == m_sessions.end()) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* This can be called in the context of the session that is currently being
|
||||
* deleted. Therefore, we should schedule deletion on the next event loop iteration
|
||||
*/
|
||||
foundSession->second->deleteLater();
|
||||
foundSession->second.release();
|
||||
m_sessions.erase(foundSession);
|
||||
}
|
||||
|
||||
void KWalletFreedesktopService::onCollectionCreated(const QDBusObjectPath &path)
|
||||
{
|
||||
Q_EMIT CollectionCreated(path);
|
||||
|
||||
QVariantMap props;
|
||||
props.insert(QStringLiteral("Collections"), QVariant::fromValue(collections()));
|
||||
onPropertiesChanged(props);
|
||||
}
|
||||
|
||||
void KWalletFreedesktopService::onCollectionChanged(const QDBusObjectPath &path)
|
||||
{
|
||||
Q_EMIT CollectionChanged(path);
|
||||
}
|
||||
|
||||
void KWalletFreedesktopService::onCollectionDeleted(const QDBusObjectPath &path)
|
||||
{
|
||||
const auto collectionMapPos = m_collections.find(path.path());
|
||||
if (collectionMapPos == m_collections.end()) {
|
||||
return;
|
||||
}
|
||||
auto &collectionPair = *collectionMapPos;
|
||||
collectionPair.second->itemAttributes().deleteFile();
|
||||
|
||||
/* This can be called in the context of the collection that is currently being
|
||||
* deleted. Therefore, we should schedule deletion on the next event loop iteration
|
||||
*/
|
||||
collectionPair.second->deleteLater();
|
||||
collectionPair.second.release();
|
||||
m_collections.erase(collectionMapPos);
|
||||
|
||||
Q_EMIT CollectionDeleted(path);
|
||||
|
||||
QVariantMap props;
|
||||
props[QStringLiteral("Collections")] = QVariant::fromValue(collections());
|
||||
onPropertiesChanged(props);
|
||||
}
|
||||
|
||||
void KWalletFreedesktopService::onPropertiesChanged(const QVariantMap &properties)
|
||||
{
|
||||
auto msg = QDBusMessage::createSignal(fdoObjectPath().path(), QStringLiteral("org.freedesktop.DBus.Properties"), QStringLiteral("PropertiesChanged"));
|
||||
auto args = QVariantList();
|
||||
args << QStringLiteral("org.freedesktop.Secret.Service") << properties << QStringList();
|
||||
msg.setArguments(args);
|
||||
QDBusConnection::sessionBus().send(msg);
|
||||
}
|
||||
|
||||
QDataStream &operator<<(QDataStream &stream, const QDBusObjectPath &value)
|
||||
{
|
||||
return stream << value.path();
|
||||
}
|
||||
|
||||
QDataStream &operator>>(QDataStream &stream, QDBusObjectPath &value)
|
||||
{
|
||||
QString str;
|
||||
stream >> str;
|
||||
value = QDBusObjectPath(str);
|
||||
return stream;
|
||||
}
|
||||
|
||||
const QDBusArgument &operator>>(const QDBusArgument &arg, PropertiesMap &value)
|
||||
{
|
||||
arg.beginMap();
|
||||
value.map.clear();
|
||||
|
||||
while (!arg.atEnd()) {
|
||||
arg.beginMapEntry();
|
||||
QString key;
|
||||
QVariant val;
|
||||
arg >> key >> val;
|
||||
|
||||
/* For org.freedesktop.Secret.Item.Attributes */
|
||||
if (val.canConvert<QDBusArgument>()) {
|
||||
auto metaArg = val.value<QDBusArgument>();
|
||||
StrStrMap metaMap;
|
||||
metaArg >> metaMap;
|
||||
val = QVariant::fromValue(metaMap);
|
||||
}
|
||||
value.map.insert(key, val);
|
||||
|
||||
arg.endMapEntry();
|
||||
}
|
||||
arg.endMap();
|
||||
|
||||
return arg;
|
||||
}
|
||||
|
||||
QDBusArgument &operator<<(QDBusArgument &arg, const PropertiesMap &value)
|
||||
{
|
||||
arg << value.map;
|
||||
return arg;
|
||||
}
|
||||
|
||||
void explicit_zero_mem(void *data, size_t size)
|
||||
{
|
||||
#if defined(KWALLETD_HAVE_EXPLICIT_BZERO)
|
||||
explicit_bzero(data, size);
|
||||
#elif defined(KWALLETD_HAVE_RTLSECUREZEROMEMORY)
|
||||
RtlSecureZeroMemory(data, size);
|
||||
#else
|
||||
auto p = reinterpret_cast<volatile char *>(data);
|
||||
for (size_t i = 0; i < size; ++i) {
|
||||
p[i] = 0;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#include "moc_kwalletfreedesktopservice.cpp"
|
||||
+226
@@ -0,0 +1,226 @@
|
||||
/*
|
||||
This file is part of the KDE libraries
|
||||
SPDX-FileCopyrightText: 2021 Slava Aseev <nullptrnine@basealt.ru>
|
||||
|
||||
SPDX-License-Identifier: LGPL-2.0-or-later
|
||||
*/
|
||||
#ifndef _KWALLETFREEDESKTOPSERVICE_H_
|
||||
#define _KWALLETFREEDESKTOPSERVICE_H_
|
||||
|
||||
#include <KConfig>
|
||||
#include <QDBusArgument>
|
||||
#include <QDBusServiceWatcher>
|
||||
#include <QHash>
|
||||
#include <QPointer>
|
||||
#include <QString>
|
||||
#include <QtCrypto>
|
||||
|
||||
#include "kwalletdbuscontext.h"
|
||||
|
||||
#define FDO_APPID QString()
|
||||
#define FDO_SECRETS_SERVICE_OBJECT "/org/freedesktop/secrets"
|
||||
#define FDO_ALIAS_PATH "/org/freedesktop/secrets/aliases/"
|
||||
|
||||
static inline constexpr size_t FDO_SECRETS_CIPHER_KEY_SIZE = 16;
|
||||
static inline constexpr int FDO_DH_PUBLIC_KEY_SIZE = 128;
|
||||
|
||||
class KWalletD;
|
||||
|
||||
class FreedesktopSecret
|
||||
{
|
||||
public:
|
||||
FreedesktopSecret() = default;
|
||||
|
||||
FreedesktopSecret(QDBusObjectPath iSession, const QCA::SecureArray &iValue, QString iMimeType)
|
||||
: session(std::move(iSession))
|
||||
, value(iValue)
|
||||
, mimeType(std::move(iMimeType))
|
||||
{
|
||||
}
|
||||
|
||||
friend QDBusArgument &operator<<(QDBusArgument &arg, const FreedesktopSecret &secret);
|
||||
friend const QDBusArgument &operator>>(const QDBusArgument &arg, FreedesktopSecret &secret);
|
||||
|
||||
QDBusObjectPath session;
|
||||
QCA::SecureArray parameters;
|
||||
QCA::SecureArray value;
|
||||
QString mimeType;
|
||||
};
|
||||
|
||||
struct PropertiesMap {
|
||||
QVariantMap map;
|
||||
};
|
||||
|
||||
struct EntryLocation {
|
||||
static EntryLocation fromUniqueLabel(const struct FdoUniqueLabel &uniqLabel);
|
||||
struct FdoUniqueLabel toUniqueLabel() const;
|
||||
|
||||
bool operator==(const EntryLocation &rhs) const
|
||||
{
|
||||
return folder == rhs.folder && key == rhs.key;
|
||||
}
|
||||
|
||||
bool operator!=(const EntryLocation &rhs) const
|
||||
{
|
||||
return !(*this == rhs);
|
||||
}
|
||||
|
||||
QString folder;
|
||||
QString key;
|
||||
};
|
||||
|
||||
struct FdoUniqueLabel {
|
||||
static FdoUniqueLabel fromEntryLocation(const EntryLocation &entryLocation);
|
||||
static FdoUniqueLabel fromName(const QString &name);
|
||||
static QString makeName(const QString &label, int copyId);
|
||||
|
||||
bool operator==(const FdoUniqueLabel &rhs) const
|
||||
{
|
||||
return copyId == rhs.copyId && label == rhs.label;
|
||||
}
|
||||
|
||||
bool operator!=(const FdoUniqueLabel &rhs) const
|
||||
{
|
||||
return !(*this == rhs);
|
||||
}
|
||||
|
||||
QString toName() const;
|
||||
EntryLocation toEntryLocation() const;
|
||||
|
||||
QString label;
|
||||
int copyId = -1;
|
||||
};
|
||||
|
||||
typedef QMap<QDBusObjectPath, FreedesktopSecret> FreedesktopSecretMap;
|
||||
typedef QMap<QString, QString> StrStrMap;
|
||||
|
||||
Q_DECLARE_METATYPE(FreedesktopSecret)
|
||||
Q_DECLARE_METATYPE(FreedesktopSecretMap)
|
||||
Q_DECLARE_METATYPE(PropertiesMap)
|
||||
Q_DECLARE_METATYPE(StrStrMap)
|
||||
Q_DECLARE_METATYPE(QCA::SecureArray)
|
||||
|
||||
class KWalletFreedesktopSession;
|
||||
class KWalletFreedesktopSessionAlgorithm;
|
||||
class KWalletFreedesktopCollection;
|
||||
class KWalletFreedesktopPrompt;
|
||||
class KWalletFreedesktopItem;
|
||||
|
||||
class KWalletFreedesktopService : public QObject, protected FDO_DBUS_CONTEXT
|
||||
{
|
||||
/* org.freedesktop.Secret.Service properties */
|
||||
public:
|
||||
Q_PROPERTY(QList<QDBusObjectPath> Collections READ collections)
|
||||
QList<QDBusObjectPath> collections() const;
|
||||
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit KWalletFreedesktopService(KWalletD *parent);
|
||||
~KWalletFreedesktopService();
|
||||
|
||||
KWalletFreedesktopService(const KWalletFreedesktopService &) = delete;
|
||||
KWalletFreedesktopService &operator=(const KWalletFreedesktopService &) = delete;
|
||||
|
||||
KWalletFreedesktopService(KWalletFreedesktopService &&) = delete;
|
||||
KWalletFreedesktopService &operator=(KWalletFreedesktopService &&) = delete;
|
||||
|
||||
static QString wrapToCollectionPath(const QString &itemPath);
|
||||
|
||||
static QDBusObjectPath nextPromptPath();
|
||||
KWalletD *backend() const;
|
||||
QDBusObjectPath fdoObjectPath() const;
|
||||
|
||||
bool desecret(const QDBusMessage &message, FreedesktopSecret &secret);
|
||||
bool ensecret(const QDBusMessage &message, FreedesktopSecret &secret);
|
||||
KWalletFreedesktopItem *getItemByObjectPath(const QDBusObjectPath &path) const;
|
||||
KWalletFreedesktopCollection *getCollectionByWalletName(const QString &walletName) const;
|
||||
KWalletFreedesktopPrompt *getPromptByObjectPath(const QDBusObjectPath &path) const;
|
||||
|
||||
FdoUniqueLabel makeUniqueCollectionLabel(const QString &label);
|
||||
QString makeUniqueWalletName(const QString &labelPrefix);
|
||||
QDBusObjectPath makeUniqueObjectPath(const QString &walletName) const;
|
||||
|
||||
QString resolveIfAlias(QString alias);
|
||||
QStringList readAliasesFor(const QString &walletName);
|
||||
void createCollectionAlias(const QString &alias, KWalletFreedesktopCollection *collection);
|
||||
void createCollectionAlias(const QString &alias, const QString &walletName);
|
||||
void updateCollectionAlias(const QString &alias, const QString &walletName);
|
||||
void removeAlias(const QString &alias);
|
||||
|
||||
void deletePrompt(const QString &objectPath);
|
||||
void deleteSession(const QString &objectPath);
|
||||
QDBusObjectPath promptUnlockCollection(const QString &walletName, int handle);
|
||||
|
||||
/* Emitters */
|
||||
void onCollectionCreated(const QDBusObjectPath &path);
|
||||
void onCollectionChanged(const QDBusObjectPath &path);
|
||||
void onCollectionDeleted(const QDBusObjectPath &path);
|
||||
void onPropertiesChanged(const QVariantMap &properties);
|
||||
|
||||
private Q_SLOTS:
|
||||
void lockCollection(const QString &name);
|
||||
void entryUpdated(const QString &walletName, const QString &folder, const QString &entryName);
|
||||
void entryDeleted(const QString &walletName, const QString &folder, const QString &entryName);
|
||||
void entryRenamed(const QString &walletName, const QString &folder, const QString &oldName, const QString &newName);
|
||||
void walletDeleted(const QString &walletName);
|
||||
void walletCreated(const QString &walletCreated);
|
||||
/*
|
||||
void slotServiceOwnerChanged(const QString &name, const QString &oldOwner,
|
||||
const QString &newOwner);
|
||||
*/
|
||||
|
||||
private:
|
||||
std::unique_ptr<KWalletFreedesktopSessionAlgorithm> createSessionAlgorithmPlain() const;
|
||||
std::unique_ptr<KWalletFreedesktopSessionAlgorithm> createSessionAlgorithmDhAes(const QByteArray &clientKey) const;
|
||||
QString createSession(std::unique_ptr<KWalletFreedesktopSessionAlgorithm> algorithm);
|
||||
QString defaultWalletName(KConfigGroup &cfg);
|
||||
|
||||
private:
|
||||
std::map<QString, std::unique_ptr<KWalletFreedesktopSession>> m_sessions;
|
||||
std::map<QString, std::unique_ptr<KWalletFreedesktopCollection>> m_collections;
|
||||
std::map<QString, std::unique_ptr<KWalletFreedesktopPrompt>> m_prompts;
|
||||
|
||||
uint64_t m_session_counter = 0;
|
||||
|
||||
/*
|
||||
QDBusServiceWatcher _serviceWatcher;
|
||||
*/
|
||||
KWalletD *m_parent;
|
||||
QCA::Initializer m_init;
|
||||
KConfig m_kwalletrc;
|
||||
|
||||
/* Freedesktop API */
|
||||
|
||||
/* org.freedesktop.Secret.Service methods */
|
||||
public Q_SLOTS:
|
||||
QDBusObjectPath CreateCollection(const QVariantMap &properties, const QString &alias, QDBusObjectPath &prompt);
|
||||
FreedesktopSecretMap GetSecrets(const QList<QDBusObjectPath> &items, const QDBusObjectPath &session);
|
||||
QList<QDBusObjectPath> Lock(const QList<QDBusObjectPath> &objects, QDBusObjectPath &Prompt);
|
||||
QDBusVariant OpenSession(const QString &algorithm, const QDBusVariant &input, QDBusObjectPath &result);
|
||||
QDBusObjectPath ReadAlias(const QString &name);
|
||||
QList<QDBusObjectPath> SearchItems(const StrStrMap &attributes, QList<QDBusObjectPath> &locked);
|
||||
void SetAlias(const QString &name, const QDBusObjectPath &collection);
|
||||
QList<QDBusObjectPath> Unlock(const QList<QDBusObjectPath> &objects, QDBusObjectPath &prompt);
|
||||
|
||||
/* org.freedesktop.Secret.Service signals */
|
||||
Q_SIGNALS:
|
||||
void CollectionChanged(const QDBusObjectPath &collection);
|
||||
void CollectionCreated(const QDBusObjectPath &collection);
|
||||
void CollectionDeleted(const QDBusObjectPath &collection);
|
||||
};
|
||||
|
||||
QDataStream &operator<<(QDataStream &stream, const QDBusObjectPath &value);
|
||||
QDataStream &operator>>(QDataStream &stream, QDBusObjectPath &value);
|
||||
|
||||
const QDBusArgument &operator>>(const QDBusArgument &arg, PropertiesMap &value);
|
||||
QDBusArgument &operator<<(QDBusArgument &arg, const PropertiesMap &value);
|
||||
|
||||
QDataStream &operator<<(QDataStream &stream, const QCA::SecureArray &value);
|
||||
QDataStream &operator>>(QDataStream &stream, QCA::SecureArray &value);
|
||||
QDBusArgument &operator<<(QDBusArgument &arg, const QCA::SecureArray &value);
|
||||
const QDBusArgument &operator>>(const QDBusArgument &arg, QCA::SecureArray &buf);
|
||||
|
||||
void explicit_zero_mem(void *data, size_t size);
|
||||
|
||||
#endif
|
||||
+143
@@ -0,0 +1,143 @@
|
||||
/*
|
||||
This file is part of the KDE libraries
|
||||
SPDX-FileCopyrightText: 2021 Slava Aseev <nullptrnine@basealt.ru>
|
||||
|
||||
SPDX-License-Identifier: LGPL-2.0-or-later
|
||||
*/
|
||||
#include "kwalletfreedesktopsession.h"
|
||||
|
||||
#include "kwalletfreedesktopsessionadaptor.h"
|
||||
#include <QDBusConnection>
|
||||
|
||||
KWalletFreedesktopSession::KWalletFreedesktopSession(KWalletFreedesktopService *service,
|
||||
std::unique_ptr<KWalletFreedesktopSessionAlgorithm> algorithm,
|
||||
QString sessionPath,
|
||||
const QDBusConnection &connection,
|
||||
const QDBusMessage &message)
|
||||
: m_service(service)
|
||||
, m_algorithm(std::move(algorithm))
|
||||
, m_sessionPath(std::move(sessionPath))
|
||||
, m_serviceBusName(message.service())
|
||||
{
|
||||
(void)new KWalletFreedesktopSessionAdaptor(this);
|
||||
QDBusConnection::sessionBus().registerObject(m_sessionPath, this);
|
||||
|
||||
m_serviceWatcher.setConnection(connection);
|
||||
m_serviceWatcher.addWatchedService(m_serviceBusName);
|
||||
m_serviceWatcher.setWatchMode(QDBusServiceWatcher::WatchForOwnerChange);
|
||||
connect(&m_serviceWatcher, &QDBusServiceWatcher::serviceOwnerChanged, this, &KWalletFreedesktopSession::slotServiceOwnerChanged);
|
||||
}
|
||||
|
||||
void KWalletFreedesktopSession::slotServiceOwnerChanged(const QString &, const QString &, const QString &)
|
||||
{
|
||||
fdoService()->deleteSession(m_sessionPath);
|
||||
}
|
||||
|
||||
void KWalletFreedesktopSession::Close()
|
||||
{
|
||||
if (message().service() != m_serviceBusName) {
|
||||
sendErrorReply(QDBusError::ErrorType::UnknownObject, QStringLiteral("Can't find session ") + m_sessionPath);
|
||||
} else {
|
||||
fdoService()->deleteSession(m_sessionPath);
|
||||
}
|
||||
}
|
||||
|
||||
QByteArray KWalletFreedesktopSession::negotiationOutput() const
|
||||
{
|
||||
return m_algorithm->negotiationOutput();
|
||||
}
|
||||
|
||||
bool KWalletFreedesktopSession::encrypt(const QDBusMessage &message, FreedesktopSecret &secret) const
|
||||
{
|
||||
if (message.service() != m_serviceBusName) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return m_algorithm->encrypt(secret);
|
||||
}
|
||||
|
||||
bool KWalletFreedesktopSession::decrypt(const QDBusMessage &message, FreedesktopSecret &secret) const
|
||||
{
|
||||
if (message.service() != m_serviceBusName) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return m_algorithm->decrypt(secret);
|
||||
}
|
||||
|
||||
KWalletFreedesktopService *KWalletFreedesktopSession::fdoService() const
|
||||
{
|
||||
return m_service;
|
||||
}
|
||||
|
||||
KWalletD *KWalletFreedesktopSession::backend() const
|
||||
{
|
||||
return fdoService()->backend();
|
||||
}
|
||||
|
||||
QDBusObjectPath KWalletFreedesktopSession::fdoObjectPath() const
|
||||
{
|
||||
return QDBusObjectPath(m_sessionPath);
|
||||
}
|
||||
|
||||
QByteArray KWalletFreedesktopSessionAlgorithmPlain::negotiationOutput() const
|
||||
{
|
||||
return QByteArray();
|
||||
}
|
||||
|
||||
bool KWalletFreedesktopSessionAlgorithmPlain::encrypt(FreedesktopSecret &secret) const
|
||||
{
|
||||
secret.parameters = QByteArray();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool KWalletFreedesktopSessionAlgorithmPlain::decrypt(FreedesktopSecret &) const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
KWalletFreedesktopSessionAlgorithmDhAes::KWalletFreedesktopSessionAlgorithmDhAes(const QCA::PublicKey &publicKey, QCA::SymmetricKey symmetricKey)
|
||||
: m_publicKey(publicKey)
|
||||
, m_symmetricKey(std::move(symmetricKey))
|
||||
{
|
||||
}
|
||||
|
||||
QByteArray KWalletFreedesktopSessionAlgorithmDhAes::negotiationOutput() const
|
||||
{
|
||||
return m_publicKey.toDH().y().toArray().toByteArray();
|
||||
}
|
||||
|
||||
bool KWalletFreedesktopSessionAlgorithmDhAes::encrypt(FreedesktopSecret &secret) const
|
||||
{
|
||||
auto initVector = QCA::InitializationVector(FDO_SECRETS_CIPHER_KEY_SIZE);
|
||||
auto cipher = QCA::Cipher(QStringLiteral("aes128"), QCA::Cipher::CBC, QCA::Cipher::PKCS7, QCA::Encode, m_symmetricKey, initVector);
|
||||
QCA::SecureArray result;
|
||||
result.append(cipher.update(QCA::MemoryRegion(secret.value)));
|
||||
if (cipher.ok()) {
|
||||
result.append(cipher.final());
|
||||
if (cipher.ok()) {
|
||||
secret.value = std::move(result);
|
||||
secret.parameters = initVector;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool KWalletFreedesktopSessionAlgorithmDhAes::decrypt(FreedesktopSecret &secret) const
|
||||
{
|
||||
auto cipher =
|
||||
QCA::Cipher(QStringLiteral("aes128"), QCA::Cipher::CBC, QCA::Cipher::PKCS7, QCA::Decode, m_symmetricKey, QCA::InitializationVector(secret.parameters));
|
||||
QCA::SecureArray result;
|
||||
result.append(cipher.update(QCA::MemoryRegion(secret.value)));
|
||||
if (cipher.ok()) {
|
||||
result.append(cipher.final());
|
||||
if (cipher.ok()) {
|
||||
secret.value = std::move(result);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
#include "moc_kwalletfreedesktopsession.cpp"
|
||||
@@ -0,0 +1,93 @@
|
||||
/*
|
||||
This file is part of the KDE libraries
|
||||
SPDX-FileCopyrightText: 2021 Slava Aseev <nullptrnine@basealt.ru>
|
||||
|
||||
SPDX-License-Identifier: LGPL-2.0-or-later
|
||||
*/
|
||||
#ifndef _KWALLETFREEDESKTOPSESSION_H_
|
||||
#define _KWALLETFREEDESKTOPSESSION_H_
|
||||
|
||||
#include "kwalletfreedesktopservice.h"
|
||||
#include <QDBusContext>
|
||||
#include <QDBusObjectPath>
|
||||
#include <QDBusServiceWatcher>
|
||||
#include <QtCrypto>
|
||||
|
||||
#define FDO_SECRETS_SESSION_PATH FDO_SECRETS_SERVICE_OBJECT "/session/"
|
||||
|
||||
class KWalletD;
|
||||
|
||||
class KWalletFreedesktopSessionAlgorithm
|
||||
{
|
||||
public:
|
||||
virtual ~KWalletFreedesktopSessionAlgorithm() = default;
|
||||
virtual QByteArray negotiationOutput() const = 0;
|
||||
virtual bool encrypt(FreedesktopSecret &secret) const = 0;
|
||||
virtual bool decrypt(FreedesktopSecret &secret) const = 0;
|
||||
};
|
||||
|
||||
class KWalletFreedesktopSession : public QObject, protected QDBusContext
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
KWalletFreedesktopSession(class KWalletFreedesktopService *parent,
|
||||
std::unique_ptr<KWalletFreedesktopSessionAlgorithm> algorithm,
|
||||
QString sessionPath,
|
||||
const QDBusConnection &connection,
|
||||
const QDBusMessage &message);
|
||||
|
||||
KWalletFreedesktopSession(const KWalletFreedesktopSession &) = delete;
|
||||
KWalletFreedesktopSession &operator=(const KWalletFreedesktopSession &) = delete;
|
||||
|
||||
KWalletFreedesktopSession(KWalletFreedesktopSession &&) = delete;
|
||||
KWalletFreedesktopSession &operator=(KWalletFreedesktopSession &&) = delete;
|
||||
|
||||
KWalletFreedesktopService *fdoService() const;
|
||||
KWalletD *backend() const;
|
||||
QDBusObjectPath fdoObjectPath() const;
|
||||
|
||||
QByteArray negotiationOutput() const;
|
||||
bool encrypt(const QDBusMessage &message, FreedesktopSecret &secret) const;
|
||||
bool decrypt(const QDBusMessage &message, FreedesktopSecret &secret) const;
|
||||
|
||||
private Q_SLOTS:
|
||||
void slotServiceOwnerChanged(const QString &name, const QString &oldOwner, const QString &newOwner);
|
||||
|
||||
private:
|
||||
class KWalletFreedesktopService *m_service;
|
||||
std::unique_ptr<KWalletFreedesktopSessionAlgorithm> m_algorithm;
|
||||
QString m_sessionPath;
|
||||
QString m_serviceBusName;
|
||||
QDBusServiceWatcher m_serviceWatcher;
|
||||
|
||||
/* Freedesktop API */
|
||||
|
||||
/* org.freedesktop.Secret.Session methods */
|
||||
public Q_SLOTS:
|
||||
void Close();
|
||||
};
|
||||
|
||||
class KWalletFreedesktopSessionAlgorithmPlain : public KWalletFreedesktopSessionAlgorithm
|
||||
{
|
||||
public:
|
||||
QByteArray negotiationOutput() const override;
|
||||
bool encrypt(FreedesktopSecret &secret) const override;
|
||||
bool decrypt(FreedesktopSecret &secret) const override;
|
||||
};
|
||||
|
||||
class KWalletFreedesktopSessionAlgorithmDhAes : public KWalletFreedesktopSessionAlgorithm
|
||||
{
|
||||
public:
|
||||
KWalletFreedesktopSessionAlgorithmDhAes(const QCA::PublicKey &publicKey, QCA::SymmetricKey symmetricKey);
|
||||
|
||||
QByteArray negotiationOutput() const override;
|
||||
bool encrypt(FreedesktopSecret &secret) const override;
|
||||
bool decrypt(FreedesktopSecret &secret) const override;
|
||||
|
||||
private:
|
||||
QCA::PublicKey m_publicKey;
|
||||
QCA::SymmetricKey m_symmetricKey;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,86 @@
|
||||
/*
|
||||
This file is part of the KDE libraries
|
||||
SPDX-FileCopyrightText: 2023 Nicolas Fella <nicolas.fella@gmx.de>
|
||||
|
||||
SPDX-License-Identifier: LGPL-2.0-or-later
|
||||
*/
|
||||
|
||||
#include "kwalletportalsecrets.h"
|
||||
|
||||
#include "kwalletportalsecretsadaptor.h"
|
||||
|
||||
#include <QRandomGenerator>
|
||||
|
||||
KWalletPortalSecrets::KWalletPortalSecrets(KWalletD *parent)
|
||||
: QObject(parent)
|
||||
, m_kwalletd(parent)
|
||||
{
|
||||
(void)new KWalletPortalSecretsAdaptor(this);
|
||||
|
||||
QDBusConnection::sessionBus().registerService(QStringLiteral("org.freedesktop.impl.portal.desktop.kwallet"));
|
||||
QDBusConnection::sessionBus().registerObject(QStringLiteral("/org/freedesktop/portal/desktop"), this, QDBusConnection::ExportAdaptors);
|
||||
|
||||
connect(m_kwalletd, &KWalletD::walletAsyncOpened, this, &KWalletPortalSecrets::walletOpened);
|
||||
}
|
||||
|
||||
uint KWalletPortalSecrets::RetrieveSecret(const QDBusObjectPath &handle,
|
||||
const QString &app_id,
|
||||
const QDBusUnixFileDescriptor &fd,
|
||||
const QVariantMap &options,
|
||||
QVariantMap &results)
|
||||
{
|
||||
Q_UNUSED(handle);
|
||||
Q_UNUSED(options);
|
||||
Q_UNUSED(results);
|
||||
|
||||
setDelayedReply(true);
|
||||
|
||||
const QString wallet = m_kwalletd->networkWallet();
|
||||
|
||||
int transactionId = m_kwalletd->openAsync(wallet, 0, "xdg-desktop-portal", false, connection(), message());
|
||||
Request request{message(), fd.fileDescriptor(), app_id};
|
||||
m_pendingRequests.insert(transactionId, request);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void KWalletPortalSecrets::walletOpened(int transactionId, int walletHandle)
|
||||
{
|
||||
if (!m_pendingRequests.contains(transactionId)) {
|
||||
// wallet open request was not from us
|
||||
return;
|
||||
}
|
||||
|
||||
const Request request = m_pendingRequests.take(transactionId);
|
||||
|
||||
bool exists = m_kwalletd->hasEntry(walletHandle, "xdg-desktop-portal", request.appId, "xdg-desktop-portal");
|
||||
|
||||
QByteArray secret;
|
||||
|
||||
if (exists) {
|
||||
secret = m_kwalletd->readEntry(walletHandle, "xdg-desktop-portal", request.appId, "xdg-desktop-portal");
|
||||
} else {
|
||||
secret = generateSecret();
|
||||
m_kwalletd->writeEntry(walletHandle, "xdg-desktop-portal", request.appId, secret, "xdg-desktop-portal");
|
||||
m_kwalletd->sync(walletHandle, "xdg-desktop-portal");
|
||||
}
|
||||
|
||||
QFile outFile;
|
||||
outFile.open(request.fd, QIODevice::ReadWrite);
|
||||
|
||||
outFile.write(secret);
|
||||
|
||||
const auto replyList = QVariantList{{(uint)0}, {{QVariantMap{}}}};
|
||||
auto reply = request.message.createReply(replyList);
|
||||
QDBusConnection::sessionBus().send(reply);
|
||||
}
|
||||
|
||||
QByteArray KWalletPortalSecrets::generateSecret() const
|
||||
{
|
||||
const int secretSize = 64;
|
||||
QByteArray secret;
|
||||
secret.resize(secretSize);
|
||||
QRandomGenerator::securelySeeded().generate(secret.begin(), secret.end());
|
||||
|
||||
return secret;
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
This file is part of the KDE libraries
|
||||
SPDX-FileCopyrightText: 2023 Nicolas Fella <nicolas.fella@gmx.de>
|
||||
|
||||
SPDX-License-Identifier: LGPL-2.0-or-later
|
||||
*/
|
||||
|
||||
#ifndef KWALLETPORTALSECRETS_H
|
||||
#define KWALLETPORTALSECRETS_H
|
||||
|
||||
#include <QDBusMessage>
|
||||
#include <QDBusObjectPath>
|
||||
#include <QDBusUnixFileDescriptor>
|
||||
#include <QObject>
|
||||
|
||||
#include "kwalletd.h"
|
||||
|
||||
class KWalletPortalSecrets : public QObject, protected QDBusContext
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
KWalletPortalSecrets(KWalletD *parent);
|
||||
|
||||
public Q_SLOTS:
|
||||
uint
|
||||
RetrieveSecret(const QDBusObjectPath &handle, const QString &app_id, const QDBusUnixFileDescriptor &fd, const QVariantMap &options, QVariantMap &results);
|
||||
|
||||
private Q_SLOTS:
|
||||
void walletOpened(int id, int handle);
|
||||
|
||||
private:
|
||||
struct Request {
|
||||
QDBusMessage message;
|
||||
int fd;
|
||||
QString appId;
|
||||
};
|
||||
|
||||
QByteArray generateSecret() const;
|
||||
|
||||
QHash<int, Request> m_pendingRequests;
|
||||
|
||||
KWalletD *m_kwalletd;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,161 @@
|
||||
/*
|
||||
This file is part of the KDE Wallet Daemon
|
||||
SPDX-FileCopyrightText: 2008 Michael Leupold <lemma@confuego.org>
|
||||
|
||||
SPDX-License-Identifier: LGPL-2.0-or-later
|
||||
*/
|
||||
|
||||
#include "kwalletsessionstore.h"
|
||||
|
||||
class KWalletSessionStore::Session
|
||||
{
|
||||
public:
|
||||
QString m_service; // client dbus service (or empty)
|
||||
int m_handle; // backend handle
|
||||
};
|
||||
|
||||
KWalletSessionStore::KWalletSessionStore()
|
||||
{
|
||||
}
|
||||
|
||||
KWalletSessionStore::~KWalletSessionStore()
|
||||
{
|
||||
for (const QList<Session *> &l : std::as_const(m_sessions)) {
|
||||
qDeleteAll(l);
|
||||
}
|
||||
}
|
||||
|
||||
void KWalletSessionStore::addSession(const QString &appid, const QString &service, int handle)
|
||||
{
|
||||
Session *sess = new Session();
|
||||
sess->m_service = service;
|
||||
sess->m_handle = handle;
|
||||
m_sessions[appid].append(sess);
|
||||
}
|
||||
|
||||
bool KWalletSessionStore::hasSession(const QString &appid, int handle) const
|
||||
{
|
||||
if (!m_sessions.contains(appid)) {
|
||||
return false;
|
||||
} else if (handle == -1) {
|
||||
return true;
|
||||
}
|
||||
|
||||
QList<Session *>::const_iterator it;
|
||||
QList<Session *>::const_iterator end = m_sessions[appid].constEnd();
|
||||
for (it = m_sessions[appid].constBegin(); it != end; ++it) {
|
||||
Q_ASSERT(*it);
|
||||
if ((*it)->m_handle == handle) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
QList<KWalletAppHandlePair> KWalletSessionStore::findSessions(const QString &service) const
|
||||
{
|
||||
QList<KWalletAppHandlePair> rc;
|
||||
const QList<QString> sessionKeys(m_sessions.keys());
|
||||
for (const QString &appid : sessionKeys) {
|
||||
const auto lst = m_sessions[appid];
|
||||
for (const Session *sess : lst) {
|
||||
Q_ASSERT(sess);
|
||||
if (sess->m_service == service) {
|
||||
rc.append(qMakePair(appid, sess->m_handle));
|
||||
}
|
||||
}
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
bool KWalletSessionStore::removeSession(const QString &appid, const QString &service, int handle)
|
||||
{
|
||||
if (!m_sessions.contains(appid)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
QList<Session *>::const_iterator it;
|
||||
QList<Session *>::const_iterator end = m_sessions[appid].constEnd();
|
||||
for (it = m_sessions[appid].constBegin(); it != end; ++it) {
|
||||
Q_ASSERT(*it);
|
||||
if ((*it)->m_service == service && (*it)->m_handle == handle) {
|
||||
Session *sess = *it;
|
||||
m_sessions[appid].removeAll(sess);
|
||||
delete sess;
|
||||
if (m_sessions[appid].isEmpty()) {
|
||||
m_sessions.remove(appid);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
int KWalletSessionStore::removeAllSessions(const QString &appid, int handle)
|
||||
{
|
||||
if (!m_sessions.contains(appid)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
QList<Session *>::iterator it;
|
||||
QList<Session *>::iterator end = m_sessions[appid].end();
|
||||
for (it = m_sessions[appid].begin(); it != end; ++it) {
|
||||
Q_ASSERT(*it);
|
||||
if ((*it)->m_handle == handle) {
|
||||
delete *it;
|
||||
*it = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
int removed = m_sessions[appid].removeAll(nullptr);
|
||||
if (m_sessions[appid].isEmpty()) {
|
||||
m_sessions.remove(appid);
|
||||
}
|
||||
|
||||
return removed;
|
||||
}
|
||||
|
||||
int KWalletSessionStore::removeAllSessions(int handle)
|
||||
{
|
||||
QList<QString> appremove;
|
||||
int numrem = 0;
|
||||
const QList<QString> sessionKeys(m_sessions.keys());
|
||||
for (const QString &appid : sessionKeys) {
|
||||
QList<Session *>::iterator it;
|
||||
QList<Session *>::iterator end = m_sessions[appid].end();
|
||||
for (it = m_sessions[appid].begin(); it != end; ++it) {
|
||||
Q_ASSERT(*it);
|
||||
if ((*it)->m_handle == handle) {
|
||||
delete *it;
|
||||
*it = nullptr;
|
||||
numrem++;
|
||||
}
|
||||
}
|
||||
// remove all zeroed sessions
|
||||
m_sessions[appid].removeAll(nullptr);
|
||||
if (m_sessions[appid].isEmpty()) {
|
||||
appremove.append(appid);
|
||||
}
|
||||
}
|
||||
|
||||
// now remove all applications without sessions
|
||||
for (const QString &appid : std::as_const(appremove)) {
|
||||
m_sessions.remove(appid);
|
||||
}
|
||||
|
||||
return numrem;
|
||||
}
|
||||
|
||||
QStringList KWalletSessionStore::getApplications(int handle) const
|
||||
{
|
||||
QStringList rc;
|
||||
const auto lst = m_sessions.keys();
|
||||
for (const QString &appid : lst) {
|
||||
if (hasSession(appid, handle)) {
|
||||
rc.append(appid);
|
||||
}
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
This file is part of the KDE Wallet Daemon
|
||||
SPDX-FileCopyrightText: 2008 Michael Leupold <lemma@confuego.org>
|
||||
|
||||
SPDX-License-Identifier: LGPL-2.0-or-later
|
||||
*/
|
||||
|
||||
#ifndef _KWALLETSESSIONSTORE_H_
|
||||
#define _KWALLETSESSIONSTORE_H_
|
||||
|
||||
#include <QHash>
|
||||
#include <QList>
|
||||
#include <QPair>
|
||||
#include <QString>
|
||||
#include <QStringList>
|
||||
|
||||
typedef QPair<QString, int> KWalletAppHandlePair;
|
||||
|
||||
class KWalletSessionStore
|
||||
{
|
||||
public:
|
||||
KWalletSessionStore();
|
||||
~KWalletSessionStore();
|
||||
|
||||
KWalletSessionStore(const KWalletSessionStore &) = delete;
|
||||
KWalletSessionStore &operator=(const KWalletSessionStore &) = delete;
|
||||
|
||||
// add a new session
|
||||
void addSession(const QString &appid, const QString &service, int handle);
|
||||
// check if the application has a session using that handle
|
||||
bool hasSession(const QString &appid, int handle = -1) const;
|
||||
// find all sessions a service has
|
||||
QList<KWalletAppHandlePair> findSessions(const QString &service) const;
|
||||
// remove a specific session
|
||||
bool removeSession(const QString &appid, const QString &service, int handle);
|
||||
// remove all sessions an application has to a specific handle
|
||||
int removeAllSessions(const QString &appid, int handle);
|
||||
// remove all sessions related to a handle
|
||||
int removeAllSessions(int handle);
|
||||
// get all applications using a handle
|
||||
QStringList getApplications(int handle) const;
|
||||
|
||||
private:
|
||||
class Session;
|
||||
QHash<QString, QList<Session *>> m_sessions; // appid => session
|
||||
};
|
||||
|
||||
#endif // _KWALLETSESSIONSTORE_H_
|
||||
@@ -0,0 +1,317 @@
|
||||
/*
|
||||
This file is part of the KDE libraries
|
||||
SPDX-FileCopyrightText: 2004 George Staikos <staikos@kde.org>
|
||||
|
||||
SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
*/
|
||||
|
||||
#include "kwalletwizard.h"
|
||||
|
||||
#include "ui_kwalletwizardpageexplanation.h"
|
||||
#include "ui_kwalletwizardpageintro.h"
|
||||
#include "ui_kwalletwizardpageoptions.h"
|
||||
#include "ui_kwalletwizardpagepassword.h"
|
||||
#ifdef HAVE_GPGMEPP
|
||||
#include "ui_kwalletwizardpagegpgkey.h"
|
||||
#include "ui_kwalletwizardpagepasswordgpg.h"
|
||||
#endif
|
||||
|
||||
#include <KLocalizedString>
|
||||
#include <QButtonGroup>
|
||||
#include <QDebug>
|
||||
#include <QIcon>
|
||||
|
||||
#ifdef HAVE_GPGMEPP
|
||||
#include <KMessageBox>
|
||||
#include <QComboBox>
|
||||
#include <gpgme++/context.h>
|
||||
#include <gpgme++/key.h>
|
||||
#include <gpgme++/keylistresult.h>
|
||||
#endif
|
||||
|
||||
class PageIntro : public QWizardPage
|
||||
{
|
||||
public:
|
||||
explicit PageIntro(QWidget *parent)
|
||||
: QWizardPage(parent)
|
||||
{
|
||||
ui.setupUi(this);
|
||||
|
||||
ui.ktitlewidget->setText("<h1>" + i18n("KWallet") + "</h1>");
|
||||
ui.ktitlewidget->setIcon(QIcon::fromTheme(QStringLiteral("kwalletmanager")));
|
||||
|
||||
bg = new QButtonGroup(this);
|
||||
bg->setExclusive(true);
|
||||
bg->addButton(ui._basic, 0);
|
||||
bg->addButton(ui._advanced, 1);
|
||||
|
||||
// force the "basic" button to be selected
|
||||
ui._basic->setChecked(true);
|
||||
}
|
||||
|
||||
QButtonGroup *bg;
|
||||
|
||||
private:
|
||||
Ui::KWalletWizardPageIntro ui;
|
||||
};
|
||||
|
||||
class PagePassword : public QWizardPage
|
||||
{
|
||||
public:
|
||||
explicit PagePassword(KWalletWizard *parent)
|
||||
: QWizardPage(parent)
|
||||
{
|
||||
ui.setupUi(this);
|
||||
|
||||
registerField(QStringLiteral("useWallet"), ui._useWallet);
|
||||
registerField(QStringLiteral("pass1"), ui._pass1);
|
||||
registerField(QStringLiteral("pass2"), ui._pass2);
|
||||
#ifdef HAVE_GPGMEPP
|
||||
registerField(QStringLiteral("useGPG"), ui._radioGpg);
|
||||
registerField(QStringLiteral("useBlowfish"), ui._radioBlowfish);
|
||||
connect(ui._radioBlowfish, &QRadioButton::toggled, parent, &KWalletWizard::passwordPageUpdate);
|
||||
#endif
|
||||
|
||||
connect(ui._useWallet, &QCheckBox::clicked, parent, &KWalletWizard::passwordPageUpdate);
|
||||
connect(ui._pass1, &QLineEdit::textChanged, parent, &KWalletWizard::passwordPageUpdate);
|
||||
connect(ui._pass2, &QLineEdit::textChanged, parent, &KWalletWizard::passwordPageUpdate);
|
||||
ui._useWallet->setChecked(true);
|
||||
}
|
||||
|
||||
int nextId() const override
|
||||
{
|
||||
#ifdef HAVE_GPGMEPP
|
||||
int nextId = -1;
|
||||
if (field(QStringLiteral("useWallet")).toBool()) {
|
||||
if (field(QStringLiteral("useBlowfish")).toBool()) {
|
||||
nextId = static_cast<KWalletWizard *>(wizard())->wizardType() == KWalletWizard::Basic
|
||||
? -1
|
||||
: KWalletWizard::PageOptionsId; // same as non GPGMEPP case
|
||||
} else {
|
||||
nextId = KWalletWizard::PageGpgKeyId;
|
||||
}
|
||||
}
|
||||
|
||||
return nextId;
|
||||
#else
|
||||
return static_cast<KWalletWizard *>(wizard())->wizardType() == KWalletWizard::Basic ? -1 : KWalletWizard::PageOptionsId;
|
||||
#endif
|
||||
}
|
||||
|
||||
void setMatchLabelText(const QString &text)
|
||||
{
|
||||
ui._matchLabel->setText(text);
|
||||
}
|
||||
|
||||
private:
|
||||
#ifdef HAVE_GPGMEPP
|
||||
Ui::KWalletWizardPagePasswordGpg ui;
|
||||
#else
|
||||
Ui::KWalletWizardPagePassword ui;
|
||||
#endif
|
||||
};
|
||||
|
||||
#ifdef HAVE_GPGMEPP
|
||||
typedef std::vector<GpgME::Key> KeysVector;
|
||||
Q_DECLARE_METATYPE(GpgME::Key)
|
||||
|
||||
struct AddKeyToCombo {
|
||||
QComboBox *_list;
|
||||
AddKeyToCombo(QComboBox *list)
|
||||
: _list(list)
|
||||
{
|
||||
}
|
||||
void operator()(const GpgME::Key &k)
|
||||
{
|
||||
QString text = QStringLiteral("%1 (%2)").arg(k.shortKeyID(), k.userID(0).email());
|
||||
QVariant varKey;
|
||||
varKey.setValue(k);
|
||||
_list->addItem(text, varKey);
|
||||
}
|
||||
};
|
||||
|
||||
class PageGpgKey : public QWizardPage
|
||||
{
|
||||
public:
|
||||
explicit PageGpgKey(QWidget *parent)
|
||||
: QWizardPage(parent)
|
||||
, userHasGpgKeys(false)
|
||||
{
|
||||
ui.setupUi(this);
|
||||
|
||||
registerField(QStringLiteral("gpgKey"), ui._gpgKey);
|
||||
|
||||
KeysVector keys;
|
||||
GpgME::initializeLibrary();
|
||||
GpgME::Error err = GpgME::checkEngine(GpgME::OpenPGP);
|
||||
if (err) {
|
||||
qDebug() << "OpenPGP not supported on your system!";
|
||||
KMessageBox::error(
|
||||
this,
|
||||
i18n("The GpgME library failed to initialize for the OpenPGP protocol. Please check your system's configuration then try again."));
|
||||
} else {
|
||||
std::shared_ptr<GpgME::Context> ctx(GpgME::Context::createForProtocol(GpgME::OpenPGP));
|
||||
if (nullptr == ctx) {
|
||||
KMessageBox::error(
|
||||
this,
|
||||
i18n("The GpgME library failed to initialize for the OpenPGP protocol. Please check your system's configuration then try again."));
|
||||
} else {
|
||||
ctx->setKeyListMode(GpgME::KeyListMode::Local);
|
||||
err = ctx->startKeyListing();
|
||||
while (!err) {
|
||||
GpgME::Key k = ctx->nextKey(err);
|
||||
if (err) {
|
||||
break;
|
||||
}
|
||||
if (!k.isInvalid() && k.canEncrypt() && (k.ownerTrust() == GpgME::Key::Ultimate)) {
|
||||
keys.push_back(k);
|
||||
}
|
||||
}
|
||||
ctx->endKeyListing();
|
||||
}
|
||||
}
|
||||
std::for_each(keys.begin(), keys.end(), AddKeyToCombo(ui._gpgKey));
|
||||
|
||||
userHasGpgKeys = keys.size() > 0;
|
||||
if (userHasGpgKeys) {
|
||||
ui.stackedWidget->setCurrentWidget(ui._pageWhenHasKeys);
|
||||
} else {
|
||||
ui.stackedWidget->setCurrentWidget(ui._pageNoKeys);
|
||||
setFinalPage(true);
|
||||
}
|
||||
Q_EMIT completeChanged();
|
||||
}
|
||||
|
||||
int nextId() const override
|
||||
{
|
||||
return static_cast<KWalletWizard *>(wizard())->wizardType() == KWalletWizard::Basic ? -1 : KWalletWizard::PageOptionsId;
|
||||
}
|
||||
|
||||
bool isComplete() const override
|
||||
{
|
||||
return userHasGpgKeys;
|
||||
}
|
||||
|
||||
bool hasGpgKeys() const
|
||||
{
|
||||
return userHasGpgKeys;
|
||||
}
|
||||
|
||||
GpgME::Key gpgKey() const
|
||||
{
|
||||
QVariant varKey = ui._gpgKey->itemData(field(QStringLiteral("gpgKey")).toInt());
|
||||
return varKey.value<GpgME::Key>();
|
||||
}
|
||||
|
||||
private:
|
||||
Ui::KWalletWizardPageGpgKey ui;
|
||||
bool userHasGpgKeys;
|
||||
};
|
||||
#endif
|
||||
|
||||
class PageOptions : public QWizardPage
|
||||
{
|
||||
public:
|
||||
explicit PageOptions(QWidget *parent)
|
||||
: QWizardPage(parent)
|
||||
{
|
||||
ui.setupUi(this);
|
||||
|
||||
registerField(QStringLiteral("closeWhenIdle"), ui._closeIdle);
|
||||
registerField(QStringLiteral("networkWallet"), ui._networkWallet);
|
||||
}
|
||||
|
||||
private:
|
||||
Ui::KWalletWizardPageOptions ui;
|
||||
};
|
||||
|
||||
class PageExplanation : public QWizardPage
|
||||
{
|
||||
public:
|
||||
PageExplanation(QWidget *parent)
|
||||
: QWizardPage(parent)
|
||||
{
|
||||
ui.setupUi(this);
|
||||
setFinalPage(true);
|
||||
}
|
||||
|
||||
private:
|
||||
Ui::KWalletWizardPageExplanation ui;
|
||||
};
|
||||
|
||||
KWalletWizard::KWalletWizard(QWidget *parent)
|
||||
: QWizard(parent)
|
||||
{
|
||||
setOption(HaveFinishButtonOnEarlyPages);
|
||||
|
||||
m_pageIntro = new PageIntro(this);
|
||||
setPage(PageIntroId, m_pageIntro);
|
||||
m_pagePasswd = new PagePassword(this);
|
||||
setPage(PagePasswordId, m_pagePasswd);
|
||||
#ifdef HAVE_GPGMEPP
|
||||
m_pageGpgKey = new PageGpgKey(this);
|
||||
setPage(PageGpgKeyId, m_pageGpgKey);
|
||||
#endif
|
||||
setPage(PageOptionsId, new PageOptions(this));
|
||||
setPage(PageExplanationId, new PageExplanation(this));
|
||||
|
||||
resize(500, 420);
|
||||
}
|
||||
|
||||
void KWalletWizard::passwordPageUpdate()
|
||||
{
|
||||
bool complete = true;
|
||||
if (field(QStringLiteral("useWallet")).toBool()) {
|
||||
#ifdef HAVE_GPGMEPP
|
||||
if (field(QStringLiteral("useBlowfish")).toBool()) {
|
||||
m_pagePasswd->setFinalPage(wizardType() == Basic);
|
||||
button(NextButton)->setVisible(wizardType() != Basic);
|
||||
#endif
|
||||
if (field(QStringLiteral("pass1")).toString() == field(QStringLiteral("pass2")).toString()) {
|
||||
if (field(QStringLiteral("pass1")).toString().isEmpty()) {
|
||||
m_pagePasswd->setMatchLabelText(i18n("<qt>Password is empty. <b>(WARNING: Insecure)</b></qt>"));
|
||||
} else {
|
||||
m_pagePasswd->setMatchLabelText(i18n("Passwords match."));
|
||||
}
|
||||
} else {
|
||||
m_pagePasswd->setMatchLabelText(i18n("Passwords do not match."));
|
||||
complete = false;
|
||||
}
|
||||
#ifdef HAVE_GPGMEPP
|
||||
} else {
|
||||
m_pagePasswd->setFinalPage(false);
|
||||
button(NextButton)->setEnabled(true);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
} else {
|
||||
m_pagePasswd->setMatchLabelText(QString());
|
||||
}
|
||||
button(wizardType() == Basic ? FinishButton : NextButton)->setEnabled(complete);
|
||||
}
|
||||
|
||||
KWalletWizard::WizardType KWalletWizard::wizardType() const
|
||||
{
|
||||
return (KWalletWizard::WizardType)m_pageIntro->bg->checkedId();
|
||||
}
|
||||
|
||||
void KWalletWizard::initializePage(int id)
|
||||
{
|
||||
switch (id) {
|
||||
case PagePasswordId: {
|
||||
bool islast = m_pageIntro->bg->checkedId() == 0;
|
||||
m_pagePasswd->setFinalPage(islast);
|
||||
button(NextButton)->setVisible(!islast);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef HAVE_GPGMEPP
|
||||
GpgME::Key KWalletWizard::gpgKey() const
|
||||
{
|
||||
return m_pageGpgKey->gpgKey();
|
||||
}
|
||||
#endif
|
||||
|
||||
#include "moc_kwalletwizard.cpp"
|
||||
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
This file is part of the KDE libraries
|
||||
SPDX-FileCopyrightText: 2004 George Staikos <staikos@kde.org>
|
||||
|
||||
SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
*/
|
||||
|
||||
#ifndef KWALLETWIZARD_H
|
||||
#define KWALLETWIZARD_H
|
||||
|
||||
#include <QWizard>
|
||||
#ifdef HAVE_GPGMEPP
|
||||
#include <gpgme++/key.h>
|
||||
#endif
|
||||
|
||||
class PageGpgKey;
|
||||
class PagePassword;
|
||||
class PageIntro;
|
||||
|
||||
class KWalletWizard : public QWizard
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
enum WizardType { Basic, Advanced };
|
||||
|
||||
static const int PageIntroId = 0;
|
||||
static const int PagePasswordId = 1;
|
||||
#ifdef HAVE_GPGMEPP
|
||||
static const int PageGpgKeyId = 2;
|
||||
#endif
|
||||
static const int PageOptionsId = 3;
|
||||
static const int PageExplanationId = 4;
|
||||
|
||||
explicit KWalletWizard(QWidget *parent = nullptr);
|
||||
|
||||
WizardType wizardType() const;
|
||||
|
||||
#ifdef HAVE_GPGMEPP
|
||||
GpgME::Key gpgKey() const;
|
||||
#endif // HAVE_GPGMEPP
|
||||
|
||||
protected:
|
||||
void initializePage(int id) override;
|
||||
|
||||
protected Q_SLOTS:
|
||||
friend class PagePassword;
|
||||
void passwordPageUpdate();
|
||||
|
||||
private:
|
||||
PageIntro *m_pageIntro;
|
||||
PagePassword *m_pagePasswd;
|
||||
#ifdef HAVE_GPGMEPP
|
||||
PageGpgKey *m_pageGpgKey;
|
||||
#endif
|
||||
};
|
||||
|
||||
#endif
|
||||
+31
@@ -0,0 +1,31 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>KWalletWizardPageExplanation</class>
|
||||
<widget class="QWidget" name="KWalletWizardPageExplanation">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>478</width>
|
||||
<height>215</height>
|
||||
</rect>
|
||||
</property>
|
||||
<layout class="QVBoxLayout">
|
||||
<item>
|
||||
<widget class="QLabel" name="textLabel2_3">
|
||||
<property name="text">
|
||||
<string><html><head/><body><p>The KDE Wallet system stores your data in a <span style=" font-style:italic;">wallet</span> file on your local hard disk. The data is only written in the encrypted form of your choice - blowfish algorithm with your password as the key or using a GPG encryption key. When a wallet is opened, the wallet manager application will launch and display an icon in the system tray. You can use this application to manage all of your wallets. It even permits you to drag wallets and wallet contents, allowing you to easily copy a wallet to a remote system.</p></body></html></string>
|
||||
</property>
|
||||
<property name="textFormat">
|
||||
<enum>Qt::RichText</enum>
|
||||
</property>
|
||||
<property name="wordWrap">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||
@@ -0,0 +1,96 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>KWalletWizardPageGpgKey</class>
|
||||
<widget class="QWidget" name="KWalletWizardPageGpgKey">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>436</width>
|
||||
<height>309</height>
|
||||
</rect>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_3">
|
||||
<item>
|
||||
<widget class="QStackedWidget" name="stackedWidget">
|
||||
<property name="currentIndex">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<widget class="QWidget" name="_pageWhenHasKeys">
|
||||
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||
<item>
|
||||
<widget class="QLabel" name="label_3">
|
||||
<property name="text">
|
||||
<string><html><head/><body><p>The GPG-based wallet use a GPG encryption key to securely encrypt data on disk. The key must be available when decrypting is needed or your wallet will not be accessible. For example, if you choose a SmartCard-based encryption key, the GPG system will prompt you to enter it and its associated PIN when attempting to open the wallet. <span style=" font-weight:600;">NOTE:</span> this list contains only &quot;ultimate-level&quot; trusted keys.</p></body></html></string>
|
||||
</property>
|
||||
<property name="textFormat">
|
||||
<enum>Qt::AutoText</enum>
|
||||
</property>
|
||||
<property name="wordWrap">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="enabled">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Select encryption GPG key:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QComboBox" name="_gpgKey">
|
||||
<property name="enabled">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="verticalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>173</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QWidget" name="_pageNoKeys">
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<widget class="QLabel" name="label_2">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Expanding">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Unable to locate at least one <b>encrypting GPG key</b>. KDE Wallet needs such <b>encrypting key</b> to securely store passwords or other sensitive data on disk. If you still want to setup a GPG-based wallet, then cancel this wizard, set-up an <b>encrypting GPG key</b>, then retry this assistant. Otherwise, you may still click back, then choose a classic, blowfish encrypted file format on the previous page.</string>
|
||||
</property>
|
||||
<property name="wordWrap">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||
@@ -0,0 +1,127 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>KWalletWizardPageIntro</class>
|
||||
<widget class="QWidget" name="KWalletWizardPageIntro">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>449</width>
|
||||
<height>327</height>
|
||||
</rect>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<widget class="KTitleWidget" name="ktitlewidget">
|
||||
<property name="comment">
|
||||
<string>The KDE Wallet System</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="textLabel2">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Welcome to KWallet, the KDE Wallet System. KWallet allows you to store your passwords and other personal information on disk in an encrypted file, preventing others from viewing the information. This wizard will tell you about KWallet and help you configure it for the first time.</string>
|
||||
</property>
|
||||
<property name="textFormat">
|
||||
<enum>Qt::RichText</enum>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignVCenter</set>
|
||||
</property>
|
||||
<property name="wordWrap">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="margin">
|
||||
<number>12</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<spacer name="horizontalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeType">
|
||||
<enum>QSizePolicy::Fixed</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QVBoxLayout">
|
||||
<item>
|
||||
<widget class="QRadioButton" name="_basic">
|
||||
<property name="text">
|
||||
<string>&Basic setup (recommended)</string>
|
||||
</property>
|
||||
<property name="checked">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QRadioButton" name="_advanced">
|
||||
<property name="text">
|
||||
<string>&Advanced setup</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer_2">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<spacer>
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeType">
|
||||
<enum>QSizePolicy::Expanding</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>21</width>
|
||||
<height>21</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<customwidgets>
|
||||
<customwidget>
|
||||
<class>KTitleWidget</class>
|
||||
<extends>QWidget</extends>
|
||||
<header>ktitlewidget.h</header>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||
@@ -0,0 +1,79 @@
|
||||
<ui version="4.0" >
|
||||
<class>KWalletWizardPageOptions</class>
|
||||
<widget class="QWidget" name="KWalletWizardPageOptions" >
|
||||
<property name="geometry" >
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>436</width>
|
||||
<height>214</height>
|
||||
</rect>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" >
|
||||
<item>
|
||||
<widget class="QLabel" name="textLabel1_3" >
|
||||
<property name="text" >
|
||||
<string>The KDE Wallet system allows you to control the level of security of your personal data. Some of these settings do impact usability. While the default settings are generally acceptable for most users, you may wish to change some of them. You may further tune these settings from the KWallet control module.</string>
|
||||
</property>
|
||||
<property name="textFormat" >
|
||||
<enum>Qt::RichText</enum>
|
||||
</property>
|
||||
<property name="alignment" >
|
||||
<set>Qt::AlignVCenter</set>
|
||||
</property>
|
||||
<property name="wordWrap" >
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer>
|
||||
<property name="orientation" >
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeType" >
|
||||
<enum>QSizePolicy::MinimumExpanding</enum>
|
||||
</property>
|
||||
<property name="sizeHint" >
|
||||
<size>
|
||||
<width>21</width>
|
||||
<height>10</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="_closeIdle" >
|
||||
<property name="text" >
|
||||
<string>Automatically close idle wallets</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="_networkWallet" >
|
||||
<property name="text" >
|
||||
<string>Store network passwords and local passwords in separate wallet files</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer>
|
||||
<property name="orientation" >
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeType" >
|
||||
<enum>QSizePolicy::MinimumExpanding</enum>
|
||||
</property>
|
||||
<property name="sizeHint" >
|
||||
<size>
|
||||
<width>21</width>
|
||||
<height>10</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||
+282
@@ -0,0 +1,282 @@
|
||||
<ui version="4.0" >
|
||||
<class>KWalletWizardPagePassword</class>
|
||||
<widget class="QWidget" name="KWalletWizardPagePassword" >
|
||||
<property name="geometry" >
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>526</width>
|
||||
<height>401</height>
|
||||
</rect>
|
||||
</property>
|
||||
<layout class="QGridLayout" >
|
||||
<item row="0" column="0" colspan="4" >
|
||||
<widget class="QLabel" name="textLabel3" >
|
||||
<property name="text" >
|
||||
<string>Various applications may attempt to use the KDE wallet to store passwords or other information such as web form data and cookies. If you would like these applications to use the wallet, you must enable it now and choose a password. The password you choose <i>cannot</i> be recovered if it is lost, and will allow anyone who knows it to obtain all the information contained in the wallet.</string>
|
||||
</property>
|
||||
<property name="textFormat" >
|
||||
<enum>Qt::RichText</enum>
|
||||
</property>
|
||||
<property name="wordWrap" >
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0" colspan="4" >
|
||||
<widget class="QCheckBox" name="_useWallet" >
|
||||
<property name="text" >
|
||||
<string>Yes, I wish to use the KDE wallet to store my personal information.</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1" colspan="2" >
|
||||
<spacer>
|
||||
<property name="orientation" >
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeType" >
|
||||
<enum>QSizePolicy::Expanding</enum>
|
||||
</property>
|
||||
<property name="sizeHint" >
|
||||
<size>
|
||||
<width>21</width>
|
||||
<height>51</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item row="3" column="0" >
|
||||
<spacer>
|
||||
<property name="orientation" >
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeType" >
|
||||
<enum>QSizePolicy::Expanding</enum>
|
||||
</property>
|
||||
<property name="sizeHint" >
|
||||
<size>
|
||||
<width>111</width>
|
||||
<height>31</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item row="3" column="1" >
|
||||
<layout class="QVBoxLayout" >
|
||||
<property name="spacing" >
|
||||
<number>6</number>
|
||||
</property>
|
||||
<property name="leftMargin" >
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin" >
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin" >
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin" >
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QLabel" name="textLabel1_3" >
|
||||
<property name="enabled" >
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="text" >
|
||||
<string>Enter a new password:</string>
|
||||
</property>
|
||||
<property name="alignment" >
|
||||
<set>Qt::AlignAbsolute|Qt::AlignBottom|Qt::AlignCenter|Qt::AlignHCenter|Qt::AlignHorizontal_Mask|Qt::AlignJustify|Qt::AlignLeading|Qt::AlignLeft|Qt::AlignRight|Qt::AlignTop|Qt::AlignTrailing|Qt::AlignVCenter|Qt::AlignVertical_Mask</set>
|
||||
</property>
|
||||
<property name="buddy" >
|
||||
<cstring>_pass1</cstring>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="textLabel2_3" >
|
||||
<property name="enabled" >
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="text" >
|
||||
<string>Verify password:</string>
|
||||
</property>
|
||||
<property name="alignment" >
|
||||
<set>Qt::AlignAbsolute|Qt::AlignBottom|Qt::AlignCenter|Qt::AlignHCenter|Qt::AlignHorizontal_Mask|Qt::AlignJustify|Qt::AlignLeading|Qt::AlignLeft|Qt::AlignRight|Qt::AlignTop|Qt::AlignTrailing|Qt::AlignVCenter|Qt::AlignVertical_Mask</set>
|
||||
</property>
|
||||
<property name="buddy" >
|
||||
<cstring>_pass2</cstring>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="3" column="2" >
|
||||
<layout class="QVBoxLayout" >
|
||||
<property name="spacing" >
|
||||
<number>6</number>
|
||||
</property>
|
||||
<property name="leftMargin" >
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin" >
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin" >
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin" >
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QLineEdit" name="_pass1" >
|
||||
<property name="enabled" >
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="echoMode" >
|
||||
<enum>QLineEdit::Password</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLineEdit" name="_pass2" >
|
||||
<property name="enabled" >
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="echoMode" >
|
||||
<enum>QLineEdit::Password</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="3" column="3" >
|
||||
<spacer>
|
||||
<property name="orientation" >
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeType" >
|
||||
<enum>QSizePolicy::Expanding</enum>
|
||||
</property>
|
||||
<property name="sizeHint" >
|
||||
<size>
|
||||
<width>101</width>
|
||||
<height>21</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item row="4" column="1" colspan="2" >
|
||||
<spacer>
|
||||
<property name="orientation" >
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeType" >
|
||||
<enum>QSizePolicy::Expanding</enum>
|
||||
</property>
|
||||
<property name="sizeHint" >
|
||||
<size>
|
||||
<width>21</width>
|
||||
<height>70</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item row="5" column="0" colspan="4" >
|
||||
<widget class="QLabel" name="_matchLabel" >
|
||||
<property name="text" >
|
||||
<string/>
|
||||
</property>
|
||||
<property name="alignment" >
|
||||
<set>Qt::AlignAbsolute|Qt::AlignBottom|Qt::AlignCenter|Qt::AlignHCenter|Qt::AlignHorizontal_Mask|Qt::AlignJustify|Qt::AlignLeading|Qt::AlignLeft|Qt::AlignRight|Qt::AlignTop|Qt::AlignTrailing|Qt::AlignVCenter|Qt::AlignVertical_Mask</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections>
|
||||
<connection>
|
||||
<sender>_useWallet</sender>
|
||||
<signal>toggled(bool)</signal>
|
||||
<receiver>textLabel1_3</receiver>
|
||||
<slot>setEnabled(bool)</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel" >
|
||||
<x>108</x>
|
||||
<y>119</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel" >
|
||||
<x>217</x>
|
||||
<y>226</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>_useWallet</sender>
|
||||
<signal>toggled(bool)</signal>
|
||||
<receiver>_pass1</receiver>
|
||||
<slot>setEnabled(bool)</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel" >
|
||||
<x>455</x>
|
||||
<y>125</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel" >
|
||||
<x>394</x>
|
||||
<y>226</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>_useWallet</sender>
|
||||
<signal>toggled(bool)</signal>
|
||||
<receiver>textLabel2_3</receiver>
|
||||
<slot>setEnabled(bool)</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel" >
|
||||
<x>60</x>
|
||||
<y>120</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel" >
|
||||
<x>131</x>
|
||||
<y>257</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>_useWallet</sender>
|
||||
<signal>toggled(bool)</signal>
|
||||
<receiver>_pass2</receiver>
|
||||
<slot>setEnabled(bool)</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel" >
|
||||
<x>487</x>
|
||||
<y>124</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel" >
|
||||
<x>371</x>
|
||||
<y>257</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>_useWallet</sender>
|
||||
<signal>clicked()</signal>
|
||||
<receiver>_pass1</receiver>
|
||||
<slot>setFocus()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel" >
|
||||
<x>259</x>
|
||||
<y>119</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel" >
|
||||
<x>269</x>
|
||||
<y>237</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
</connections>
|
||||
</ui>
|
||||
+345
@@ -0,0 +1,345 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>KWalletWizardPagePasswordGpg</class>
|
||||
<widget class="QWidget" name="KWalletWizardPagePasswordGpg">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>448</width>
|
||||
<height>385</height>
|
||||
</rect>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||
<item>
|
||||
<widget class="QLabel" name="textLabel3">
|
||||
<property name="text">
|
||||
<string><html><head/><body><p>Various applications may attempt to use the KDE wallet to store passwords or other information such as web form data and cookies. If you would like these applications to use the wallet, you must enable it now and choose method for its encryption.</p><p>GPG method is more secure, but you must have configured at least one encrypting key on your system.</p><p>If you choose the classic format, be warned that the password you choose <span style=" font-style:italic;">cannot</span> be recovered if it is lost, and will allow anyone who knows it to obtain all the information contained in the wallet.</p></body></html></string>
|
||||
</property>
|
||||
<property name="textFormat">
|
||||
<enum>Qt::RichText</enum>
|
||||
</property>
|
||||
<property name="wordWrap">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="_useWallet">
|
||||
<property name="text">
|
||||
<string>Yes, I wish to use the KDE wallet to store my personal information.</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="_groupBox">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="MinimumExpanding">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="title">
|
||||
<string>What kind of encryption do you wish?</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<widget class="QRadioButton" name="_radioGpg">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Use GPG encryption, for better protection</string>
|
||||
</property>
|
||||
<property name="checked">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QRadioButton" name="_radioBlowfish">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Classic, blowfish encrypted file</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
||||
<item>
|
||||
<spacer>
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeType">
|
||||
<enum>QSizePolicy::Expanding</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>28</width>
|
||||
<height>28</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<layout class="QVBoxLayout">
|
||||
<property name="spacing">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<property name="margin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QLabel" name="textLabel1_3">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Enter a new password:</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignAbsolute|Qt::AlignBottom|Qt::AlignCenter|Qt::AlignHCenter|Qt::AlignHorizontal_Mask|Qt::AlignJustify|Qt::AlignLeading|Qt::AlignLeft|Qt::AlignRight|Qt::AlignTop|Qt::AlignTrailing|Qt::AlignVCenter|Qt::AlignVertical_Mask</set>
|
||||
</property>
|
||||
<property name="buddy">
|
||||
<cstring>_pass1</cstring>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="textLabel2_3">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Verify password:</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignAbsolute|Qt::AlignBottom|Qt::AlignCenter|Qt::AlignHCenter|Qt::AlignHorizontal_Mask|Qt::AlignJustify|Qt::AlignLeading|Qt::AlignLeft|Qt::AlignRight|Qt::AlignTop|Qt::AlignTrailing|Qt::AlignVCenter|Qt::AlignVertical_Mask</set>
|
||||
</property>
|
||||
<property name="buddy">
|
||||
<cstring>_pass2</cstring>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QVBoxLayout">
|
||||
<property name="spacing">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<property name="margin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QLineEdit" name="_pass1">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="echoMode">
|
||||
<enum>QLineEdit::Password</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLineEdit" name="_pass2">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="echoMode">
|
||||
<enum>QLineEdit::Password</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<spacer>
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeType">
|
||||
<enum>QSizePolicy::Expanding</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>98</width>
|
||||
<height>18</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="_matchLabel">
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignAbsolute|Qt::AlignBottom|Qt::AlignCenter|Qt::AlignHCenter|Qt::AlignHorizontal_Mask|Qt::AlignJustify|Qt::AlignLeading|Qt::AlignLeft|Qt::AlignRight|Qt::AlignTop|Qt::AlignTrailing|Qt::AlignVCenter|Qt::AlignVertical_Mask</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="verticalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>31</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<customwidgets>
|
||||
</customwidgets>
|
||||
<resources/>
|
||||
<connections>
|
||||
<connection>
|
||||
<sender>_radioBlowfish</sender>
|
||||
<signal>toggled(bool)</signal>
|
||||
<receiver>textLabel1_3</receiver>
|
||||
<slot>setEnabled(bool)</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>239</x>
|
||||
<y>220</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>213</x>
|
||||
<y>249</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>_radioBlowfish</sender>
|
||||
<signal>toggled(bool)</signal>
|
||||
<receiver>_pass1</receiver>
|
||||
<slot>setEnabled(bool)</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>239</x>
|
||||
<y>220</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>331</x>
|
||||
<y>249</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>_radioBlowfish</sender>
|
||||
<signal>toggled(bool)</signal>
|
||||
<receiver>textLabel2_3</receiver>
|
||||
<slot>setEnabled(bool)</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>239</x>
|
||||
<y>220</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>142</x>
|
||||
<y>277</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>_radioBlowfish</sender>
|
||||
<signal>toggled(bool)</signal>
|
||||
<receiver>_pass2</receiver>
|
||||
<slot>setEnabled(bool)</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>239</x>
|
||||
<y>220</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>331</x>
|
||||
<y>277</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>_radioBlowfish</sender>
|
||||
<signal>clicked()</signal>
|
||||
<receiver>_pass1</receiver>
|
||||
<slot>setFocus()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>239</x>
|
||||
<y>220</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>331</x>
|
||||
<y>249</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>_useWallet</sender>
|
||||
<signal>toggled(bool)</signal>
|
||||
<receiver>_groupBox</receiver>
|
||||
<slot>setEnabled(bool)</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>42</x>
|
||||
<y>112</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>33</x>
|
||||
<y>193</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>_useWallet</sender>
|
||||
<signal>toggled(bool)</signal>
|
||||
<receiver>_radioGpg</receiver>
|
||||
<slot>setEnabled(bool)</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>50</x>
|
||||
<y>112</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>63</x>
|
||||
<y>166</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>_useWallet</sender>
|
||||
<signal>toggled(bool)</signal>
|
||||
<receiver>_radioBlowfish</receiver>
|
||||
<slot>setEnabled(bool)</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>85</x>
|
||||
<y>112</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>97</x>
|
||||
<y>220</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
</connections>
|
||||
</ui>
|
||||
@@ -0,0 +1,222 @@
|
||||
/*
|
||||
This file is part of the KDE project
|
||||
SPDX-FileCopyrightText: 2008 Michael Leupold <lemma@confuego.org>
|
||||
SPDX-FileCopyrightText: 2014 Alex Fiestas <afiestas@kde.org>
|
||||
|
||||
SPDX-License-Identifier: LGPL-2.0-only
|
||||
*/
|
||||
|
||||
#include "kwalletd_debug.h"
|
||||
#include <KAboutData>
|
||||
#include <KConfig>
|
||||
#include <KConfigGroup>
|
||||
#include <KCrash>
|
||||
#include <KDBusService>
|
||||
#include <KLocalizedString>
|
||||
|
||||
#include <QApplication>
|
||||
#include <QCommandLineParser>
|
||||
#include <QIcon>
|
||||
#include <QSessionManager>
|
||||
#include <QString>
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include "backend/kwalletbackend.h" //For the hash size
|
||||
#include "kwalletd.h"
|
||||
#include "kwalletd_version.h"
|
||||
#include "kwalletfreedesktopservice.h"
|
||||
|
||||
#ifndef Q_OS_WIN
|
||||
#include <sys/socket.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/un.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#define BSIZE 1000
|
||||
static int pipefd = 0;
|
||||
static int socketfd = 0;
|
||||
#endif
|
||||
|
||||
static bool isWalletEnabled()
|
||||
{
|
||||
KConfig cfg(QStringLiteral("kwalletrc"));
|
||||
KConfigGroup walletGroup(&cfg, "Wallet");
|
||||
return walletGroup.readEntry("Enabled", true);
|
||||
}
|
||||
|
||||
#ifndef Q_OS_WIN
|
||||
// Waits until the PAM_MODULE sends the hash
|
||||
static char *waitForHash()
|
||||
{
|
||||
qCDebug(KWALLETD_LOG) << "kwalletd5: Waiting for hash on" << pipefd;
|
||||
int totalRead = 0;
|
||||
int readBytes = 0;
|
||||
int attempts = 0;
|
||||
char *buf = (char *)malloc(sizeof(char) * PBKDF2_SHA512_KEYSIZE);
|
||||
memset(buf, '\0', PBKDF2_SHA512_KEYSIZE);
|
||||
while (totalRead != PBKDF2_SHA512_KEYSIZE) {
|
||||
readBytes = read(pipefd, buf + totalRead, PBKDF2_SHA512_KEYSIZE - totalRead);
|
||||
if (readBytes == -1 || attempts > 5) {
|
||||
free(buf);
|
||||
return nullptr;
|
||||
}
|
||||
totalRead += readBytes;
|
||||
++attempts;
|
||||
}
|
||||
|
||||
close(pipefd);
|
||||
return buf;
|
||||
}
|
||||
|
||||
// Waits until startkde sends the environment variables
|
||||
static int waitForEnvironment()
|
||||
{
|
||||
qCDebug(KWALLETD_LOG) << "kwalletd5: waitingForEnvironment on:" << socketfd;
|
||||
|
||||
int s2;
|
||||
struct sockaddr_un remote;
|
||||
socklen_t t = sizeof(remote);
|
||||
if ((s2 = accept(socketfd, (struct sockaddr *)&remote, &t)) == -1) {
|
||||
qCWarning(KWALLETD_LOG) << "kwalletd5: Couldn't accept incoming connection";
|
||||
return -1;
|
||||
}
|
||||
qCDebug(KWALLETD_LOG) << "kwalletd5: client connected";
|
||||
|
||||
char str[BSIZE] = {'\0'};
|
||||
|
||||
int chop = 0;
|
||||
FILE *s3 = fdopen(dup(s2), "r");
|
||||
while (!feof(s3)) {
|
||||
if (fgets(str, BSIZE, s3)) {
|
||||
chop = strlen(str) - 1;
|
||||
if (str[chop] == '\n') {
|
||||
str[chop] = '\0';
|
||||
}
|
||||
putenv(strdup(str));
|
||||
}
|
||||
}
|
||||
fclose(s3);
|
||||
|
||||
qCDebug(KWALLETD_LOG) << "kwalletd5: client disconnected";
|
||||
close(socketfd);
|
||||
return 1;
|
||||
}
|
||||
|
||||
char *checkPamModule(int argc, char **argv)
|
||||
{
|
||||
qCDebug(KWALLETD_LOG) << "kwalletd5: Checking for pam module";
|
||||
char *hash = nullptr;
|
||||
int x = 1;
|
||||
for (; x < argc; ++x) {
|
||||
if (strcmp(argv[x], "--pam-login") != 0) {
|
||||
continue;
|
||||
}
|
||||
qCDebug(KWALLETD_LOG) << "kwalletd5: Got pam-login param";
|
||||
argv[x] = nullptr;
|
||||
x++;
|
||||
// We need at least 2 extra arguments after --pam-login
|
||||
if (x + 1 > argc) {
|
||||
qCWarning(KWALLETD_LOG) << "kwalletd5: Invalid arguments (less than needed)";
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// first socket for the hash, comes from a pipe
|
||||
pipefd = atoi(argv[x]);
|
||||
argv[x] = nullptr;
|
||||
x++;
|
||||
// second socket for environment, comes from a localsocket
|
||||
socketfd = atoi(argv[x]);
|
||||
argv[x] = nullptr;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!pipefd || !socketfd) {
|
||||
qCWarning(KWALLETD_LOG) << "Lacking a socket, pipe:" << pipefd << "env:" << socketfd;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
hash = waitForHash();
|
||||
|
||||
if (hash == nullptr || waitForEnvironment() == -1) {
|
||||
qCWarning(KWALLETD_LOG) << "kwalletd5: Hash or environment not received";
|
||||
free(hash);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return hash;
|
||||
}
|
||||
#endif
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
char *hash = nullptr;
|
||||
#ifndef Q_OS_WIN
|
||||
if (getenv("PAM_KWALLET5_LOGIN")) {
|
||||
hash = checkPamModule(argc, argv);
|
||||
}
|
||||
#endif
|
||||
|
||||
QApplication app(argc, argv);
|
||||
app.setWindowIcon(QIcon::fromTheme(QStringLiteral("kwalletmanager")));
|
||||
|
||||
// this kwalletd5 program should be able to start with KDE4's kwalletd
|
||||
// using kwalletd name would prevent KDBusService unique instance to initialize
|
||||
// so we setApplicationName("kwalletd6")
|
||||
KAboutData aboutdata("kwalletd6",
|
||||
i18n("KDE Wallet Service"),
|
||||
KWALLETD_VERSION_STRING,
|
||||
i18n("KDE Wallet Service"),
|
||||
KAboutLicense::LGPL,
|
||||
i18n("(C) 2002-2013, The KDE Developers"));
|
||||
aboutdata.addAuthor(i18n("Valentin Rusu"), i18n("Former Maintainer, GPG backend support"), QStringLiteral("kde@rusu.info"));
|
||||
aboutdata.addAuthor(i18n("Michael Leupold"), i18n("Former Maintainer"), QStringLiteral("lemma@confuego.org"));
|
||||
aboutdata.addAuthor(i18n("George Staikos"), i18n("Former maintainer"), QStringLiteral("staikos@kde.org"));
|
||||
aboutdata.addAuthor(i18n("Thiago Maceira"), i18n("D-Bus Interface"), QStringLiteral("thiago@kde.org"));
|
||||
|
||||
KAboutData::setApplicationData(aboutdata);
|
||||
|
||||
KCrash::initialize();
|
||||
|
||||
KDBusService dbusUniqueInstance(KDBusService::Unique);
|
||||
|
||||
// NOTE: the command should be parsed only after KDBusService instantiation
|
||||
QCommandLineParser cmdParser;
|
||||
aboutdata.setupCommandLine(&cmdParser);
|
||||
cmdParser.process(app);
|
||||
|
||||
app.setQuitOnLastWindowClosed(false);
|
||||
auto disableSessionManagement = [](QSessionManager &sm) {
|
||||
sm.setRestartHint(QSessionManager::RestartNever);
|
||||
};
|
||||
QObject::connect(&app, &QGuiApplication::commitDataRequest, disableSessionManagement);
|
||||
QObject::connect(&app, &QGuiApplication::saveStateRequest, disableSessionManagement);
|
||||
|
||||
// check if kwallet is disabled
|
||||
if (!isWalletEnabled()) {
|
||||
qCDebug(KWALLETD_LOG) << "kwalletd is disabled!";
|
||||
|
||||
/* Do not keep dbus-daemon waiting for the org.freedesktop.secrets if kwallet is disabled */
|
||||
KWalletFreedesktopService(nullptr);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
KWalletD walletd;
|
||||
qCDebug(KWALLETD_LOG) << "kwalletd6 started";
|
||||
|
||||
#ifndef Q_OS_WIN
|
||||
if (hash) {
|
||||
QByteArray passHash(hash, PBKDF2_SHA512_KEYSIZE);
|
||||
int wallet = walletd.pamOpen(KWallet::Wallet::LocalWallet(), passHash, 0);
|
||||
if (wallet < 0) {
|
||||
qCWarning(KWALLETD_LOG) << "Wallet failed to get opened by PAM, error code is" << wallet;
|
||||
} else {
|
||||
qCDebug(KWALLETD_LOG) << "Wallet opened by PAM";
|
||||
}
|
||||
free(hash);
|
||||
}
|
||||
#endif
|
||||
|
||||
return app.exec();
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
[D-BUS Service]
|
||||
Name=org.kde.kwalletd5
|
||||
Exec=@KDE_INSTALL_FULL_BINDIR@/kwalletd6
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
[D-BUS Service]
|
||||
Name=org.kde.kwalletd5
|
||||
Exec=kwalletd6
|
||||
@@ -0,0 +1,51 @@
|
||||
# SPDX-FileCopyrightText: None
|
||||
# SPDX-License-Identifier: CC0-1.0
|
||||
|
||||
[Desktop Entry]
|
||||
Type=Application
|
||||
Exec=kwalletd6
|
||||
Name=KDE Wallet Service
|
||||
Name[ar]=خدمة حافظة كِيدِي
|
||||
Name[az]=KDE Cüzdanı Xidməti
|
||||
Name[bg]=Услуга Портфейл на KDE
|
||||
Name[ca]=Servei de carteres de KDE
|
||||
Name[ca@valencia]=Servei de carteres de KDE
|
||||
Name[cs]=Služba úschovny KDE
|
||||
Name[de]=KDE-Dienst für Passwortspeicher
|
||||
Name[el]=Υπηρεσία πορτοφολιού του KDE
|
||||
Name[en_GB]=KDE Wallet Service
|
||||
Name[eo]=Trezoreja Servilo de KDE
|
||||
Name[es]=Servicio de carteras de KDE
|
||||
Name[eu]=KDEren zorro-zerbitzua
|
||||
Name[fi]=KDE:n lompakkopalvelin
|
||||
Name[fr]=Serveur de portefeuilles de KDE
|
||||
Name[gl]=Servizo de carteiras de KDE
|
||||
Name[he]=שירות הארנק של KDE
|
||||
Name[hu]=KDE jelszókezelő szolgáltatás
|
||||
Name[ia]=Servicio de Portafolio de KDE
|
||||
Name[is]=KDE Wallet-þjónusta
|
||||
Name[it]=Servizio portafogli di KDE
|
||||
Name[ka]=KDE-ის საფულის სერვისი
|
||||
Name[ko]=KDE 지갑 서비스
|
||||
Name[lt]=KDE slaptažodinės tarnyba
|
||||
Name[lv]=KDE maka serviss
|
||||
Name[nl]=KDE Portefeuilleservice
|
||||
Name[nn]=KDE Lommebok-teneste
|
||||
Name[pa]=KDE ਵਾਲਟ ਸਰਵਿਸ
|
||||
Name[pl]=Usługa Portfela KDE
|
||||
Name[pt]=Serviço da Carteira do KDE
|
||||
Name[pt_BR]=Serviço de carteiras do KDE
|
||||
Name[ro]=Serviciul de portofel KDE
|
||||
Name[ru]=Служба бумажника KDE
|
||||
Name[sa]=केडीई बटुआ सेवा
|
||||
Name[sk]=Služba KDE Wallet
|
||||
Name[sl]=Storitev KDE listnice
|
||||
Name[sv]=KDE:s plånbokstjänst
|
||||
Name[tr]=KDE Cüzdan Hizmeti
|
||||
Name[uk]=Служба торбинок KDE
|
||||
Name[vi]=Dịch vụ Ví KDE
|
||||
Name[x-test]=xxKDE Wallet Servicexx
|
||||
Name[zh_CN]=KDE 密码库服务
|
||||
Name[zh_TW]=KDE 錢包伺服器
|
||||
NoDisplay=true
|
||||
Icon=kwalletmanager
|
||||
@@ -0,0 +1,3 @@
|
||||
[D-BUS Service]
|
||||
Name=org.kde.kwalletd6
|
||||
Exec=@KDE_INSTALL_FULL_BINDIR@/kwalletd6
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
[D-BUS Service]
|
||||
Name=org.kde.kwalletd6
|
||||
Exec=kwalletd6
|
||||
Reference in New Issue
Block a user