From 2fb542b3ba19a077fe9b488f5dbcf380948d513c Mon Sep 17 00:00:00 2001 From: Jonathan White Date: Fri, 12 Jan 2024 18:45:07 -0500 Subject: [PATCH] Fix support for referenced URL fields --- src/browser/BrowserService.cpp | 17 +------------ src/browser/BrowserService.h | 1 - src/core/Entry.cpp | 8 +++--- tests/TestBrowser.cpp | 45 +++++++++++++++++++++++++++++++--- tests/TestBrowser.h | 1 + 5 files changed, 49 insertions(+), 23 deletions(-) diff --git a/src/browser/BrowserService.cpp b/src/browser/BrowserService.cpp index 3989f60aea..c91619d6d7 100644 --- a/src/browser/BrowserService.cpp +++ b/src/browser/BrowserService.cpp @@ -885,7 +885,7 @@ QList BrowserService::sortEntries(QList& entries, const QString& // Build map of prioritized entries QMultiMap priorities; for (auto* entry : entries) { - priorities.insert(sortPriority(getEntryURLs(entry), siteUrl, formUrl), entry); + priorities.insert(sortPriority(entry->getAllUrls(), siteUrl, formUrl), entry); } auto keys = priorities.uniqueKeys(); @@ -1363,21 +1363,6 @@ bool BrowserService::checkLegacySettings(QSharedPointer db) return dialogResult == MessageBox::Yes; } -QStringList BrowserService::getEntryURLs(const Entry* entry) -{ - QStringList urlList; - urlList << entry->url(); - - // Handle additional URL's - for (const auto& key : entry->attributes()->keys()) { - if (key.startsWith(ADDITIONAL_URL)) { - urlList << entry->attributes()->value(key); - } - } - - return urlList; -} - void BrowserService::hideWindow() const { if (m_prevWindowState == WindowState::Minimized) { diff --git a/src/browser/BrowserService.h b/src/browser/BrowserService.h index d813e5618f..2839923ff8 100644 --- a/src/browser/BrowserService.h +++ b/src/browser/BrowserService.h @@ -161,7 +161,6 @@ private slots: QString getDatabaseRootUuid(); QString getDatabaseRecycleBinUuid(); bool checkLegacySettings(QSharedPointer db); - QStringList getEntryURLs(const Entry* entry); void hideWindow() const; void raiseWindow(const bool force = false); diff --git a/src/core/Entry.cpp b/src/core/Entry.cpp index 95b22f3877..718ff4b9e6 100644 --- a/src/core/Entry.cpp +++ b/src/core/Entry.cpp @@ -377,16 +377,18 @@ QString Entry::url() const QStringList Entry::getAllUrls() const { QStringList urlList; + auto entryUrl = url(); - if (!url().isEmpty()) { - urlList << url(); + if (!entryUrl.isEmpty()) { + urlList << (EntryAttributes::matchReference(entryUrl).hasMatch() ? resolveMultiplePlaceholders(entryUrl) + : entryUrl); } for (const auto& key : m_attributes->keys()) { if (key.startsWith("KP2A_URL")) { auto additionalUrl = m_attributes->value(key); if (!additionalUrl.isEmpty()) { - urlList << additionalUrl; + urlList << resolveMultiplePlaceholders(additionalUrl); } } } diff --git a/tests/TestBrowser.cpp b/tests/TestBrowser.cpp index 77cd4d071b..d7345537d6 100644 --- a/tests/TestBrowser.cpp +++ b/tests/TestBrowser.cpp @@ -202,8 +202,7 @@ void TestBrowser::testSortPriority() QScopedPointer entry(new Entry()); entry->setUrl(entryUrl); - QCOMPARE(m_browserService->sortPriority(m_browserService->getEntryURLs(entry.data()), siteUrl, formUrl), - expectedScore); + QCOMPARE(m_browserService->sortPriority(entry->getAllUrls(), siteUrl, formUrl), expectedScore); } void TestBrowser::testSortPriority_data() @@ -344,7 +343,7 @@ void TestBrowser::testSearchEntriesByUUID() for (Entry* entry : entries) { QString testUrl = "keepassxc://by-uuid/" + entry->uuidToHex(); - /* Look for an entry with that UUID. First using handleEntry, then through the search */ + /* Look for an entry with that UUID. First using shouldIncludeEntry, then through the search */ QCOMPARE(m_browserService->shouldIncludeEntry(entry, testUrl, ""), true); auto result = m_browserService->searchEntries(db, testUrl, ""); QCOMPARE(result.length(), 1); @@ -371,6 +370,46 @@ void TestBrowser::testSearchEntriesByUUID() } } +void TestBrowser::testSearchEntriesByReference() +{ + auto db = QSharedPointer::create(); + auto* root = db->rootGroup(); + + /* The URLs don't really matter for this test, we just need some entries */ + QStringList urls = {"https://subdomain.example.com", + "example.com", // Only includes a partial URL for references + "https://another.domain.com", // Additional URL as full reference + "https://subdomain.somesite.com", // Additional URL as partial reference + "", // Full reference will be added to https://subdomain.example.com + "" // Partial reference will be added to https://subdomain.example.com + "https://www.notincluded.com"}; // Should not show in search + auto entries = createEntries(urls, root); + + auto firstEntryUuid = entries.first()->uuidToHex(); + auto secondEntryUuid = entries[1]->uuidToHex(); + auto fullReference = QString("{REF:A@I:%1}").arg(firstEntryUuid); + auto partialReference = QString("https://subdomain.{REF:A@I:%1}").arg(secondEntryUuid); + entries[2]->attributes()->set(BrowserService::ADDITIONAL_URL, fullReference); + entries[3]->attributes()->set(BrowserService::ADDITIONAL_URL, partialReference); + entries[4]->setUrl(fullReference); + entries[5]->setUrl(partialReference); + + auto result = m_browserService->searchEntries(db, "https://subdomain.example.com", ""); + QCOMPARE(result.length(), 6); + QCOMPARE(result[0]->url(), urls[0]); + QCOMPARE(result[1]->url(), urls[1]); + QCOMPARE(result[2]->url(), urls[2]); + QCOMPARE(result[2]->resolveMultiplePlaceholders(result[2]->attributes()->value(BrowserService::ADDITIONAL_URL)), + urls[0]); + QCOMPARE(result[3]->url(), urls[3]); + QCOMPARE(result[3]->resolveMultiplePlaceholders(result[3]->attributes()->value(BrowserService::ADDITIONAL_URL)), + urls[0]); + QCOMPARE(result[4]->url(), fullReference); + QCOMPARE(result[4]->resolveMultiplePlaceholders(result[4]->url()), urls[0]); // Should be resolved to the main entry + QCOMPARE(result[5]->url(), partialReference); + QCOMPARE(result[5]->resolveMultiplePlaceholders(result[5]->url()), urls[0]); // Should be resolved to the main entry +} + void TestBrowser::testSearchEntriesWithPort() { auto db = QSharedPointer::create(); diff --git a/tests/TestBrowser.h b/tests/TestBrowser.h index 7093a50659..ed8146b574 100644 --- a/tests/TestBrowser.h +++ b/tests/TestBrowser.h @@ -44,6 +44,7 @@ private slots: void testSearchEntries(); void testSearchEntriesByPath(); void testSearchEntriesByUUID(); + void testSearchEntriesByReference(); void testSearchEntriesWithPort(); void testSearchEntriesWithAdditionalURLs(); void testInvalidEntries();