mirror of
https://github.com/keepassxreboot/keepassxc.git
synced 2024-12-25 23:39:45 -05:00
Browser connection keys and rules are stored in custom data instead of attributes (#1497)
This commit is contained in:
parent
cfa1eca249
commit
efdb43dc53
@ -222,6 +222,7 @@ add_subdirectory(browser)
|
||||
add_subdirectory(proxy)
|
||||
if(WITH_XC_BROWSER)
|
||||
set(keepassxcbrowser_LIB keepassxcbrowser)
|
||||
set(keepassx_SOURCES ${keepassx_SOURCES} gui/dbsettings/DatabaseSettingsWidgetBrowser.cpp)
|
||||
endif()
|
||||
|
||||
add_subdirectory(autotype)
|
||||
|
@ -566,15 +566,3 @@ QString BrowserAction::incrementNonce(const QString& nonce)
|
||||
sodium_increment(n.data(), n.size());
|
||||
return getQByteArray(n.data(), n.size()).toBase64();
|
||||
}
|
||||
|
||||
void BrowserAction::removeSharedEncryptionKeys()
|
||||
{
|
||||
QMutexLocker locker(&m_mutex);
|
||||
m_browserService.removeSharedEncryptionKeys();
|
||||
}
|
||||
|
||||
void BrowserAction::removeStoredPermissions()
|
||||
{
|
||||
QMutexLocker locker(&m_mutex);
|
||||
m_browserService.removeStoredPermissions();
|
||||
}
|
||||
|
@ -54,10 +54,6 @@ public:
|
||||
|
||||
QJsonObject readResponse(const QJsonObject& json);
|
||||
|
||||
public slots:
|
||||
void removeSharedEncryptionKeys();
|
||||
void removeStoredPermissions();
|
||||
|
||||
private:
|
||||
QJsonObject handleAction(const QJsonObject& json);
|
||||
QJsonObject handleChangePublicKeys(const QJsonObject& json, const QString& action);
|
||||
|
@ -21,7 +21,7 @@
|
||||
#include "core/EntryAttributes.h"
|
||||
#include <QtCore>
|
||||
|
||||
static const char KEEPASSBROWSER_NAME[] = "KeePassXC-Browser Settings";
|
||||
static const char KEEPASSXCBROWSER_NAME[] = "KeePassXC-Browser Settings";
|
||||
|
||||
BrowserEntryConfig::BrowserEntryConfig(QObject* parent)
|
||||
: QObject(parent)
|
||||
@ -82,7 +82,7 @@ void BrowserEntryConfig::setRealm(const QString& realm)
|
||||
|
||||
bool BrowserEntryConfig::load(const Entry* entry)
|
||||
{
|
||||
QString s = entry->attributes()->value(KEEPASSBROWSER_NAME);
|
||||
QString s = entry->customData()->value(KEEPASSXCBROWSER_NAME);
|
||||
if (s.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
@ -104,5 +104,5 @@ void BrowserEntryConfig::save(Entry* entry)
|
||||
QVariantMap v = qo2qv(this);
|
||||
QJsonObject o = QJsonObject::fromVariantMap(v);
|
||||
QByteArray json = QJsonDocument(o).toJson(QJsonDocument::Compact);
|
||||
entry->attributes()->set(KEEPASSBROWSER_NAME, json);
|
||||
entry->customData()->set(KEEPASSXCBROWSER_NAME, json);
|
||||
}
|
||||
|
@ -24,15 +24,12 @@
|
||||
#include "ui_BrowserOptionDialog.h"
|
||||
|
||||
#include <QFileDialog>
|
||||
#include <QMessageBox>
|
||||
|
||||
BrowserOptionDialog::BrowserOptionDialog(QWidget* parent)
|
||||
: QWidget(parent)
|
||||
, m_ui(new Ui::BrowserOptionDialog())
|
||||
{
|
||||
m_ui->setupUi(this);
|
||||
connect(m_ui->removeSharedEncryptionKeys, SIGNAL(clicked()), this, SIGNAL(removeSharedEncryptionKeys()));
|
||||
connect(m_ui->removeStoredPermissions, SIGNAL(clicked()), this, SIGNAL(removeStoredPermissions()));
|
||||
|
||||
m_ui->extensionLabel->setOpenExternalLinks(true);
|
||||
m_ui->extensionLabel->setText(tr("KeePassXC-Browser is needed for the browser integration to work. <br />Download it for %1 and %2.").arg(
|
||||
|
@ -21,6 +21,7 @@
|
||||
#define BROWSEROPTIONDIALOG_H
|
||||
|
||||
#include <QScopedPointer>
|
||||
#include <QPointer>
|
||||
#include <QWidget>
|
||||
|
||||
namespace Ui
|
||||
@ -40,10 +41,6 @@ public slots:
|
||||
void loadSettings();
|
||||
void saveSettings();
|
||||
|
||||
signals:
|
||||
void removeSharedEncryptionKeys();
|
||||
void removeStoredPermissions();
|
||||
|
||||
private slots:
|
||||
void showProxyLocationFileDialog();
|
||||
|
||||
|
@ -145,7 +145,7 @@
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="verticalSpacer_3">
|
||||
<spacer name="verticalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
@ -215,7 +215,7 @@
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="verticalSpacer">
|
||||
<spacer name="verticalSpacer_2">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
@ -230,36 +230,6 @@
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_3">
|
||||
<item>
|
||||
<widget class="QPushButton" name="removeSharedEncryptionKeys">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>&Disconnect all browsers</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="removeStoredPermissions">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Forget all remembered &permissions</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="verticalSpacer_2">
|
||||
<property name="orientation">
|
||||
@ -376,7 +346,7 @@
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="verticalSpacer_4">
|
||||
<spacer name="verticalSpacer_5">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
|
@ -35,10 +35,14 @@
|
||||
#include "core/PasswordGenerator.h"
|
||||
#include "gui/MainWindow.h"
|
||||
|
||||
static const char KEEPASSXCBROWSER_NAME[] = "KeePassXC-Browser Settings";
|
||||
static const char ASSOCIATE_KEY_PREFIX[] = "Public Key: ";
|
||||
const char BrowserService::KEEPASSXCBROWSER_NAME[] = "KeePassXC-Browser Settings";
|
||||
const char BrowserService::ASSOCIATE_KEY_PREFIX[] = "KPXC_BROWSER_";
|
||||
static const char KEEPASSXCBROWSER_GROUP_NAME[] = "KeePassXC-Browser Passwords";
|
||||
static int KEEPASSXCBROWSER_DEFAULT_ICON = 1;
|
||||
// These are for the settings and password conversion
|
||||
const char BrowserService::LEGACY_ASSOCIATE_KEY_PREFIX[] = "Public Key: ";
|
||||
static const char KEEPASSHTTP_NAME[] = "KeePassHttp Settings";
|
||||
static const char KEEPASSHTTP_GROUP_NAME[] = "KeePassHttp Passwords";
|
||||
|
||||
BrowserService::BrowserService(DatabaseTabWidget* parent)
|
||||
: m_dbTabWidget(parent)
|
||||
@ -46,12 +50,15 @@ BrowserService::BrowserService(DatabaseTabWidget* parent)
|
||||
, m_bringToFrontRequested(false)
|
||||
, m_keepassBrowserUUID(QUuid::fromRfc4122(QByteArray::fromHex("de887cc3036343b8974b5911b8816224")))
|
||||
{
|
||||
connect(m_dbTabWidget, SIGNAL(databaseLocked(DatabaseWidget*)), this, SLOT(databaseLocked(DatabaseWidget*)));
|
||||
connect(m_dbTabWidget, SIGNAL(databaseUnlocked(DatabaseWidget*)), this, SLOT(databaseUnlocked(DatabaseWidget*)));
|
||||
connect(m_dbTabWidget,
|
||||
SIGNAL(activateDatabaseChanged(DatabaseWidget*)),
|
||||
this,
|
||||
SLOT(activateDatabaseChanged(DatabaseWidget*)));
|
||||
// Don't connect the signals when used from DatabaseSettingsWidgetBrowser (parent is nullptr)
|
||||
if (m_dbTabWidget) {
|
||||
connect(m_dbTabWidget, SIGNAL(databaseLocked(DatabaseWidget*)), this, SLOT(databaseLocked(DatabaseWidget*)));
|
||||
connect(m_dbTabWidget, SIGNAL(databaseUnlocked(DatabaseWidget*)), this, SLOT(databaseUnlocked(DatabaseWidget*)));
|
||||
connect(m_dbTabWidget,
|
||||
SIGNAL(activateDatabaseChanged(DatabaseWidget*)),
|
||||
this,
|
||||
SLOT(activateDatabaseChanged(DatabaseWidget*)));
|
||||
}
|
||||
}
|
||||
|
||||
bool BrowserService::isDatabaseOpened() const
|
||||
@ -107,12 +114,12 @@ QString BrowserService::getDatabaseRootUuid()
|
||||
{
|
||||
Database* db = getDatabase();
|
||||
if (!db) {
|
||||
return QString();
|
||||
return {};
|
||||
}
|
||||
|
||||
Group* rootGroup = db->rootGroup();
|
||||
if (!rootGroup) {
|
||||
return QString();
|
||||
return {};
|
||||
}
|
||||
|
||||
return rootGroup->uuidToHex();
|
||||
@ -122,46 +129,16 @@ QString BrowserService::getDatabaseRecycleBinUuid()
|
||||
{
|
||||
Database* db = getDatabase();
|
||||
if (!db) {
|
||||
return QString();
|
||||
return {};
|
||||
}
|
||||
|
||||
Group* recycleBin = db->metadata()->recycleBin();
|
||||
if (!recycleBin) {
|
||||
return QString();
|
||||
return {};
|
||||
}
|
||||
return recycleBin->uuidToHex();
|
||||
}
|
||||
|
||||
Entry* BrowserService::getConfigEntry(bool create)
|
||||
{
|
||||
Entry* entry = nullptr;
|
||||
Database* db = getDatabase();
|
||||
if (!db) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
entry = db->resolveEntry(m_keepassBrowserUUID);
|
||||
if (!entry && create) {
|
||||
entry = new Entry();
|
||||
entry->setTitle(QLatin1String(KEEPASSXCBROWSER_NAME));
|
||||
entry->setUuid(m_keepassBrowserUUID);
|
||||
entry->setAutoTypeEnabled(false);
|
||||
entry->setGroup(db->rootGroup());
|
||||
return entry;
|
||||
}
|
||||
|
||||
if (entry && entry->group() == db->metadata()->recycleBin()) {
|
||||
if (!create) {
|
||||
return nullptr;
|
||||
} else {
|
||||
entry->setGroup(db->rootGroup());
|
||||
return entry;
|
||||
}
|
||||
}
|
||||
|
||||
return entry;
|
||||
}
|
||||
|
||||
QString BrowserService::storeKey(const QString& key)
|
||||
{
|
||||
QString id;
|
||||
@ -172,8 +149,8 @@ QString BrowserService::storeKey(const QString& key)
|
||||
return id;
|
||||
}
|
||||
|
||||
Entry* config = getConfigEntry(true);
|
||||
if (!config) {
|
||||
Database* db = getDatabase();
|
||||
if (!db) {
|
||||
return {};
|
||||
}
|
||||
|
||||
@ -199,7 +176,7 @@ QString BrowserService::storeKey(const QString& key)
|
||||
return {};
|
||||
}
|
||||
|
||||
contains = config->attributes()->contains(QLatin1String(ASSOCIATE_KEY_PREFIX) + id);
|
||||
contains = db->metadata()->customData()->contains(QLatin1String(ASSOCIATE_KEY_PREFIX) + id);
|
||||
if (contains) {
|
||||
dialogResult = QMessageBox::warning(nullptr,
|
||||
tr("KeePassXC: Overwrite existing key?"),
|
||||
@ -210,18 +187,18 @@ QString BrowserService::storeKey(const QString& key)
|
||||
}
|
||||
} while (contains && dialogResult == QMessageBox::No);
|
||||
|
||||
config->attributes()->set(QLatin1String(ASSOCIATE_KEY_PREFIX) + id, key, true);
|
||||
db->metadata()->customData()->set(QLatin1String(ASSOCIATE_KEY_PREFIX) + id, key);
|
||||
return id;
|
||||
}
|
||||
|
||||
QString BrowserService::getKey(const QString& id)
|
||||
{
|
||||
Entry* config = getConfigEntry();
|
||||
if (!config) {
|
||||
return QString();
|
||||
Database* db = getDatabase();
|
||||
if (!db) {
|
||||
return {};
|
||||
}
|
||||
|
||||
return config->attributes()->value(QLatin1String(ASSOCIATE_KEY_PREFIX) + id);
|
||||
return db->metadata()->customData()->value(QLatin1String(ASSOCIATE_KEY_PREFIX) + id);
|
||||
}
|
||||
|
||||
QJsonArray BrowserService::findMatchingEntries(const QString& id,
|
||||
@ -445,12 +422,9 @@ QList<Entry*> BrowserService::searchEntries(const QString& url, const StringPair
|
||||
if (Database* db = dbWidget->database()) {
|
||||
// Check if database is connected with KeePassXC-Browser
|
||||
for (const StringPair keyPair : keyList) {
|
||||
Entry* entry = db->resolveEntry(m_keepassBrowserUUID);
|
||||
if (entry) {
|
||||
QString key = entry->attributes()->value(QLatin1String(ASSOCIATE_KEY_PREFIX) + keyPair.first);
|
||||
if (!key.isEmpty() && keyPair.second == key) {
|
||||
databases << db;
|
||||
}
|
||||
QString key = db->metadata()->customData()->value(QLatin1String(ASSOCIATE_KEY_PREFIX) + keyPair.first);
|
||||
if (!key.isEmpty() && keyPair.second == key) {
|
||||
databases << db;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -472,102 +446,70 @@ QList<Entry*> BrowserService::searchEntries(const QString& url, const StringPair
|
||||
return entries;
|
||||
}
|
||||
|
||||
void BrowserService::removeSharedEncryptionKeys()
|
||||
void BrowserService::convertAttributesToCustomData(Database *currentDb)
|
||||
{
|
||||
if (!isDatabaseOpened()) {
|
||||
QMessageBox::critical(0,
|
||||
tr("KeePassXC: Database locked!"),
|
||||
tr("The active database is locked!\n"
|
||||
"Please unlock the selected database or choose another one which is unlocked."),
|
||||
QMessageBox::Ok);
|
||||
return;
|
||||
}
|
||||
|
||||
Entry* entry = getConfigEntry();
|
||||
if (!entry) {
|
||||
QMessageBox::information(0,
|
||||
tr("KeePassXC: Settings not available!"),
|
||||
tr("The active database does not contain a settings entry."),
|
||||
QMessageBox::Ok);
|
||||
return;
|
||||
}
|
||||
|
||||
QStringList keysToRemove;
|
||||
for (const QString& key : entry->attributes()->keys()) {
|
||||
if (key.startsWith(ASSOCIATE_KEY_PREFIX)) {
|
||||
keysToRemove << key;
|
||||
}
|
||||
}
|
||||
|
||||
if (keysToRemove.isEmpty()) {
|
||||
QMessageBox::information(0,
|
||||
tr("KeePassXC: No keys found"),
|
||||
tr("No shared encryption keys found in KeePassXC settings."),
|
||||
QMessageBox::Ok);
|
||||
return;
|
||||
}
|
||||
|
||||
entry->beginUpdate();
|
||||
for (const QString& key : keysToRemove) {
|
||||
entry->attributes()->remove(key);
|
||||
}
|
||||
entry->endUpdate();
|
||||
|
||||
const int count = keysToRemove.count();
|
||||
QMessageBox::information(0,
|
||||
tr("KeePassXC: Removed keys from database"),
|
||||
tr("Successfully removed %n encryption key(s) from KeePassXC settings.", "", count),
|
||||
QMessageBox::Ok);
|
||||
}
|
||||
|
||||
void BrowserService::removeStoredPermissions()
|
||||
{
|
||||
if (!isDatabaseOpened()) {
|
||||
QMessageBox::critical(0,
|
||||
tr("KeePassXC: Database locked!"),
|
||||
tr("The active database is locked!\n"
|
||||
"Please unlock the selected database or choose another one which is unlocked."),
|
||||
QMessageBox::Ok);
|
||||
return;
|
||||
}
|
||||
|
||||
Database* db = m_dbTabWidget->currentDatabaseWidget()->database();
|
||||
Database* db = currentDb ? currentDb : getDatabase();
|
||||
if (!db) {
|
||||
return;
|
||||
}
|
||||
|
||||
QList<Entry*> entries = db->rootGroup()->entriesRecursive();
|
||||
|
||||
QProgressDialog progress(tr("Removing stored permissions…"), tr("Abort"), 0, entries.count());
|
||||
QProgressDialog progress(tr("Converting attributes to custom data…"), tr("Abort"), 0, entries.count());
|
||||
progress.setWindowModality(Qt::WindowModal);
|
||||
|
||||
uint counter = 0;
|
||||
int counter = 0;
|
||||
int keyCounter = 0;
|
||||
for (Entry* entry : entries) {
|
||||
if (progress.wasCanceled()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (entry->attributes()->contains(KEEPASSXCBROWSER_NAME)) {
|
||||
entry->beginUpdate();
|
||||
entry->attributes()->remove(KEEPASSXCBROWSER_NAME);
|
||||
entry->endUpdate();
|
||||
if (moveSettingsToCustomData(entry, KEEPASSHTTP_NAME)) {
|
||||
++counter;
|
||||
}
|
||||
if (moveSettingsToCustomData(entry, KEEPASSXCBROWSER_NAME)) {
|
||||
++counter;
|
||||
}
|
||||
|
||||
if (entry->title() == KEEPASSHTTP_NAME || entry->title() == KEEPASSXCBROWSER_NAME) {
|
||||
keyCounter += moveKeysToCustomData(entry, db);
|
||||
delete entry;
|
||||
}
|
||||
|
||||
progress.setValue(progress.value() + 1);
|
||||
}
|
||||
progress.reset();
|
||||
|
||||
if (counter > 0) {
|
||||
QMessageBox::information(0,
|
||||
tr("KeePassXC: Removed permissions"),
|
||||
tr("Successfully removed permissions from %n entry(s).", "", counter),
|
||||
QMessageBox::information(0, tr("KeePassXC: Converted KeePassHTTP attributes"),
|
||||
tr("Successfully converted attributes from %1 entry(s).\n"
|
||||
"Moved %2 keys to custom data.", "").arg(counter).arg(keyCounter),
|
||||
QMessageBox::Ok);
|
||||
} else if (counter == 0 && keyCounter > 0) {
|
||||
QMessageBox::information(0, tr("KeePassXC: Converted KeePassHTTP attributes"),
|
||||
tr("Successfully moved %n keys to custom data.", "", keyCounter),
|
||||
QMessageBox::Ok);
|
||||
} else {
|
||||
QMessageBox::information(0,
|
||||
tr("KeePassXC: No entry with permissions found!"),
|
||||
tr("The active database does not contain an entry with permissions."),
|
||||
QMessageBox::information(0, tr("KeePassXC: No entry with KeePassHTTP attributes found!"),
|
||||
tr("The active database does not contain an entry with KeePassHTTP attributes."),
|
||||
QMessageBox::Ok);
|
||||
}
|
||||
|
||||
// Rename password groupName
|
||||
Group* rootGroup = db->rootGroup();
|
||||
if (!rootGroup) {
|
||||
return;
|
||||
}
|
||||
|
||||
const QString keePassBrowserGroupName = QLatin1String(KEEPASSXCBROWSER_GROUP_NAME);
|
||||
const QString keePassHttpGroupName = QLatin1String(KEEPASSHTTP_GROUP_NAME);
|
||||
|
||||
for (Group* g : rootGroup->groupsRecursive(true)) {
|
||||
if (g->name() == keePassHttpGroupName) {
|
||||
g->setName(keePassBrowserGroupName);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
QList<Entry*> BrowserService::sortEntries(QList<Entry*>& pwEntries, const QString& host, const QString& entryUrl)
|
||||
@ -873,6 +815,75 @@ Database* BrowserService::selectedDatabase()
|
||||
return getDatabase();
|
||||
}
|
||||
|
||||
bool BrowserService::moveSettingsToCustomData(Entry* entry, const QString& name) const
|
||||
{
|
||||
if (entry->attributes()->contains(name)) {
|
||||
QString attr = entry->attributes()->value(name);
|
||||
entry->beginUpdate();
|
||||
if (!attr.isEmpty()) {
|
||||
entry->customData()->set(KEEPASSXCBROWSER_NAME, attr);
|
||||
}
|
||||
entry->attributes()->remove(name);
|
||||
entry->endUpdate();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
int BrowserService::moveKeysToCustomData(Entry* entry, Database* db) const
|
||||
{
|
||||
int keyCounter = 0;
|
||||
for (const auto& key : entry->attributes()->keys()) {
|
||||
if (key.contains(LEGACY_ASSOCIATE_KEY_PREFIX)) {
|
||||
QString publicKey = key;
|
||||
publicKey.remove(LEGACY_ASSOCIATE_KEY_PREFIX);
|
||||
|
||||
// Add key to database custom data
|
||||
if (db && !db->metadata()->customData()->contains(QLatin1String(ASSOCIATE_KEY_PREFIX) + publicKey)) {
|
||||
db->metadata()->customData()->set(QLatin1String(ASSOCIATE_KEY_PREFIX) + publicKey, entry->attributes()->value(key));
|
||||
++keyCounter;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return keyCounter;
|
||||
}
|
||||
|
||||
bool BrowserService::checkLegacySettings()
|
||||
{
|
||||
Database* db = getDatabase();
|
||||
if (!db) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool legacySettingsFound = false;
|
||||
QList<Entry*> entries = db->rootGroup()->entriesRecursive();
|
||||
for (const auto& e : entries) {
|
||||
if ((e->attributes()->contains(KEEPASSHTTP_NAME) || e->attributes()->contains(KEEPASSXCBROWSER_NAME)) ||
|
||||
(e->title() == KEEPASSHTTP_NAME || e->title() == KEEPASSXCBROWSER_NAME)) {
|
||||
legacySettingsFound = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!legacySettingsFound) {
|
||||
return false;
|
||||
}
|
||||
|
||||
auto dialogResult = QMessageBox::warning(nullptr,
|
||||
tr("KeePassXC: Legacy browser integration settings detected"),
|
||||
tr("Legacy browser integration settings have been detected.\n"
|
||||
"Do you want to upgrade the settings to the latest standard?\n"
|
||||
"This is necessary to maintain compatibility with the browser plugin."),
|
||||
QMessageBox::Yes | QMessageBox::No);
|
||||
|
||||
if (dialogResult == QMessageBox::No) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void BrowserService::databaseLocked(DatabaseWidget* dbWidget)
|
||||
{
|
||||
if (dbWidget) {
|
||||
@ -888,6 +899,10 @@ void BrowserService::databaseUnlocked(DatabaseWidget* dbWidget)
|
||||
m_bringToFrontRequested = false;
|
||||
}
|
||||
emit databaseUnlocked();
|
||||
|
||||
if (checkLegacySettings()) {
|
||||
convertAttributesToCustomData();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -55,8 +55,12 @@ public:
|
||||
Database* selectedDb = nullptr);
|
||||
QList<Entry*> searchEntries(Database* db, const QString& hostname, const QString& url);
|
||||
QList<Entry*> searchEntries(const QString& url, const StringPairList& keyList);
|
||||
void removeSharedEncryptionKeys();
|
||||
void removeStoredPermissions();
|
||||
void convertAttributesToCustomData(Database *currentDb = nullptr);
|
||||
|
||||
public:
|
||||
static const char KEEPASSXCBROWSER_NAME[];
|
||||
static const char ASSOCIATE_KEY_PREFIX[];
|
||||
static const char LEGACY_ASSOCIATE_KEY_PREFIX[];
|
||||
|
||||
public slots:
|
||||
QJsonArray findMatchingEntries(const QString& id,
|
||||
@ -106,6 +110,9 @@ private:
|
||||
QString baseDomain(const QString& url) const;
|
||||
Database* getDatabase();
|
||||
Database* selectedDatabase();
|
||||
bool moveSettingsToCustomData(Entry* entry, const QString& name) const;
|
||||
int moveKeysToCustomData(Entry* entry, Database* db) const;
|
||||
bool checkLegacySettings();
|
||||
|
||||
private:
|
||||
DatabaseTabWidget* const m_dbTabWidget;
|
||||
|
@ -207,18 +207,6 @@ void NativeMessagingHost::disconnectSocket()
|
||||
}
|
||||
}
|
||||
|
||||
void NativeMessagingHost::removeSharedEncryptionKeys()
|
||||
{
|
||||
QMutexLocker locker(&m_mutex);
|
||||
m_browserService.removeSharedEncryptionKeys();
|
||||
}
|
||||
|
||||
void NativeMessagingHost::removeStoredPermissions()
|
||||
{
|
||||
QMutexLocker locker(&m_mutex);
|
||||
m_browserService.removeStoredPermissions();
|
||||
}
|
||||
|
||||
void NativeMessagingHost::databaseLocked()
|
||||
{
|
||||
QJsonObject response;
|
||||
|
@ -37,10 +37,6 @@ public:
|
||||
void run();
|
||||
void stop();
|
||||
|
||||
public slots:
|
||||
void removeSharedEncryptionKeys();
|
||||
void removeStoredPermissions();
|
||||
|
||||
signals:
|
||||
void quit();
|
||||
|
||||
|
@ -84,12 +84,6 @@ public:
|
||||
QWidget* createWidget() override
|
||||
{
|
||||
BrowserOptionDialog* dlg = new BrowserOptionDialog();
|
||||
QObject::connect(dlg,
|
||||
SIGNAL(removeSharedEncryptionKeys()),
|
||||
m_nativeMessagingHost.data(),
|
||||
SLOT(removeSharedEncryptionKeys()));
|
||||
QObject::connect(
|
||||
dlg, SIGNAL(removeStoredPermissions()), m_nativeMessagingHost.data(), SLOT(removeStoredPermissions()));
|
||||
return dlg;
|
||||
}
|
||||
|
||||
@ -108,8 +102,8 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
QSharedPointer<NativeMessagingHost> m_nativeMessagingHost;
|
||||
private:
|
||||
QSharedPointer<NativeMessagingHost> m_nativeMessagingHost;
|
||||
};
|
||||
#endif
|
||||
|
||||
|
@ -21,6 +21,9 @@
|
||||
#include "DatabaseSettingsWidgetGeneral.h"
|
||||
#include "DatabaseSettingsWidgetEncryption.h"
|
||||
#include "DatabaseSettingsWidgetMasterKey.h"
|
||||
#ifdef WITH_XC_BROWSER
|
||||
#include "DatabaseSettingsWidgetBrowser.h"
|
||||
#endif
|
||||
|
||||
#include "core/Config.h"
|
||||
#include "core/FilePath.h"
|
||||
@ -34,6 +37,9 @@ DatabaseSettingsDialog::DatabaseSettingsDialog(QWidget* parent)
|
||||
, m_securityTabWidget(new QTabWidget(this))
|
||||
, m_masterKeyWidget(new DatabaseSettingsWidgetMasterKey(this))
|
||||
, m_encryptionWidget(new DatabaseSettingsWidgetEncryption(this))
|
||||
#ifdef WITH_XC_BROWSER
|
||||
, m_browserWidget(new DatabaseSettingsWidgetBrowser(this))
|
||||
#endif
|
||||
{
|
||||
m_ui->setupUi(this);
|
||||
|
||||
@ -55,6 +61,11 @@ DatabaseSettingsDialog::DatabaseSettingsDialog(QWidget* parent)
|
||||
connect(m_ui->categoryList, SIGNAL(categoryChanged(int)), m_ui->stackedWidget, SLOT(setCurrentIndex(int)));
|
||||
connect(m_ui->advancedSettingsToggle, SIGNAL(toggled(bool)), SLOT(toggleAdvancedMode(bool)));
|
||||
|
||||
#ifdef WITH_XC_BROWSER
|
||||
m_ui->categoryList->addCategory(tr("Browser Integration"), FilePath::instance()->icon("apps", "internet-web-browser"));
|
||||
m_ui->stackedWidget->addWidget(m_browserWidget);
|
||||
#endif
|
||||
|
||||
pageChanged();
|
||||
}
|
||||
|
||||
@ -68,6 +79,9 @@ void DatabaseSettingsDialog::load(Database* db)
|
||||
m_generalWidget->load(db);
|
||||
m_masterKeyWidget->load(db);
|
||||
m_encryptionWidget->load(db);
|
||||
#ifdef WITH_XC_BROWSER
|
||||
m_browserWidget->load(db);
|
||||
#endif
|
||||
m_ui->advancedSettingsToggle->setChecked(config()->get("GUI/AdvancedSettings", false).toBool());
|
||||
m_db = db;
|
||||
}
|
||||
|
@ -19,6 +19,7 @@
|
||||
#define KEEPASSX_DATABASESETTINGSWIDGET_H
|
||||
|
||||
#include "gui/DialogyWidget.h"
|
||||
#include "config-keepassx.h"
|
||||
|
||||
#include <QScopedPointer>
|
||||
#include <QPointer>
|
||||
@ -27,6 +28,9 @@ class Database;
|
||||
class DatabaseSettingsWidgetGeneral;
|
||||
class DatabaseSettingsWidgetEncryption;
|
||||
class DatabaseSettingsWidgetMasterKey;
|
||||
#ifdef WITH_XC_BROWSER
|
||||
class DatabaseSettingsWidgetBrowser;
|
||||
#endif
|
||||
class QTabWidget;
|
||||
|
||||
namespace Ui
|
||||
@ -68,6 +72,9 @@ private:
|
||||
QPointer<QTabWidget> m_securityTabWidget;
|
||||
QPointer<DatabaseSettingsWidgetMasterKey> m_masterKeyWidget;
|
||||
QPointer<DatabaseSettingsWidgetEncryption> m_encryptionWidget;
|
||||
#ifdef WITH_XC_BROWSER
|
||||
QPointer<DatabaseSettingsWidgetBrowser> m_browserWidget;
|
||||
#endif
|
||||
};
|
||||
|
||||
#endif // KEEPASSX_DATABASESETTINGSWIDGET_H
|
||||
|
245
src/gui/dbsettings/DatabaseSettingsWidgetBrowser.cpp
Normal file
245
src/gui/dbsettings/DatabaseSettingsWidgetBrowser.cpp
Normal file
@ -0,0 +1,245 @@
|
||||
/*
|
||||
* Copyright (C) 2018 KeePassXC Team <team@keepassxc.org>
|
||||
* Copyright (C) 2018 Sami Vänttinen <sami.vanttinen@protonmail.com>
|
||||
*
|
||||
* 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 "DatabaseSettingsWidgetBrowser.h"
|
||||
#include <QProgressDialog>
|
||||
#include "core/Clock.h"
|
||||
#include "core/Database.h"
|
||||
#include "core/Entry.h"
|
||||
#include "core/Group.h"
|
||||
#include "core/Metadata.h"
|
||||
#include "gui/MessageBox.h"
|
||||
#include "browser/BrowserSettings.h"
|
||||
#include "ui_DatabaseSettingsWidgetBrowser.h"
|
||||
|
||||
DatabaseSettingsWidgetBrowser::DatabaseSettingsWidgetBrowser(QWidget* parent)
|
||||
: DatabaseSettingsWidget(parent), m_ui(new Ui::DatabaseSettingsWidgetBrowser())
|
||||
, m_customData(new CustomData(this))
|
||||
, m_customDataModel(new QStandardItemModel(this))
|
||||
, m_browserService(nullptr)
|
||||
{
|
||||
m_ui->setupUi(this);
|
||||
m_ui->removeCustomDataButton->setEnabled(false);
|
||||
m_ui->customDataTable->setModel(m_customDataModel);
|
||||
|
||||
settingsWarning();
|
||||
connect(m_ui->customDataTable->selectionModel(), SIGNAL(selectionChanged(QItemSelection, QItemSelection)),
|
||||
SLOT(toggleRemoveButton(QItemSelection)));
|
||||
connect(m_ui->removeCustomDataButton, SIGNAL(clicked()), SLOT(removeSelectedKey()));
|
||||
connect(m_ui->convertToCustomData, SIGNAL(clicked()), this, SLOT(convertAttributesToCustomData()));
|
||||
connect(m_ui->convertToCustomData, SIGNAL(clicked()), this, SLOT(updateSharedKeyList()));
|
||||
connect(m_ui->removeSharedEncryptionKeys, SIGNAL(clicked()), this, SLOT(removeSharedEncryptionKeys()));
|
||||
connect(m_ui->removeSharedEncryptionKeys, SIGNAL(clicked()), this, SLOT(updateSharedKeyList()));
|
||||
connect(m_ui->removeStoredPermissions, SIGNAL(clicked()), this, SLOT(removeStoredPermissions()));
|
||||
}
|
||||
|
||||
DatabaseSettingsWidgetBrowser::~DatabaseSettingsWidgetBrowser()
|
||||
{
|
||||
}
|
||||
|
||||
CustomData* DatabaseSettingsWidgetBrowser::customData() const
|
||||
{
|
||||
// Returns the current database customData from metadata. Otherwise return an empty customData member.
|
||||
if (m_db) {
|
||||
return m_db->metadata()->customData();
|
||||
}
|
||||
return m_customData;
|
||||
}
|
||||
|
||||
void DatabaseSettingsWidgetBrowser::initialize()
|
||||
{
|
||||
updateModel();
|
||||
settingsWarning();
|
||||
}
|
||||
|
||||
void DatabaseSettingsWidgetBrowser::uninitialize()
|
||||
{
|
||||
}
|
||||
|
||||
void DatabaseSettingsWidgetBrowser::showEvent(QShowEvent* event)
|
||||
{
|
||||
QWidget::showEvent(event);
|
||||
}
|
||||
|
||||
bool DatabaseSettingsWidgetBrowser::save()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
void DatabaseSettingsWidgetBrowser::removeSelectedKey()
|
||||
{
|
||||
if (QMessageBox::Yes != MessageBox::question(this,
|
||||
tr("Delete the selected key?"),
|
||||
tr("Do you really want to delete the selected key?\n"
|
||||
"This may prevent connection to the browser plugin."),
|
||||
QMessageBox::Yes | QMessageBox::Cancel, QMessageBox::Cancel)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const QItemSelectionModel* itemSelectionModel = m_ui->customDataTable->selectionModel();
|
||||
if (itemSelectionModel) {
|
||||
for (const QModelIndex& index : itemSelectionModel->selectedRows(0)) {
|
||||
QString key = index.data().toString();
|
||||
key.insert(0, BrowserService::ASSOCIATE_KEY_PREFIX);
|
||||
customData()->remove(key);
|
||||
}
|
||||
updateModel();
|
||||
}
|
||||
}
|
||||
|
||||
void DatabaseSettingsWidgetBrowser::toggleRemoveButton(const QItemSelection& selected)
|
||||
{
|
||||
m_ui->removeCustomDataButton->setEnabled(!selected.isEmpty());
|
||||
}
|
||||
|
||||
void DatabaseSettingsWidgetBrowser::updateModel()
|
||||
{
|
||||
m_customDataModel->clear();
|
||||
m_customDataModel->setHorizontalHeaderLabels({tr("Key"), tr("Value")});
|
||||
|
||||
for (const QString& key : customData()->keys()) {
|
||||
if (key.startsWith(BrowserService::ASSOCIATE_KEY_PREFIX)) {
|
||||
QString strippedKey = key;
|
||||
strippedKey.remove(BrowserService::ASSOCIATE_KEY_PREFIX);
|
||||
m_customDataModel->appendRow(QList<QStandardItem*>()
|
||||
<< new QStandardItem(strippedKey)
|
||||
<< new QStandardItem(customData()->value(key)));
|
||||
}
|
||||
}
|
||||
|
||||
m_ui->removeCustomDataButton->setEnabled(false);
|
||||
}
|
||||
|
||||
void DatabaseSettingsWidgetBrowser::settingsWarning()
|
||||
{
|
||||
if (!browserSettings()->isEnabled()) {
|
||||
m_ui->convertToCustomData->setEnabled(false);
|
||||
m_ui->removeSharedEncryptionKeys->setEnabled(false);
|
||||
m_ui->removeStoredPermissions->setEnabled(false);
|
||||
m_ui->customDataTable->setEnabled(false);
|
||||
m_ui->warningWidget->showMessage(tr("Enable Browser Integration to access these settings."), MessageWidget::Warning);
|
||||
m_ui->warningWidget->setCloseButtonVisible(false);
|
||||
m_ui->warningWidget->setAutoHideTimeout(-1);
|
||||
} else {
|
||||
m_ui->convertToCustomData->setEnabled(true);
|
||||
m_ui->removeSharedEncryptionKeys->setEnabled(true);
|
||||
m_ui->removeStoredPermissions->setEnabled(true);
|
||||
m_ui->customDataTable->setEnabled(true);
|
||||
m_ui->warningWidget->hideMessage();
|
||||
}
|
||||
}
|
||||
|
||||
void DatabaseSettingsWidgetBrowser::removeSharedEncryptionKeys()
|
||||
{
|
||||
if (QMessageBox::Yes != MessageBox::question(this,
|
||||
tr("Disconnect all browsers"),
|
||||
tr("Do you really want to disconnect all browsers?\n"
|
||||
"This may prevent connection to the browser plugin."),
|
||||
QMessageBox::Yes | QMessageBox::Cancel, QMessageBox::Cancel)) {
|
||||
return;
|
||||
}
|
||||
|
||||
QStringList keysToRemove;
|
||||
for (const QString& key : m_db->metadata()->customData()->keys()) {
|
||||
if (key.startsWith(BrowserService::ASSOCIATE_KEY_PREFIX)) {
|
||||
keysToRemove << key;
|
||||
}
|
||||
}
|
||||
|
||||
if (keysToRemove.isEmpty()) {
|
||||
QMessageBox::information(this,
|
||||
tr("KeePassXC: No keys found"),
|
||||
tr("No shared encryption keys found in KeePassXC settings."),
|
||||
QMessageBox::Ok);
|
||||
return;
|
||||
}
|
||||
|
||||
for (const QString& key : keysToRemove) {
|
||||
m_db->metadata()->customData()->remove(key);
|
||||
}
|
||||
|
||||
const int count = keysToRemove.count();
|
||||
QMessageBox::information(this,
|
||||
tr("KeePassXC: Removed keys from database"),
|
||||
tr("Successfully removed %n encryption key(s) from KeePassXC settings.", "", count),
|
||||
QMessageBox::Ok);
|
||||
}
|
||||
|
||||
void DatabaseSettingsWidgetBrowser::removeStoredPermissions()
|
||||
{
|
||||
if (QMessageBox::Yes != MessageBox::question(this,
|
||||
tr("Forget all site-specific settings on entries"),
|
||||
tr("Do you really want forget all site-specific settings on every entry?\n"
|
||||
"Permissions to access entries will be revoked."),
|
||||
QMessageBox::Yes | QMessageBox::Cancel, QMessageBox::Cancel)) {
|
||||
return;
|
||||
}
|
||||
|
||||
QList<Entry*> entries = m_db->rootGroup()->entriesRecursive();
|
||||
|
||||
QProgressDialog progress(tr("Removing stored permissions…"), tr("Abort"), 0, entries.count());
|
||||
progress.setWindowModality(Qt::WindowModal);
|
||||
|
||||
uint counter = 0;
|
||||
for (Entry* entry : entries) {
|
||||
if (progress.wasCanceled()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (entry->customData()->contains(BrowserService::KEEPASSXCBROWSER_NAME)) {
|
||||
entry->beginUpdate();
|
||||
entry->customData()->remove(BrowserService::KEEPASSXCBROWSER_NAME);
|
||||
entry->endUpdate();
|
||||
++counter;
|
||||
}
|
||||
progress.setValue(progress.value() + 1);
|
||||
}
|
||||
progress.reset();
|
||||
|
||||
if (counter > 0) {
|
||||
QMessageBox::information(this,
|
||||
tr("KeePassXC: Removed permissions"),
|
||||
tr("Successfully removed permissions from %n entry(s).", "", counter),
|
||||
QMessageBox::Ok);
|
||||
} else {
|
||||
QMessageBox::information(this,
|
||||
tr("KeePassXC: No entry with permissions found!"),
|
||||
tr("The active database does not contain an entry with permissions."),
|
||||
QMessageBox::Ok);
|
||||
}
|
||||
}
|
||||
|
||||
void DatabaseSettingsWidgetBrowser::convertAttributesToCustomData()
|
||||
{
|
||||
if (QMessageBox::Yes != MessageBox::question(this,
|
||||
tr("Move KeePassHTTP attributes to custom data"),
|
||||
tr("Do you really want to move all legacy browser integration data to the latest standard?\n"
|
||||
"This is necessary to maintain compatibility with the browser plugin."),
|
||||
QMessageBox::Yes | QMessageBox::Cancel, QMessageBox::Cancel)) {
|
||||
return;
|
||||
}
|
||||
|
||||
m_browserService.convertAttributesToCustomData(m_db);
|
||||
}
|
||||
|
||||
// Updates the shared key list after the list is cleared
|
||||
void DatabaseSettingsWidgetBrowser::updateSharedKeyList()
|
||||
{
|
||||
updateModel();
|
||||
}
|
||||
|
78
src/gui/dbsettings/DatabaseSettingsWidgetBrowser.h
Normal file
78
src/gui/dbsettings/DatabaseSettingsWidgetBrowser.h
Normal file
@ -0,0 +1,78 @@
|
||||
/*
|
||||
* Copyright (C) 2018 KeePassXC Team <team@keepassxc.org>
|
||||
* Copyright (C) 2018 Sami Vänttinen <sami.vanttinen@protonmail.com>
|
||||
*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
#ifndef KEEPASSXC_DATABASESETTINGSWIDGETBROWSER_H
|
||||
#define KEEPASSXC_DATABASESETTINGSWIDGETBROWSER_H
|
||||
|
||||
#include "DatabaseSettingsWidget.h"
|
||||
|
||||
#include <QPointer>
|
||||
#include <QScopedPointer>
|
||||
#include <QStandardItemModel>
|
||||
#include <QItemSelection>
|
||||
#include "core/CustomData.h"
|
||||
#include "gui/DatabaseTabWidget.h"
|
||||
#include "browser/BrowserService.h"
|
||||
|
||||
class Database;
|
||||
namespace Ui
|
||||
{
|
||||
class DatabaseSettingsWidgetBrowser;
|
||||
}
|
||||
|
||||
class DatabaseSettingsWidgetBrowser : public DatabaseSettingsWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit DatabaseSettingsWidgetBrowser(QWidget* parent = nullptr);
|
||||
Q_DISABLE_COPY(DatabaseSettingsWidgetBrowser);
|
||||
~DatabaseSettingsWidgetBrowser() override;
|
||||
|
||||
CustomData* customData() const;
|
||||
inline bool hasAdvancedMode() const override { return false; }
|
||||
|
||||
public slots:
|
||||
void initialize() override;
|
||||
void uninitialize() override;
|
||||
bool save() override;
|
||||
|
||||
private slots:
|
||||
void removeSelectedKey();
|
||||
void toggleRemoveButton(const QItemSelection& selected);
|
||||
void updateSharedKeyList();
|
||||
void removeSharedEncryptionKeys();
|
||||
void removeStoredPermissions();
|
||||
void convertAttributesToCustomData();
|
||||
|
||||
private:
|
||||
void updateModel();
|
||||
void settingsWarning();
|
||||
|
||||
protected:
|
||||
void showEvent(QShowEvent* event) override;
|
||||
|
||||
const QScopedPointer<Ui::DatabaseSettingsWidgetBrowser> m_ui;
|
||||
|
||||
private:
|
||||
QPointer<CustomData> m_customData;
|
||||
QPointer<QStandardItemModel> m_customDataModel;
|
||||
BrowserService m_browserService;
|
||||
};
|
||||
|
||||
#endif //KEEPASSXC_DATABASESETTINGSWIDGETBROWSER_H
|
174
src/gui/dbsettings/DatabaseSettingsWidgetBrowser.ui
Normal file
174
src/gui/dbsettings/DatabaseSettingsWidgetBrowser.ui
Normal file
@ -0,0 +1,174 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>DatabaseSettingsWidgetBrowser</class>
|
||||
<widget class="QWidget" name="DatabaseSettingsWidgetBrowser">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>453</width>
|
||||
<height>374</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>450</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="MessageWidget" name="warningWidget" native="true">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="groupBox">
|
||||
<property name="title">
|
||||
<string>KeePassXC-Browser settings</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<widget class="QPushButton" name="removeSharedEncryptionKeys">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>&Disconnect all browsers</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="removeStoredPermissions">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Forg&et all site-specific settings on entries</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
||||
<item>
|
||||
<widget class="QPushButton" name="convertToCustomData">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Move KeePassHTTP attributes to KeePassXC-Browser &custom data</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="groupBox_2">
|
||||
<property name="title">
|
||||
<string>Stored keys</string>
|
||||
</property>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_3">
|
||||
<item>
|
||||
<widget class="QGroupBox" name="groupBox">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_4">
|
||||
<item>
|
||||
<widget class="QTableView" name="customDataTable">
|
||||
<property name="editTriggers">
|
||||
<set>QAbstractItemView::NoEditTriggers</set>
|
||||
</property>
|
||||
<property name="selectionBehavior">
|
||||
<enum>QAbstractItemView::SelectRows</enum>
|
||||
</property>
|
||||
<attribute name="horizontalHeaderDefaultSectionSize">
|
||||
<number>200</number>
|
||||
</attribute>
|
||||
<attribute name="horizontalHeaderStretchLastSection">
|
||||
<bool>true</bool>
|
||||
</attribute>
|
||||
<attribute name="verticalHeaderVisible">
|
||||
<bool>false</bool>
|
||||
</attribute>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_3">
|
||||
<item>
|
||||
<widget class="QPushButton" name="removeCustomDataButton">
|
||||
<property name="text">
|
||||
<string>Remove</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="verticalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>40</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<customwidgets>
|
||||
<customwidget>
|
||||
<class>MessageWidget</class>
|
||||
<extends>QWidget</extends>
|
||||
<header>gui/MessageWidget.h</header>
|
||||
<container>1</container>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
Loading…
Reference in New Issue
Block a user