mirror of
https://github.com/keepassxreboot/keepassxc.git
synced 2026-03-11 08:54:48 +00:00
This plugin implements the Secret Storage specification version 0.2. While running KeePassXC, it acts as a Secret Service server, registered on DBus, so clients like seahorse, python-secretstorage, or other implementations can connect and access the exposed database in KeePassXC. Squashed commits: - Initial code - Add SessionAdaptor and fix build - The skeletons for all dbus objects are in place - Implement collection creation and deletion - Emit collectionChanged signal - Implement app-wise settings page - Implement error message on GUI - Implement settings - Fix uuid to dbus path - Implement app level settings - Add freedesktop logo - Implement database settings page - Change database settings to a treeview - Move all settings read/write to one place - Rename SecretServiceOptionsPage to SettingsWidgetFdoSecrets - Fix selected group can not be saved if the user hasn't click on the item - Show selected group per database in app settings - Disable editing of various readonly widgets - Remove unused warning about non exposed database - Fix method signature on dbus adaptors - Fix type derived from DBusObject not recognized as QDBusContext - Resolve a few TODOs around error handling - Remove const when passing DBus exposed objects - Move dismiss to PromptBase - Implement per collection locking/unlocking - Fix const correctness on Item::setSecret - Implement SecretService::getSecrets - Rework the signal connections around collections. - Remove generateId from DBusObject - Per spec, use encoded label as DBus object path for collections - Fix some corner cases around collection name changes - Implement alias - Fix wrong alias dbus path - Implement encryption per spec - Cleanup SessionCipher - Implement searchItems for SecretService - Use Tools::uuidToHex - Implement Item attributes and delete - Implement createItem - Always check if the database is unlocked before perform any operation - Add missing ReadAlias/SetAlias on service - Reorganize and fix OpenSession always returning empty output - Overhaul error handling - Make sure default alias is always present - Remove collection aliases early in doDelete - Handles all content types, fix setProperties not working - Fix sometimes there is an extraneous leading zero when converting from MPI - Fix session encryption negotiation - Do not expose recycle bin - Protect against the methods not called from DBus - Also emit collectionChanged signal when lock state changes - Show notification when entry secret is requested - Add a README file - Actually close session when client disconnects - Gracefully return alternative label when collection is locked - Reorganize, rename secretservice to fdosecrets - Fix issues reported by clazy - Unify UI strings and fix icon - Implement a setting to skip confirmation when deleting entries from DBus - Remove some unused debugging log - Simply ignore errors when DBus context is not available. QtDBus won't set QDBusContext when deliver property get/set, and there is no way to get a QDBusMessage in property getter/setter. - Simplify GcryptMPI using std::unique_ptr and add unit test - Format code in fdosecrets - Move DBusReturnImpl to details namespace - Fix crash when locking a database: don't modify exposedGroup setting in customData when database is deleted - Make sure Collection::searchItems works, whether it's locked or not - Fix FdoSecrets::Collection becomes empty after a database reload - Fix crash when looping while modifying the list
173 lines
5.3 KiB
C++
173 lines
5.3 KiB
C++
/*
|
|
* Copyright (C) 2019 Aetf <aetf@unlimitedcodeworks.xyz>
|
|
*
|
|
* This program is free software: you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation, either version 2 or (at your option)
|
|
* version 3 of the License.
|
|
*
|
|
* This program 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 General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
#include "DatabaseSettingsWidgetFdoSecrets.h"
|
|
#include "ui_DatabaseSettingsWidgetFdoSecrets.h"
|
|
|
|
#include "fdosecrets/FdoSecretsSettings.h"
|
|
|
|
#include "core/Database.h"
|
|
#include "core/Group.h"
|
|
#include "core/Metadata.h"
|
|
#include "gui/group/GroupModel.h"
|
|
|
|
#include <QSortFilterProxyModel>
|
|
|
|
namespace
|
|
{
|
|
enum class ExposedGroup
|
|
{
|
|
None,
|
|
Expose
|
|
};
|
|
} // namespace
|
|
|
|
class DatabaseSettingsWidgetFdoSecrets::GroupModelNoRecycle : public QSortFilterProxyModel
|
|
{
|
|
Q_OBJECT
|
|
|
|
Database* m_db;
|
|
|
|
public:
|
|
explicit GroupModelNoRecycle(Database* db)
|
|
: m_db(db)
|
|
{
|
|
Q_ASSERT(db);
|
|
setSourceModel(new GroupModel(m_db, this));
|
|
}
|
|
|
|
Group* groupFromIndex(const QModelIndex& index) const
|
|
{
|
|
return groupFromSourceIndex(mapToSource(index));
|
|
}
|
|
|
|
Group* groupFromSourceIndex(const QModelIndex& index) const
|
|
{
|
|
auto groupModel = qobject_cast<GroupModel*>(sourceModel());
|
|
Q_ASSERT(groupModel);
|
|
return groupModel->groupFromIndex(index);
|
|
}
|
|
|
|
QModelIndex indexFromGroup(Group* group) const
|
|
{
|
|
auto groupModel = qobject_cast<GroupModel*>(sourceModel());
|
|
Q_ASSERT(groupModel);
|
|
return mapFromSource(groupModel->index(group));
|
|
}
|
|
|
|
protected:
|
|
bool filterAcceptsRow(int source_row, const QModelIndex& source_parent) const override
|
|
{
|
|
auto source_idx = sourceModel()->index(source_row, 0, source_parent);
|
|
if (!source_idx.isValid()) {
|
|
return false;
|
|
}
|
|
|
|
auto recycleBin = m_db->metadata()->recycleBin();
|
|
if (!recycleBin) {
|
|
return true;
|
|
}
|
|
|
|
// can not call mapFromSource, which internally calls filterAcceptsRow
|
|
auto group = groupFromSourceIndex(source_idx);
|
|
|
|
return group->uuid() != recycleBin->uuid();
|
|
}
|
|
};
|
|
|
|
DatabaseSettingsWidgetFdoSecrets::DatabaseSettingsWidgetFdoSecrets(QWidget* parent)
|
|
: QWidget(parent)
|
|
, m_ui(new Ui::DatabaseSettingsWidgetFdoSecrets)
|
|
{
|
|
m_ui->setupUi(this);
|
|
m_ui->buttonGroup->setId(m_ui->radioDonotExpose, static_cast<int>(ExposedGroup::None));
|
|
m_ui->buttonGroup->setId(m_ui->radioExpose, static_cast<int>(ExposedGroup::Expose));
|
|
|
|
// make sure there is at least a selection
|
|
connect(m_ui->radioExpose, &QRadioButton::toggled, this, [this](bool checked) {
|
|
if (checked && !m_ui->selectGroup->selectionModel()->hasSelection()) {
|
|
auto model = m_ui->selectGroup->model();
|
|
if (model) {
|
|
auto idx = model->index(0, 0);
|
|
m_ui->selectGroup->selectionModel()->select(idx, QItemSelectionModel::SelectCurrent);
|
|
}
|
|
}
|
|
});
|
|
}
|
|
|
|
DatabaseSettingsWidgetFdoSecrets::~DatabaseSettingsWidgetFdoSecrets() = default;
|
|
|
|
void DatabaseSettingsWidgetFdoSecrets::loadSettings(QSharedPointer<Database> db)
|
|
{
|
|
m_db = std::move(db);
|
|
|
|
m_model.reset(new GroupModelNoRecycle(m_db.data()));
|
|
m_ui->selectGroup->setModel(m_model.data());
|
|
|
|
auto group = m_db->rootGroup()->findGroupByUuid(FdoSecrets::settings()->exposedGroup(m_db));
|
|
if (!group) {
|
|
m_ui->radioDonotExpose->setChecked(true);
|
|
} else {
|
|
auto idx = m_model->indexFromGroup(group);
|
|
m_ui->selectGroup->selectionModel()->select(idx, QItemSelectionModel::SelectCurrent);
|
|
// expand all its parents
|
|
idx = idx.parent();
|
|
while (idx.isValid()) {
|
|
m_ui->selectGroup->expand(idx);
|
|
idx = idx.parent();
|
|
}
|
|
m_ui->radioExpose->setChecked(true);
|
|
}
|
|
|
|
settingsWarning();
|
|
}
|
|
|
|
void DatabaseSettingsWidgetFdoSecrets::saveSettings()
|
|
{
|
|
Q_ASSERT(m_db);
|
|
Q_ASSERT(m_model);
|
|
|
|
QUuid exposedGroup;
|
|
switch (static_cast<ExposedGroup>(m_ui->buttonGroup->checkedId())) {
|
|
case ExposedGroup::None:
|
|
break;
|
|
case ExposedGroup::Expose: {
|
|
auto idx = m_ui->selectGroup->selectionModel()->selectedIndexes().takeFirst();
|
|
Q_ASSERT(idx.isValid());
|
|
exposedGroup = m_model->groupFromIndex(idx)->uuid();
|
|
break;
|
|
}
|
|
}
|
|
|
|
FdoSecrets::settings()->setExposedGroup(m_db, exposedGroup);
|
|
}
|
|
|
|
void DatabaseSettingsWidgetFdoSecrets::settingsWarning()
|
|
{
|
|
if (FdoSecrets::settings()->isEnabled()) {
|
|
m_ui->groupBox->setEnabled(true);
|
|
m_ui->warningWidget->hideMessage();
|
|
} else {
|
|
m_ui->groupBox->setEnabled(false);
|
|
m_ui->warningWidget->showMessage(tr("Enable fd.o Secret Service to access these settings."),
|
|
MessageWidget::Warning);
|
|
m_ui->warningWidget->setCloseButtonVisible(false);
|
|
m_ui->warningWidget->setAutoHideTimeout(-1);
|
|
}
|
|
}
|
|
|
|
#include "DatabaseSettingsWidgetFdoSecrets.moc"
|