mirror of
https://github.com/keepassxreboot/keepassxc.git
synced 2025-01-24 13:41:33 -05:00
FdoSecrest: allow remember decision for future entries
Also added a reset decision button in session management tab Fixes #7464 * Fix distorted button in settings page: the default margin in QToolBar is too large for our use case in a table row.
This commit is contained in:
parent
1e73d549ed
commit
7d3c3b09fb
@ -78,10 +78,6 @@
|
|||||||
<source>Command Line</source>
|
<source>Command Line</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
|
||||||
<source>Your decision for above entries will be remembered for the duration the requesting client is running.</source>
|
|
||||||
<translation type="unfinished"></translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
<message>
|
||||||
<source>Details</source>
|
<source>Details</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
@ -95,7 +91,15 @@
|
|||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<source>Deny All</source>
|
<source>Your decision will be remembered for the duration while both the requesting client AND KeePassXC are running.</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Deny All && Future</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Allow All && &Future</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
</context>
|
</context>
|
||||||
@ -5398,6 +5402,14 @@ We recommend you use the AppImage available on our downloads page.</source>
|
|||||||
<source>Disconnect this application</source>
|
<source>Disconnect this application</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Reset</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Reset any remembered decisions for this application</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
</context>
|
</context>
|
||||||
<context>
|
<context>
|
||||||
<name>Merger</name>
|
<name>Merger</name>
|
||||||
|
@ -73,8 +73,8 @@ namespace FdoSecrets
|
|||||||
|
|
||||||
bool DBusClient::itemKnown(const QUuid& uuid) const
|
bool DBusClient::itemKnown(const QUuid& uuid) const
|
||||||
{
|
{
|
||||||
return m_authorizedAll || m_allowed.contains(uuid) || m_allowedOnce.contains(uuid) || m_denied.contains(uuid)
|
return m_authorizedAll != AuthDecision::Undecided || m_allowed.contains(uuid) || m_allowedOnce.contains(uuid)
|
||||||
|| m_deniedOnce.contains(uuid);
|
|| m_denied.contains(uuid) || m_deniedOnce.contains(uuid);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool DBusClient::itemAuthorized(const QUuid& uuid) const
|
bool DBusClient::itemAuthorized(const QUuid& uuid) const
|
||||||
@ -83,10 +83,16 @@ namespace FdoSecrets
|
|||||||
// everyone is authorized if this is not enabled
|
// everyone is authorized if this is not enabled
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (m_authorizedAll) {
|
|
||||||
// this client is trusted
|
// check if we have catch-all decision
|
||||||
|
if (m_authorizedAll == AuthDecision::Allowed) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
if (m_authorizedAll == AuthDecision::Denied) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// individual decisions
|
||||||
if (m_deniedOnce.contains(uuid) || m_denied.contains(uuid)) {
|
if (m_deniedOnce.contains(uuid) || m_denied.contains(uuid)) {
|
||||||
// explicitly denied
|
// explicitly denied
|
||||||
return false;
|
return false;
|
||||||
@ -132,14 +138,21 @@ namespace FdoSecrets
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void DBusClient::setAllAuthorized(bool authorized)
|
void DBusClient::setAllAuthorized(AuthDecision authorized)
|
||||||
{
|
{
|
||||||
|
// once variants doesn't make sense here
|
||||||
|
if (authorized == AuthDecision::AllowedOnce) {
|
||||||
|
authorized = AuthDecision::Allowed;
|
||||||
|
}
|
||||||
|
if (authorized == AuthDecision::DeniedOnce) {
|
||||||
|
authorized = AuthDecision::Denied;
|
||||||
|
}
|
||||||
m_authorizedAll = authorized;
|
m_authorizedAll = authorized;
|
||||||
}
|
}
|
||||||
|
|
||||||
void DBusClient::clearAuthorization()
|
void DBusClient::clearAuthorization()
|
||||||
{
|
{
|
||||||
m_authorizedAll = false;
|
m_authorizedAll = AuthDecision::Undecided;
|
||||||
m_allowed.clear();
|
m_allowed.clear();
|
||||||
m_allowedOnce.clear();
|
m_allowedOnce.clear();
|
||||||
m_denied.clear();
|
m_denied.clear();
|
||||||
|
@ -159,7 +159,7 @@ namespace FdoSecrets
|
|||||||
/**
|
/**
|
||||||
* Authorize client to access all items.
|
* Authorize client to access all items.
|
||||||
*/
|
*/
|
||||||
void setAllAuthorized(bool authorized = true);
|
void setAllAuthorized(AuthDecision authorized);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Forget all previous authorization.
|
* Forget all previous authorization.
|
||||||
@ -176,7 +176,7 @@ namespace FdoSecrets
|
|||||||
QPointer<DBusMgr> m_dbus;
|
QPointer<DBusMgr> m_dbus;
|
||||||
PeerInfo m_process;
|
PeerInfo m_process;
|
||||||
|
|
||||||
bool m_authorizedAll{false};
|
AuthDecision m_authorizedAll{AuthDecision::Undecided};
|
||||||
|
|
||||||
QSet<QUuid> m_allowed{};
|
QSet<QUuid> m_allowed{};
|
||||||
QSet<QUuid> m_denied{};
|
QSet<QUuid> m_denied{};
|
||||||
|
@ -303,7 +303,7 @@ namespace FdoSecrets
|
|||||||
}
|
}
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
// attach a temporary property so later we can get the item
|
// attach a temporary property, so later we can get the item
|
||||||
// back from the dialog's result
|
// back from the dialog's result
|
||||||
entry->setProperty(FdoSecretsBackend, QVariant::fromValue(item.data()));
|
entry->setProperty(FdoSecretsBackend, QVariant::fromValue(item.data()));
|
||||||
entries << entry;
|
entries << entry;
|
||||||
@ -317,11 +317,11 @@ namespace FdoSecrets
|
|||||||
connect(ac, &AccessControlDialog::finished, ac, &AccessControlDialog::deleteLater);
|
connect(ac, &AccessControlDialog::finished, ac, &AccessControlDialog::deleteLater);
|
||||||
ac->open();
|
ac->open();
|
||||||
} else {
|
} else {
|
||||||
itemUnlockFinished({});
|
itemUnlockFinished({}, AuthDecision::Undecided);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void UnlockPrompt::itemUnlockFinished(const QHash<Entry*, AuthDecision>& decisions)
|
void UnlockPrompt::itemUnlockFinished(const QHash<Entry*, AuthDecision>& decisions, AuthDecision forFutureEntries)
|
||||||
{
|
{
|
||||||
auto client = m_client.lock();
|
auto client = m_client.lock();
|
||||||
if (!client) {
|
if (!client) {
|
||||||
@ -345,6 +345,9 @@ namespace FdoSecrets
|
|||||||
m_numRejected += 1;
|
m_numRejected += 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (forFutureEntries != AuthDecision::Undecided) {
|
||||||
|
client->setAllAuthorized(forFutureEntries);
|
||||||
|
}
|
||||||
// if anything is not unlocked, treat the whole prompt as dismissed
|
// if anything is not unlocked, treat the whole prompt as dismissed
|
||||||
// so the client has a chance to handle the error
|
// so the client has a chance to handle the error
|
||||||
finishPrompt(m_numRejected > 0);
|
finishPrompt(m_numRejected > 0);
|
||||||
|
@ -169,7 +169,7 @@ namespace FdoSecrets
|
|||||||
QVariant currentResult() const override;
|
QVariant currentResult() const override;
|
||||||
|
|
||||||
void collectionUnlockFinished(bool accepted);
|
void collectionUnlockFinished(bool accepted);
|
||||||
void itemUnlockFinished(const QHash<Entry*, AuthDecision>& results);
|
void itemUnlockFinished(const QHash<Entry*, AuthDecision>& results, AuthDecision forFutureEntries);
|
||||||
void unlockItems();
|
void unlockItems();
|
||||||
|
|
||||||
static constexpr auto FdoSecretsBackend = "FdoSecretsBackend";
|
static constexpr auto FdoSecretsBackend = "FdoSecretsBackend";
|
||||||
|
@ -68,8 +68,6 @@ AccessControlDialog::AccessControlDialog(QWindow* parent,
|
|||||||
m_ui->itemsTable->resizeColumnsToContents();
|
m_ui->itemsTable->resizeColumnsToContents();
|
||||||
|
|
||||||
// the info widget
|
// the info widget
|
||||||
m_ui->rememberMsg->setMessageType(MessageWidget::Information);
|
|
||||||
m_ui->rememberMsg->show(); // sync with m_rememberCheck->setChecked(true)
|
|
||||||
m_ui->exePathWarn->setMessageType(MessageWidget::Warning);
|
m_ui->exePathWarn->setMessageType(MessageWidget::Warning);
|
||||||
m_ui->exePathWarn->hide();
|
m_ui->exePathWarn->hide();
|
||||||
|
|
||||||
@ -81,19 +79,28 @@ AccessControlDialog::AccessControlDialog(QWindow* parent,
|
|||||||
m_ui->buttonBox->addButton(detailsButtonText + QStringLiteral(" >>"), QDialogButtonBox::HelpRole);
|
m_ui->buttonBox->addButton(detailsButtonText + QStringLiteral(" >>"), QDialogButtonBox::HelpRole);
|
||||||
detailsButton->setCheckable(true);
|
detailsButton->setCheckable(true);
|
||||||
|
|
||||||
|
QString tooltip = QStringLiteral("<p align='justify'>%1</p>")
|
||||||
|
.arg(tr("Your decision will be remembered for the duration while both the requesting client "
|
||||||
|
"AND KeePassXC are running."));
|
||||||
|
|
||||||
m_rememberCheck = new QCheckBox(tr("Remember"), this);
|
m_rememberCheck = new QCheckBox(tr("Remember"), this);
|
||||||
m_rememberCheck->setObjectName("rememberCheck"); // for testing
|
m_rememberCheck->setObjectName("rememberCheck"); // for testing
|
||||||
m_rememberCheck->setChecked(true);
|
m_rememberCheck->setChecked(true);
|
||||||
m_ui->buttonBox->addButton(m_rememberCheck, QDialogButtonBox::ActionRole);
|
m_ui->buttonBox->addButton(m_rememberCheck, QDialogButtonBox::ActionRole);
|
||||||
|
m_rememberCheck->setToolTip(tooltip);
|
||||||
|
|
||||||
auto allowButton = m_ui->buttonBox->addButton(tr("Allow Selected"), QDialogButtonBox::AcceptRole);
|
auto allowButton = m_ui->buttonBox->addButton(tr("Allow Selected"), QDialogButtonBox::AcceptRole);
|
||||||
allowButton->setDefault(true);
|
allowButton->setDefault(true);
|
||||||
|
|
||||||
auto cancelButton = m_ui->buttonBox->addButton(tr("Deny All"), QDialogButtonBox::RejectRole);
|
auto cancelButton = m_ui->buttonBox->addButton(tr("Deny All && Future"), QDialogButtonBox::RejectRole);
|
||||||
|
cancelButton->setToolTip(tooltip);
|
||||||
|
|
||||||
|
auto allowAllButton = m_ui->buttonBox->addButton(tr("Allow All && &Future"), QDialogButtonBox::AcceptRole);
|
||||||
|
allowAllButton->setToolTip(tooltip);
|
||||||
|
|
||||||
connect(cancelButton, &QPushButton::clicked, this, [this]() { done(DenyAll); });
|
connect(cancelButton, &QPushButton::clicked, this, [this]() { done(DenyAll); });
|
||||||
connect(allowButton, &QPushButton::clicked, this, [this]() { done(AllowSelected); });
|
connect(allowButton, &QPushButton::clicked, this, [this]() { done(AllowSelected); });
|
||||||
connect(m_rememberCheck, &QCheckBox::clicked, this, &AccessControlDialog::rememberChecked);
|
connect(allowAllButton, &QPushButton::clicked, this, [this]() { done(AllowAll); });
|
||||||
connect(detailsButton, &QPushButton::clicked, this, [=](bool checked) {
|
connect(detailsButton, &QPushButton::clicked, this, [=](bool checked) {
|
||||||
m_ui->detailsContainer->setVisible(checked);
|
m_ui->detailsContainer->setVisible(checked);
|
||||||
if (checked) {
|
if (checked) {
|
||||||
@ -119,6 +126,9 @@ AccessControlDialog::AccessControlDialog(QWindow* parent,
|
|||||||
detailsButton->click();
|
detailsButton->click();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// adjust size after we initialize the button box
|
||||||
|
adjustSize();
|
||||||
|
|
||||||
allowButton->setFocus();
|
allowButton->setFocus();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -146,15 +156,6 @@ void AccessControlDialog::setupDetails(const FdoSecrets::PeerInfo& info)
|
|||||||
m_ui->detailsContainer->hide();
|
m_ui->detailsContainer->hide();
|
||||||
}
|
}
|
||||||
|
|
||||||
void AccessControlDialog::rememberChecked(bool checked)
|
|
||||||
{
|
|
||||||
if (checked) {
|
|
||||||
m_ui->rememberMsg->animatedShow();
|
|
||||||
} else {
|
|
||||||
m_ui->rememberMsg->animatedHide();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void AccessControlDialog::denyEntryClicked(Entry* entry, const QModelIndex& index)
|
void AccessControlDialog::denyEntryClicked(Entry* entry, const QModelIndex& index)
|
||||||
{
|
{
|
||||||
m_decisions.insert(entry, AuthDecision::Denied);
|
m_decisions.insert(entry, AuthDecision::Denied);
|
||||||
@ -166,32 +167,35 @@ void AccessControlDialog::denyEntryClicked(Entry* entry, const QModelIndex& inde
|
|||||||
|
|
||||||
void AccessControlDialog::dialogFinished(int result)
|
void AccessControlDialog::dialogFinished(int result)
|
||||||
{
|
{
|
||||||
auto allow = m_rememberCheck->isChecked() ? AuthDecision::Allowed : AuthDecision::AllowedOnce;
|
auto decision = AuthDecision::Undecided;
|
||||||
auto deny = m_rememberCheck->isChecked() ? AuthDecision::Denied : AuthDecision::DeniedOnce;
|
auto futureDecision = AuthDecision::Undecided;
|
||||||
|
switch (result) {
|
||||||
|
case AllowSelected:
|
||||||
|
decision = m_rememberCheck->isChecked() ? AuthDecision::Allowed : AuthDecision::AllowedOnce;
|
||||||
|
break;
|
||||||
|
case AllowAll:
|
||||||
|
decision = AuthDecision::Allowed;
|
||||||
|
futureDecision = AuthDecision::Allowed;
|
||||||
|
break;
|
||||||
|
case DenyAll:
|
||||||
|
decision = AuthDecision::Denied;
|
||||||
|
futureDecision = AuthDecision::Denied;
|
||||||
|
break;
|
||||||
|
case Rejected:
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
for (int row = 0; row != m_model->rowCount({}); ++row) {
|
for (int row = 0; row != m_model->rowCount({}); ++row) {
|
||||||
auto entry = m_model->data(m_model->index(row, 2), Qt::EditRole).value<Entry*>();
|
auto entry = m_model->data(m_model->index(row, 2), Qt::EditRole).value<Entry*>();
|
||||||
auto selected = m_model->data(m_model->index(row, 0), Qt::CheckStateRole).value<Qt::CheckState>();
|
auto selected = m_model->data(m_model->index(row, 0), Qt::CheckStateRole).value<Qt::CheckState>();
|
||||||
Q_ASSERT(entry);
|
Q_ASSERT(entry);
|
||||||
switch (result) {
|
|
||||||
case AllowSelected:
|
auto undecided = result == AllowSelected && !selected;
|
||||||
if (selected) {
|
m_decisions.insert(entry, undecided ? AuthDecision::Undecided : decision);
|
||||||
m_decisions.insert(entry, allow);
|
|
||||||
} else {
|
|
||||||
m_decisions.insert(entry, AuthDecision::Undecided);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case DenyAll:
|
|
||||||
m_decisions.insert(entry, deny);
|
|
||||||
break;
|
|
||||||
case Rejected:
|
|
||||||
default:
|
|
||||||
m_decisions.insert(entry, AuthDecision::Undecided);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
emit finished(m_decisions);
|
emit finished(m_decisions, futureDecision);
|
||||||
}
|
}
|
||||||
|
|
||||||
QHash<Entry*, AuthDecision> AccessControlDialog::decisions() const
|
QHash<Entry*, AuthDecision> AccessControlDialog::decisions() const
|
||||||
|
@ -66,16 +66,16 @@ public:
|
|||||||
{
|
{
|
||||||
Rejected,
|
Rejected,
|
||||||
AllowSelected,
|
AllowSelected,
|
||||||
|
AllowAll,
|
||||||
DenyAll,
|
DenyAll,
|
||||||
};
|
};
|
||||||
|
|
||||||
QHash<Entry*, AuthDecision> decisions() const;
|
QHash<Entry*, AuthDecision> decisions() const;
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void finished(const QHash<Entry*, AuthDecision>& results);
|
void finished(const QHash<Entry*, AuthDecision>& results, AuthDecision forFutureEntries);
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void rememberChecked(bool checked);
|
|
||||||
void denyEntryClicked(Entry* entry, const QModelIndex& index);
|
void denyEntryClicked(Entry* entry, const QModelIndex& index);
|
||||||
void dialogFinished(int result);
|
void dialogFinished(int result);
|
||||||
|
|
||||||
|
@ -122,16 +122,6 @@
|
|||||||
</attribute>
|
</attribute>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
|
||||||
<widget class="MessageWidget" name="rememberMsg" native="true">
|
|
||||||
<property name="text" stdset="0">
|
|
||||||
<string>Your decision for above entries will be remembered for the duration the requesting client is running.</string>
|
|
||||||
</property>
|
|
||||||
<property name="closeButtonVisible" stdset="0">
|
|
||||||
<bool>false</bool>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item>
|
<item>
|
||||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||||
<item>
|
<item>
|
||||||
|
@ -26,7 +26,8 @@
|
|||||||
|
|
||||||
#include "gui/DatabaseWidget.h"
|
#include "gui/DatabaseWidget.h"
|
||||||
|
|
||||||
#include <QToolBar>
|
#include <QAction>
|
||||||
|
#include <QToolButton>
|
||||||
|
|
||||||
using FdoSecrets::DBusClientPtr;
|
using FdoSecrets::DBusClientPtr;
|
||||||
using FdoSecrets::SettingsClientModel;
|
using FdoSecrets::SettingsClientModel;
|
||||||
@ -34,7 +35,7 @@ using FdoSecrets::SettingsDatabaseModel;
|
|||||||
|
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
class ManageDatabase : public QToolBar
|
class ManageDatabase : public QWidget
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
@ -42,18 +43,9 @@ namespace
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
explicit ManageDatabase(FdoSecretsPlugin* plugin, QWidget* parent = nullptr)
|
explicit ManageDatabase(FdoSecretsPlugin* plugin, QWidget* parent = nullptr)
|
||||||
: QToolBar(parent)
|
: QWidget(parent)
|
||||||
, m_plugin(plugin)
|
, m_plugin(plugin)
|
||||||
{
|
{
|
||||||
setFloatable(false);
|
|
||||||
setMovable(false);
|
|
||||||
|
|
||||||
// use a dummy widget to center the buttons
|
|
||||||
auto spacer = new QWidget(this);
|
|
||||||
spacer->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred);
|
|
||||||
spacer->setVisible(true);
|
|
||||||
addWidget(spacer);
|
|
||||||
|
|
||||||
// db settings
|
// db settings
|
||||||
m_dbSettingsAct = new QAction(tr("Database settings"), this);
|
m_dbSettingsAct = new QAction(tr("Database settings"), this);
|
||||||
m_dbSettingsAct->setIcon(icons()->icon(QStringLiteral("document-edit")));
|
m_dbSettingsAct->setIcon(icons()->icon(QStringLiteral("document-edit")));
|
||||||
@ -63,14 +55,12 @@ namespace
|
|||||||
if (!m_dbWidget) {
|
if (!m_dbWidget) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
auto db = m_dbWidget;
|
|
||||||
m_plugin->serviceInstance()->doSwitchToDatabaseSettings(m_dbWidget);
|
m_plugin->serviceInstance()->doSwitchToDatabaseSettings(m_dbWidget);
|
||||||
});
|
});
|
||||||
addAction(m_dbSettingsAct);
|
|
||||||
|
|
||||||
// unlock/lock
|
// unlock/lock
|
||||||
m_lockAct = new QAction(tr("Unlock database"), this);
|
m_lockAct = new QAction(tr("Unlock database"), this);
|
||||||
m_lockAct->setIcon(icons()->icon(QStringLiteral("object-locked")));
|
m_lockAct->setIcon(icons()->icon(QStringLiteral("object-unlocked")));
|
||||||
m_lockAct->setToolTip(tr("Unlock database to show more information"));
|
m_lockAct->setToolTip(tr("Unlock database to show more information"));
|
||||||
connect(m_lockAct, &QAction::triggered, this, [this]() {
|
connect(m_lockAct, &QAction::triggered, this, [this]() {
|
||||||
if (!m_dbWidget) {
|
if (!m_dbWidget) {
|
||||||
@ -83,13 +73,23 @@ namespace
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
addAction(m_lockAct);
|
// layout
|
||||||
|
auto dbSettingsBtn = new QToolButton(this);
|
||||||
|
dbSettingsBtn->setAutoRaise(true);
|
||||||
|
dbSettingsBtn->setDefaultAction(m_dbSettingsAct);
|
||||||
|
|
||||||
// use a dummy widget to center the buttons
|
auto lockBtn = new QToolButton(this);
|
||||||
spacer = new QWidget(this);
|
lockBtn->setAutoRaise(true);
|
||||||
spacer->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred);
|
lockBtn->setDefaultAction(m_lockAct);
|
||||||
spacer->setVisible(true);
|
|
||||||
addWidget(spacer);
|
auto layout = new QHBoxLayout(this);
|
||||||
|
layout->setContentsMargins(1, 1, 1, 1);
|
||||||
|
layout->setSpacing(1);
|
||||||
|
|
||||||
|
layout->addStretch();
|
||||||
|
layout->addWidget(dbSettingsBtn);
|
||||||
|
layout->addWidget(lockBtn);
|
||||||
|
layout->addStretch();
|
||||||
}
|
}
|
||||||
|
|
||||||
DatabaseWidget* dbWidget() const
|
DatabaseWidget* dbWidget() const
|
||||||
@ -127,14 +127,20 @@ namespace
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
connect(m_dbWidget, &DatabaseWidget::databaseLocked, this, [this]() {
|
connect(m_dbWidget, &DatabaseWidget::databaseLocked, this, [this]() {
|
||||||
|
if (!m_lockAct || !m_dbSettingsAct) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
m_lockAct->setText(tr("Unlock database"));
|
m_lockAct->setText(tr("Unlock database"));
|
||||||
m_lockAct->setIcon(icons()->icon(QStringLiteral("object-locked")));
|
m_lockAct->setIcon(icons()->icon(QStringLiteral("object-unlocked")));
|
||||||
m_lockAct->setToolTip(tr("Unlock database to show more information"));
|
m_lockAct->setToolTip(tr("Unlock database to show more information"));
|
||||||
m_dbSettingsAct->setEnabled(false);
|
m_dbSettingsAct->setEnabled(false);
|
||||||
});
|
});
|
||||||
connect(m_dbWidget, &DatabaseWidget::databaseUnlocked, this, [this]() {
|
connect(m_dbWidget, &DatabaseWidget::databaseUnlocked, this, [this]() {
|
||||||
|
if (!m_lockAct || !m_dbSettingsAct) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
m_lockAct->setText(tr("Lock database"));
|
m_lockAct->setText(tr("Lock database"));
|
||||||
m_lockAct->setIcon(icons()->icon(QStringLiteral("object-unlocked")));
|
m_lockAct->setIcon(icons()->icon(QStringLiteral("object-locked")));
|
||||||
m_lockAct->setToolTip(tr("Lock database"));
|
m_lockAct->setToolTip(tr("Lock database"));
|
||||||
m_dbSettingsAct->setEnabled(true);
|
m_dbSettingsAct->setEnabled(true);
|
||||||
});
|
});
|
||||||
@ -147,7 +153,7 @@ namespace
|
|||||||
QAction* m_lockAct = nullptr;
|
QAction* m_lockAct = nullptr;
|
||||||
};
|
};
|
||||||
|
|
||||||
class ManageSession : public QToolBar
|
class ManageSession : public QWidget
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
@ -155,17 +161,8 @@ namespace
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
explicit ManageSession(QWidget* parent = nullptr)
|
explicit ManageSession(QWidget* parent = nullptr)
|
||||||
: QToolBar(parent)
|
: QWidget(parent)
|
||||||
{
|
{
|
||||||
setFloatable(false);
|
|
||||||
setMovable(false);
|
|
||||||
|
|
||||||
// use a dummy widget to center the buttons
|
|
||||||
auto spacer = new QWidget(this);
|
|
||||||
spacer->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred);
|
|
||||||
spacer->setVisible(true);
|
|
||||||
addWidget(spacer);
|
|
||||||
|
|
||||||
auto disconnectAct = new QAction(tr("Disconnect"), this);
|
auto disconnectAct = new QAction(tr("Disconnect"), this);
|
||||||
disconnectAct->setIcon(icons()->icon(QStringLiteral("dialog-close")));
|
disconnectAct->setIcon(icons()->icon(QStringLiteral("dialog-close")));
|
||||||
disconnectAct->setToolTip(tr("Disconnect this application"));
|
disconnectAct->setToolTip(tr("Disconnect this application"));
|
||||||
@ -174,13 +171,33 @@ namespace
|
|||||||
m_client->disconnectDBus();
|
m_client->disconnectDBus();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
addAction(disconnectAct);
|
|
||||||
|
|
||||||
// use a dummy widget to center the buttons
|
auto resetAct = new QAction(tr("Reset"), this);
|
||||||
spacer = new QWidget(this);
|
resetAct->setIcon(icons()->icon(QStringLiteral("refresh")));
|
||||||
spacer->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred);
|
resetAct->setToolTip(tr("Reset any remembered decisions for this application"));
|
||||||
spacer->setVisible(true);
|
connect(resetAct, &QAction::triggered, this, [this]() {
|
||||||
addWidget(spacer);
|
if (m_client) {
|
||||||
|
m_client->clearAuthorization();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// layout
|
||||||
|
auto disconnectBtn = new QToolButton(this);
|
||||||
|
disconnectBtn->setAutoRaise(true);
|
||||||
|
disconnectBtn->setDefaultAction(disconnectAct);
|
||||||
|
|
||||||
|
auto resetBtn = new QToolButton(this);
|
||||||
|
resetBtn->setAutoRaise(true);
|
||||||
|
resetBtn->setDefaultAction(resetAct);
|
||||||
|
|
||||||
|
auto layout = new QHBoxLayout(this);
|
||||||
|
layout->setContentsMargins(1, 1, 1, 1);
|
||||||
|
layout->setSpacing(1);
|
||||||
|
|
||||||
|
layout->addStretch();
|
||||||
|
layout->addWidget(resetBtn);
|
||||||
|
layout->addWidget(disconnectBtn);
|
||||||
|
layout->addStretch();
|
||||||
}
|
}
|
||||||
|
|
||||||
const DBusClientPtr& client() const
|
const DBusClientPtr& client() const
|
||||||
|
@ -608,6 +608,62 @@ void TestGuiFdoSecrets::testServiceUnlockItems()
|
|||||||
DBUS_COMPARE(item->locked(), false);
|
DBUS_COMPARE(item->locked(), false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void TestGuiFdoSecrets::testServiceUnlockItemsIncludeFutureEntries()
|
||||||
|
{
|
||||||
|
FdoSecrets::settings()->setConfirmAccessItem(true);
|
||||||
|
|
||||||
|
auto service = enableService();
|
||||||
|
VERIFY(service);
|
||||||
|
auto coll = getDefaultCollection(service);
|
||||||
|
VERIFY(coll);
|
||||||
|
auto item = getFirstItem(coll);
|
||||||
|
VERIFY(item);
|
||||||
|
auto sess = openSession(service, DhIetf1024Sha256Aes128CbcPkcs7::Algorithm);
|
||||||
|
VERIFY(sess);
|
||||||
|
|
||||||
|
DBUS_COMPARE(item->locked(), true);
|
||||||
|
|
||||||
|
{
|
||||||
|
DBUS_GET2(unlocked, promptPath, service->Unlock({QDBusObjectPath(item->path())}));
|
||||||
|
// nothing is unlocked immediately without user's action
|
||||||
|
COMPARE(unlocked, {});
|
||||||
|
|
||||||
|
auto prompt = getProxy<PromptProxy>(promptPath);
|
||||||
|
VERIFY(prompt);
|
||||||
|
QSignalSpy spyPromptCompleted(prompt.data(), SIGNAL(Completed(bool, QDBusVariant)));
|
||||||
|
VERIFY(spyPromptCompleted.isValid());
|
||||||
|
|
||||||
|
// nothing is unlocked yet
|
||||||
|
COMPARE(spyPromptCompleted.count(), 0);
|
||||||
|
DBUS_COMPARE(item->locked(), true);
|
||||||
|
|
||||||
|
// drive the prompt
|
||||||
|
DBUS_VERIFY(prompt->Prompt(""));
|
||||||
|
// remember and include future entries
|
||||||
|
VERIFY(driveAccessControlDialog(true, true));
|
||||||
|
|
||||||
|
VERIFY(waitForSignal(spyPromptCompleted, 1));
|
||||||
|
{
|
||||||
|
auto args = spyPromptCompleted.takeFirst();
|
||||||
|
COMPARE(args.size(), 2);
|
||||||
|
COMPARE(args.at(0).toBool(), false);
|
||||||
|
COMPARE(getSignalVariantArgument<QList<QDBusObjectPath>>(args.at(1)), {QDBusObjectPath(item->path())});
|
||||||
|
}
|
||||||
|
|
||||||
|
// unlocked
|
||||||
|
DBUS_COMPARE(item->locked(), false);
|
||||||
|
}
|
||||||
|
|
||||||
|
// check other entries are also unlocked
|
||||||
|
{
|
||||||
|
DBUS_GET(itemPaths, coll->items());
|
||||||
|
VERIFY(itemPaths.size() > 1);
|
||||||
|
auto anotherItem = getProxy<ItemProxy>(itemPaths.last());
|
||||||
|
VERIFY(anotherItem);
|
||||||
|
DBUS_COMPARE(anotherItem->locked(), false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void TestGuiFdoSecrets::testServiceLock()
|
void TestGuiFdoSecrets::testServiceLock()
|
||||||
{
|
{
|
||||||
auto service = enableService();
|
auto service = enableService();
|
||||||
@ -1635,7 +1691,7 @@ TestGuiFdoSecrets::encryptPassword(QByteArray value, QString contentType, const
|
|||||||
return m_clientCipher->encrypt(ss.unmarshal(m_plugin->dbus())).marshal();
|
return m_clientCipher->encrypt(ss.unmarshal(m_plugin->dbus())).marshal();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool TestGuiFdoSecrets::driveAccessControlDialog(bool remember)
|
bool TestGuiFdoSecrets::driveAccessControlDialog(bool remember, bool includeFutureEntries)
|
||||||
{
|
{
|
||||||
processEvents();
|
processEvents();
|
||||||
for (auto w : QApplication::topLevelWidgets()) {
|
for (auto w : QApplication::topLevelWidgets()) {
|
||||||
@ -1647,7 +1703,13 @@ bool TestGuiFdoSecrets::driveAccessControlDialog(bool remember)
|
|||||||
auto rememberCheck = dlg->findChild<QCheckBox*>("rememberCheck");
|
auto rememberCheck = dlg->findChild<QCheckBox*>("rememberCheck");
|
||||||
VERIFY(rememberCheck);
|
VERIFY(rememberCheck);
|
||||||
rememberCheck->setChecked(remember);
|
rememberCheck->setChecked(remember);
|
||||||
dlg->done(AccessControlDialog::AllowSelected);
|
|
||||||
|
if (includeFutureEntries) {
|
||||||
|
dlg->done(AccessControlDialog::AllowAll);
|
||||||
|
} else {
|
||||||
|
dlg->done(AccessControlDialog::AllowSelected);
|
||||||
|
}
|
||||||
|
|
||||||
processEvents();
|
processEvents();
|
||||||
VERIFY(dlg->isHidden());
|
VERIFY(dlg->isHidden());
|
||||||
return true;
|
return true;
|
||||||
|
@ -71,6 +71,7 @@ private slots:
|
|||||||
void testServiceUnlock();
|
void testServiceUnlock();
|
||||||
void testServiceUnlockDatabaseConcurrent();
|
void testServiceUnlockDatabaseConcurrent();
|
||||||
void testServiceUnlockItems();
|
void testServiceUnlockItems();
|
||||||
|
void testServiceUnlockItemsIncludeFutureEntries();
|
||||||
void testServiceLock();
|
void testServiceLock();
|
||||||
void testServiceLockConcurrent();
|
void testServiceLockConcurrent();
|
||||||
|
|
||||||
@ -103,7 +104,7 @@ private slots:
|
|||||||
private:
|
private:
|
||||||
bool driveUnlockDialog();
|
bool driveUnlockDialog();
|
||||||
bool driveNewDatabaseWizard();
|
bool driveNewDatabaseWizard();
|
||||||
bool driveAccessControlDialog(bool remember = true);
|
bool driveAccessControlDialog(bool remember = true, bool includeFutureEntries = false);
|
||||||
bool waitForSignal(QSignalSpy& spy, int expectedCount);
|
bool waitForSignal(QSignalSpy& spy, int expectedCount);
|
||||||
|
|
||||||
void processEvents();
|
void processEvents();
|
||||||
|
Loading…
Reference in New Issue
Block a user