diff --git a/share/translations/keepassxc_en.ts b/share/translations/keepassxc_en.ts
index 409fa8a9d4..b7d5892882 100644
--- a/share/translations/keepassxc_en.ts
+++ b/share/translations/keepassxc_en.ts
@@ -6084,6 +6084,12 @@ Do you want to overwrite it?
+
+
+
+
PasswordEditWidget
diff --git a/src/core/Tools.h b/src/core/Tools.h
index 4316a44e84..85c1b53c09 100644
--- a/src/core/Tools.h
+++ b/src/core/Tools.h
@@ -22,6 +22,7 @@
#include "core/Global.h"
#include
+#include
#include
class QIODevice;
@@ -100,6 +101,19 @@ namespace Tools
return version;
}
+ // Checks if all values are found inside the list. Returns a list of values not found.
+ template QList getMissingValuesFromList(const QList& list, const QList& required)
+ {
+ QList missingValues;
+ for (const auto& r : required) {
+ if (!list.contains(r)) {
+ missingValues << r;
+ }
+ }
+
+ return missingValues;
+ }
+
QVariantMap qo2qvm(const QObject* object, const QStringList& ignoredProperties = {"objectName"});
QString substituteBackupFilePath(QString pattern, const QString& databasePath);
diff --git a/src/gui/passkeys/PasskeyImporter.cpp b/src/gui/passkeys/PasskeyImporter.cpp
index df83ddb70e..77e37c689b 100644
--- a/src/gui/passkeys/PasskeyImporter.cpp
+++ b/src/gui/passkeys/PasskeyImporter.cpp
@@ -22,6 +22,7 @@
#include "browser/BrowserService.h"
#include "core/Entry.h"
#include "core/Group.h"
+#include "core/Tools.h"
#include "gui/FileDialog.h"
#include "gui/MessageBox.h"
#include
@@ -61,18 +62,20 @@ void PasskeyImporter::importSelectedFile(QFile& file, QSharedPointer&
return;
}
- const auto relyingParty = passkeyObject["relyingParty"].toString();
- const auto url = passkeyObject["url"].toString();
- const auto username = passkeyObject["username"].toString();
- const auto credentialId = passkeyObject["credentialId"].toString();
- const auto userHandle = passkeyObject["userHandle"].toString();
const auto privateKey = passkeyObject["privateKey"].toString();
-
- if (relyingParty.isEmpty() || username.isEmpty() || credentialId.isEmpty() || userHandle.isEmpty()
- || privateKey.isEmpty()) {
+ const auto missingKeys = Tools::getMissingValuesFromList(passkeyObject.keys(),
+ QStringList() << "relyingParty"
+ << "url"
+ << "username"
+ << "credentialId"
+ << "userHandle"
+ << "privateKey");
+
+ if (!missingKeys.isEmpty()) {
MessageBox::information(nullptr,
tr("Cannot import Passkey"),
- tr("Cannot import Passkey file \"%1\". Data is missing.").arg(file.fileName()));
+ tr("Cannot import Passkey file \"%1\".\nThe following data is missing:\n%2")
+ .arg(file.fileName(), missingKeys.join(", ")));
} else if (!privateKey.startsWith("-----BEGIN PRIVATE KEY-----")
|| !privateKey.trimmed().endsWith("-----END PRIVATE KEY-----")) {
MessageBox::information(
@@ -80,6 +83,11 @@ void PasskeyImporter::importSelectedFile(QFile& file, QSharedPointer&
tr("Cannot import Passkey"),
tr("Cannot import Passkey file \"%1\". Private key is missing or malformed.").arg(file.fileName()));
} else {
+ const auto relyingParty = passkeyObject["relyingParty"].toString();
+ const auto url = passkeyObject["url"].toString();
+ const auto username = passkeyObject["username"].toString();
+ const auto credentialId = passkeyObject["credentialId"].toString();
+ const auto userHandle = passkeyObject["userHandle"].toString();
showImportDialog(database, url, relyingParty, username, credentialId, userHandle, privateKey, entry);
}
}
@@ -109,7 +117,7 @@ void PasskeyImporter::showImportDialog(QSharedPointer& database,
// Store to entry if given directly
if (entry) {
browserService()->addPasskeyToEntry(
- entry, relyingParty, relyingParty, username, userId, userHandle, privateKey);
+ entry, relyingParty, relyingParty, username, credentialId, userHandle, privateKey);
return;
}
@@ -122,7 +130,7 @@ void PasskeyImporter::showImportDialog(QSharedPointer& database,
auto selectedEntry = group->findEntryByUuid(passkeyImportDialog.getSelectedEntryUuid());
if (selectedEntry) {
browserService()->addPasskeyToEntry(
- selectedEntry, relyingParty, relyingParty, username, userId, userHandle, privateKey);
+ selectedEntry, relyingParty, relyingParty, username, credentialId, userHandle, privateKey);
}
}
diff --git a/tests/TestTools.cpp b/tests/TestTools.cpp
index f1cba482bf..1067aa565d 100644
--- a/tests/TestTools.cpp
+++ b/tests/TestTools.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2021 KeePassXC Team
+ * Copyright (C) 2023 KeePassXC Team
*
* 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
@@ -239,3 +239,30 @@ void TestTools::testConvertToRegex_data()
<< input << static_cast(Tools::RegexConvertOpts::WILDCARD_UNLIMITED_MATCH)
<< QString(R"(te\|st.*t\?\[5\]\^\(test\)\;\'\,\.)");
}
+
+void TestTools::testArrayContainsValues()
+{
+ const auto values = QStringList() << "first"
+ << "second"
+ << "third";
+
+ // One missing
+ const auto result1 = Tools::getMissingValuesFromList(values,
+ QStringList() << "first"
+ << "second"
+ << "none");
+ QCOMPARE(result1.length(), 1);
+ QCOMPARE(result1.first(), QString("none"));
+
+ // All found
+ const auto result2 = Tools::getMissingValuesFromList(values,
+ QStringList() << "first"
+ << "second"
+ << "third");
+ QCOMPARE(result2.length(), 0);
+
+ // None are found
+ const auto numberValues = {1, 2, 3, 4, 5};
+ const auto result3 = Tools::getMissingValuesFromList(numberValues, {6, 7, 8});
+ QCOMPARE(result3.length(), 3);
+}
diff --git a/tests/TestTools.h b/tests/TestTools.h
index 2e8cbb8bb0..377b00fdb8 100644
--- a/tests/TestTools.h
+++ b/tests/TestTools.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2021 KeePassXC Team
+ * Copyright (C) 2023 KeePassXC Team
*
* 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
@@ -35,6 +35,7 @@ private slots:
void testEscapeRegex_data();
void testConvertToRegex();
void testConvertToRegex_data();
+ void testArrayContainsValues();
};
#endif // KEEPASSX_TESTTOOLS_H