Refactor Database and Database widgets (#2491)

The Database, DatabaseWidget, and DatabaseTabWidget classes share many responsibilities in inconsistent ways resulting in impenetrable and unmaintainable code and a diverse set of bugs and architecture restrictions. This patch reworks the architecture, responsibilities of, and dependencies between these classes.

The core changes are:

* Move loading and saving logic from widgets into the Database class
* Get rid of the DatabaseManagerStruct and move all the information contained in it into the Database
* Let database objects keep track of modifications and dirty/clean state instead of handing this to external widgets
* Move GUI interactions for loading and saving from the DatabaseTabWidget into the DatabaseWidget (resolves #2494 as a side-effect)
* Heavily clean up DatabaseTabWidget and degrade it to a slightly glorified QTabWidget
* Use QSharedPointers for all Database objects
* Remove the modifiedImmediate signal and replace it with a markAsModified() method
* Implement proper tabName() method instead of reading back titles from GUI widgets (resolves #1389 and its duplicates #2146 #855)
* Fix unwanted AES-KDF downgrade if database uses Argon2 and has CustomData
* Improve code

This patch is also the first major step towards solving issues #476 and #2322.
This commit is contained in:
Janek Bevendorff 2018-11-22 11:47:31 +01:00 committed by GitHub
parent 917c4cc18b
commit d612cad09a
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
115 changed files with 2116 additions and 2165 deletions

View file

@ -69,7 +69,7 @@ bool BrowserService::isDatabaseOpened() const
return false;
}
return dbWidget->currentMode() == DatabaseWidget::ViewMode || dbWidget->currentMode() == DatabaseWidget::EditMode;
return dbWidget->currentMode() == DatabaseWidget::Mode::ViewMode || dbWidget->currentMode() == DatabaseWidget::Mode::EditMode;
}
bool BrowserService::openDatabase(bool triggerUnlock)
@ -83,7 +83,7 @@ bool BrowserService::openDatabase(bool triggerUnlock)
return false;
}
if (dbWidget->currentMode() == DatabaseWidget::ViewMode || dbWidget->currentMode() == DatabaseWidget::EditMode) {
if (dbWidget->currentMode() == DatabaseWidget::Mode::ViewMode || dbWidget->currentMode() == DatabaseWidget::Mode::EditMode) {
return true;
}
@ -106,14 +106,14 @@ void BrowserService::lockDatabase()
return;
}
if (dbWidget->currentMode() == DatabaseWidget::ViewMode || dbWidget->currentMode() == DatabaseWidget::EditMode) {
if (dbWidget->currentMode() == DatabaseWidget::Mode::ViewMode || dbWidget->currentMode() == DatabaseWidget::Mode::EditMode) {
dbWidget->lock();
}
}
QString BrowserService::getDatabaseRootUuid()
{
Database* db = getDatabase();
auto db = getDatabase();
if (!db) {
return {};
}
@ -128,7 +128,7 @@ QString BrowserService::getDatabaseRootUuid()
QString BrowserService::getDatabaseRecycleBinUuid()
{
Database* db = getDatabase();
auto db = getDatabase();
if (!db) {
return {};
}
@ -150,7 +150,7 @@ QString BrowserService::storeKey(const QString& key)
return id;
}
Database* db = getDatabase();
auto db = getDatabase();
if (!db) {
return {};
}
@ -194,7 +194,7 @@ QString BrowserService::storeKey(const QString& key)
QString BrowserService::getKey(const QString& id)
{
Database* db = getDatabase();
auto db = getDatabase();
if (!db) {
return {};
}
@ -268,13 +268,10 @@ QJsonArray BrowserService::findMatchingEntries(const QString& id,
return result;
}
void BrowserService::addEntry(const QString& id,
const QString& login,
const QString& password,
const QString& url,
const QString& submitUrl,
const QString& realm,
Database* selectedDb)
void BrowserService::addEntry(const QString& id, const QString& login,
const QString& password, const QString& url,
const QString& submitUrl, const QString& realm,
QSharedPointer<Database> selectedDb)
{
if (thread() != QThread::currentThread()) {
QMetaObject::invokeMethod(this,
@ -286,10 +283,10 @@ void BrowserService::addEntry(const QString& id,
Q_ARG(QString, url),
Q_ARG(QString, submitUrl),
Q_ARG(QString, realm),
Q_ARG(Database*, selectedDb));
Q_ARG(QSharedPointer<Database>, selectedDb));
}
Database* db = selectedDb ? selectedDb : selectedDatabase();
auto db = selectedDb ? selectedDb : selectedDatabase();
if (!db) {
return;
}
@ -299,7 +296,7 @@ void BrowserService::addEntry(const QString& id,
return;
}
Entry* entry = new Entry();
auto* entry = new Entry();
entry->setUuid(QUuid::createUuid());
entry->setTitle(QUrl(url).host());
entry->setUrl(url);
@ -341,12 +338,12 @@ void BrowserService::updateEntry(const QString& id,
Q_ARG(QString, submitUrl));
}
Database* db = selectedDatabase();
auto db = selectedDatabase();
if (!db) {
return;
}
Entry* entry = db->resolveEntry(QUuid::fromRfc4122(QByteArray::fromHex(uuid.toLatin1())));
Entry* entry = db->rootGroup()->findEntryByUuid(QUuid::fromRfc4122(QByteArray::fromHex(uuid.toLatin1())));
if (!entry) {
// If entry is not found for update, add a new one to the selected database
addEntry(id, login, password, url, submitUrl, "", db);
@ -382,10 +379,10 @@ void BrowserService::updateEntry(const QString& id,
}
}
QList<Entry*> BrowserService::searchEntries(Database* db, const QString& hostname, const QString& url)
QList<Entry*> BrowserService::searchEntries(QSharedPointer<Database> db, const QString& hostname, const QString& url)
{
QList<Entry*> entries;
Group* rootGroup = db->rootGroup();
auto* rootGroup = db->rootGroup();
if (!rootGroup) {
return entries;
}
@ -415,12 +412,12 @@ QList<Entry*> BrowserService::searchEntries(Database* db, const QString& hostnam
QList<Entry*> BrowserService::searchEntries(const QString& url, const StringPairList& keyList)
{
// Get the list of databases to search
QList<Database*> databases;
QList<QSharedPointer<Database>> databases;
if (browserSettings()->searchInAllDatabases()) {
const int count = m_dbTabWidget->count();
for (int i = 0; i < count; ++i) {
if (DatabaseWidget* dbWidget = qobject_cast<DatabaseWidget*>(m_dbTabWidget->widget(i))) {
if (Database* db = dbWidget->database()) {
if (auto* dbWidget = qobject_cast<DatabaseWidget*>(m_dbTabWidget->widget(i))) {
if (const auto& db = dbWidget->database()) {
// Check if database is connected with KeePassXC-Browser
for (const StringPair& keyPair : keyList) {
QString key = db->metadata()->customData()->value(QLatin1String(ASSOCIATE_KEY_PREFIX) + keyPair.first);
@ -431,7 +428,7 @@ QList<Entry*> BrowserService::searchEntries(const QString& url, const StringPair
}
}
}
} else if (Database* db = getDatabase()) {
} else if (const auto& db = getDatabase()) {
databases << db;
}
@ -439,7 +436,7 @@ QList<Entry*> BrowserService::searchEntries(const QString& url, const StringPair
QString hostname = QUrl(url).host();
QList<Entry*> entries;
do {
for (Database* db : databases) {
for (const auto& db : databases) {
entries << searchEntries(db, hostname, url);
}
} while (entries.isEmpty() && removeFirstDomain(hostname));
@ -447,9 +444,9 @@ QList<Entry*> BrowserService::searchEntries(const QString& url, const StringPair
return entries;
}
void BrowserService::convertAttributesToCustomData(Database *currentDb)
void BrowserService::convertAttributesToCustomData(QSharedPointer<Database> currentDb)
{
Database* db = currentDb ? currentDb : getDatabase();
auto db = currentDb ? currentDb : getDatabase();
if (!db) {
return;
}
@ -651,9 +648,9 @@ BrowserService::checkAccess(const Entry* entry, const QString& host, const QStri
return Unknown;
}
Group* BrowserService::findCreateAddEntryGroup(Database* selectedDb)
Group* BrowserService::findCreateAddEntryGroup(QSharedPointer<Database> selectedDb)
{
Database* db = selectedDb ? selectedDb : getDatabase();
auto db = selectedDb ? selectedDb : getDatabase();
if (!db) {
return nullptr;
}
@ -668,11 +665,11 @@ Group* BrowserService::findCreateAddEntryGroup(Database* selectedDb)
for (const Group* g : rootGroup->groupsRecursive(true)) {
if (g->name() == groupName) {
return db->resolveGroup(g->uuid());
return db->rootGroup()->findGroupByUuid(g->uuid());
}
}
Group* group = new Group();
auto* group = new Group();
group->setUuid(QUuid::createUuid());
group->setName(groupName);
group->setIcon(KEEPASSXCBROWSER_DEFAULT_ICON);
@ -775,26 +772,26 @@ QString BrowserService::baseDomain(const QString& url) const
return baseDomain;
}
Database* BrowserService::getDatabase()
QSharedPointer<Database> BrowserService::getDatabase()
{
if (DatabaseWidget* dbWidget = m_dbTabWidget->currentDatabaseWidget()) {
if (Database* db = dbWidget->database()) {
if (const auto& db = dbWidget->database()) {
return db;
}
}
return nullptr;
return {};
}
Database* BrowserService::selectedDatabase()
QSharedPointer<Database> BrowserService::selectedDatabase()
{
QList<DatabaseWidget*> databaseWidgets;
for (int i = 0;; ++i) {
const auto dbStruct = m_dbTabWidget->indexDatabaseManagerStruct(i);
for (int i = 0; ; ++i) {
auto* dbWidget = m_dbTabWidget->databaseWidgetFromIndex(i);
// Add only open databases
if (dbStruct.dbWidget && dbStruct.dbWidget->dbHasKey() &&
(dbStruct.dbWidget->currentMode() == DatabaseWidget::ViewMode ||
dbStruct.dbWidget->currentMode() == DatabaseWidget::EditMode)) {
databaseWidgets.push_back(dbStruct.dbWidget);
if (dbWidget && dbWidget->database()->hasKey() &&
(dbWidget->currentMode() == DatabaseWidget::Mode::ViewMode ||
dbWidget->currentMode() == DatabaseWidget::Mode::EditMode)) {
databaseWidgets.push_back(dbWidget);
continue;
}
@ -813,7 +810,7 @@ Database* BrowserService::selectedDatabase()
return databaseWidgets[index]->database();
}
} else {
return nullptr;
return {};
}
}
@ -836,7 +833,7 @@ bool BrowserService::moveSettingsToCustomData(Entry* entry, const QString& name)
return false;
}
int BrowserService::moveKeysToCustomData(Entry* entry, Database* db) const
int BrowserService::moveKeysToCustomData(Entry* entry, QSharedPointer<Database> db) const
{
int keyCounter = 0;
for (const auto& key : entry->attributes()->keys()) {
@ -857,7 +854,7 @@ int BrowserService::moveKeysToCustomData(Entry* entry, Database* db) const
bool BrowserService::checkLegacySettings()
{
Database* db = getDatabase();
auto db = getDatabase();
if (!db) {
return false;
}
@ -882,12 +879,8 @@ bool BrowserService::checkLegacySettings()
"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;
return dialogResult == QMessageBox::Yes;
}
void BrowserService::databaseLocked(DatabaseWidget* dbWidget)
@ -916,7 +909,7 @@ void BrowserService::activateDatabaseChanged(DatabaseWidget* dbWidget)
{
if (dbWidget) {
auto currentMode = dbWidget->currentMode();
if (currentMode == DatabaseWidget::ViewMode || currentMode == DatabaseWidget::EditMode) {
if (currentMode == DatabaseWidget::Mode::ViewMode || currentMode == DatabaseWidget::Mode::EditMode) {
emit databaseUnlocked();
} else {
emit databaseLocked();