mirror of
https://github.com/keepassxreboot/keepassxc.git
synced 2024-10-01 01:26:01 -04:00
Browser: Asynchronous Access Confirm dialog
This commit is contained in:
parent
612c1098ea
commit
ef6d8f1138
@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2013 Francois Ferrand
|
* Copyright (C) 2013 Francois Ferrand
|
||||||
* Copyright (C) 2017 KeePassXC Team <team@keepassxc.org>
|
* Copyright (C) 2022 KeePassXC Team <team@keepassxc.org>
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* 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
|
* it under the terms of the GNU General Public License as published by
|
||||||
@ -21,25 +21,41 @@
|
|||||||
#include <QUrl>
|
#include <QUrl>
|
||||||
|
|
||||||
#include "core/Entry.h"
|
#include "core/Entry.h"
|
||||||
|
#include <QCloseEvent>
|
||||||
|
|
||||||
BrowserAccessControlDialog::BrowserAccessControlDialog(QWidget* parent)
|
BrowserAccessControlDialog::BrowserAccessControlDialog(QWidget* parent)
|
||||||
: QDialog(parent)
|
: QDialog(parent)
|
||||||
, m_ui(new Ui::BrowserAccessControlDialog())
|
, m_ui(new Ui::BrowserAccessControlDialog())
|
||||||
|
, m_entriesAccepted(false)
|
||||||
{
|
{
|
||||||
setWindowFlags(windowFlags() | Qt::WindowStaysOnTopHint);
|
setWindowFlags(windowFlags() | Qt::WindowStaysOnTopHint);
|
||||||
|
|
||||||
m_ui->setupUi(this);
|
m_ui->setupUi(this);
|
||||||
|
|
||||||
connect(m_ui->allowButton, SIGNAL(clicked()), SLOT(accept()));
|
connect(m_ui->allowButton, SIGNAL(clicked()), SLOT(acceptSelections()));
|
||||||
connect(m_ui->cancelButton, SIGNAL(clicked()), SLOT(reject()));
|
connect(m_ui->denyButton, SIGNAL(clicked()), SLOT(rejectSelections()));
|
||||||
|
connect(this, SIGNAL(rejected()), this, SIGNAL(closed()));
|
||||||
}
|
}
|
||||||
|
|
||||||
BrowserAccessControlDialog::~BrowserAccessControlDialog()
|
BrowserAccessControlDialog::~BrowserAccessControlDialog()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void BrowserAccessControlDialog::setItems(const QList<Entry*>& items, const QString& urlString, bool httpAuth)
|
void BrowserAccessControlDialog::closeEvent(QCloseEvent* event)
|
||||||
{
|
{
|
||||||
|
// Emits closed signal when clicking X from title bar
|
||||||
|
emit closed();
|
||||||
|
event->accept();
|
||||||
|
}
|
||||||
|
|
||||||
|
void BrowserAccessControlDialog::setItems(const QList<Entry*>& entriesToConfirm,
|
||||||
|
const QList<Entry*>& allowedEntries,
|
||||||
|
const QString& urlString,
|
||||||
|
bool httpAuth)
|
||||||
|
{
|
||||||
|
m_entriesToConfirm = entriesToConfirm;
|
||||||
|
m_allowedEntries = allowedEntries;
|
||||||
|
|
||||||
QUrl url(urlString);
|
QUrl url(urlString);
|
||||||
m_ui->siteLabel->setText(m_ui->siteLabel->text().arg(
|
m_ui->siteLabel->setText(m_ui->siteLabel->text().arg(
|
||||||
url.toDisplayString(QUrl::RemoveUserInfo | QUrl::RemovePath | QUrl::RemoveQuery | QUrl::RemoveFragment)));
|
url.toDisplayString(QUrl::RemoveUserInfo | QUrl::RemovePath | QUrl::RemoveQuery | QUrl::RemoveFragment)));
|
||||||
@ -47,11 +63,11 @@ void BrowserAccessControlDialog::setItems(const QList<Entry*>& items, const QStr
|
|||||||
m_ui->rememberDecisionCheckBox->setVisible(!httpAuth);
|
m_ui->rememberDecisionCheckBox->setVisible(!httpAuth);
|
||||||
m_ui->rememberDecisionCheckBox->setChecked(false);
|
m_ui->rememberDecisionCheckBox->setChecked(false);
|
||||||
|
|
||||||
m_ui->itemsTable->setRowCount(items.count());
|
m_ui->itemsTable->setRowCount(entriesToConfirm.count());
|
||||||
m_ui->itemsTable->setColumnCount(2);
|
m_ui->itemsTable->setColumnCount(2);
|
||||||
|
|
||||||
int row = 0;
|
int row = 0;
|
||||||
for (const auto& entry : items) {
|
for (const auto& entry : entriesToConfirm) {
|
||||||
auto item = new QTableWidgetItem();
|
auto item = new QTableWidgetItem();
|
||||||
item->setText(entry->title() + " - " + entry->username());
|
item->setText(entry->title() + " - " + entry->username());
|
||||||
item->setData(Qt::UserRole, row);
|
item->setData(Qt::UserRole, row);
|
||||||
@ -61,11 +77,13 @@ void BrowserAccessControlDialog::setItems(const QList<Entry*>& items, const QStr
|
|||||||
|
|
||||||
auto disableButton = new QPushButton(tr("Disable for this site"));
|
auto disableButton = new QPushButton(tr("Disable for this site"));
|
||||||
disableButton->setAutoDefault(false);
|
disableButton->setAutoDefault(false);
|
||||||
|
|
||||||
connect(disableButton, &QAbstractButton::pressed, [&, item] {
|
connect(disableButton, &QAbstractButton::pressed, [&, item] {
|
||||||
emit disableAccess(item);
|
emit disableAccess(item);
|
||||||
m_ui->itemsTable->removeRow(item->row());
|
m_ui->itemsTable->removeRow(item->row());
|
||||||
|
|
||||||
if (m_ui->itemsTable->rowCount() == 0) {
|
if (m_ui->itemsTable->rowCount() == 0) {
|
||||||
reject();
|
emit closed();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
m_ui->itemsTable->setCellWidget(row, 1, disableButton);
|
m_ui->itemsTable->setCellWidget(row, 1, disableButton);
|
||||||
@ -84,6 +102,11 @@ bool BrowserAccessControlDialog::remember() const
|
|||||||
return m_ui->rememberDecisionCheckBox->isChecked();
|
return m_ui->rememberDecisionCheckBox->isChecked();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool BrowserAccessControlDialog::entriesAccepted() const
|
||||||
|
{
|
||||||
|
return m_entriesAccepted;
|
||||||
|
}
|
||||||
|
|
||||||
QList<QTableWidgetItem*> BrowserAccessControlDialog::getSelectedEntries() const
|
QList<QTableWidgetItem*> BrowserAccessControlDialog::getSelectedEntries() const
|
||||||
{
|
{
|
||||||
QList<QTableWidgetItem*> selected;
|
QList<QTableWidgetItem*> selected;
|
||||||
@ -107,3 +130,19 @@ QList<QTableWidgetItem*> BrowserAccessControlDialog::getNonSelectedEntries() con
|
|||||||
}
|
}
|
||||||
return notSelected;
|
return notSelected;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void BrowserAccessControlDialog::acceptSelections()
|
||||||
|
{
|
||||||
|
auto selectedEntries = getSelectedEntries();
|
||||||
|
|
||||||
|
m_entriesAccepted = true;
|
||||||
|
emit acceptEntries(selectedEntries, m_entriesToConfirm, m_allowedEntries);
|
||||||
|
emit closed();
|
||||||
|
}
|
||||||
|
|
||||||
|
void BrowserAccessControlDialog::rejectSelections()
|
||||||
|
{
|
||||||
|
auto rejectedEntries = getNonSelectedEntries();
|
||||||
|
emit rejectEntries(rejectedEntries, m_entriesToConfirm);
|
||||||
|
emit closed();
|
||||||
|
}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2013 Francois Ferrand
|
* Copyright (C) 2013 Francois Ferrand
|
||||||
* Copyright (C) 2017 KeePassXC Team <team@keepassxc.org>
|
* Copyright (C) 2022 KeePassXC Team <team@keepassxc.org>
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* 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
|
* it under the terms of the GNU General Public License as published by
|
||||||
@ -37,17 +37,34 @@ public:
|
|||||||
explicit BrowserAccessControlDialog(QWidget* parent = nullptr);
|
explicit BrowserAccessControlDialog(QWidget* parent = nullptr);
|
||||||
~BrowserAccessControlDialog() override;
|
~BrowserAccessControlDialog() override;
|
||||||
|
|
||||||
void setItems(const QList<Entry*>& items, const QString& urlString, bool httpAuth);
|
void setItems(const QList<Entry*>& entriesToConfirm,
|
||||||
|
const QList<Entry*>& allowedEntries,
|
||||||
|
const QString& urlString,
|
||||||
|
bool httpAuth);
|
||||||
bool remember() const;
|
bool remember() const;
|
||||||
|
bool entriesAccepted() const;
|
||||||
|
|
||||||
QList<QTableWidgetItem*> getSelectedEntries() const;
|
QList<QTableWidgetItem*> getSelectedEntries() const;
|
||||||
QList<QTableWidgetItem*> getNonSelectedEntries() const;
|
QList<QTableWidgetItem*> getNonSelectedEntries() const;
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void disableAccess(QTableWidgetItem* item);
|
void disableAccess(QTableWidgetItem* item);
|
||||||
|
void acceptEntries(QList<QTableWidgetItem*> items, QList<Entry*> entriesToConfirm, QList<Entry*> allowedEntries);
|
||||||
|
void rejectEntries(QList<QTableWidgetItem*> items, QList<Entry*> entriesToConfirm);
|
||||||
|
void closed();
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
void acceptSelections();
|
||||||
|
void rejectSelections();
|
||||||
|
|
||||||
|
private:
|
||||||
|
void closeEvent(QCloseEvent* event) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QScopedPointer<Ui::BrowserAccessControlDialog> m_ui;
|
QScopedPointer<Ui::BrowserAccessControlDialog> m_ui;
|
||||||
|
QList<Entry*> m_entriesToConfirm;
|
||||||
|
QList<Entry*> m_allowedEntries;
|
||||||
|
bool m_entriesAccepted;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // BROWSERACCESSCONTROLDIALOG_H
|
#endif // BROWSERACCESSCONTROLDIALOG_H
|
||||||
|
@ -97,7 +97,7 @@
|
|||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<widget class="QPushButton" name="cancelButton">
|
<widget class="QPushButton" name="denyButton">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Deny All</string>
|
<string>Deny All</string>
|
||||||
</property>
|
</property>
|
||||||
|
@ -76,7 +76,7 @@ QJsonObject BrowserAction::handleAction(QLocalSocket* socket, const QJsonObject&
|
|||||||
} else if (action.compare("test-associate") == 0) {
|
} else if (action.compare("test-associate") == 0) {
|
||||||
return handleTestAssociate(json, action);
|
return handleTestAssociate(json, action);
|
||||||
} else if (action.compare("get-logins") == 0) {
|
} else if (action.compare("get-logins") == 0) {
|
||||||
return handleGetLogins(json, action);
|
return handleGetLogins(socket, json, action);
|
||||||
} else if (action.compare("generate-password") == 0) {
|
} else if (action.compare("generate-password") == 0) {
|
||||||
return handleGeneratePassword(socket, json, action);
|
return handleGeneratePassword(socket, json, action);
|
||||||
} else if (action.compare("set-login") == 0) {
|
} else if (action.compare("set-login") == 0) {
|
||||||
@ -231,10 +231,11 @@ QJsonObject BrowserAction::handleTestAssociate(const QJsonObject& json, const QS
|
|||||||
return buildResponse(action, message, newNonce);
|
return buildResponse(action, message, newNonce);
|
||||||
}
|
}
|
||||||
|
|
||||||
QJsonObject BrowserAction::handleGetLogins(const QJsonObject& json, const QString& action)
|
QJsonObject BrowserAction::handleGetLogins(QLocalSocket* socket, const QJsonObject& json, const QString& action)
|
||||||
{
|
{
|
||||||
const QString hash = browserService()->getDatabaseHash();
|
const QString hash = browserService()->getDatabaseHash();
|
||||||
const QString nonce = json.value("nonce").toString();
|
const QString nonce = json.value("nonce").toString();
|
||||||
|
const auto incrementedNonce = browserMessageBuilder()->incrementNonce(nonce);
|
||||||
const QString encrypted = json.value("message").toString();
|
const QString encrypted = json.value("message").toString();
|
||||||
|
|
||||||
if (!m_associated) {
|
if (!m_associated) {
|
||||||
@ -263,21 +264,31 @@ QJsonObject BrowserAction::handleGetLogins(const QJsonObject& json, const QStrin
|
|||||||
const QString formUrl = decrypted.value("submitUrl").toString();
|
const QString formUrl = decrypted.value("submitUrl").toString();
|
||||||
const QString auth = decrypted.value("httpAuth").toString();
|
const QString auth = decrypted.value("httpAuth").toString();
|
||||||
const bool httpAuth = auth.compare(TRUE_STR) == 0;
|
const bool httpAuth = auth.compare(TRUE_STR) == 0;
|
||||||
const QJsonArray users = browserService()->findMatchingEntries(id, siteUrl, formUrl, "", keyList, httpAuth);
|
auto requestId = decrypted.value("requestID").toString();
|
||||||
|
|
||||||
if (users.isEmpty()) {
|
if (browserService()->isAccessConfirmRequested()) {
|
||||||
return getErrorReply(action, ERROR_KEEPASS_NO_LOGINS_FOUND);
|
auto errorReply = getErrorReply(action, ERROR_KEEPASS_ACTION_CANCELLED_OR_DENIED);
|
||||||
|
|
||||||
|
if (!requestId.isEmpty()) {
|
||||||
|
errorReply["requestID"] = requestId;
|
||||||
|
}
|
||||||
|
|
||||||
|
return errorReply;
|
||||||
}
|
}
|
||||||
|
|
||||||
const QString newNonce = browserMessageBuilder()->incrementNonce(nonce);
|
browserService()->findEntries(socket,
|
||||||
|
incrementedNonce,
|
||||||
QJsonObject message = browserMessageBuilder()->buildMessage(newNonce);
|
m_clientPublicKey,
|
||||||
message["count"] = users.count();
|
m_secretKey,
|
||||||
message["entries"] = users;
|
id,
|
||||||
message["hash"] = hash;
|
hash,
|
||||||
message["id"] = id;
|
requestId,
|
||||||
|
siteUrl,
|
||||||
return buildResponse(action, message, newNonce);
|
formUrl,
|
||||||
|
"",
|
||||||
|
keyList,
|
||||||
|
httpAuth);
|
||||||
|
return QJsonObject();
|
||||||
}
|
}
|
||||||
|
|
||||||
QJsonObject BrowserAction::handleGeneratePassword(QLocalSocket* socket, const QJsonObject& json, const QString& action)
|
QJsonObject BrowserAction::handleGeneratePassword(QLocalSocket* socket, const QJsonObject& json, const QString& action)
|
||||||
|
@ -37,7 +37,7 @@ private:
|
|||||||
QJsonObject handleGetDatabaseHash(const QJsonObject& json, const QString& action);
|
QJsonObject handleGetDatabaseHash(const QJsonObject& json, const QString& action);
|
||||||
QJsonObject handleAssociate(const QJsonObject& json, const QString& action);
|
QJsonObject handleAssociate(const QJsonObject& json, const QString& action);
|
||||||
QJsonObject handleTestAssociate(const QJsonObject& json, const QString& action);
|
QJsonObject handleTestAssociate(const QJsonObject& json, const QString& action);
|
||||||
QJsonObject handleGetLogins(const QJsonObject& json, const QString& action);
|
QJsonObject handleGetLogins(QLocalSocket* socket, const QJsonObject& json, const QString& action);
|
||||||
QJsonObject handleGeneratePassword(QLocalSocket* socket, const QJsonObject& json, const QString& action);
|
QJsonObject handleGeneratePassword(QLocalSocket* socket, const QJsonObject& json, const QString& action);
|
||||||
QJsonObject handleSetLogin(const QJsonObject& json, const QString& action);
|
QJsonObject handleSetLogin(const QJsonObject& json, const QString& action);
|
||||||
QJsonObject handleLockDatabase(const QJsonObject& json, const QString& action);
|
QJsonObject handleLockDatabase(const QJsonObject& json, const QString& action);
|
||||||
|
@ -18,7 +18,6 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "BrowserService.h"
|
#include "BrowserService.h"
|
||||||
#include "BrowserAccessControlDialog.h"
|
|
||||||
#include "BrowserAction.h"
|
#include "BrowserAction.h"
|
||||||
#include "BrowserEntryConfig.h"
|
#include "BrowserEntryConfig.h"
|
||||||
#include "BrowserEntrySaveDialog.h"
|
#include "BrowserEntrySaveDialog.h"
|
||||||
@ -65,9 +64,9 @@ Q_GLOBAL_STATIC(BrowserService, s_browserService);
|
|||||||
BrowserService::BrowserService()
|
BrowserService::BrowserService()
|
||||||
: QObject()
|
: QObject()
|
||||||
, m_browserHost(new BrowserHost)
|
, m_browserHost(new BrowserHost)
|
||||||
, m_dialogActive(false)
|
|
||||||
, m_bringToFrontRequested(false)
|
, m_bringToFrontRequested(false)
|
||||||
, m_passwordGeneratorRequested(false)
|
, m_passwordGeneratorRequested(false)
|
||||||
|
, m_accessConfirmRequested(false)
|
||||||
, m_prevWindowState(WindowState::Normal)
|
, m_prevWindowState(WindowState::Normal)
|
||||||
, m_keepassBrowserUUID(Tools::hexToUuid("de887cc3036343b8974b5911b8816224"))
|
, m_keepassBrowserUUID(Tools::hexToUuid("de887cc3036343b8974b5911b8816224"))
|
||||||
{
|
{
|
||||||
@ -315,6 +314,219 @@ QString BrowserService::getCurrentTotp(const QString& uuid)
|
|||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void BrowserService::findEntries(QLocalSocket* socket,
|
||||||
|
const QString& nonce,
|
||||||
|
const QString& publicKey,
|
||||||
|
const QString& secretKey,
|
||||||
|
const QString& dbid,
|
||||||
|
const QString& hash,
|
||||||
|
const QString& requestId,
|
||||||
|
const QString& siteUrl,
|
||||||
|
const QString& formUrl,
|
||||||
|
const QString& realm,
|
||||||
|
const StringPairList& keyList,
|
||||||
|
const bool httpAuth)
|
||||||
|
{
|
||||||
|
Q_UNUSED(dbid);
|
||||||
|
const bool alwaysAllowAccess = browserSettings()->alwaysAllowAccess();
|
||||||
|
const bool ignoreHttpAuth = browserSettings()->httpAuthPermission();
|
||||||
|
const QString siteHost = QUrl(siteUrl).host();
|
||||||
|
const QString formHost = QUrl(formUrl).host();
|
||||||
|
|
||||||
|
// Check entries for authorization
|
||||||
|
QList<Entry*> entriesToConfirm;
|
||||||
|
QList<Entry*> allowedEntries;
|
||||||
|
for (auto* entry : searchEntries(siteUrl, formUrl, keyList)) {
|
||||||
|
auto entryCustomData = entry->customData();
|
||||||
|
|
||||||
|
if (!httpAuth
|
||||||
|
&& ((entryCustomData->contains(BrowserService::OPTION_ONLY_HTTP_AUTH)
|
||||||
|
&& entryCustomData->value(BrowserService::OPTION_ONLY_HTTP_AUTH) == TRUE_STR)
|
||||||
|
|| entry->group()->resolveCustomDataTriState(BrowserService::OPTION_ONLY_HTTP_AUTH) == Group::Enable)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (httpAuth
|
||||||
|
&& ((entryCustomData->contains(BrowserService::OPTION_NOT_HTTP_AUTH)
|
||||||
|
&& entryCustomData->value(BrowserService::OPTION_NOT_HTTP_AUTH) == TRUE_STR)
|
||||||
|
|| entry->group()->resolveCustomDataTriState(BrowserService::OPTION_NOT_HTTP_AUTH) == Group::Enable)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// HTTP Basic Auth always needs a confirmation
|
||||||
|
if (!ignoreHttpAuth && httpAuth) {
|
||||||
|
entriesToConfirm.append(entry);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (checkAccess(entry, siteHost, formHost, realm)) {
|
||||||
|
case Denied:
|
||||||
|
continue;
|
||||||
|
|
||||||
|
case Unknown:
|
||||||
|
if (alwaysAllowAccess) {
|
||||||
|
allowedEntries.append(entry);
|
||||||
|
} else {
|
||||||
|
entriesToConfirm.append(entry);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Allowed:
|
||||||
|
allowedEntries.append(entry);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (entriesToConfirm.isEmpty()) {
|
||||||
|
sendCredentialsToClient(allowedEntries, socket, nonce, publicKey, secretKey, hash, dbid, siteUrl, formUrl);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
confirmEntries(socket,
|
||||||
|
nonce,
|
||||||
|
publicKey,
|
||||||
|
secretKey,
|
||||||
|
dbid,
|
||||||
|
hash,
|
||||||
|
requestId,
|
||||||
|
allowedEntries,
|
||||||
|
entriesToConfirm,
|
||||||
|
siteUrl,
|
||||||
|
siteHost,
|
||||||
|
formHost,
|
||||||
|
realm,
|
||||||
|
httpAuth);
|
||||||
|
}
|
||||||
|
|
||||||
|
void BrowserService::confirmEntries(QLocalSocket* socket,
|
||||||
|
const QString& incrementedNonce,
|
||||||
|
const QString& publicKey,
|
||||||
|
const QString& secretKey,
|
||||||
|
const QString& id,
|
||||||
|
const QString& hash,
|
||||||
|
const QString& requestId,
|
||||||
|
QList<Entry*>& allowedEntries,
|
||||||
|
QList<Entry*>& entriesToConfirm,
|
||||||
|
const QString& siteUrl,
|
||||||
|
const QString& siteHost,
|
||||||
|
const QString& formUrl,
|
||||||
|
const QString& realm,
|
||||||
|
const bool httpAuth)
|
||||||
|
{
|
||||||
|
if (entriesToConfirm.isEmpty() || m_accessConfirmRequested) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!m_accessControlDialog) {
|
||||||
|
|
||||||
|
m_accessControlDialog.reset(new BrowserAccessControlDialog());
|
||||||
|
|
||||||
|
connect(
|
||||||
|
m_currentDatabaseWidget, SIGNAL(databaseLockRequested()), m_accessControlDialog.data(), SIGNAL(closed()));
|
||||||
|
|
||||||
|
connect(m_accessControlDialog.data(),
|
||||||
|
&BrowserAccessControlDialog::disableAccess,
|
||||||
|
m_accessControlDialog.data(),
|
||||||
|
[=](QTableWidgetItem* item) {
|
||||||
|
auto entry = entriesToConfirm[item->row()];
|
||||||
|
denyEntry(entry, siteHost, formUrl, realm);
|
||||||
|
});
|
||||||
|
|
||||||
|
connect(m_accessControlDialog.data(), &BrowserAccessControlDialog::closed, m_accessControlDialog.data(), [=] {
|
||||||
|
if (!m_accessControlDialog->entriesAccepted()) {
|
||||||
|
auto errorMessage =
|
||||||
|
browserMessageBuilder()->getErrorReply("get-logins", ERROR_KEEPASS_ACTION_CANCELLED_OR_DENIED);
|
||||||
|
errorMessage["requestID"] = requestId;
|
||||||
|
m_browserHost->sendClientMessage(socket, errorMessage);
|
||||||
|
}
|
||||||
|
|
||||||
|
m_accessControlDialog.reset();
|
||||||
|
hideWindow();
|
||||||
|
m_accessConfirmRequested = false;
|
||||||
|
});
|
||||||
|
|
||||||
|
connect(m_accessControlDialog.data(),
|
||||||
|
&BrowserAccessControlDialog::acceptEntries,
|
||||||
|
m_accessControlDialog.data(),
|
||||||
|
[=](QList<QTableWidgetItem*> items, QList<Entry*> entries, QList<Entry*> allowed) {
|
||||||
|
QList<Entry*> selectedEntries;
|
||||||
|
|
||||||
|
for (auto item : items) {
|
||||||
|
auto entry = entries[item->row()];
|
||||||
|
if (m_accessControlDialog->remember()) {
|
||||||
|
allowEntry(entry, siteHost, formUrl, realm);
|
||||||
|
}
|
||||||
|
|
||||||
|
selectedEntries.append(entry);
|
||||||
|
}
|
||||||
|
|
||||||
|
hideWindow();
|
||||||
|
|
||||||
|
if (!selectedEntries.isEmpty()) {
|
||||||
|
allowed.append(selectedEntries);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (allowed.isEmpty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ensure that database is not locked when the popup was visible
|
||||||
|
if (!isDatabaseOpened()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
sendCredentialsToClient(
|
||||||
|
allowed, socket, incrementedNonce, publicKey, secretKey, hash, id, siteUrl, formUrl);
|
||||||
|
});
|
||||||
|
|
||||||
|
connect(m_accessControlDialog.data(),
|
||||||
|
&BrowserAccessControlDialog::rejectEntries,
|
||||||
|
m_accessControlDialog.data(),
|
||||||
|
[=](QList<QTableWidgetItem*> items, QList<Entry*> entries) {
|
||||||
|
Q_UNUSED(items); // We might need this later if single entries can be denied from the list
|
||||||
|
for (auto entry : entries) {
|
||||||
|
if (m_accessControlDialog->remember()) {
|
||||||
|
denyEntry(entry, siteHost, formUrl, realm);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
m_accessControlDialog->setItems(entriesToConfirm, allowedEntries, siteUrl, httpAuth);
|
||||||
|
m_accessControlDialog->show();
|
||||||
|
}
|
||||||
|
|
||||||
|
m_accessConfirmRequested = true;
|
||||||
|
updateWindowState();
|
||||||
|
}
|
||||||
|
|
||||||
|
void BrowserService::sendCredentialsToClient(QList<Entry*>& allowedEntries,
|
||||||
|
QLocalSocket* socket,
|
||||||
|
const QString& incrementedNonce,
|
||||||
|
const QString& publicKey,
|
||||||
|
const QString& secretKey,
|
||||||
|
const QString& hash,
|
||||||
|
const QString& id,
|
||||||
|
const QString siteUrl,
|
||||||
|
const QString& formUrl)
|
||||||
|
{
|
||||||
|
allowedEntries = sortEntries(allowedEntries, siteUrl, formUrl);
|
||||||
|
|
||||||
|
QJsonArray result;
|
||||||
|
for (auto* entry : allowedEntries) {
|
||||||
|
result.append(prepareEntry(entry));
|
||||||
|
}
|
||||||
|
|
||||||
|
QJsonObject message = browserMessageBuilder()->buildMessage(incrementedNonce);
|
||||||
|
message["count"] = result.count();
|
||||||
|
message["entries"] = result;
|
||||||
|
message["hash"] = hash;
|
||||||
|
message["id"] = id;
|
||||||
|
|
||||||
|
m_browserHost->sendClientMessage(
|
||||||
|
socket, browserMessageBuilder()->buildResponse("get-logins", message, incrementedNonce, publicKey, secretKey));
|
||||||
|
hideWindow();
|
||||||
|
}
|
||||||
|
|
||||||
void BrowserService::showPasswordGenerator(QLocalSocket* socket,
|
void BrowserService::showPasswordGenerator(QLocalSocket* socket,
|
||||||
const QString& incrementedNonce,
|
const QString& incrementedNonce,
|
||||||
const QString& publicKey,
|
const QString& publicKey,
|
||||||
@ -341,9 +553,11 @@ void BrowserService::showPasswordGenerator(QLocalSocket* socket,
|
|||||||
[=](const QString& password) {
|
[=](const QString& password) {
|
||||||
QJsonObject message = browserMessageBuilder()->buildMessage(incrementedNonce);
|
QJsonObject message = browserMessageBuilder()->buildMessage(incrementedNonce);
|
||||||
message["password"] = password;
|
message["password"] = password;
|
||||||
sendPassword(socket,
|
m_browserHost->sendClientMessage(
|
||||||
browserMessageBuilder()->buildResponse(
|
socket,
|
||||||
"generate-password", message, incrementedNonce, publicKey, secretKey));
|
browserMessageBuilder()->buildResponse(
|
||||||
|
"generate-password", message, incrementedNonce, publicKey, secretKey));
|
||||||
|
hideWindow();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -353,17 +567,16 @@ void BrowserService::showPasswordGenerator(QLocalSocket* socket,
|
|||||||
m_passwordGenerator->activateWindow();
|
m_passwordGenerator->activateWindow();
|
||||||
}
|
}
|
||||||
|
|
||||||
void BrowserService::sendPassword(QLocalSocket* socket, const QJsonObject& message)
|
|
||||||
{
|
|
||||||
m_browserHost->sendClientMessage(socket, message);
|
|
||||||
hideWindow();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool BrowserService::isPasswordGeneratorRequested() const
|
bool BrowserService::isPasswordGeneratorRequested() const
|
||||||
{
|
{
|
||||||
return m_passwordGeneratorRequested;
|
return m_passwordGeneratorRequested;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool BrowserService::isAccessConfirmRequested() const
|
||||||
|
{
|
||||||
|
return m_accessConfirmRequested;
|
||||||
|
}
|
||||||
|
|
||||||
QString BrowserService::storeKey(const QString& key)
|
QString BrowserService::storeKey(const QString& key)
|
||||||
{
|
{
|
||||||
auto db = getDatabase();
|
auto db = getDatabase();
|
||||||
@ -426,91 +639,6 @@ QString BrowserService::getKey(const QString& id)
|
|||||||
return db->metadata()->customData()->value(CustomData::BrowserKeyPrefix + id);
|
return db->metadata()->customData()->value(CustomData::BrowserKeyPrefix + id);
|
||||||
}
|
}
|
||||||
|
|
||||||
QJsonArray BrowserService::findMatchingEntries(const QString& dbid,
|
|
||||||
const QString& siteUrl,
|
|
||||||
const QString& formUrl,
|
|
||||||
const QString& realm,
|
|
||||||
const StringPairList& keyList,
|
|
||||||
const bool httpAuth)
|
|
||||||
{
|
|
||||||
Q_UNUSED(dbid);
|
|
||||||
const bool alwaysAllowAccess = browserSettings()->alwaysAllowAccess();
|
|
||||||
const bool ignoreHttpAuth = browserSettings()->httpAuthPermission();
|
|
||||||
const QString siteHost = QUrl(siteUrl).host();
|
|
||||||
const QString formHost = QUrl(formUrl).host();
|
|
||||||
|
|
||||||
// Check entries for authorization
|
|
||||||
QList<Entry*> pwEntriesToConfirm;
|
|
||||||
QList<Entry*> pwEntries;
|
|
||||||
for (auto* entry : searchEntries(siteUrl, formUrl, keyList)) {
|
|
||||||
auto entryCustomData = entry->customData();
|
|
||||||
|
|
||||||
if (!httpAuth
|
|
||||||
&& ((entryCustomData->contains(BrowserService::OPTION_ONLY_HTTP_AUTH)
|
|
||||||
&& entryCustomData->value(BrowserService::OPTION_ONLY_HTTP_AUTH) == TRUE_STR)
|
|
||||||
|| entry->group()->resolveCustomDataTriState(BrowserService::OPTION_ONLY_HTTP_AUTH) == Group::Enable)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (httpAuth
|
|
||||||
&& ((entryCustomData->contains(BrowserService::OPTION_NOT_HTTP_AUTH)
|
|
||||||
&& entryCustomData->value(BrowserService::OPTION_NOT_HTTP_AUTH) == TRUE_STR)
|
|
||||||
|| entry->group()->resolveCustomDataTriState(BrowserService::OPTION_NOT_HTTP_AUTH) == Group::Enable)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// HTTP Basic Auth always needs a confirmation
|
|
||||||
if (!ignoreHttpAuth && httpAuth) {
|
|
||||||
pwEntriesToConfirm.append(entry);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (checkAccess(entry, siteHost, formHost, realm)) {
|
|
||||||
case Denied:
|
|
||||||
continue;
|
|
||||||
|
|
||||||
case Unknown:
|
|
||||||
if (alwaysAllowAccess) {
|
|
||||||
pwEntries.append(entry);
|
|
||||||
} else {
|
|
||||||
pwEntriesToConfirm.append(entry);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case Allowed:
|
|
||||||
pwEntries.append(entry);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Confirm entries
|
|
||||||
QList<Entry*> selectedEntriesToConfirm =
|
|
||||||
confirmEntries(pwEntriesToConfirm, siteUrl, siteHost, formHost, realm, httpAuth);
|
|
||||||
if (!selectedEntriesToConfirm.isEmpty()) {
|
|
||||||
pwEntries.append(selectedEntriesToConfirm);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (pwEntries.isEmpty()) {
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
// Ensure that database is not locked when the popup was visible
|
|
||||||
if (!isDatabaseOpened()) {
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
// Sort results
|
|
||||||
pwEntries = sortEntries(pwEntries, siteUrl, formUrl);
|
|
||||||
|
|
||||||
// Fill the list
|
|
||||||
QJsonArray result;
|
|
||||||
for (auto* entry : pwEntries) {
|
|
||||||
result.append(prepareEntry(entry));
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
void BrowserService::addEntry(const QString& dbid,
|
void BrowserService::addEntry(const QString& dbid,
|
||||||
const QString& login,
|
const QString& login,
|
||||||
const QString& password,
|
const QString& password,
|
||||||
@ -822,13 +950,12 @@ void BrowserService::requestGlobalAutoType(const QString& search)
|
|||||||
emit osUtils->globalShortcutTriggered("autotype", search);
|
emit osUtils->globalShortcutTriggered("autotype", search);
|
||||||
}
|
}
|
||||||
|
|
||||||
QList<Entry*>
|
QList<Entry*> BrowserService::sortEntries(QList<Entry*>& pwEntries, const QString& siteUrl, const QString& formUrl)
|
||||||
BrowserService::sortEntries(QList<Entry*>& pwEntries, const QString& siteUrlStr, const QString& formUrlStr)
|
|
||||||
{
|
{
|
||||||
// Build map of prioritized entries
|
// Build map of prioritized entries
|
||||||
QMultiMap<int, Entry*> priorities;
|
QMultiMap<int, Entry*> priorities;
|
||||||
for (auto* entry : pwEntries) {
|
for (auto* entry : pwEntries) {
|
||||||
priorities.insert(sortPriority(getEntryURLs(entry), siteUrlStr, formUrlStr), entry);
|
priorities.insert(sortPriority(getEntryURLs(entry), siteUrl, formUrl), entry);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto keys = priorities.uniqueKeys();
|
auto keys = priorities.uniqueKeys();
|
||||||
@ -847,66 +974,38 @@ BrowserService::sortEntries(QList<Entry*>& pwEntries, const QString& siteUrlStr,
|
|||||||
return results;
|
return results;
|
||||||
}
|
}
|
||||||
|
|
||||||
QList<Entry*> BrowserService::confirmEntries(QList<Entry*>& pwEntriesToConfirm,
|
void BrowserService::allowEntry(Entry* entry, const QString& siteHost, const QString& formUrl, const QString& realm)
|
||||||
const QString& siteUrl,
|
|
||||||
const QString& siteHost,
|
|
||||||
const QString& formUrl,
|
|
||||||
const QString& realm,
|
|
||||||
const bool httpAuth)
|
|
||||||
{
|
{
|
||||||
if (pwEntriesToConfirm.isEmpty() || m_dialogActive) {
|
BrowserEntryConfig config;
|
||||||
return {};
|
config.load(entry);
|
||||||
|
config.allow(siteHost);
|
||||||
|
|
||||||
|
if (!formUrl.isEmpty() && siteHost != formUrl) {
|
||||||
|
config.allow(formUrl);
|
||||||
}
|
}
|
||||||
|
|
||||||
m_dialogActive = true;
|
if (!realm.isEmpty()) {
|
||||||
updateWindowState();
|
config.setRealm(realm);
|
||||||
BrowserAccessControlDialog accessControlDialog;
|
|
||||||
|
|
||||||
connect(m_currentDatabaseWidget, SIGNAL(databaseLockRequested()), &accessControlDialog, SLOT(reject()));
|
|
||||||
|
|
||||||
connect(&accessControlDialog, &BrowserAccessControlDialog::disableAccess, [&](QTableWidgetItem* item) {
|
|
||||||
auto entry = pwEntriesToConfirm[item->row()];
|
|
||||||
BrowserEntryConfig config;
|
|
||||||
config.load(entry);
|
|
||||||
config.deny(siteHost);
|
|
||||||
if (!formUrl.isEmpty() && siteHost != formUrl) {
|
|
||||||
config.deny(formUrl);
|
|
||||||
}
|
|
||||||
if (!realm.isEmpty()) {
|
|
||||||
config.setRealm(realm);
|
|
||||||
}
|
|
||||||
config.save(entry);
|
|
||||||
});
|
|
||||||
|
|
||||||
accessControlDialog.setItems(pwEntriesToConfirm, siteUrl, httpAuth);
|
|
||||||
|
|
||||||
QList<Entry*> allowedEntries;
|
|
||||||
if (accessControlDialog.exec() == QDialog::Accepted) {
|
|
||||||
const auto selectedEntries = accessControlDialog.getSelectedEntries();
|
|
||||||
for (auto item : accessControlDialog.getSelectedEntries()) {
|
|
||||||
auto entry = pwEntriesToConfirm[item->row()];
|
|
||||||
if (accessControlDialog.remember()) {
|
|
||||||
BrowserEntryConfig config;
|
|
||||||
config.load(entry);
|
|
||||||
config.allow(siteHost);
|
|
||||||
if (!formUrl.isEmpty() && siteHost != formUrl) {
|
|
||||||
config.allow(formUrl);
|
|
||||||
}
|
|
||||||
if (!realm.isEmpty()) {
|
|
||||||
config.setRealm(realm);
|
|
||||||
}
|
|
||||||
config.save(entry);
|
|
||||||
}
|
|
||||||
allowedEntries.append(entry);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Re-hide the application if it wasn't visible before
|
config.save(entry);
|
||||||
hideWindow();
|
}
|
||||||
|
|
||||||
m_dialogActive = false;
|
void BrowserService::denyEntry(Entry* entry, const QString& siteHost, const QString& formUrl, const QString& realm)
|
||||||
|
{
|
||||||
|
BrowserEntryConfig config;
|
||||||
|
config.load(entry);
|
||||||
|
config.deny(siteHost);
|
||||||
|
|
||||||
return allowedEntries;
|
if (!formUrl.isEmpty() && siteHost != formUrl) {
|
||||||
|
config.deny(formUrl);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!realm.isEmpty()) {
|
||||||
|
config.setRealm(realm);
|
||||||
|
}
|
||||||
|
|
||||||
|
config.save(entry);
|
||||||
}
|
}
|
||||||
|
|
||||||
QJsonObject BrowserService::prepareEntry(const Entry* entry)
|
QJsonObject BrowserService::prepareEntry(const Entry* entry)
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2013 Francois Ferrand
|
* Copyright (C) 2013 Francois Ferrand
|
||||||
* Copyright (C) 2017 Sami Vänttinen <sami.vanttinen@protonmail.com>
|
* Copyright (C) 2017 Sami Vänttinen <sami.vanttinen@protonmail.com>
|
||||||
* Copyright (C) 2021 KeePassXC Team <team@keepassxc.org>
|
* Copyright (C) 2022 KeePassXC Team <team@keepassxc.org>
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* 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
|
* it under the terms of the GNU General Public License as published by
|
||||||
@ -20,6 +20,7 @@
|
|||||||
#ifndef BROWSERSERVICE_H
|
#ifndef BROWSERSERVICE_H
|
||||||
#define BROWSERSERVICE_H
|
#define BROWSERSERVICE_H
|
||||||
|
|
||||||
|
#include "BrowserAccessControlDialog.h"
|
||||||
#include "core/Entry.h"
|
#include "core/Entry.h"
|
||||||
#include "gui/PasswordGeneratorWidget.h"
|
#include "gui/PasswordGeneratorWidget.h"
|
||||||
|
|
||||||
@ -64,12 +65,13 @@ public:
|
|||||||
const QString& secretKey);
|
const QString& secretKey);
|
||||||
void sendPassword(QLocalSocket* socket, const QJsonObject& message);
|
void sendPassword(QLocalSocket* socket, const QJsonObject& message);
|
||||||
bool isPasswordGeneratorRequested() const;
|
bool isPasswordGeneratorRequested() const;
|
||||||
|
bool isAccessConfirmRequested() const;
|
||||||
|
|
||||||
void addEntry(const QString& dbid,
|
void addEntry(const QString& dbid,
|
||||||
const QString& login,
|
const QString& login,
|
||||||
const QString& password,
|
const QString& password,
|
||||||
const QString& siteUrlStr,
|
const QString& siteUrl,
|
||||||
const QString& formUrlStr,
|
const QString& formUrl,
|
||||||
const QString& realm,
|
const QString& realm,
|
||||||
const QString& group,
|
const QString& group,
|
||||||
const QString& groupUuid,
|
const QString& groupUuid,
|
||||||
@ -79,17 +81,21 @@ public:
|
|||||||
const QString& uuid,
|
const QString& uuid,
|
||||||
const QString& login,
|
const QString& login,
|
||||||
const QString& password,
|
const QString& password,
|
||||||
const QString& siteUrlStr,
|
const QString& siteUrl,
|
||||||
const QString& formUrlStr);
|
const QString& formUrl);
|
||||||
bool deleteEntry(const QString& uuid);
|
bool deleteEntry(const QString& uuid);
|
||||||
|
void findEntries(QLocalSocket* socket,
|
||||||
QJsonArray findMatchingEntries(const QString& dbid,
|
const QString& nonce,
|
||||||
const QString& siteUrlStr,
|
const QString& publicKey,
|
||||||
const QString& formUrlStr,
|
const QString& secretKey,
|
||||||
const QString& realm,
|
const QString& dbid,
|
||||||
const StringPairList& keyList,
|
const QString& hash,
|
||||||
const bool httpAuth = false);
|
const QString& requestId,
|
||||||
|
const QString& siteUrl,
|
||||||
|
const QString& formUrl,
|
||||||
|
const QString& realm,
|
||||||
|
const StringPairList& keyList,
|
||||||
|
const bool httpAuth = false);
|
||||||
void requestGlobalAutoType(const QString& search);
|
void requestGlobalAutoType(const QString& search);
|
||||||
static void convertAttributesToCustomData(QSharedPointer<Database> db);
|
static void convertAttributesToCustomData(QSharedPointer<Database> db);
|
||||||
|
|
||||||
@ -132,13 +138,32 @@ private:
|
|||||||
QList<Entry*> searchEntries(const QSharedPointer<Database>& db, const QString& siteUrl, const QString& formUrl);
|
QList<Entry*> searchEntries(const QSharedPointer<Database>& db, const QString& siteUrl, const QString& formUrl);
|
||||||
QList<Entry*> searchEntries(const QString& siteUrl, const QString& formUrl, const StringPairList& keyList);
|
QList<Entry*> searchEntries(const QString& siteUrl, const QString& formUrl, const StringPairList& keyList);
|
||||||
QList<Entry*> sortEntries(QList<Entry*>& pwEntries, const QString& siteUrl, const QString& formUrl);
|
QList<Entry*> sortEntries(QList<Entry*>& pwEntries, const QString& siteUrl, const QString& formUrl);
|
||||||
QList<Entry*> confirmEntries(QList<Entry*>& pwEntriesToConfirm,
|
void confirmEntries(QLocalSocket* socket,
|
||||||
const QString& siteUrl,
|
const QString& incrementedNonce,
|
||||||
const QString& siteHost,
|
const QString& publicKey,
|
||||||
const QString& formUrl,
|
const QString& secretKey,
|
||||||
const QString& realm,
|
const QString& id,
|
||||||
const bool httpAuth);
|
const QString& hash,
|
||||||
|
const QString& requestId,
|
||||||
|
QList<Entry*>& allowedEntries,
|
||||||
|
QList<Entry*>& entriesToConfirm,
|
||||||
|
const QString& siteUrl,
|
||||||
|
const QString& siteHost,
|
||||||
|
const QString& formUrl,
|
||||||
|
const QString& realm,
|
||||||
|
const bool httpAuth);
|
||||||
|
void sendCredentialsToClient(QList<Entry*>& allowedEntries,
|
||||||
|
QLocalSocket* socket,
|
||||||
|
const QString& incrementedNonce,
|
||||||
|
const QString& publicKey,
|
||||||
|
const QString& secretKey,
|
||||||
|
const QString& hash,
|
||||||
|
const QString& id,
|
||||||
|
const QString siteUrl,
|
||||||
|
const QString& formUrl);
|
||||||
QJsonObject prepareEntry(const Entry* entry);
|
QJsonObject prepareEntry(const Entry* entry);
|
||||||
|
void allowEntry(Entry* entry, const QString& siteHost, const QString& formUrl, const QString& realm);
|
||||||
|
void denyEntry(Entry* entry, const QString& siteHost, const QString& formUrl, const QString& realm);
|
||||||
QJsonArray getChildrenFromGroup(Group* group);
|
QJsonArray getChildrenFromGroup(Group* group);
|
||||||
Access checkAccess(const Entry* entry, const QString& siteHost, const QString& formHost, const QString& realm);
|
Access checkAccess(const Entry* entry, const QString& siteHost, const QString& formHost, const QString& realm);
|
||||||
Group* getDefaultEntryGroup(const QSharedPointer<Database>& selectedDb = {});
|
Group* getDefaultEntryGroup(const QSharedPointer<Database>& selectedDb = {});
|
||||||
@ -171,14 +196,15 @@ private:
|
|||||||
QPointer<BrowserHost> m_browserHost;
|
QPointer<BrowserHost> m_browserHost;
|
||||||
QHash<QString, QSharedPointer<BrowserAction>> m_browserClients;
|
QHash<QString, QSharedPointer<BrowserAction>> m_browserClients;
|
||||||
|
|
||||||
bool m_dialogActive;
|
|
||||||
bool m_bringToFrontRequested;
|
bool m_bringToFrontRequested;
|
||||||
bool m_passwordGeneratorRequested;
|
bool m_passwordGeneratorRequested;
|
||||||
|
bool m_accessConfirmRequested;
|
||||||
WindowState m_prevWindowState;
|
WindowState m_prevWindowState;
|
||||||
QUuid m_keepassBrowserUUID;
|
QUuid m_keepassBrowserUUID;
|
||||||
|
|
||||||
QPointer<DatabaseWidget> m_currentDatabaseWidget;
|
QPointer<DatabaseWidget> m_currentDatabaseWidget;
|
||||||
QScopedPointer<PasswordGeneratorWidget> m_passwordGenerator;
|
QScopedPointer<PasswordGeneratorWidget> m_passwordGenerator;
|
||||||
|
QScopedPointer<BrowserAccessControlDialog> m_accessControlDialog;
|
||||||
|
|
||||||
Q_DISABLE_COPY(BrowserService);
|
Q_DISABLE_COPY(BrowserService);
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user