Add support for multiple URLs in an entry

* Fixes #398

The new Browser Integration entry settings page has a list view with any additional URL's. These URL's are added to the entry attributes with KP2A_URL_<counter>, which means those are directly compatible with Keepass2Android.
This commit is contained in:
varjolintu
2019-08-15 12:35:11 +03:00
committed by Jonathan White
parent e50261a99c
commit f726d7501f
19 changed files with 568 additions and 104 deletions

View File

@@ -89,7 +89,7 @@ endmacro(add_unit_test)
set(TEST_LIBRARIES
keepassx_core
${keepasshttp_LIB}
${keepassxcbrowser_LIB}
${autotype_LIB}
Qt5::Core
Qt5::Concurrent

View File

@@ -245,6 +245,40 @@ void TestBrowser::testSearchEntriesWithPort()
QCOMPARE(result[0]->url(), QString("http://127.0.0.1:443"));
}
void TestBrowser::testSearchEntriesWithAdditionalURLs()
{
auto db = QSharedPointer<Database>::create();
auto* root = db->rootGroup();
QList<Entry*> entries;
QList<QString> urls;
urls.push_back("https://github.com/");
urls.push_back("https://www.example.com");
urls.push_back("http://domain.com");
for (int i = 0; i < urls.length(); ++i) {
auto entry = new Entry();
entry->setGroup(root);
entry->beginUpdate();
entry->setUrl(urls[i]);
entry->setUsername(QString("User %1").arg(i));
entry->endUpdate();
entries.push_back(entry);
}
// Add an additional URL to the first entry
entries.first()->attributes()->set(BrowserService::ADDITIONAL_URL, "https://keepassxc.org");
auto result = m_browserService->searchEntries(db, "github.com", "https://github.com"); // db, hostname, url
QCOMPARE(result.length(), 1);
QCOMPARE(result[0]->url(), QString("https://github.com/"));
// Search the additional URL. It should return the same entry
auto additionalResult = m_browserService->searchEntries(db, "keepassxc.org", "https://keepassxc.org");
QCOMPARE(additionalResult.length(), 1);
QCOMPARE(additionalResult[0]->url(), QString("https://github.com/"));
}
void TestBrowser::testSortEntries()
{
auto db = QSharedPointer<Database>::create();

View File

@@ -42,6 +42,7 @@ private slots:
void testSortPriority();
void testSearchEntries();
void testSearchEntriesWithPort();
void testSearchEntriesWithAdditionalURLs();
void testSortEntries();
void testGetDatabaseGroups();

View File

@@ -549,8 +549,7 @@ void TestCli::testCreate()
m_stderrFile->reset();
m_stdoutFile->reset();
QCOMPARE(m_stdoutFile->readLine(),
QByteArray("Enter password to encrypt database (optional): \n"));
QCOMPARE(m_stdoutFile->readLine(), QByteArray("Enter password to encrypt database (optional): \n"));
QCOMPARE(m_stdoutFile->readLine(), QByteArray("Successfully created new database.\n"));
Utils::Test::setNextPassword("a");
@@ -578,8 +577,7 @@ void TestCli::testCreate()
m_stdoutFile->seek(pos);
m_stderrFile->seek(errPos);
QCOMPARE(m_stdoutFile->readLine(),
QByteArray("Enter password to encrypt database (optional): \n"));
QCOMPARE(m_stdoutFile->readLine(), QByteArray("Enter password to encrypt database (optional): \n"));
QCOMPARE(m_stdoutFile->readLine(), QByteArray("Successfully created new database.\n"));
Utils::Test::setNextPassword("a");
@@ -596,8 +594,7 @@ void TestCli::testCreate()
m_stdoutFile->seek(pos);
m_stderrFile->seek(errPos);
QCOMPARE(m_stdoutFile->readLine(),
QByteArray("Enter password to encrypt database (optional): \n"));
QCOMPARE(m_stdoutFile->readLine(), QByteArray("Enter password to encrypt database (optional): \n"));
QCOMPARE(m_stdoutFile->readLine(), QByteArray("Successfully created new database.\n"));
Utils::Test::setNextPassword("a");
@@ -1041,8 +1038,7 @@ void TestCli::testImport()
importCmd.execute({"import", "-q", m_xmlFile->fileName(), databaseFilenameQuiet});
m_stdoutFile->seek(pos);
QCOMPARE(m_stdoutFile->readAll(),
QByteArray("Enter password to encrypt database (optional): \n"));
QCOMPARE(m_stdoutFile->readAll(), QByteArray("Enter password to encrypt database (optional): \n"));
Utils::Test::setNextPassword("a");
auto dbQuiet = QSharedPointer<Database>(Utils::unlockDatabase(databaseFilenameQuiet, true, "", "", Utils::DEVNULL));

View File

@@ -124,7 +124,7 @@ void TestEntry::testClone()
QVERIFY(entryCloneResetTime->timeInfo().creationTime() != entryOrg->timeInfo().creationTime());
// Date back history of original entry
Entry * firstHistoryItem = entryOrg->historyItems()[0];
Entry* firstHistoryItem = entryOrg->historyItems()[0];
TimeInfo entryOrgHistoryTimeInfo = firstHistoryItem->timeInfo();
QDateTime datedBackEntryOrgModificationTime = entryOrgHistoryTimeInfo.lastModificationTime().addMSecs(-10);
entryOrgHistoryTimeInfo.setLastModificationTime(datedBackEntryOrgModificationTime);
@@ -140,9 +140,8 @@ void TestEntry::testClone()
// Timeinfo of history items should not be modified
QList<Entry*> entryOrgHistory = entryOrg->historyItems(), clonedHistory = entryCloneHistory->historyItems();
auto entryOrgHistoryItem = entryOrgHistory.constBegin();
for(auto entryCloneHistoryItem = clonedHistory.constBegin()
;entryCloneHistoryItem != clonedHistory.constEnd()
;++entryCloneHistoryItem, ++entryOrgHistoryItem) {
for (auto entryCloneHistoryItem = clonedHistory.constBegin(); entryCloneHistoryItem != clonedHistory.constEnd();
++entryCloneHistoryItem, ++entryOrgHistoryItem) {
QCOMPARE((*entryOrgHistoryItem)->timeInfo(), (*entryCloneHistoryItem)->timeInfo());
}

View File

@@ -25,6 +25,8 @@
#include <QDebug>
#include <QDialogButtonBox>
#include <QLineEdit>
#include <QListView>
#include <QPlainTextEdit>
#include <QPushButton>
#include <QTableView>
#include <QToolBar>
@@ -128,6 +130,9 @@ void TestGuiBrowser::cleanupTestCase()
void TestGuiBrowser::testEntrySettings()
{
// Enable the Browser Integration
config()->set("Browser/Enabled", true);
auto* toolBar = m_mainWindow->findChild<QToolBar*>("toolBar");
auto* entryView = m_dbWidget->findChild<EntryView*>("entryView");
@@ -146,7 +151,7 @@ void TestGuiBrowser::testEntrySettings()
auto* editEntryWidget = m_dbWidget->findChild<EditEntryWidget*>("editEntryWidget");
// Switch to Properties page and select all rows from the custom data table
editEntryWidget->setCurrentPage(4);
editEntryWidget->setCurrentPage(5);
auto customDataTableView = editEntryWidget->findChild<QTableView*>("customDataTable");
QVERIFY(customDataTableView);
QTest::mouseClick(customDataTableView, Qt::LeftButton);
@@ -171,6 +176,56 @@ void TestGuiBrowser::testEntrySettings()
QCOMPARE(entry->customData()->size(), 0);
}
void TestGuiBrowser::testAdditionalURLs()
{
auto* toolBar = m_mainWindow->findChild<QToolBar*>("toolBar");
auto* entryView = m_dbWidget->findChild<EntryView*>("entryView");
entryView->setFocus();
QVERIFY(entryView->hasFocus());
// Select the first entry in the database
QModelIndex entryItem = entryView->model()->index(0, 1);
clickIndex(entryItem, entryView, Qt::LeftButton);
auto* entryEditAction = m_mainWindow->findChild<QAction*>("actionEntryEdit");
QWidget* entryEditWidget = toolBar->widgetForAction(entryEditAction);
QTest::mouseClick(entryEditWidget, Qt::LeftButton);
QCOMPARE(m_dbWidget->currentMode(), DatabaseWidget::Mode::EditMode);
auto* editEntryWidget = m_dbWidget->findChild<EditEntryWidget*>("editEntryWidget");
// Switch to Browser Integration page and add three URL's
editEntryWidget->setCurrentPage(4);
auto* addURLButton = editEntryWidget->findChild<QPushButton*>("addURLButton");
QVERIFY(addURLButton);
auto* urlList = editEntryWidget->findChild<QListView*>("additionalURLsView");
QVERIFY(urlList);
QStringList testURLs = {"https://example1.com", "https://example2.com", "https://example3.com"};
for (const auto& url : testURLs) {
QTest::mouseClick(addURLButton, Qt::LeftButton);
QApplication::processEvents();
QTest::keyClicks(urlList->focusWidget(), url);
QTest::keyClick(urlList->focusWidget(), Qt::Key_Enter);
}
// Check the values from attributesEdit
editEntryWidget->setCurrentPage(1);
auto* attributesView = editEntryWidget->findChild<QListView*>("attributesView");
auto* attrTextEdit = editEntryWidget->findChild<QPlainTextEdit*>("attributesEdit");
// Go top of the list
attributesView->setFocus();
QTest::keyClick(attributesView->focusWidget(), Qt::Key_PageUp);
for (const auto& url : testURLs) {
QCOMPARE(attrTextEdit->toPlainText(), url);
QTest::keyClick(attributesView->focusWidget(), Qt::Key_Down);
}
}
void TestGuiBrowser::triggerAction(const QString& name)
{
auto* action = m_mainWindow->findChild<QAction*>(name);

View File

@@ -44,6 +44,7 @@ private slots:
void cleanupTestCase();
void testEntrySettings();
void testAdditionalURLs();
private:
void triggerAction(const QString& name);