diff options
author | Jonathan White <support@dmapps.us> | 2022-09-01 13:54:34 +0300 |
---|---|---|
committer | Jonathan White <support@dmapps.us> | 2022-09-05 17:40:48 +0300 |
commit | 735b245a3be0716735101095a77aa38295e0a28e (patch) | |
tree | 8e5e9d54d11b5695d9b49112dd0d22b49ae9cb34 | |
parent | bd809ba90b25d9a0a7634353025efcd0e4c66880 (diff) |
Fix OPVault import when there are multiple OTP fieldshotfix/opvault-totp
* Fix #8371 - store multiple OTP fields as `otp_#` instead of silently discarding them.
-rw-r--r-- | src/format/OpVaultReaderSections.cpp | 11 | ||||
-rw-r--r-- | tests/TestOpVaultReader.cpp | 10 |
2 files changed, 20 insertions, 1 deletions
diff --git a/src/format/OpVaultReaderSections.cpp b/src/format/OpVaultReaderSections.cpp index 610f997ec..661b9d6c3 100644 --- a/src/format/OpVaultReaderSections.cpp +++ b/src/format/OpVaultReaderSections.cpp @@ -84,7 +84,16 @@ void OpVaultReader::fillFromSectionField(Entry* entry, const QString& sectionNam auto kind = field["k"].toString(); if (attrName.startsWith("TOTP_")) { - if (attrValue.startsWith("otpauth://")) { + if (entry->hasTotp()) { + // Store multiple TOTP definitions as additional otp attributes + int i = 0; + QString name("otp"); + auto attributes = entry->attributes()->keys(); + while (attributes.contains(name)) { + name = QString("otp_%1").arg(++i); + } + entry->attributes()->set(name, attrValue); + } else if (attrValue.startsWith("otpauth://")) { QUrlQuery query(attrValue); // at least as of 1Password 7, they don't append the digits= and period= which totp.cpp requires if (!query.hasQueryItem("digits")) { diff --git a/tests/TestOpVaultReader.cpp b/tests/TestOpVaultReader.cpp index aa95880a0..a5d05e9b0 100644 --- a/tests/TestOpVaultReader.cpp +++ b/tests/TestOpVaultReader.cpp @@ -24,6 +24,7 @@ #include "format/OpVaultReader.h" #include "totp/totp.h" +#include <QJsonObject> #include <QList> #include <QStringList> #include <QTest> @@ -110,6 +111,15 @@ void TestOpVaultReader::testReadIntoDatabase() QCOMPARE(totpSettings->digits, static_cast<unsigned int>(8)); QCOMPARE(totpSettings->step, static_cast<unsigned int>(45)); + // Add another OTP to this entry to confirm it doesn't overwrite the existing one + auto field = QJsonObject::fromVariantMap({{"n", "TOTP_SETTINGS"}, {"v", "otpauth://test.url?digits=6"}}); + reader.fillFromSectionField(entry, "", field); + QVERIFY(entry->hasTotp()); + totpSettings = entry->totpSettings(); + QCOMPARE(totpSettings->digits, static_cast<unsigned int>(8)); + QCOMPARE(totpSettings->step, static_cast<unsigned int>(45)); + QVERIFY(entry->attributes()->contains("otp_1")); + // Confirm trashed entries are sent to the recycle bin auto recycleBin = db->metadata()->recycleBin(); QVERIFY(recycleBin); |