diff --git a/docs/topics/UserInterface.adoc b/docs/topics/UserInterface.adoc
index b60b28a66d..456c09ea63 100644
--- a/docs/topics/UserInterface.adoc
+++ b/docs/topics/UserInterface.adoc
@@ -86,7 +86,7 @@ Additionally, the following environment variables may be useful when running the
|KPXC_CONFIG | Override default path to roaming configuration file
|KPXC_CONFIG_LOCAL | Override default path to local configuration file
|KPXC_INITIAL_DIR | Override initial location picking for databases
-|SSH_AUTH_SOCKET | Path of the unix file socket that the agent uses for communication with other processes (SSH Agent)
+|SSH_AUTH_SOCK | Path of the unix file socket that the agent uses for communication with other processes (SSH Agent)
|QT_SCALE_FACTOR [numeric] | Defines a global scale factor for the whole application, including point-sized fonts.
|QT_SCREEN_SCALE_FACTORS [list] | Specifies scale factors for each screen. See https://doc.qt.io/qt-5/highdpi.html#high-dpi-support-in-qt
|QT_SCALE_FACTOR_ROUNDING_POLICY | Control device pixel ratio rounding to the nearest integer. See https://doc.qt.io/qt-5/highdpi.html#high-dpi-support-in-qt
diff --git a/share/translations/keepassxc_en.ts b/share/translations/keepassxc_en.ts
index 4427ca4882..884c34d9e9 100644
--- a/share/translations/keepassxc_en.ts
+++ b/share/translations/keepassxc_en.ts
@@ -3468,10 +3468,6 @@ Supported extensions are: %1.
-
-
-
-
@@ -3513,6 +3509,10 @@ Supported extensions are: %1.
+
+
+
+
EditWidgetProperties
diff --git a/share/windows/wix-template.xml b/share/windows/wix-template.xml
index ae937ce709..add2af2974 100644
--- a/share/windows/wix-template.xml
+++ b/share/windows/wix-template.xml
@@ -92,6 +92,9 @@
+
+
+
@@ -116,12 +119,17 @@
-
-
-
+
+
+
+
+
+
+
+
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 07534bbd7f..c0b62f8586 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -59,6 +59,7 @@ set(keepassx_SOURCES
core/TimeDelta.cpp
core/TimeInfo.cpp
core/Tools.cpp
+ core/Totp.cpp
core/Translator.cpp
core/UrlTools.cpp
cli/Utils.cpp
@@ -193,8 +194,7 @@ set(keepassx_SOURCES
streams/LayeredStream.cpp
streams/qtiocompressor.cpp
streams/StoreDataStream.cpp
- streams/SymmetricCipherStream.cpp
- totp/totp.cpp)
+ streams/SymmetricCipherStream.cpp)
if(APPLE)
set(keepassx_SOURCES
${keepassx_SOURCES}
diff --git a/src/core/Entry.cpp b/src/core/Entry.cpp
index 04120e90b2..e237ae53d5 100644
--- a/src/core/Entry.cpp
+++ b/src/core/Entry.cpp
@@ -24,7 +24,7 @@
#include "core/Metadata.h"
#include "core/PasswordHealth.h"
#include "core/Tools.h"
-#include "totp/totp.h"
+#include "core/Totp.h"
#include
#include
@@ -566,7 +566,7 @@ void Entry::setTotp(QSharedPointer settings)
m_attributes->remove(Totp::ATTRIBUTE_SEED);
m_attributes->remove(Totp::ATTRIBUTE_SETTINGS);
- if (settings->key.isEmpty()) {
+ if (!settings || settings->key.isEmpty()) {
m_data.totpSettings.reset();
} else {
m_data.totpSettings = std::move(settings);
@@ -1279,11 +1279,11 @@ void Entry::setGroup(Group* group, bool trackPrevious)
}
}
+ QObject::setParent(group);
+
m_group = group;
group->addEntry(this);
- QObject::setParent(group);
-
if (m_updateTimeinfo) {
m_data.timeInfo.setLocationChanged(Clock::currentDateTimeUtc());
}
diff --git a/src/core/Merger.cpp b/src/core/Merger.cpp
index fd30da7aa4..0ffb94b9e6 100644
--- a/src/core/Merger.cpp
+++ b/src/core/Merger.cpp
@@ -338,6 +338,7 @@ Merger::ChangeList Merger::resolveEntryConflict_MergeHistories(const MergeContex
const int comparison = compare(targetEntry->timeInfo().lastModificationTime(),
sourceEntry->timeInfo().lastModificationTime(),
CompareItemIgnoreMilliseconds);
+ const int maxItems = targetEntry->database()->metadata()->historyMaxItems();
if (comparison < 0) {
Group* currentGroup = targetEntry->group();
Entry* clonedEntry = sourceEntry->clone(Entry::CloneIncludeHistory);
@@ -346,15 +347,15 @@ Merger::ChangeList Merger::resolveEntryConflict_MergeHistories(const MergeContex
qPrintable(sourceEntry->title()),
qPrintable(currentGroup->name()));
changes << tr("Synchronizing from newer source %1 [%2]").arg(targetEntry->title(), targetEntry->uuidToHex());
- moveEntry(clonedEntry, currentGroup);
- mergeHistory(targetEntry, clonedEntry, mergeMethod);
+ mergeHistory(targetEntry, clonedEntry, mergeMethod, maxItems);
eraseEntry(targetEntry);
+ moveEntry(clonedEntry, currentGroup);
} else {
qDebug("Merge %s/%s with local on top/under %s",
qPrintable(targetEntry->title()),
qPrintable(sourceEntry->title()),
qPrintable(targetEntry->group()->name()));
- const bool changed = mergeHistory(sourceEntry, targetEntry, mergeMethod);
+ const bool changed = mergeHistory(sourceEntry, targetEntry, mergeMethod, maxItems);
if (changed) {
changes
<< tr("Synchronizing from older source %1 [%2]").arg(targetEntry->title(), targetEntry->uuidToHex());
@@ -400,7 +401,10 @@ Merger::resolveEntryConflict(const MergeContext& context, const Entry* sourceEnt
return changes;
}
-bool Merger::mergeHistory(const Entry* sourceEntry, Entry* targetEntry, Group::MergeMode mergeMethod)
+bool Merger::mergeHistory(const Entry* sourceEntry,
+ Entry* targetEntry,
+ Group::MergeMode mergeMethod,
+ const int maxItems)
{
Q_UNUSED(mergeMethod);
const auto targetHistoryItems = targetEntry->historyItems();
@@ -473,7 +477,6 @@ bool Merger::mergeHistory(const Entry* sourceEntry, Entry* targetEntry, Group::M
}
bool changed = false;
- const int maxItems = targetEntry->database()->metadata()->historyMaxItems();
const auto updatedHistoryItems = merged.values();
for (int i = 0; i < maxItems; ++i) {
const Entry* oldEntry = targetHistoryItems.value(targetHistoryItems.count() - i);
diff --git a/src/core/Merger.h b/src/core/Merger.h
index 4b277f9561..ea45a6d141 100644
--- a/src/core/Merger.h
+++ b/src/core/Merger.h
@@ -50,7 +50,7 @@ class Merger : public QObject
ChangeList mergeDeletions(const MergeContext& context);
ChangeList mergeMetadata(const MergeContext& context);
bool markOlderEntry(Entry* entry);
- bool mergeHistory(const Entry* sourceEntry, Entry* targetEntry, Group::MergeMode mergeMethod);
+ bool mergeHistory(const Entry* sourceEntry, Entry* targetEntry, Group::MergeMode mergeMethod, const int maxItems);
void moveEntry(Entry* entry, Group* targetGroup);
void moveGroup(Group* group, Group* targetGroup);
// remove an entry without a trace in the deletedObjects - needed for elemination cloned entries
diff --git a/src/core/PasswordGenerator.cpp b/src/core/PasswordGenerator.cpp
index 01641bc802..aa0f3e7172 100644
--- a/src/core/PasswordGenerator.cpp
+++ b/src/core/PasswordGenerator.cpp
@@ -261,8 +261,10 @@ QVector PasswordGenerator::passwordGroups() const
if (!m_custom.isEmpty()) {
PasswordGroup group;
- for (auto ch : m_custom) {
- group.append(ch);
+ for (const auto& ch : m_custom) {
+ if (!group.contains(ch)) {
+ group.append(ch);
+ }
}
passwordGroups.append(group);
diff --git a/src/totp/totp.cpp b/src/core/Totp.cpp
similarity index 97%
rename from src/totp/totp.cpp
rename to src/core/Totp.cpp
index dc58f158db..f55312a9db 100644
--- a/src/totp/totp.cpp
+++ b/src/core/Totp.cpp
@@ -16,7 +16,7 @@
* along with this program. If not, see .
*/
-#include "totp.h"
+#include "Totp.h"
#include "core/Base32.h"
#include "core/Clock.h"
@@ -59,6 +59,11 @@ static QString getNameForHashType(const Totp::Algorithm hashType)
QSharedPointer Totp::parseSettings(const QString& rawSettings, const QString& key)
{
+ // Early out if both strings are empty
+ if (rawSettings.isEmpty() && key.isEmpty()) {
+ return {};
+ }
+
// Create default settings
auto settings = createSettings(key, DEFAULT_DIGITS, DEFAULT_STEP);
@@ -96,6 +101,11 @@ QSharedPointer Totp::parseSettings(const QString& rawSettings, c
settings->algorithm = getHashTypeByName(query.queryItemValue("otpHashMode"));
}
} else {
+ if (settings->key.isEmpty()) {
+ // Legacy format cannot work with an empty key
+ return {};
+ }
+
// Parse semi-colon separated values ([step];[digits|S])
settings->format = StorageFormat::LEGACY;
auto vars = rawSettings.split(";");
diff --git a/src/totp/totp.h b/src/core/Totp.h
similarity index 100%
rename from src/totp/totp.h
rename to src/core/Totp.h
diff --git a/src/fdosecrets/objects/Collection.cpp b/src/fdosecrets/objects/Collection.cpp
index 4cc6ca537d..be452d4299 100644
--- a/src/fdosecrets/objects/Collection.cpp
+++ b/src/fdosecrets/objects/Collection.cpp
@@ -495,6 +495,10 @@ namespace FdoSecrets
}
auto item = Item::Create(this, entry);
+ if (!item) {
+ return;
+ }
+
m_items << item;
m_entryToItem[entry] = item;
diff --git a/src/format/OpVaultReaderSections.cpp b/src/format/OpVaultReaderSections.cpp
index 661b9d6c3e..d05f8fca12 100644
--- a/src/format/OpVaultReaderSections.cpp
+++ b/src/format/OpVaultReaderSections.cpp
@@ -18,7 +18,7 @@
#include "OpVaultReader.h"
#include "core/Entry.h"
-#include "totp/totp.h"
+#include "core/Totp.h"
#include
#include
diff --git a/src/gui/DatabaseOpenWidget.cpp b/src/gui/DatabaseOpenWidget.cpp
index f3adeee29b..fcda80e43b 100644
--- a/src/gui/DatabaseOpenWidget.cpp
+++ b/src/gui/DatabaseOpenWidget.cpp
@@ -513,12 +513,12 @@ void DatabaseOpenWidget::hardwareKeyResponse(bool found)
void DatabaseOpenWidget::openHardwareKeyHelp()
{
- QDesktopServices::openUrl(QUrl("https://keepassxc.org/docs#faq-cat-yubikey"));
+ QDesktopServices::openUrl(QUrl("https://keepassxc.org/docs/#faq-yubikey-2fa"));
}
void DatabaseOpenWidget::openKeyFileHelp()
{
- QDesktopServices::openUrl(QUrl("https://keepassxc.org/docs#faq-cat-keyfile"));
+ QDesktopServices::openUrl(QUrl("https://keepassxc.org/docs/#faq-keyfile-howto"));
}
void DatabaseOpenWidget::setUserInteractionLock(bool state)
diff --git a/src/gui/DatabaseWidget.cpp b/src/gui/DatabaseWidget.cpp
index 94fa2fbe75..deeec3662f 100644
--- a/src/gui/DatabaseWidget.cpp
+++ b/src/gui/DatabaseWidget.cpp
@@ -493,6 +493,10 @@ void DatabaseWidget::setupTotp()
auto setupTotpDialog = new TotpSetupDialog(this, currentEntry);
connect(setupTotpDialog, SIGNAL(totpUpdated()), SIGNAL(entrySelectionChanged()));
+ if (currentWidget() == m_editEntryWidget) {
+ // Entry is being edited, tell it when we are finished updating TOTP
+ connect(setupTotpDialog, SIGNAL(totpUpdated()), m_editEntryWidget, SLOT(updateTotp()));
+ }
connect(this, &DatabaseWidget::databaseLockRequested, setupTotpDialog, &TotpSetupDialog::close);
setupTotpDialog->open();
}
@@ -2151,7 +2155,7 @@ bool DatabaseWidget::performSave(QString& errorMessage, const QString& fileName)
m_groupView->setDisabled(false);
m_tagView->setDisabled(false);
- if (focusWidget) {
+ if (focusWidget && focusWidget->isVisible()) {
focusWidget->setFocus();
}
diff --git a/src/gui/EditWidgetIcons.cpp b/src/gui/EditWidgetIcons.cpp
index 25542730cc..c91974c4c4 100644
--- a/src/gui/EditWidgetIcons.cpp
+++ b/src/gui/EditWidgetIcons.cpp
@@ -222,7 +222,7 @@ void EditWidgetIcons::iconReceived(const QString& url, const QImage& icon)
QString message(tr("Unable to fetch favicon."));
if (!config()->get(Config::Security_IconDownloadFallback).toBool()) {
message.append("\n").append(
- tr("You can enable the DuckDuckGo website icon service under Tools -> Settings -> Security"));
+ tr("You can enable the DuckDuckGo website icon service under Application Settings -> Security"));
}
emit messageEditEntry(message, MessageWidget::Error);
return;
diff --git a/src/gui/EntryPreviewWidget.cpp b/src/gui/EntryPreviewWidget.cpp
index 7d7151c0db..b7c8ca1bcc 100644
--- a/src/gui/EntryPreviewWidget.cpp
+++ b/src/gui/EntryPreviewWidget.cpp
@@ -21,10 +21,10 @@
#include "Application.h"
#include "core/Config.h"
+#include "core/Totp.h"
#include "gui/Clipboard.h"
#include "gui/Font.h"
#include "gui/Icons.h"
-#include "totp/totp.h"
#if defined(WITH_XC_KEESHARE)
#include "keeshare/KeeShare.h"
#include "keeshare/KeeShareSettings.h"
diff --git a/src/gui/TotpDialog.cpp b/src/gui/TotpDialog.cpp
index e856f5d6a4..577fa10563 100644
--- a/src/gui/TotpDialog.cpp
+++ b/src/gui/TotpDialog.cpp
@@ -20,9 +20,9 @@
#include "ui_TotpDialog.h"
#include "core/Clock.h"
+#include "core/Totp.h"
#include "gui/Clipboard.h"
#include "gui/MainWindow.h"
-#include "totp/totp.h"
#include
#include
diff --git a/src/gui/TotpExportSettingsDialog.cpp b/src/gui/TotpExportSettingsDialog.cpp
index 1ac5231d40..8e56d5d2ec 100644
--- a/src/gui/TotpExportSettingsDialog.cpp
+++ b/src/gui/TotpExportSettingsDialog.cpp
@@ -17,11 +17,11 @@
#include "TotpExportSettingsDialog.h"
+#include "core/Totp.h"
#include "gui/Clipboard.h"
#include "gui/MainWindow.h"
#include "gui/SquareSvgWidget.h"
#include "qrcode/QrCode.h"
-#include "totp/totp.h"
#include
#include
diff --git a/src/gui/TotpSetupDialog.cpp b/src/gui/TotpSetupDialog.cpp
index d33d9ce398..e796e1d5e3 100644
--- a/src/gui/TotpSetupDialog.cpp
+++ b/src/gui/TotpSetupDialog.cpp
@@ -19,8 +19,8 @@
#include "ui_TotpSetupDialog.h"
#include "core/Base32.h"
+#include "core/Totp.h"
#include "gui/MessageBox.h"
-#include "totp/totp.h"
TotpSetupDialog::TotpSetupDialog(QWidget* parent, Entry* entry)
: QDialog(parent)
diff --git a/src/gui/csvImport/CsvImportWidget.cpp b/src/gui/csvImport/CsvImportWidget.cpp
index a3a30e4c33..08f6d6589c 100644
--- a/src/gui/csvImport/CsvImportWidget.cpp
+++ b/src/gui/csvImport/CsvImportWidget.cpp
@@ -22,9 +22,9 @@
#include
#include "core/Clock.h"
+#include "core/Totp.h"
#include "format/KeePass2Writer.h"
#include "gui/MessageBox.h"
-#include "totp/totp.h"
// I wanted to make the CSV import GUI future-proof, so if one day you need a new field,
// all you have to do is add a field to m_columnHeader, and the GUI will follow:
@@ -208,7 +208,7 @@ void CsvImportWidget::writeDatabase()
auto otpString = m_parserModel->data(m_parserModel->index(r, 6));
if (otpString.isValid() && !otpString.toString().isEmpty()) {
auto totp = Totp::parseSettings(otpString.toString());
- if (totp->key.isEmpty()) {
+ if (!totp || totp->key.isEmpty()) {
// Bare secret, use default TOTP settings
totp = Totp::parseSettings({}, otpString.toString());
}
diff --git a/src/gui/entry/EditEntryWidget.cpp b/src/gui/entry/EditEntryWidget.cpp
index a1297d4c0c..b84fa2488f 100644
--- a/src/gui/entry/EditEntryWidget.cpp
+++ b/src/gui/entry/EditEntryWidget.cpp
@@ -114,6 +114,7 @@ EditEntryWidget::EditEntryWidget(QWidget* parent)
m_entryModifiedTimer.setSingleShot(true);
m_entryModifiedTimer.setInterval(0);
connect(&m_entryModifiedTimer, &QTimer::timeout, this, [this] {
+ // TODO: Upon refactor of this widget, this needs to merge unsaved changes in the UI
if (isVisible() && m_entry) {
setForms(m_entry);
}
@@ -704,6 +705,13 @@ void EditEntryWidget::toKeeAgentSettings(KeeAgentSettings& settings) const
settings.setSaveAttachmentToTempFile(m_sshAgentSettings.saveAttachmentToTempFile());
}
+void EditEntryWidget::updateTotp()
+{
+ if (m_entry) {
+ m_attributesModel->setEntryAttributes(m_entry->attributes());
+ }
+}
+
void EditEntryWidget::browsePrivateKey()
{
auto fileName = fileDialog()->getOpenFileName(this, tr("Select private key"), FileDialog::getLastDir("sshagent"));
@@ -828,8 +836,6 @@ void EditEntryWidget::loadEntry(Entry* entry,
m_create = create;
m_history = history;
- connect(m_entry, &Entry::modified, this, [this] { m_entryModifiedTimer.start(); });
-
if (history) {
setHeadline(QString("%1 \u2022 %2").arg(parentName, tr("Entry history")));
} else {
@@ -837,6 +843,8 @@ void EditEntryWidget::loadEntry(Entry* entry,
setHeadline(QString("%1 \u2022 %2").arg(parentName, tr("Add entry")));
} else {
setHeadline(QString("%1 \u2022 %2 \u2022 %3").arg(parentName, entry->title(), tr("Edit entry")));
+ // Reload entry details if changed outside of the edit dialog
+ connect(m_entry, &Entry::modified, this, [this] { m_entryModifiedTimer.start(); });
}
}
@@ -1143,6 +1151,7 @@ bool EditEntryWidget::commitEntry()
}
m_historyModel->setEntries(m_entry->historyItems(), m_entry);
+ setPageHidden(m_historyWidget, m_history || m_entry->historyItems().count() < 1);
m_advancedUi->attachmentsWidget->linkAttachments(m_entry->attachments());
showMessage(tr("Entry updated successfully."), MessageWidget::Positive);
diff --git a/src/gui/entry/EditEntryWidget.h b/src/gui/entry/EditEntryWidget.h
index 3bd67032f3..fddf64eda8 100644
--- a/src/gui/entry/EditEntryWidget.h
+++ b/src/gui/entry/EditEntryWidget.h
@@ -118,6 +118,7 @@ private slots:
void updateSSHAgentAttachment();
void updateSSHAgentAttachments();
void updateSSHAgentKeyInfo();
+ void updateTotp();
void browsePrivateKey();
void addKeyToAgent();
void removeKeyFromAgent();
diff --git a/src/gui/entry/EntryHistoryModel.cpp b/src/gui/entry/EntryHistoryModel.cpp
index acde63cb52..618f4328f0 100644
--- a/src/gui/entry/EntryHistoryModel.cpp
+++ b/src/gui/entry/EntryHistoryModel.cpp
@@ -158,9 +158,10 @@ void EntryHistoryModel::deleteIndex(QModelIndex index)
{
auto entry = entryFromIndex(index);
if (entry) {
- beginRemoveRows(QModelIndex(), m_historyEntries.indexOf(entry), m_historyEntries.indexOf(entry));
+ beginRemoveRows(QModelIndex(), index.row(), index.row());
m_historyEntries.removeAll(entry);
m_deletedHistoryEntries << entry;
+ m_historyModifications.erase(m_historyModifications.begin() + index.row());
endRemoveRows();
}
}
diff --git a/src/gui/entry/EntryView.cpp b/src/gui/entry/EntryView.cpp
index 868250a666..419a08d753 100644
--- a/src/gui/entry/EntryView.cpp
+++ b/src/gui/entry/EntryView.cpp
@@ -219,11 +219,12 @@ void EntryView::displaySearch(const QList& entries)
m_model->setEntries(entries);
header()->showSection(EntryModel::ParentGroup);
+ setFirstEntryActive();
+
// Reset sort column to 'Group', overrides DatabaseWidgetStateSync
m_sortModel->sort(EntryModel::ParentGroup, Qt::AscendingOrder);
sortByColumn(EntryModel::ParentGroup, Qt::AscendingOrder);
- setFirstEntryActive();
m_inSearchMode = true;
}
@@ -545,6 +546,8 @@ void EntryView::startDrag(Qt::DropActions supportedActions)
listWidget.addItem(item);
}
+ listWidget.setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
+ listWidget.setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
listWidget.setStyleSheet("QListWidget { background-color: palette(highlight); border: 1px solid palette(dark); "
"padding: 4px; color: palette(highlighted-text); }");
auto width = listWidget.sizeHintForColumn(0) + 2 * listWidget.frameWidth();
diff --git a/src/gui/styles/base/classicstyle.qss b/src/gui/styles/base/classicstyle.qss
index f7d3c0fb47..d0ab2b88fc 100644
--- a/src/gui/styles/base/classicstyle.qss
+++ b/src/gui/styles/base/classicstyle.qss
@@ -9,8 +9,9 @@ QToolTip {
DatabaseWidget #SearchBanner, DatabaseWidget #KeeShareBanner {
font-weight: bold;
- background-color: rgb(94, 161, 14);
- border: 1px solid rgb(190, 190, 190);
+ background-color: palette(highlight);
+ color: palette(highlighted-text);
+ border: 1px solid palette(dark);
padding: 2px;
}
diff --git a/tests/TestCsvExporter.cpp b/tests/TestCsvExporter.cpp
index 4854da1116..c4c937e5d8 100644
--- a/tests/TestCsvExporter.cpp
+++ b/tests/TestCsvExporter.cpp
@@ -22,9 +22,9 @@
#include
#include "core/Group.h"
+#include "core/Totp.h"
#include "crypto/Crypto.h"
#include "format/CsvExporter.h"
-#include "totp/totp.h"
QTEST_GUILESS_MAIN(TestCsvExporter)
diff --git a/tests/TestOpVaultReader.cpp b/tests/TestOpVaultReader.cpp
index a5d05e9b07..4899d335fb 100644
--- a/tests/TestOpVaultReader.cpp
+++ b/tests/TestOpVaultReader.cpp
@@ -20,9 +20,9 @@
#include "config-keepassx-tests.h"
#include "core/Group.h"
#include "core/Metadata.h"
+#include "core/Totp.h"
#include "crypto/Crypto.h"
#include "format/OpVaultReader.h"
-#include "totp/totp.h"
#include
#include
diff --git a/tests/TestTotp.cpp b/tests/TestTotp.cpp
index bb3b55dbd8..f2bb3d47a3 100644
--- a/tests/TestTotp.cpp
+++ b/tests/TestTotp.cpp
@@ -19,8 +19,8 @@
#include "TestTotp.h"
#include "core/Entry.h"
+#include "core/Totp.h"
#include "crypto/Crypto.h"
-#include "totp/totp.h"
#include
@@ -97,6 +97,14 @@ void TestTotp::testParseSecret()
QCOMPARE(settings->digits, 6u);
QCOMPARE(settings->step, 30u);
QCOMPARE(settings->algorithm, Totp::Algorithm::Sha1);
+
+ // Blank settings (expected failure)
+ settings = Totp::parseSettings("", "");
+ QVERIFY(settings.isNull());
+
+ // TOTP Settings with blank secret (expected failure)
+ settings = Totp::parseSettings("30;8", "");
+ QVERIFY(settings.isNull());
}
void TestTotp::testTotpCode()
@@ -164,4 +172,8 @@ void TestTotp::testEntryHistory()
entry.setTotp(settings);
QCOMPARE(entry.historyItems().size(), 2);
QCOMPARE(entry.totpSettings()->key, QString("foo"));
+ // Nullptr Settings (expected reset of TOTP)
+ entry.setTotp(nullptr);
+ QVERIFY(!entry.hasTotp());
+ QCOMPARE(entry.historyItems().size(), 3);
}
diff --git a/tests/gui/TestGui.cpp b/tests/gui/TestGui.cpp
index 178402d7eb..dbc3c11c52 100644
--- a/tests/gui/TestGui.cpp
+++ b/tests/gui/TestGui.cpp
@@ -1078,6 +1078,13 @@ void TestGui::testSearch()
QCOMPARE(groupView->currentGroup(), m_db->rootGroup());
QVERIFY(!m_dbWidget->isSearchActive());
+ // check if first entry is selected after search
+ QTest::keyClicks(searchTextEdit, "some");
+ QTRY_VERIFY(m_dbWidget->isSearchActive());
+ QTRY_COMPARE(entryView->selectedEntries().length(), 1);
+ QModelIndex index_current = entryView->indexFromEntry(entryView->currentEntry());
+ QTRY_COMPARE(index_current.row(), 0);
+
// Try to edit the first entry from the search view
// Refocus back to search edit
QTest::mouseClick(searchTextEdit, Qt::LeftButton);