mirror of
https://github.com/keepassxreboot/keepassxc.git
synced 2025-01-27 23:07:11 -05:00
Improvements to confirm access dialog
* Disable access to entries immediately within the dialog * Use checkboxes instead of row selection * Add button to deny all access immediately
This commit is contained in:
parent
7d8072bf8f
commit
0383aa104c
@ -25,29 +25,54 @@ BrowserAccessControlDialog::BrowserAccessControlDialog(QWidget* parent)
|
|||||||
: QDialog(parent)
|
: QDialog(parent)
|
||||||
, m_ui(new Ui::BrowserAccessControlDialog())
|
, m_ui(new Ui::BrowserAccessControlDialog())
|
||||||
{
|
{
|
||||||
this->setWindowFlags(windowFlags() | Qt::WindowStaysOnTopHint);
|
setWindowFlags(windowFlags() | Qt::WindowStaysOnTopHint);
|
||||||
|
|
||||||
m_ui->setupUi(this);
|
m_ui->setupUi(this);
|
||||||
connect(m_ui->allowButton, SIGNAL(clicked()), this, SLOT(accept()));
|
|
||||||
connect(m_ui->denyButton, SIGNAL(clicked()), this, SLOT(reject()));
|
connect(m_ui->allowButton, SIGNAL(clicked()), SLOT(accept()));
|
||||||
|
connect(m_ui->cancelButton, SIGNAL(clicked()), SLOT(reject()));
|
||||||
}
|
}
|
||||||
|
|
||||||
BrowserAccessControlDialog::~BrowserAccessControlDialog()
|
BrowserAccessControlDialog::~BrowserAccessControlDialog()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void BrowserAccessControlDialog::setUrl(const QString& url)
|
void BrowserAccessControlDialog::setItems(const QList<Entry*>& items, const QString& hostname, bool httpAuth)
|
||||||
{
|
{
|
||||||
m_ui->label->setText(QString(tr("%1 has requested access to passwords for the following item(s).\n"
|
m_ui->siteLabel->setText(m_ui->siteLabel->text().arg(hostname));
|
||||||
"Please select whether you want to allow access."))
|
|
||||||
.arg(QUrl(url).host()));
|
|
||||||
}
|
|
||||||
|
|
||||||
void BrowserAccessControlDialog::setItems(const QList<Entry*>& items)
|
m_ui->rememberDecisionCheckBox->setVisible(!httpAuth);
|
||||||
{
|
m_ui->rememberDecisionCheckBox->setChecked(false);
|
||||||
for (Entry* entry : items) {
|
|
||||||
m_ui->itemsList->addItem(entry->title() + " - " + entry->username());
|
m_ui->itemsTable->setRowCount(items.count());
|
||||||
|
m_ui->itemsTable->setColumnCount(2);
|
||||||
|
|
||||||
|
int row = 0;
|
||||||
|
for (const auto& entry : items) {
|
||||||
|
auto item = new QTableWidgetItem();
|
||||||
|
item->setText(entry->title() + " - " + entry->username());
|
||||||
|
item->setData(Qt::UserRole, row);
|
||||||
|
item->setCheckState(Qt::Checked);
|
||||||
|
item->setFlags(item->flags() | Qt::ItemIsUserCheckable);
|
||||||
|
m_ui->itemsTable->setItem(row, 0, item);
|
||||||
|
|
||||||
|
auto disableButton = new QPushButton(tr("Disable for this site"));
|
||||||
|
connect(disableButton, &QAbstractButton::pressed, [&, item] {
|
||||||
|
emit disableAccess(item);
|
||||||
|
m_ui->itemsTable->removeRow(item->row());
|
||||||
|
if (m_ui->itemsTable->rowCount() == 0) {
|
||||||
|
reject();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
m_ui->itemsTable->setCellWidget(row, 1, disableButton);
|
||||||
|
|
||||||
|
++row;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
m_ui->itemsTable->resizeColumnsToContents();
|
||||||
|
m_ui->itemsTable->horizontalHeader()->setSectionResizeMode(0, QHeaderView::Stretch);
|
||||||
|
|
||||||
|
m_ui->allowButton->setFocus();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool BrowserAccessControlDialog::remember() const
|
bool BrowserAccessControlDialog::remember() const
|
||||||
@ -55,12 +80,26 @@ bool BrowserAccessControlDialog::remember() const
|
|||||||
return m_ui->rememberDecisionCheckBox->isChecked();
|
return m_ui->rememberDecisionCheckBox->isChecked();
|
||||||
}
|
}
|
||||||
|
|
||||||
void BrowserAccessControlDialog::setRemember(bool r)
|
QList<QTableWidgetItem*> BrowserAccessControlDialog::getSelectedEntries() const
|
||||||
{
|
{
|
||||||
m_ui->rememberDecisionCheckBox->setChecked(r);
|
QList<QTableWidgetItem*> selected;
|
||||||
|
for (int i = 0; i < m_ui->itemsTable->rowCount(); ++i) {
|
||||||
|
auto item = m_ui->itemsTable->item(i, 0);
|
||||||
|
if (item->checkState() == Qt::Checked) {
|
||||||
|
selected.append(item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return selected;
|
||||||
}
|
}
|
||||||
|
|
||||||
void BrowserAccessControlDialog::setHTTPAuth(bool httpAuth)
|
QList<QTableWidgetItem*> BrowserAccessControlDialog::getNonSelectedEntries() const
|
||||||
{
|
{
|
||||||
m_ui->rememberDecisionCheckBox->setVisible(!httpAuth);
|
QList<QTableWidgetItem*> notSelected;
|
||||||
|
for (int i = 0; i < m_ui->itemsTable->rowCount(); ++i) {
|
||||||
|
auto item = m_ui->itemsTable->item(i, 0);
|
||||||
|
if (item->checkState() != Qt::Checked) {
|
||||||
|
notSelected.append(item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return notSelected;
|
||||||
}
|
}
|
||||||
|
@ -21,6 +21,7 @@
|
|||||||
|
|
||||||
#include <QDialog>
|
#include <QDialog>
|
||||||
#include <QScopedPointer>
|
#include <QScopedPointer>
|
||||||
|
#include <QTableWidgetItem>
|
||||||
|
|
||||||
class Entry;
|
class Entry;
|
||||||
|
|
||||||
@ -35,13 +36,16 @@ class BrowserAccessControlDialog : public QDialog
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
explicit BrowserAccessControlDialog(QWidget* parent = nullptr);
|
explicit BrowserAccessControlDialog(QWidget* parent = nullptr);
|
||||||
~BrowserAccessControlDialog();
|
~BrowserAccessControlDialog() override;
|
||||||
|
|
||||||
void setUrl(const QString& url);
|
void setItems(const QList<Entry*>& items, const QString& hostname, bool httpAuth);
|
||||||
void setItems(const QList<Entry*>& items);
|
|
||||||
bool remember() const;
|
bool remember() const;
|
||||||
void setRemember(bool r);
|
|
||||||
void setHTTPAuth(bool httpAuth);
|
QList<QTableWidgetItem*> getSelectedEntries() const;
|
||||||
|
QList<QTableWidgetItem*> getNonSelectedEntries() const;
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void disableAccess(QTableWidgetItem* item);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QScopedPointer<Ui::BrowserAccessControlDialog> m_ui;
|
QScopedPointer<Ui::BrowserAccessControlDialog> m_ui;
|
||||||
|
@ -6,29 +6,50 @@
|
|||||||
<rect>
|
<rect>
|
||||||
<x>0</x>
|
<x>0</x>
|
||||||
<y>0</y>
|
<y>0</y>
|
||||||
<width>400</width>
|
<width>405</width>
|
||||||
<height>221</height>
|
<height>200</height>
|
||||||
</rect>
|
</rect>
|
||||||
</property>
|
</property>
|
||||||
<property name="windowTitle">
|
<property name="windowTitle">
|
||||||
<string>KeePassXC-Browser Confirm Access</string>
|
<string>KeePassXC - Browser Access Request</string>
|
||||||
</property>
|
</property>
|
||||||
<layout class="QVBoxLayout" name="verticalLayout">
|
<layout class="QVBoxLayout" name="verticalLayout">
|
||||||
<item>
|
<item>
|
||||||
<widget class="QLabel" name="label">
|
<widget class="QLabel" name="siteLabel">
|
||||||
|
<property name="font">
|
||||||
|
<font>
|
||||||
|
<weight>75</weight>
|
||||||
|
<bold>true</bold>
|
||||||
|
</font>
|
||||||
|
</property>
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string/>
|
<string>%1 is requesting access to the following entries:</string>
|
||||||
|
</property>
|
||||||
|
<property name="alignment">
|
||||||
|
<set>Qt::AlignCenter</set>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<widget class="QListWidget" name="itemsList"/>
|
<widget class="QTableWidget" name="itemsTable">
|
||||||
</item>
|
<property name="editTriggers">
|
||||||
<item>
|
<set>QAbstractItemView::NoEditTriggers</set>
|
||||||
<widget class="QCheckBox" name="rememberDecisionCheckBox">
|
|
||||||
<property name="text">
|
|
||||||
<string>Remember this decision</string>
|
|
||||||
</property>
|
</property>
|
||||||
|
<property name="showDropIndicator" stdset="0">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
|
<property name="selectionMode">
|
||||||
|
<enum>QAbstractItemView::NoSelection</enum>
|
||||||
|
</property>
|
||||||
|
<property name="cornerButtonEnabled">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
|
<attribute name="horizontalHeaderVisible">
|
||||||
|
<bool>false</bool>
|
||||||
|
</attribute>
|
||||||
|
<attribute name="verticalHeaderVisible">
|
||||||
|
<bool>false</bool>
|
||||||
|
</attribute>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
@ -47,22 +68,35 @@
|
|||||||
</spacer>
|
</spacer>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<widget class="QPushButton" name="allowButton">
|
<widget class="QCheckBox" name="rememberDecisionCheckBox">
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>Remember access to checked entries</string>
|
||||||
|
</property>
|
||||||
<property name="accessibleName">
|
<property name="accessibleName">
|
||||||
<string>Allow access</string>
|
<string>Remember access to checked entries</string>
|
||||||
</property>
|
</property>
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Allow</string>
|
<string>Remember</string>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<widget class="QPushButton" name="denyButton">
|
<widget class="QPushButton" name="allowButton">
|
||||||
<property name="accessibleName">
|
<property name="accessibleName">
|
||||||
<string>Deny access</string>
|
<string>Allow access to entries</string>
|
||||||
</property>
|
</property>
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Deny</string>
|
<string>Allow Selected</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QPushButton" name="cancelButton">
|
||||||
|
<property name="text">
|
||||||
|
<string>Deny All</string>
|
||||||
|
</property>
|
||||||
|
<property name="autoDefault">
|
||||||
|
<bool>false</bool>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
|
@ -417,8 +417,9 @@ QJsonArray BrowserService::findMatchingEntries(const QString& id,
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Confirm entries
|
// Confirm entries
|
||||||
if (confirmEntries(pwEntriesToConfirm, url, host, submitUrl, realm, httpAuth)) {
|
QList<Entry*> selectedEntriesToConfirm = confirmEntries(pwEntriesToConfirm, url, host, submitHost, realm, httpAuth);
|
||||||
pwEntries.append(pwEntriesToConfirm);
|
if (!selectedEntriesToConfirm.isEmpty()) {
|
||||||
|
pwEntries.append(selectedEntriesToConfirm);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pwEntries.isEmpty()) {
|
if (pwEntries.isEmpty()) {
|
||||||
@ -788,59 +789,66 @@ QList<Entry*> BrowserService::sortEntries(QList<Entry*>& pwEntries, const QStrin
|
|||||||
return results;
|
return results;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool BrowserService::confirmEntries(QList<Entry*>& pwEntriesToConfirm,
|
QList<Entry*> BrowserService::confirmEntries(QList<Entry*>& pwEntriesToConfirm,
|
||||||
const QString& url,
|
const QString& url,
|
||||||
const QString& host,
|
const QString& host,
|
||||||
const QString& submitUrl,
|
const QString& submitHost,
|
||||||
const QString& realm,
|
const QString& realm,
|
||||||
const bool httpAuth)
|
const bool httpAuth)
|
||||||
{
|
{
|
||||||
if (pwEntriesToConfirm.isEmpty() || m_dialogActive) {
|
if (pwEntriesToConfirm.isEmpty() || m_dialogActive) {
|
||||||
return false;
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
m_dialogActive = true;
|
m_dialogActive = true;
|
||||||
BrowserAccessControlDialog accessControlDialog;
|
BrowserAccessControlDialog accessControlDialog;
|
||||||
|
|
||||||
connect(m_dbTabWidget, SIGNAL(databaseLocked(DatabaseWidget*)), &accessControlDialog, SLOT(reject()));
|
connect(m_dbTabWidget, SIGNAL(databaseLocked(DatabaseWidget*)), &accessControlDialog, SLOT(reject()));
|
||||||
accessControlDialog.setUrl(!submitUrl.isEmpty() ? submitUrl : url);
|
connect(&accessControlDialog, &BrowserAccessControlDialog::disableAccess, [&](QTableWidgetItem* item) {
|
||||||
accessControlDialog.setItems(pwEntriesToConfirm);
|
auto entry = pwEntriesToConfirm[item->row()];
|
||||||
accessControlDialog.setHTTPAuth(httpAuth);
|
BrowserEntryConfig config;
|
||||||
|
config.load(entry);
|
||||||
|
config.deny(host);
|
||||||
|
if (!submitHost.isEmpty() && host != submitHost) {
|
||||||
|
config.deny(submitHost);
|
||||||
|
}
|
||||||
|
if (!realm.isEmpty()) {
|
||||||
|
config.setRealm(realm);
|
||||||
|
}
|
||||||
|
config.save(entry);
|
||||||
|
});
|
||||||
|
|
||||||
|
accessControlDialog.setItems(pwEntriesToConfirm, !submitHost.isEmpty() ? submitHost : url, httpAuth);
|
||||||
|
|
||||||
raiseWindow();
|
raiseWindow();
|
||||||
accessControlDialog.show();
|
accessControlDialog.show();
|
||||||
accessControlDialog.activateWindow();
|
accessControlDialog.activateWindow();
|
||||||
accessControlDialog.raise();
|
accessControlDialog.raise();
|
||||||
|
|
||||||
const QString submitHost = QUrl(submitUrl).host();
|
QList<Entry*> allowedEntries;
|
||||||
int res = accessControlDialog.exec();
|
if (accessControlDialog.exec() == QDialog::Accepted) {
|
||||||
if (accessControlDialog.remember()) {
|
const auto selectedEntries = accessControlDialog.getSelectedEntries();
|
||||||
for (auto* entry : pwEntriesToConfirm) {
|
for (auto item : accessControlDialog.getSelectedEntries()) {
|
||||||
BrowserEntryConfig config;
|
auto entry = pwEntriesToConfirm[item->row()];
|
||||||
config.load(entry);
|
if (accessControlDialog.remember()) {
|
||||||
if (res == QDialog::Accepted) {
|
BrowserEntryConfig config;
|
||||||
|
config.load(entry);
|
||||||
config.allow(host);
|
config.allow(host);
|
||||||
if (!submitHost.isEmpty() && host != submitHost)
|
|
||||||
config.allow(submitHost);
|
|
||||||
} else if (res == QDialog::Rejected) {
|
|
||||||
config.deny(host);
|
|
||||||
if (!submitHost.isEmpty() && host != submitHost) {
|
if (!submitHost.isEmpty() && host != submitHost) {
|
||||||
config.deny(submitHost);
|
config.allow(submitHost);
|
||||||
}
|
}
|
||||||
|
if (!realm.isEmpty()) {
|
||||||
|
config.setRealm(realm);
|
||||||
|
}
|
||||||
|
config.save(entry);
|
||||||
}
|
}
|
||||||
if (!realm.isEmpty()) {
|
allowedEntries.append(entry);
|
||||||
config.setRealm(realm);
|
|
||||||
}
|
|
||||||
config.save(entry);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
m_dialogActive = false;
|
m_dialogActive = false;
|
||||||
hideWindow();
|
hideWindow();
|
||||||
if (res == QDialog::Accepted) {
|
return allowedEntries;
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QJsonObject BrowserService::prepareEntry(const Entry* entry)
|
QJsonObject BrowserService::prepareEntry(const Entry* entry)
|
||||||
|
@ -118,12 +118,12 @@ private:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
QList<Entry*> sortEntries(QList<Entry*>& pwEntries, const QString& host, const QString& submitUrl);
|
QList<Entry*> sortEntries(QList<Entry*>& pwEntries, const QString& host, const QString& submitUrl);
|
||||||
bool confirmEntries(QList<Entry*>& pwEntriesToConfirm,
|
QList<Entry*> confirmEntries(QList<Entry*>& pwEntriesToConfirm,
|
||||||
const QString& url,
|
const QString& url,
|
||||||
const QString& host,
|
const QString& host,
|
||||||
const QString& submitUrl,
|
const QString& submitUrl,
|
||||||
const QString& realm,
|
const QString& realm,
|
||||||
const bool httpAuth);
|
const bool httpAuth);
|
||||||
QJsonObject prepareEntry(const Entry* entry);
|
QJsonObject prepareEntry(const Entry* entry);
|
||||||
Access checkAccess(const Entry* entry, const QString& host, const QString& submitHost, const QString& realm);
|
Access checkAccess(const Entry* entry, const QString& host, const QString& submitHost, const QString& realm);
|
||||||
Group* getDefaultEntryGroup(const QSharedPointer<Database>& selectedDb = {});
|
Group* getDefaultEntryGroup(const QSharedPointer<Database>& selectedDb = {});
|
||||||
|
Loading…
x
Reference in New Issue
Block a user