From 8c7ef64fabb4cfc0d321fd04f7722d6ea67b3610 Mon Sep 17 00:00:00 2001 From: frostasm Date: Sun, 12 Nov 2017 14:34:13 +0200 Subject: [PATCH 1/7] Show "Can't resolve placeholder" warning only in debug mode --- src/core/Entry.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/core/Entry.cpp b/src/core/Entry.cpp index 53a1ad22..9dd019d5 100644 --- a/src/core/Entry.cpp +++ b/src/core/Entry.cpp @@ -730,8 +730,10 @@ QString Entry::resolvePlaceholderRecursive(const QString &placeholder, int maxDe case PlaceholderType::NotPlaceholder: return placeholder; case PlaceholderType::Unknown: - qWarning("Can't resolve placeholder %s for entry with uuid %s", qPrintable(placeholder), - qPrintable(uuid().toHex())); +#ifdef QT_DEBUG + qWarning("Can't resolve placeholder \"%s\" for entry with title: \"%s\" (uuid \"%s\") ", + qPrintable(placeholder), qPrintable(title()), qPrintable(uuid().toHex())); +#endif return placeholder; case PlaceholderType::Title: return title(); From d4d0f4c131a1e8cba473e1142ef6a577db17376a Mon Sep 17 00:00:00 2001 From: Martin Unzner Date: Sun, 12 Nov 2017 18:11:52 +0100 Subject: [PATCH 2/7] Add failing test for complete entry resolution --- tests/TestEntry.cpp | 82 +++++++++++++++++++++++++++++++++++++++++++++ tests/TestEntry.h | 1 + 2 files changed, 83 insertions(+) diff --git a/tests/TestEntry.cpp b/tests/TestEntry.cpp index 90da71d5..802a27b7 100644 --- a/tests/TestEntry.cpp +++ b/tests/TestEntry.cpp @@ -344,3 +344,85 @@ void TestEntry::testResolveReferencePlaceholders() QCOMPARE(tstEntry->resolveMultiplePlaceholders(QString("{REF:A@I:%1}").arg(entry3->uuid().toHex())), QString("UrlValue")); QCOMPARE(tstEntry->resolveMultiplePlaceholders(QString("{REF:N@I:%1}").arg(entry3->uuid().toHex())), QString("NotesValue")); } + +static const char placeholders[] = { +'T', +'U', +'P', +'A', +'N', +}; + +void TestEntry::testResolveNonIdPlaceholdersToUuid() +{ + Database db; + auto* root = db.rootGroup(); + + Entry referencedEntryTitle; + referencedEntryTitle.setGroup(root); + referencedEntryTitle.setTitle("myTitle"); + referencedEntryTitle.setUuid(Uuid::random()); + + Entry referencedEntryUsername; + referencedEntryUsername.setGroup(root); + referencedEntryUsername.setUsername("myUser"); + referencedEntryUsername.setUuid(Uuid::random()); + + Entry referencedEntryPassword; + referencedEntryPassword.setGroup(root); + referencedEntryPassword.setPassword("myPassword"); + referencedEntryPassword.setUuid(Uuid::random()); + + Entry referencedEntryUrl; + referencedEntryUrl.setGroup(root); + referencedEntryUrl.setUrl("myUrl"); + referencedEntryUrl.setUuid(Uuid::random()); + + Entry referencedEntryNotes; + referencedEntryNotes.setGroup(root); + referencedEntryNotes.setNotes("myNotes"); + referencedEntryNotes.setUuid(Uuid::random()); + + for (const auto searchIn : placeholders) { + const Entry* referencedEntry = nullptr; + QString newEntryNotesRaw("{REF:I@%1:%2}"); + + switch(searchIn) { + case 'T': + referencedEntry = &referencedEntryTitle; + newEntryNotesRaw = newEntryNotesRaw.arg( + QString(searchIn), referencedEntry->title()); + break; + case 'U': + referencedEntry = &referencedEntryUsername; + newEntryNotesRaw = newEntryNotesRaw.arg( + QString(searchIn), referencedEntry->username()); + break; + case 'P': + referencedEntry = &referencedEntryPassword; + newEntryNotesRaw = newEntryNotesRaw.arg( + QString(searchIn), referencedEntry->password()); + break; + case 'A': + referencedEntry = &referencedEntryUrl; + newEntryNotesRaw = newEntryNotesRaw.arg( + QString(searchIn), referencedEntry->url()); + break; + case 'N': + referencedEntry = &referencedEntryNotes; + newEntryNotesRaw = newEntryNotesRaw.arg( + QString(searchIn), referencedEntry->notes()); + break; + default: + break; + } + + Entry newEntry; + newEntry.setGroup(root); + newEntry.setNotes(newEntryNotesRaw); + + const auto newEntryNotesResolved = + newEntry.resolveMultiplePlaceholders(newEntry.notes()); + QCOMPARE(newEntryNotesResolved, QString(referencedEntry->uuid().toHex())); + } +} diff --git a/tests/TestEntry.h b/tests/TestEntry.h index c6a72b05..44a371ba 100644 --- a/tests/TestEntry.h +++ b/tests/TestEntry.h @@ -35,6 +35,7 @@ private slots: void testResolveUrlPlaceholders(); void testResolveRecursivePlaceholders(); void testResolveReferencePlaceholders(); + void testResolveNonIdPlaceholdersToUuid(); }; #endif // KEEPASSX_TESTENTRY_H From 806dd5d78376005c64b7431b4f0dedd4a746cb81 Mon Sep 17 00:00:00 2001 From: frostasm Date: Sun, 12 Nov 2017 17:21:11 +0200 Subject: [PATCH 3/7] Add unit test to search for referenced entries based on fields other than ID --- tests/TestEntry.cpp | 49 +++++++++++++++++++++++++++++++++++++++++++++ tests/TestEntry.h | 1 + 2 files changed, 50 insertions(+) diff --git a/tests/TestEntry.cpp b/tests/TestEntry.cpp index 1e863dbe..d6ff5357 100644 --- a/tests/TestEntry.cpp +++ b/tests/TestEntry.cpp @@ -262,3 +262,52 @@ void TestEntry::testResolveRecursivePlaceholders() QCOMPARE(entry5->resolveMultiplePlaceholders(entry5->url()), url); QCOMPARE(entry5->resolveMultiplePlaceholders(entry5->title()), QString("title+/some/path+fragment+title")); } + +void TestEntry::testResolveReferencePlaceholders() +{ + Database db; + Group* root = db.rootGroup(); + + Entry* entry1 = new Entry(); + entry1->setGroup(root); + entry1->setUuid(Uuid::random()); + entry1->setTitle("Title1"); + entry1->setUsername("Username1"); + entry1->setPassword("Password1"); + entry1->setUrl("Url1"); + entry1->setNotes("Notes1"); + entry1->attributes()->set("CustomAttribute1", "CustomAttributeValue1"); + + Group* group = new Group(); + group->setParent(root); + Entry* entry2 = new Entry(); + entry2->setGroup(root); + entry2->setUuid(Uuid::random()); + entry2->setTitle("Title2"); + entry2->setUsername("Username2"); + entry2->setPassword("password2"); + entry2->setUrl("Url2"); + entry2->setNotes("Notes2"); + entry2->attributes()->set("CustomAttribute2", "CustomAttributeValue2"); + entry2->attributes()->set("CustomAttribute21", "CustomAttributeValue21"); + + Entry* entry3 = new Entry(); + entry3->setGroup(root); + entry3->setUuid(Uuid::random()); + + QCOMPARE(entry3->resolveMultiplePlaceholders(QString("{REF:T@I:%1}").arg(entry1->uuid().toHex())), QString("Title1")); + QCOMPARE(entry3->resolveMultiplePlaceholders(QString("{REF:T@T:%1}").arg(entry1->title())), QString("Title1")); + QCOMPARE(entry3->resolveMultiplePlaceholders(QString("{REF:T@U:%1}").arg(entry1->username())), QString("Title1")); + QCOMPARE(entry3->resolveMultiplePlaceholders(QString("{REF:T@P:%1}").arg(entry1->password())), QString("Title1")); + QCOMPARE(entry3->resolveMultiplePlaceholders(QString("{REF:T@A:%1}").arg(entry1->url())), QString("Title1")); + QCOMPARE(entry3->resolveMultiplePlaceholders(QString("{REF:T@N:%1}").arg(entry1->notes())), QString("Title1")); + QCOMPARE(entry3->resolveMultiplePlaceholders(QString("{REF:T@O:%1}").arg(entry1->attributes()->value("CustomAttribute1"))), QString("Title1")); + + QCOMPARE(entry3->resolveMultiplePlaceholders(QString("{REF:T@I:%1}").arg(entry1->uuid().toHex())), QString("Title1")); + QCOMPARE(entry3->resolveMultiplePlaceholders(QString("{REF:T@T:%1}").arg(entry1->title())), QString("Title1")); + QCOMPARE(entry3->resolveMultiplePlaceholders(QString("{REF:U@U:%1}").arg(entry1->username())), QString("Username1")); + QCOMPARE(entry3->resolveMultiplePlaceholders(QString("{REF:P@P:%1}").arg(entry1->password())), QString("Password1")); + QCOMPARE(entry3->resolveMultiplePlaceholders(QString("{REF:A@A:%1}").arg(entry1->url())), QString("Url1")); + QCOMPARE(entry3->resolveMultiplePlaceholders(QString("{REF:N@N:%1}").arg(entry1->notes())), QString("Notes1")); + QCOMPARE(entry3->resolveMultiplePlaceholders(QString("{REF:O@O:%1}").arg(entry1->attributes()->value("CustomAttribute1"))), QString("CustomAttributeValue1")); +} diff --git a/tests/TestEntry.h b/tests/TestEntry.h index 50fec57a..c6a72b05 100644 --- a/tests/TestEntry.h +++ b/tests/TestEntry.h @@ -34,6 +34,7 @@ private slots: void testResolveUrl(); void testResolveUrlPlaceholders(); void testResolveRecursivePlaceholders(); + void testResolveReferencePlaceholders(); }; #endif // KEEPASSX_TESTENTRY_H From b44092ac43478af6fb80593e5b278ab08278359a Mon Sep 17 00:00:00 2001 From: Martin Unzner Date: Sun, 12 Nov 2017 18:58:42 +0100 Subject: [PATCH 4/7] Add capability to resolve UUID --- src/core/Entry.cpp | 2 ++ src/core/EntryAttributes.cpp | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/core/Entry.cpp b/src/core/Entry.cpp index 05f24b5a..65e2454e 100644 --- a/src/core/Entry.cpp +++ b/src/core/Entry.cpp @@ -838,6 +838,8 @@ QString Entry::referenceFieldValue(EntryReferenceType referenceType) const return url(); case EntryReferenceType::Notes: return notes(); + case EntryReferenceType::Uuid: + return uuid().toHex(); default: break; } diff --git a/src/core/EntryAttributes.cpp b/src/core/EntryAttributes.cpp index b1b4fad6..21dcccf6 100644 --- a/src/core/EntryAttributes.cpp +++ b/src/core/EntryAttributes.cpp @@ -34,7 +34,7 @@ const QString EntryAttributes::RememberCmdExecAttr = "_EXEC_CMD"; EntryAttributes::EntryAttributes(QObject* parent) : QObject(parent) - , m_referenceRegExp("\\{REF:(?[TUPAN])@(?[TUPANIO]):(?[^}]+)\\}", + , m_referenceRegExp("\\{REF:(?[TUPANI])@(?[TUPANIO]):(?[^}]+)\\}", QRegularExpression::CaseInsensitiveOption) { clear(); From 4c4d8a5e848c2aaba14f3dc7c1e51072e9e984f9 Mon Sep 17 00:00:00 2001 From: frostasm Date: Sun, 12 Nov 2017 17:35:54 +0200 Subject: [PATCH 5/7] Implement search for reference placeholder based on fields other than ID --- src/core/Database.cpp | 55 ++++++++++++++++++ src/core/Database.h | 3 + src/core/Entry.cpp | 109 ++++++++++++++++++++++++----------- src/core/Entry.h | 15 +++++ src/core/EntryAttributes.cpp | 22 ++++--- src/core/EntryAttributes.h | 10 +++- tests/TestEntry.cpp | 65 ++++++++++++++++----- 7 files changed, 220 insertions(+), 59 deletions(-) diff --git a/src/core/Database.cpp b/src/core/Database.cpp index 3913f809..99dd94ef 100644 --- a/src/core/Database.cpp +++ b/src/core/Database.cpp @@ -98,6 +98,11 @@ Entry* Database::resolveEntry(const Uuid& uuid) return recFindEntry(uuid, m_rootGroup); } +Entry *Database::resolveEntry(const QString &text, EntryReferenceType referenceType) +{ + return recFindEntry(text, referenceType, m_rootGroup); +} + Entry* Database::recFindEntry(const Uuid& uuid, Group* group) { const QList entryList = group->entries(); @@ -118,6 +123,56 @@ Entry* Database::recFindEntry(const Uuid& uuid, Group* group) return nullptr; } +Entry *Database::recFindEntry(const QString &text, EntryReferenceType referenceType, Group *group) +{ + Q_ASSERT_X(referenceType != EntryReferenceType::Unknown, "Database::recFindEntry", + "Can't search entry with \"referenceType\" parameter equal to \"Unknown\""); + + bool found = false; + const QList entryList = group->entries(); + for (Entry* entry : entryList) { + switch (referenceType) { + case EntryReferenceType::Unknown: + return nullptr; + case EntryReferenceType::Title: + found = entry->title() == text; + break; + case EntryReferenceType::UserName: + found = entry->username() == text; + break; + case EntryReferenceType::Password: + found = entry->password() == text; + break; + case EntryReferenceType::Url: + found = entry->url() == text; + break; + case EntryReferenceType::Notes: + found = entry->notes() == text; + break; + case EntryReferenceType::Uuid: + found = entry->uuid().toHex() == text; + break; + case EntryReferenceType::CustomAttributes: + found = entry->attributes()->containsValue(text); + break; + } + + if (found) { + return entry; + } + } + + const QList children = group->children(); + for (Group* child : children) { + Entry* result = recFindEntry(text, referenceType, child); + if (result) { + return result; + } + } + + return nullptr; +} + Group* Database::resolveGroup(const Uuid& uuid) { return recFindGroup(uuid, m_rootGroup); diff --git a/src/core/Database.h b/src/core/Database.h index 26b15025..14cb0bca 100644 --- a/src/core/Database.h +++ b/src/core/Database.h @@ -27,6 +27,7 @@ #include "keys/CompositeKey.h" class Entry; +enum class EntryReferenceType; class Group; class Metadata; class QTimer; @@ -81,6 +82,7 @@ public: Metadata* metadata(); const Metadata* metadata() const; Entry* resolveEntry(const Uuid& uuid); + Entry* resolveEntry(const QString& text, EntryReferenceType referenceType); Group* resolveGroup(const Uuid& uuid); QList deletedObjects(); void addDeletedObject(const DeletedObject& delObj); @@ -142,6 +144,7 @@ private slots: private: Entry* recFindEntry(const Uuid& uuid, Group* group); + Entry* recFindEntry(const QString& text, EntryReferenceType referenceType, Group* group); Group* recFindGroup(const Uuid& uuid, Group* group); void createRecycleBin(); diff --git a/src/core/Entry.cpp b/src/core/Entry.cpp index 9dd019d5..05f24b5a 100644 --- a/src/core/Entry.cpp +++ b/src/core/Entry.cpp @@ -92,6 +92,29 @@ void Entry::setUpdateTimeinfo(bool value) m_updateTimeinfo = value; } +EntryReferenceType Entry::referenceType(const QString& referenceStr) +{ + const QString referenceLowerStr = referenceStr.toLower(); + EntryReferenceType result = EntryReferenceType::Unknown; + if (referenceLowerStr == QLatin1String("t")) { + result = EntryReferenceType::Title; + } else if (referenceLowerStr == QLatin1String("u")) { + result = EntryReferenceType::UserName; + } else if (referenceLowerStr == QLatin1String("p")) { + result = EntryReferenceType::Password; + } else if (referenceLowerStr == QLatin1String("a")) { + result = EntryReferenceType::Url; + } else if (referenceLowerStr == QLatin1String("n")) { + result = EntryReferenceType::Notes; + } else if (referenceLowerStr == QLatin1String("i")) { + result = EntryReferenceType::Uuid; + } else if (referenceLowerStr == QLatin1String("o")) { + result = EntryReferenceType::CustomAttributes; + } + + return result; +} + Uuid Entry::uuid() const { return m_uuid; @@ -764,45 +787,63 @@ QString Entry::resolvePlaceholderRecursive(const QString &placeholder, int maxDe const QString key = placeholder.mid(3, placeholder.length() - 4); // {S:attr} => mid(3, len - 4) return attributes()->hasKey(key) ? attributes()->value(key) : QString(); } - case PlaceholderType::Reference: { - // resolving references in format: {REF:@I:} - // using format from http://keepass.info/help/base/fieldrefs.html at the time of writing, - // but supporting lookups of standard fields and references by UUID only - - QString result; - QRegExp* referenceRegExp = m_attributes->referenceRegExp(); - if (referenceRegExp->indexIn(placeholder) != -1) { - constexpr int wantedFieldIndex = 1; - constexpr int referencedUuidIndex = 2; - const Uuid referencedUuid(QByteArray::fromHex(referenceRegExp->cap(referencedUuidIndex).toLatin1())); - const Entry* refEntry = m_group->database()->resolveEntry(referencedUuid); - if (refEntry) { - const QString wantedField = referenceRegExp->cap(wantedFieldIndex).toLower(); - if (wantedField == "t") { - result = refEntry->title(); - } else if (wantedField == "u") { - result = refEntry->username(); - } else if (wantedField == "p") { - result = refEntry->password(); - } else if (wantedField == "a") { - result = refEntry->url(); - } else if (wantedField == "n") { - result = refEntry->notes(); - } - - // Referencing fields of other entries only works with standard fields, not with custom user strings. - // If you want to reference a custom user string, you need to place a redirection in a standard field - // of the entry with the custom string, using {S:}, and reference the standard field. - result = refEntry->resolveMultiplePlaceholdersRecursive(result, maxDepth - 1); - } - } - return result; - } + case PlaceholderType::Reference: + return resolveReferencePlaceholderRecursive(placeholder, maxDepth); } return placeholder; } +QString Entry::resolveReferencePlaceholderRecursive(const QString &placeholder, int maxDepth) const +{ + // resolving references in format: {REF:@:} + // using format from http://keepass.info/help/base/fieldrefs.html at the time of writing + + QRegularExpression* referenceRegExp = m_attributes->referenceRegExp(); + QRegularExpressionMatch match = referenceRegExp->match(placeholder); + if (!match.hasMatch()) { + return placeholder; + } + + QString result; + const QString searchIn = match.captured(EntryAttributes::SearchInGroupName); + const QString searchText = match.captured(EntryAttributes::SearchTextGroupName); + + const EntryReferenceType searchInType = Entry::referenceType(searchIn); + const Entry* refEntry = m_group->database()->resolveEntry(searchText, searchInType); + + if (refEntry) { + const QString wantedField = match.captured(EntryAttributes::WantedFieldGroupName); + result = refEntry->referenceFieldValue(Entry::referenceType(wantedField)); + + // Referencing fields of other entries only works with standard fields, not with custom user strings. + // If you want to reference a custom user string, you need to place a redirection in a standard field + // of the entry with the custom string, using {S:}, and reference the standard field. + result = refEntry->resolveMultiplePlaceholdersRecursive(result, maxDepth - 1); + } + + return result; +} + +QString Entry::referenceFieldValue(EntryReferenceType referenceType) const +{ + switch (referenceType) { + case EntryReferenceType::Title: + return title(); + case EntryReferenceType::UserName: + return username(); + case EntryReferenceType::Password: + return password(); + case EntryReferenceType::Url: + return url(); + case EntryReferenceType::Notes: + return notes(); + default: + break; + } + return QString(); +} + Group* Entry::group() { return m_group; diff --git a/src/core/Entry.h b/src/core/Entry.h index d4d2b903..af11478b 100644 --- a/src/core/Entry.h +++ b/src/core/Entry.h @@ -36,6 +36,17 @@ class Database; class Group; +enum class EntryReferenceType { + Unknown, + Title, + UserName, + Password, + Url, + Notes, + Uuid, + CustomAttributes +}; + struct EntryData { int iconNumber; @@ -203,6 +214,10 @@ private slots: private: QString resolveMultiplePlaceholdersRecursive(const QString& str, int maxDepth) const; QString resolvePlaceholderRecursive(const QString& placeholder, int maxDepth) const; + QString resolveReferencePlaceholderRecursive(const QString& placeholder, int maxDepth) const; + QString referenceFieldValue(EntryReferenceType referenceType) const; + + static EntryReferenceType referenceType(const QString& referenceStr); const Database* database() const; template bool set(T& property, const T& value); diff --git a/src/core/EntryAttributes.cpp b/src/core/EntryAttributes.cpp index 8ffdaa8f..b1b4fad6 100644 --- a/src/core/EntryAttributes.cpp +++ b/src/core/EntryAttributes.cpp @@ -25,11 +25,17 @@ const QString EntryAttributes::URLKey = "URL"; const QString EntryAttributes::NotesKey = "Notes"; const QStringList EntryAttributes::DefaultAttributes(QStringList() << TitleKey << UserNameKey << PasswordKey << URLKey << NotesKey); + +const QString EntryAttributes::WantedFieldGroupName = "WantedField"; +const QString EntryAttributes::SearchInGroupName = "SearchIn"; +const QString EntryAttributes::SearchTextGroupName = "SearchText"; + const QString EntryAttributes::RememberCmdExecAttr = "_EXEC_CMD"; EntryAttributes::EntryAttributes(QObject* parent) : QObject(parent) - , m_referenceRegExp("\\{REF:([TUPAN])@I:([^}]+)\\}", Qt::CaseInsensitive, QRegExp::RegExp2) + , m_referenceRegExp("\\{REF:(?[TUPAN])@(?[TUPANIO]):(?[^}]+)\\}", + QRegularExpression::CaseInsensitiveOption) { clear(); } @@ -66,6 +72,11 @@ bool EntryAttributes::contains(const QString &key) const return m_attributes.contains(key); } +bool EntryAttributes::containsValue(const QString &value) const +{ + return m_attributes.values().contains(value); +} + bool EntryAttributes::isProtected(const QString& key) const { return m_protectedAttributes.contains(key); @@ -78,14 +89,11 @@ bool EntryAttributes::isReference(const QString& key) const return false; } - QString data = value(key); - if (m_referenceRegExp.indexIn(data) != -1) { - return true; - } - return false; + const QString data = value(key); + return m_referenceRegExp.match(data).hasMatch(); } -QRegExp* EntryAttributes::referenceRegExp() +QRegularExpression* EntryAttributes::referenceRegExp() { return &m_referenceRegExp; } diff --git a/src/core/EntryAttributes.h b/src/core/EntryAttributes.h index 40fc5dec..f2838865 100644 --- a/src/core/EntryAttributes.h +++ b/src/core/EntryAttributes.h @@ -21,6 +21,7 @@ #include #include +#include #include #include @@ -35,9 +36,10 @@ public: QList customKeys(); QString value(const QString& key) const; bool contains(const QString& key) const; + bool containsValue(const QString& value) const; bool isProtected(const QString& key) const; bool isReference(const QString& key) const; - QRegExp* referenceRegExp(); + QRegularExpression *referenceRegExp(); void set(const QString& key, const QString& value, bool protect = false); void remove(const QString& key); void rename(const QString& oldKey, const QString& newKey); @@ -58,6 +60,10 @@ public: static const QString RememberCmdExecAttr; static bool isDefaultAttribute(const QString& key); + static const QString WantedFieldGroupName; + static const QString SearchInGroupName; + static const QString SearchTextGroupName; + signals: void modified(); void defaultKeyModified(); @@ -74,7 +80,7 @@ signals: private: QMap m_attributes; QSet m_protectedAttributes; - QRegExp m_referenceRegExp; + QRegularExpression m_referenceRegExp; }; #endif // KEEPASSX_ENTRYATTRIBUTES_H diff --git a/tests/TestEntry.cpp b/tests/TestEntry.cpp index d6ff5357..90da71d5 100644 --- a/tests/TestEntry.cpp +++ b/tests/TestEntry.cpp @@ -285,29 +285,62 @@ void TestEntry::testResolveReferencePlaceholders() entry2->setUuid(Uuid::random()); entry2->setTitle("Title2"); entry2->setUsername("Username2"); - entry2->setPassword("password2"); + entry2->setPassword("Password2"); entry2->setUrl("Url2"); entry2->setNotes("Notes2"); entry2->attributes()->set("CustomAttribute2", "CustomAttributeValue2"); - entry2->attributes()->set("CustomAttribute21", "CustomAttributeValue21"); Entry* entry3 = new Entry(); entry3->setGroup(root); entry3->setUuid(Uuid::random()); + entry3->setTitle("{S:AttributeTitle}"); + entry3->setUsername("{S:AttributeUsername}"); + entry3->setPassword("{S:AttributePassword}"); + entry3->setUrl("{S:AttributeUrl}"); + entry3->setNotes("{S:AttributeNotes}"); + entry3->attributes()->set("AttributeTitle", "TitleValue"); + entry3->attributes()->set("AttributeUsername", "UsernameValue"); + entry3->attributes()->set("AttributePassword", "PasswordValue"); + entry3->attributes()->set("AttributeUrl", "UrlValue"); + entry3->attributes()->set("AttributeNotes", "NotesValue"); - QCOMPARE(entry3->resolveMultiplePlaceholders(QString("{REF:T@I:%1}").arg(entry1->uuid().toHex())), QString("Title1")); - QCOMPARE(entry3->resolveMultiplePlaceholders(QString("{REF:T@T:%1}").arg(entry1->title())), QString("Title1")); - QCOMPARE(entry3->resolveMultiplePlaceholders(QString("{REF:T@U:%1}").arg(entry1->username())), QString("Title1")); - QCOMPARE(entry3->resolveMultiplePlaceholders(QString("{REF:T@P:%1}").arg(entry1->password())), QString("Title1")); - QCOMPARE(entry3->resolveMultiplePlaceholders(QString("{REF:T@A:%1}").arg(entry1->url())), QString("Title1")); - QCOMPARE(entry3->resolveMultiplePlaceholders(QString("{REF:T@N:%1}").arg(entry1->notes())), QString("Title1")); - QCOMPARE(entry3->resolveMultiplePlaceholders(QString("{REF:T@O:%1}").arg(entry1->attributes()->value("CustomAttribute1"))), QString("Title1")); + Entry* tstEntry = new Entry(); + tstEntry->setGroup(root); + tstEntry->setUuid(Uuid::random()); - QCOMPARE(entry3->resolveMultiplePlaceholders(QString("{REF:T@I:%1}").arg(entry1->uuid().toHex())), QString("Title1")); - QCOMPARE(entry3->resolveMultiplePlaceholders(QString("{REF:T@T:%1}").arg(entry1->title())), QString("Title1")); - QCOMPARE(entry3->resolveMultiplePlaceholders(QString("{REF:U@U:%1}").arg(entry1->username())), QString("Username1")); - QCOMPARE(entry3->resolveMultiplePlaceholders(QString("{REF:P@P:%1}").arg(entry1->password())), QString("Password1")); - QCOMPARE(entry3->resolveMultiplePlaceholders(QString("{REF:A@A:%1}").arg(entry1->url())), QString("Url1")); - QCOMPARE(entry3->resolveMultiplePlaceholders(QString("{REF:N@N:%1}").arg(entry1->notes())), QString("Notes1")); - QCOMPARE(entry3->resolveMultiplePlaceholders(QString("{REF:O@O:%1}").arg(entry1->attributes()->value("CustomAttribute1"))), QString("CustomAttributeValue1")); + QCOMPARE(tstEntry->resolveMultiplePlaceholders(QString("{REF:T@I:%1}").arg(entry1->uuid().toHex())), QString("Title1")); + QCOMPARE(tstEntry->resolveMultiplePlaceholders(QString("{REF:T@T:%1}").arg(entry1->title())), QString("Title1")); + QCOMPARE(tstEntry->resolveMultiplePlaceholders(QString("{REF:T@U:%1}").arg(entry1->username())), QString("Title1")); + QCOMPARE(tstEntry->resolveMultiplePlaceholders(QString("{REF:T@P:%1}").arg(entry1->password())), QString("Title1")); + QCOMPARE(tstEntry->resolveMultiplePlaceholders(QString("{REF:T@A:%1}").arg(entry1->url())), QString("Title1")); + QCOMPARE(tstEntry->resolveMultiplePlaceholders(QString("{REF:T@N:%1}").arg(entry1->notes())), QString("Title1")); + QCOMPARE(tstEntry->resolveMultiplePlaceholders(QString("{REF:T@O:%1}").arg(entry1->attributes()->value("CustomAttribute1"))), QString("Title1")); + + QCOMPARE(tstEntry->resolveMultiplePlaceholders(QString("{REF:T@I:%1}").arg(entry1->uuid().toHex())), QString("Title1")); + QCOMPARE(tstEntry->resolveMultiplePlaceholders(QString("{REF:T@T:%1}").arg(entry1->title())), QString("Title1")); + QCOMPARE(tstEntry->resolveMultiplePlaceholders(QString("{REF:U@U:%1}").arg(entry1->username())), QString("Username1")); + QCOMPARE(tstEntry->resolveMultiplePlaceholders(QString("{REF:P@P:%1}").arg(entry1->password())), QString("Password1")); + QCOMPARE(tstEntry->resolveMultiplePlaceholders(QString("{REF:A@A:%1}").arg(entry1->url())), QString("Url1")); + QCOMPARE(tstEntry->resolveMultiplePlaceholders(QString("{REF:N@N:%1}").arg(entry1->notes())), QString("Notes1")); + + QCOMPARE(tstEntry->resolveMultiplePlaceholders(QString("{REF:T@I:%1}").arg(entry2->uuid().toHex())), QString("Title2")); + QCOMPARE(tstEntry->resolveMultiplePlaceholders(QString("{REF:T@T:%1}").arg(entry2->title())), QString("Title2")); + QCOMPARE(tstEntry->resolveMultiplePlaceholders(QString("{REF:T@U:%1}").arg(entry2->username())), QString("Title2")); + QCOMPARE(tstEntry->resolveMultiplePlaceholders(QString("{REF:T@P:%1}").arg(entry2->password())), QString("Title2")); + QCOMPARE(tstEntry->resolveMultiplePlaceholders(QString("{REF:T@A:%1}").arg(entry2->url())), QString("Title2")); + QCOMPARE(tstEntry->resolveMultiplePlaceholders(QString("{REF:T@N:%1}").arg(entry2->notes())), QString("Title2")); + QCOMPARE(tstEntry->resolveMultiplePlaceholders(QString("{REF:T@O:%1}").arg(entry2->attributes()->value("CustomAttribute2"))), QString("Title2")); + + QCOMPARE(tstEntry->resolveMultiplePlaceholders(QString("{REF:T@T:%1}").arg(entry2->title())), QString("Title2")); + QCOMPARE(tstEntry->resolveMultiplePlaceholders(QString("{REF:U@U:%1}").arg(entry2->username())), QString("Username2")); + QCOMPARE(tstEntry->resolveMultiplePlaceholders(QString("{REF:P@P:%1}").arg(entry2->password())), QString("Password2")); + QCOMPARE(tstEntry->resolveMultiplePlaceholders(QString("{REF:A@A:%1}").arg(entry2->url())), QString("Url2")); + QCOMPARE(tstEntry->resolveMultiplePlaceholders(QString("{REF:N@N:%1}").arg(entry2->notes())), QString("Notes2")); + + QCOMPARE(tstEntry->resolveMultiplePlaceholders(QString("{REF:T@I:%1}").arg(entry3->uuid().toHex())), QString("TitleValue")); + QCOMPARE(tstEntry->resolveMultiplePlaceholders(QString("{REF:T@I:%1}").arg(entry3->uuid().toHex())), QString("TitleValue")); + QCOMPARE(tstEntry->resolveMultiplePlaceholders(QString("{REF:U@I:%1}").arg(entry3->uuid().toHex())), QString("UsernameValue")); + QCOMPARE(tstEntry->resolveMultiplePlaceholders(QString("{REF:P@I:%1}").arg(entry3->uuid().toHex())), QString("PasswordValue")); + QCOMPARE(tstEntry->resolveMultiplePlaceholders(QString("{REF:A@I:%1}").arg(entry3->uuid().toHex())), QString("UrlValue")); + QCOMPARE(tstEntry->resolveMultiplePlaceholders(QString("{REF:N@I:%1}").arg(entry3->uuid().toHex())), QString("NotesValue")); } From d99dee9c40d8c9c3444ed0f3851dd7195a06a5ab Mon Sep 17 00:00:00 2001 From: frostasm Date: Sun, 19 Nov 2017 21:06:09 +0200 Subject: [PATCH 6/7] Small refactoring related to references placeholders --- src/core/Database.cpp | 22 ++++---- src/core/Database.h | 6 +-- src/core/Entry.cpp | 15 +++--- src/core/Entry.h | 2 +- src/core/EntryAttachments.cpp | 2 +- src/core/EntryAttributes.cpp | 22 ++++---- src/core/EntryAttributes.h | 4 +- tests/TestEntry.cpp | 94 +++++++++++++++-------------------- 8 files changed, 78 insertions(+), 89 deletions(-) diff --git a/src/core/Database.cpp b/src/core/Database.cpp index 99dd94ef..7ae9308a 100644 --- a/src/core/Database.cpp +++ b/src/core/Database.cpp @@ -95,15 +95,15 @@ const Metadata* Database::metadata() const Entry* Database::resolveEntry(const Uuid& uuid) { - return recFindEntry(uuid, m_rootGroup); + return findEntryRecursive(uuid, m_rootGroup); } -Entry *Database::resolveEntry(const QString &text, EntryReferenceType referenceType) +Entry* Database::resolveEntry(const QString& text, EntryReferenceType referenceType) { - return recFindEntry(text, referenceType, m_rootGroup); + return findEntryRecursive(text, referenceType, m_rootGroup); } -Entry* Database::recFindEntry(const Uuid& uuid, Group* group) +Entry* Database::findEntryRecursive(const Uuid& uuid, Group* group) { const QList entryList = group->entries(); for (Entry* entry : entryList) { @@ -114,7 +114,7 @@ Entry* Database::recFindEntry(const Uuid& uuid, Group* group) const QList children = group->children(); for (Group* child : children) { - Entry* result = recFindEntry(uuid, child); + Entry* result = findEntryRecursive(uuid, child); if (result) { return result; } @@ -123,9 +123,9 @@ Entry* Database::recFindEntry(const Uuid& uuid, Group* group) return nullptr; } -Entry *Database::recFindEntry(const QString &text, EntryReferenceType referenceType, Group *group) +Entry* Database::findEntryRecursive(const QString& text, EntryReferenceType referenceType, Group* group) { - Q_ASSERT_X(referenceType != EntryReferenceType::Unknown, "Database::recFindEntry", + Q_ASSERT_X(referenceType != EntryReferenceType::Unknown, "Database::findEntryRecursive", "Can't search entry with \"referenceType\" parameter equal to \"Unknown\""); bool found = false; @@ -164,7 +164,7 @@ Entry *Database::recFindEntry(const QString &text, EntryReferenceType referenceT const QList children = group->children(); for (Group* child : children) { - Entry* result = recFindEntry(text, referenceType, child); + Entry* result = findEntryRecursive(text, referenceType, child); if (result) { return result; } @@ -175,10 +175,10 @@ Entry *Database::recFindEntry(const QString &text, EntryReferenceType referenceT Group* Database::resolveGroup(const Uuid& uuid) { - return recFindGroup(uuid, m_rootGroup); + return findGroupRecursive(uuid, m_rootGroup); } -Group* Database::recFindGroup(const Uuid& uuid, Group* group) +Group* Database::findGroupRecursive(const Uuid& uuid, Group* group) { if (group->uuid() == uuid) { return group; @@ -186,7 +186,7 @@ Group* Database::recFindGroup(const Uuid& uuid, Group* group) const QList children = group->children(); for (Group* child : children) { - Group* result = recFindGroup(uuid, child); + Group* result = findGroupRecursive(uuid, child); if (result) { return result; } diff --git a/src/core/Database.h b/src/core/Database.h index 14cb0bca..b20f897f 100644 --- a/src/core/Database.h +++ b/src/core/Database.h @@ -143,9 +143,9 @@ private slots: void startModifiedTimer(); private: - Entry* recFindEntry(const Uuid& uuid, Group* group); - Entry* recFindEntry(const QString& text, EntryReferenceType referenceType, Group* group); - Group* recFindGroup(const Uuid& uuid, Group* group); + Entry* findEntryRecursive(const Uuid& uuid, Group* group); + Entry* findEntryRecursive(const QString& text, EntryReferenceType referenceType, Group* group); + Group* findGroupRecursive(const Uuid& uuid, Group* group); void createRecycleBin(); diff --git a/src/core/Entry.cpp b/src/core/Entry.cpp index 65e2454e..11ae97d7 100644 --- a/src/core/Entry.cpp +++ b/src/core/Entry.cpp @@ -722,7 +722,7 @@ void Entry::updateModifiedSinceBegin() m_modifiedSinceBegin = true; } -QString Entry::resolveMultiplePlaceholdersRecursive(const QString &str, int maxDepth) const +QString Entry::resolveMultiplePlaceholdersRecursive(const QString& str, int maxDepth) const { if (maxDepth <= 0) { qWarning("Maximum depth of replacement has been reached. Entry uuid: %s", qPrintable(uuid().toHex())); @@ -746,7 +746,7 @@ QString Entry::resolveMultiplePlaceholdersRecursive(const QString &str, int maxD return result; } -QString Entry::resolvePlaceholderRecursive(const QString &placeholder, int maxDepth) const +QString Entry::resolvePlaceholderRecursive(const QString& placeholder, int maxDepth) const { const PlaceholderType typeOfPlaceholder = placeholderType(placeholder); switch (typeOfPlaceholder) { @@ -794,13 +794,12 @@ QString Entry::resolvePlaceholderRecursive(const QString &placeholder, int maxDe return placeholder; } -QString Entry::resolveReferencePlaceholderRecursive(const QString &placeholder, int maxDepth) const +QString Entry::resolveReferencePlaceholderRecursive(const QString& placeholder, int maxDepth) const { // resolving references in format: {REF:@:} // using format from http://keepass.info/help/base/fieldrefs.html at the time of writing - QRegularExpression* referenceRegExp = m_attributes->referenceRegExp(); - QRegularExpressionMatch match = referenceRegExp->match(placeholder); + QRegularExpressionMatch match = EntryAttributes::matchReference(placeholder); if (!match.hasMatch()) { return placeholder; } @@ -903,7 +902,7 @@ const Database* Entry::database() const } } -QString Entry::maskPasswordPlaceholders(const QString &str) const +QString Entry::maskPasswordPlaceholders(const QString& str) const { QString result = str; result.replace(QRegExp("(\\{PASSWORD\\})", Qt::CaseInsensitive, QRegExp::RegExp2), "******"); @@ -920,7 +919,7 @@ QString Entry::resolvePlaceholder(const QString& placeholder) const return resolvePlaceholderRecursive(placeholder, ResolveMaximumDepth); } -QString Entry::resolveUrlPlaceholder(const QString &str, Entry::PlaceholderType placeholderType) const +QString Entry::resolveUrlPlaceholder(const QString& str, Entry::PlaceholderType placeholderType) const { if (str.isEmpty()) return QString(); @@ -956,7 +955,7 @@ QString Entry::resolveUrlPlaceholder(const QString &str, Entry::PlaceholderType return QString(); } -Entry::PlaceholderType Entry::placeholderType(const QString &placeholder) const +Entry::PlaceholderType Entry::placeholderType(const QString& placeholder) const { if (!placeholder.startsWith(QLatin1Char('{')) || !placeholder.endsWith(QLatin1Char('}'))) { return PlaceholderType::NotPlaceholder; diff --git a/src/core/Entry.h b/src/core/Entry.h index af11478b..266254e6 100644 --- a/src/core/Entry.h +++ b/src/core/Entry.h @@ -181,7 +181,7 @@ public: QString maskPasswordPlaceholders(const QString& str) const; QString resolveMultiplePlaceholders(const QString& str) const; QString resolvePlaceholder(const QString& str) const; - QString resolveUrlPlaceholder(const QString &str, PlaceholderType placeholderType) const; + QString resolveUrlPlaceholder(const QString& str, PlaceholderType placeholderType) const; PlaceholderType placeholderType(const QString& placeholder) const; QString resolveUrl(const QString& url) const; diff --git a/src/core/EntryAttachments.cpp b/src/core/EntryAttachments.cpp index 8ff66277..bab11057 100644 --- a/src/core/EntryAttachments.cpp +++ b/src/core/EntryAttachments.cpp @@ -86,7 +86,7 @@ void EntryAttachments::remove(const QString& key) emit modified(); } -void EntryAttachments::remove(const QStringList &keys) +void EntryAttachments::remove(const QStringList& keys) { if (keys.isEmpty()) { return; diff --git a/src/core/EntryAttributes.cpp b/src/core/EntryAttributes.cpp index 21dcccf6..8cc7f2f0 100644 --- a/src/core/EntryAttributes.cpp +++ b/src/core/EntryAttributes.cpp @@ -34,8 +34,6 @@ const QString EntryAttributes::RememberCmdExecAttr = "_EXEC_CMD"; EntryAttributes::EntryAttributes(QObject* parent) : QObject(parent) - , m_referenceRegExp("\\{REF:(?[TUPANI])@(?[TUPANIO]):(?[^}]+)\\}", - QRegularExpression::CaseInsensitiveOption) { clear(); } @@ -67,12 +65,12 @@ QString EntryAttributes::value(const QString& key) const return m_attributes.value(key); } -bool EntryAttributes::contains(const QString &key) const +bool EntryAttributes::contains(const QString& key) const { return m_attributes.contains(key); } -bool EntryAttributes::containsValue(const QString &value) const +bool EntryAttributes::containsValue(const QString& value) const { return m_attributes.values().contains(value); } @@ -90,12 +88,7 @@ bool EntryAttributes::isReference(const QString& key) const } const QString data = value(key); - return m_referenceRegExp.match(data).hasMatch(); -} - -QRegularExpression* EntryAttributes::referenceRegExp() -{ - return &m_referenceRegExp; + return matchReference(data).hasMatch(); } void EntryAttributes::set(const QString& key, const QString& value, bool protect) @@ -266,6 +259,15 @@ bool EntryAttributes::operator!=(const EntryAttributes& other) const || m_protectedAttributes != other.m_protectedAttributes); } +QRegularExpressionMatch EntryAttributes::matchReference(const QString& text) +{ + static QRegularExpression referenceRegExp( + "\\{REF:(?[TUPANI])@(?[TUPANIO]):(?[^}]+)\\}", + QRegularExpression::CaseInsensitiveOption); + + return referenceRegExp.match(text); +} + void EntryAttributes::clear() { emit aboutToBeReset(); diff --git a/src/core/EntryAttributes.h b/src/core/EntryAttributes.h index f2838865..f483b8a9 100644 --- a/src/core/EntryAttributes.h +++ b/src/core/EntryAttributes.h @@ -39,7 +39,6 @@ public: bool containsValue(const QString& value) const; bool isProtected(const QString& key) const; bool isReference(const QString& key) const; - QRegularExpression *referenceRegExp(); void set(const QString& key, const QString& value, bool protect = false); void remove(const QString& key); void rename(const QString& oldKey, const QString& newKey); @@ -51,6 +50,8 @@ public: bool operator==(const EntryAttributes& other) const; bool operator!=(const EntryAttributes& other) const; + static QRegularExpressionMatch matchReference(const QString& text); + static const QString TitleKey; static const QString UserNameKey; static const QString PasswordKey; @@ -80,7 +81,6 @@ signals: private: QMap m_attributes; QSet m_protectedAttributes; - QRegularExpression m_referenceRegExp; }; #endif // KEEPASSX_ENTRYATTRIBUTES_H diff --git a/tests/TestEntry.cpp b/tests/TestEntry.cpp index 802a27b7..bb117645 100644 --- a/tests/TestEntry.cpp +++ b/tests/TestEntry.cpp @@ -281,7 +281,7 @@ void TestEntry::testResolveReferencePlaceholders() Group* group = new Group(); group->setParent(root); Entry* entry2 = new Entry(); - entry2->setGroup(root); + entry2->setGroup(group); entry2->setUuid(Uuid::random()); entry2->setTitle("Title2"); entry2->setUsername("Username2"); @@ -291,7 +291,7 @@ void TestEntry::testResolveReferencePlaceholders() entry2->attributes()->set("CustomAttribute2", "CustomAttributeValue2"); Entry* entry3 = new Entry(); - entry3->setGroup(root); + entry3->setGroup(group); entry3->setUuid(Uuid::random()); entry3->setTitle("{S:AttributeTitle}"); entry3->setUsername("{S:AttributeUsername}"); @@ -308,51 +308,43 @@ void TestEntry::testResolveReferencePlaceholders() tstEntry->setGroup(root); tstEntry->setUuid(Uuid::random()); - QCOMPARE(tstEntry->resolveMultiplePlaceholders(QString("{REF:T@I:%1}").arg(entry1->uuid().toHex())), QString("Title1")); - QCOMPARE(tstEntry->resolveMultiplePlaceholders(QString("{REF:T@T:%1}").arg(entry1->title())), QString("Title1")); - QCOMPARE(tstEntry->resolveMultiplePlaceholders(QString("{REF:T@U:%1}").arg(entry1->username())), QString("Title1")); - QCOMPARE(tstEntry->resolveMultiplePlaceholders(QString("{REF:T@P:%1}").arg(entry1->password())), QString("Title1")); - QCOMPARE(tstEntry->resolveMultiplePlaceholders(QString("{REF:T@A:%1}").arg(entry1->url())), QString("Title1")); - QCOMPARE(tstEntry->resolveMultiplePlaceholders(QString("{REF:T@N:%1}").arg(entry1->notes())), QString("Title1")); - QCOMPARE(tstEntry->resolveMultiplePlaceholders(QString("{REF:T@O:%1}").arg(entry1->attributes()->value("CustomAttribute1"))), QString("Title1")); + QCOMPARE(tstEntry->resolveMultiplePlaceholders(QString("{REF:T@I:%1}").arg(entry1->uuid().toHex())), entry1->title()); + QCOMPARE(tstEntry->resolveMultiplePlaceholders(QString("{REF:T@T:%1}").arg(entry1->title())), entry1->title()); + QCOMPARE(tstEntry->resolveMultiplePlaceholders(QString("{REF:T@U:%1}").arg(entry1->username())), entry1->title()); + QCOMPARE(tstEntry->resolveMultiplePlaceholders(QString("{REF:T@P:%1}").arg(entry1->password())), entry1->title()); + QCOMPARE(tstEntry->resolveMultiplePlaceholders(QString("{REF:T@A:%1}").arg(entry1->url())), entry1->title()); + QCOMPARE(tstEntry->resolveMultiplePlaceholders(QString("{REF:T@N:%1}").arg(entry1->notes())), entry1->title()); + QCOMPARE(tstEntry->resolveMultiplePlaceholders(QString("{REF:T@O:%1}").arg(entry1->attributes()->value("CustomAttribute1"))), entry1->title()); - QCOMPARE(tstEntry->resolveMultiplePlaceholders(QString("{REF:T@I:%1}").arg(entry1->uuid().toHex())), QString("Title1")); - QCOMPARE(tstEntry->resolveMultiplePlaceholders(QString("{REF:T@T:%1}").arg(entry1->title())), QString("Title1")); - QCOMPARE(tstEntry->resolveMultiplePlaceholders(QString("{REF:U@U:%1}").arg(entry1->username())), QString("Username1")); - QCOMPARE(tstEntry->resolveMultiplePlaceholders(QString("{REF:P@P:%1}").arg(entry1->password())), QString("Password1")); - QCOMPARE(tstEntry->resolveMultiplePlaceholders(QString("{REF:A@A:%1}").arg(entry1->url())), QString("Url1")); - QCOMPARE(tstEntry->resolveMultiplePlaceholders(QString("{REF:N@N:%1}").arg(entry1->notes())), QString("Notes1")); + QCOMPARE(tstEntry->resolveMultiplePlaceholders(QString("{REF:T@I:%1}").arg(entry1->uuid().toHex())), entry1->title()); + QCOMPARE(tstEntry->resolveMultiplePlaceholders(QString("{REF:T@T:%1}").arg(entry1->title())), entry1->title()); + QCOMPARE(tstEntry->resolveMultiplePlaceholders(QString("{REF:U@U:%1}").arg(entry1->username())), entry1->username()); + QCOMPARE(tstEntry->resolveMultiplePlaceholders(QString("{REF:P@P:%1}").arg(entry1->password())), entry1->password()); + QCOMPARE(tstEntry->resolveMultiplePlaceholders(QString("{REF:A@A:%1}").arg(entry1->url())), entry1->url()); + QCOMPARE(tstEntry->resolveMultiplePlaceholders(QString("{REF:N@N:%1}").arg(entry1->notes())), entry1->notes()); - QCOMPARE(tstEntry->resolveMultiplePlaceholders(QString("{REF:T@I:%1}").arg(entry2->uuid().toHex())), QString("Title2")); - QCOMPARE(tstEntry->resolveMultiplePlaceholders(QString("{REF:T@T:%1}").arg(entry2->title())), QString("Title2")); - QCOMPARE(tstEntry->resolveMultiplePlaceholders(QString("{REF:T@U:%1}").arg(entry2->username())), QString("Title2")); - QCOMPARE(tstEntry->resolveMultiplePlaceholders(QString("{REF:T@P:%1}").arg(entry2->password())), QString("Title2")); - QCOMPARE(tstEntry->resolveMultiplePlaceholders(QString("{REF:T@A:%1}").arg(entry2->url())), QString("Title2")); - QCOMPARE(tstEntry->resolveMultiplePlaceholders(QString("{REF:T@N:%1}").arg(entry2->notes())), QString("Title2")); - QCOMPARE(tstEntry->resolveMultiplePlaceholders(QString("{REF:T@O:%1}").arg(entry2->attributes()->value("CustomAttribute2"))), QString("Title2")); + QCOMPARE(tstEntry->resolveMultiplePlaceholders(QString("{REF:T@I:%1}").arg(entry2->uuid().toHex())), entry2->title()); + QCOMPARE(tstEntry->resolveMultiplePlaceholders(QString("{REF:T@T:%1}").arg(entry2->title())), entry2->title()); + QCOMPARE(tstEntry->resolveMultiplePlaceholders(QString("{REF:T@U:%1}").arg(entry2->username())), entry2->title()); + QCOMPARE(tstEntry->resolveMultiplePlaceholders(QString("{REF:T@P:%1}").arg(entry2->password())), entry2->title()); + QCOMPARE(tstEntry->resolveMultiplePlaceholders(QString("{REF:T@A:%1}").arg(entry2->url())), entry2->title()); + QCOMPARE(tstEntry->resolveMultiplePlaceholders(QString("{REF:T@N:%1}").arg(entry2->notes())), entry2->title()); + QCOMPARE(tstEntry->resolveMultiplePlaceholders(QString("{REF:T@O:%1}").arg(entry2->attributes()->value("CustomAttribute2"))), entry2->title()); - QCOMPARE(tstEntry->resolveMultiplePlaceholders(QString("{REF:T@T:%1}").arg(entry2->title())), QString("Title2")); - QCOMPARE(tstEntry->resolveMultiplePlaceholders(QString("{REF:U@U:%1}").arg(entry2->username())), QString("Username2")); - QCOMPARE(tstEntry->resolveMultiplePlaceholders(QString("{REF:P@P:%1}").arg(entry2->password())), QString("Password2")); - QCOMPARE(tstEntry->resolveMultiplePlaceholders(QString("{REF:A@A:%1}").arg(entry2->url())), QString("Url2")); - QCOMPARE(tstEntry->resolveMultiplePlaceholders(QString("{REF:N@N:%1}").arg(entry2->notes())), QString("Notes2")); + QCOMPARE(tstEntry->resolveMultiplePlaceholders(QString("{REF:T@T:%1}").arg(entry2->title())), entry2->title()); + QCOMPARE(tstEntry->resolveMultiplePlaceholders(QString("{REF:U@U:%1}").arg(entry2->username())), entry2->username()); + QCOMPARE(tstEntry->resolveMultiplePlaceholders(QString("{REF:P@P:%1}").arg(entry2->password())), entry2->password()); + QCOMPARE(tstEntry->resolveMultiplePlaceholders(QString("{REF:A@A:%1}").arg(entry2->url())), entry2->url()); + QCOMPARE(tstEntry->resolveMultiplePlaceholders(QString("{REF:N@N:%1}").arg(entry2->notes())), entry2->notes()); - QCOMPARE(tstEntry->resolveMultiplePlaceholders(QString("{REF:T@I:%1}").arg(entry3->uuid().toHex())), QString("TitleValue")); - QCOMPARE(tstEntry->resolveMultiplePlaceholders(QString("{REF:T@I:%1}").arg(entry3->uuid().toHex())), QString("TitleValue")); - QCOMPARE(tstEntry->resolveMultiplePlaceholders(QString("{REF:U@I:%1}").arg(entry3->uuid().toHex())), QString("UsernameValue")); - QCOMPARE(tstEntry->resolveMultiplePlaceholders(QString("{REF:P@I:%1}").arg(entry3->uuid().toHex())), QString("PasswordValue")); - QCOMPARE(tstEntry->resolveMultiplePlaceholders(QString("{REF:A@I:%1}").arg(entry3->uuid().toHex())), QString("UrlValue")); - QCOMPARE(tstEntry->resolveMultiplePlaceholders(QString("{REF:N@I:%1}").arg(entry3->uuid().toHex())), QString("NotesValue")); + QCOMPARE(tstEntry->resolveMultiplePlaceholders(QString("{REF:T@I:%1}").arg(entry3->uuid().toHex())), entry3->attributes()->value("AttributeTitle")); + QCOMPARE(tstEntry->resolveMultiplePlaceholders(QString("{REF:T@I:%1}").arg(entry3->uuid().toHex())), entry3->attributes()->value("AttributeTitle")); + QCOMPARE(tstEntry->resolveMultiplePlaceholders(QString("{REF:U@I:%1}").arg(entry3->uuid().toHex())), entry3->attributes()->value("AttributeUsername")); + QCOMPARE(tstEntry->resolveMultiplePlaceholders(QString("{REF:P@I:%1}").arg(entry3->uuid().toHex())), entry3->attributes()->value("AttributePassword")); + QCOMPARE(tstEntry->resolveMultiplePlaceholders(QString("{REF:A@I:%1}").arg(entry3->uuid().toHex())), entry3->attributes()->value("AttributeUrl")); + QCOMPARE(tstEntry->resolveMultiplePlaceholders(QString("{REF:N@I:%1}").arg(entry3->uuid().toHex())), entry3->attributes()->value("AttributeNotes")); } -static const char placeholders[] = { -'T', -'U', -'P', -'A', -'N', -}; - void TestEntry::testResolveNonIdPlaceholdersToUuid() { Database db; @@ -383,35 +375,31 @@ void TestEntry::testResolveNonIdPlaceholdersToUuid() referencedEntryNotes.setNotes("myNotes"); referencedEntryNotes.setUuid(Uuid::random()); - for (const auto searchIn : placeholders) { + const QList placeholders{'T', 'U', 'P', 'A', 'N'}; + for (const QChar searchIn : placeholders) { const Entry* referencedEntry = nullptr; QString newEntryNotesRaw("{REF:I@%1:%2}"); - switch(searchIn) { + switch(searchIn.toLatin1()) { case 'T': referencedEntry = &referencedEntryTitle; - newEntryNotesRaw = newEntryNotesRaw.arg( - QString(searchIn), referencedEntry->title()); + newEntryNotesRaw = newEntryNotesRaw.arg(searchIn, referencedEntry->title()); break; case 'U': referencedEntry = &referencedEntryUsername; - newEntryNotesRaw = newEntryNotesRaw.arg( - QString(searchIn), referencedEntry->username()); + newEntryNotesRaw = newEntryNotesRaw.arg(searchIn, referencedEntry->username()); break; case 'P': referencedEntry = &referencedEntryPassword; - newEntryNotesRaw = newEntryNotesRaw.arg( - QString(searchIn), referencedEntry->password()); + newEntryNotesRaw = newEntryNotesRaw.arg(searchIn, referencedEntry->password()); break; case 'A': referencedEntry = &referencedEntryUrl; - newEntryNotesRaw = newEntryNotesRaw.arg( - QString(searchIn), referencedEntry->url()); + newEntryNotesRaw = newEntryNotesRaw.arg(searchIn, referencedEntry->url()); break; case 'N': referencedEntry = &referencedEntryNotes; - newEntryNotesRaw = newEntryNotesRaw.arg( - QString(searchIn), referencedEntry->notes()); + newEntryNotesRaw = newEntryNotesRaw.arg(searchIn, referencedEntry->notes()); break; default: break; From c4bbb76da4bcb4ee9b0c3c70967aabeb59f6a198 Mon Sep 17 00:00:00 2001 From: frostasm Date: Mon, 20 Nov 2017 09:45:26 +0200 Subject: [PATCH 7/7] Remove "Can't resolve placeholder" warning (#1137) --- src/core/Entry.cpp | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/core/Entry.cpp b/src/core/Entry.cpp index 11ae97d7..6169c109 100644 --- a/src/core/Entry.cpp +++ b/src/core/Entry.cpp @@ -751,12 +751,7 @@ QString Entry::resolvePlaceholderRecursive(const QString& placeholder, int maxDe const PlaceholderType typeOfPlaceholder = placeholderType(placeholder); switch (typeOfPlaceholder) { case PlaceholderType::NotPlaceholder: - return placeholder; case PlaceholderType::Unknown: -#ifdef QT_DEBUG - qWarning("Can't resolve placeholder \"%s\" for entry with title: \"%s\" (uuid \"%s\") ", - qPrintable(placeholder), qPrintable(title()), qPrintable(uuid().toHex())); -#endif return placeholder; case PlaceholderType::Title: return title();