diff --git a/src/fdosecrets/objects/Collection.cpp b/src/fdosecrets/objects/Collection.cpp index ccf88cecc..c826c1db0 100644 --- a/src/fdosecrets/objects/Collection.cpp +++ b/src/fdosecrets/objects/Collection.cpp @@ -24,7 +24,7 @@ #include "core/Config.h" #include "core/Database.h" -#include "core/EntrySearcher.h" +#include "core/Tools.h" #include "gui/DatabaseTabWidget.h" #include "gui/DatabaseWidget.h" @@ -233,24 +233,16 @@ namespace FdoSecrets } } - static QMap attrKeyToField{ - {EntryAttributes::TitleKey, QStringLiteral("title")}, - {EntryAttributes::UserNameKey, QStringLiteral("user")}, - {EntryAttributes::URLKey, QStringLiteral("url")}, - {EntryAttributes::NotesKey, QStringLiteral("notes")}, - }; - - QStringList terms; + QList terms; for (auto it = attributes.constBegin(); it != attributes.constEnd(); ++it) { if (it.key() == EntryAttributes::PasswordKey) { continue; } - auto field = attrKeyToField.value(it.key(), QStringLiteral("_") + Item::encodeAttributeKey(it.key())); - terms << QStringLiteral(R"raw(+%1:"%2")raw").arg(field, it.value()); + terms << attributeToTerm(it.key(), it.value()); } QList items; - const auto foundEntries = EntrySearcher().search(terms.join(' '), m_exposedGroup); + const auto foundEntries = EntrySearcher().search(terms, m_exposedGroup); items.reserve(foundEntries.size()); for (const auto& entry : foundEntries) { items << m_entryToItem.value(entry); @@ -258,6 +250,28 @@ namespace FdoSecrets return items; } + EntrySearcher::SearchTerm Collection::attributeToTerm(const QString& key, const QString& value) + { + static QMap attrKeyToField{ + {EntryAttributes::TitleKey, EntrySearcher::Field::Title}, + {EntryAttributes::UserNameKey, EntrySearcher::Field::Username}, + {EntryAttributes::URLKey, EntrySearcher::Field::Url}, + {EntryAttributes::NotesKey, EntrySearcher::Field::Notes}, + }; + + EntrySearcher::SearchTerm term{}; + term.field = attrKeyToField.value(key, EntrySearcher::Field::AttributeValue); + term.word = key; + term.exclude = false; + + const auto useWildcards = false; + const auto exactMatch = true; + const auto caseSensitive = true; + term.regex = Tools::convertToRegex(value, useWildcards, exactMatch, caseSensitive); + + return term; + } + DBusReturn Collection::createItem(const QVariantMap& properties, const SecretStruct& secret, bool replace, PromptBase*& prompt) { diff --git a/src/fdosecrets/objects/Collection.h b/src/fdosecrets/objects/Collection.h index f11669b7d..de9db3a49 100644 --- a/src/fdosecrets/objects/Collection.h +++ b/src/fdosecrets/objects/Collection.h @@ -21,6 +21,7 @@ #include "DBusObject.h" #include "adaptors/CollectionAdaptor.h" +#include "core/EntrySearcher.h" #include #include @@ -90,6 +91,8 @@ namespace FdoSecrets bool inRecycleBin(Group* group) const; bool inRecycleBin(Entry* entry) const; + static EntrySearcher::SearchTerm attributeToTerm(const QString& key, const QString& value); + public slots: // expose some methods for Prmopt to use void doLock(); diff --git a/src/fdosecrets/objects/Item.cpp b/src/fdosecrets/objects/Item.cpp index 18624bbdb..f3b8bceb7 100644 --- a/src/fdosecrets/objects/Item.cpp +++ b/src/fdosecrets/objects/Item.cpp @@ -99,10 +99,7 @@ namespace FdoSecrets // add custom attributes const auto customKeys = entryAttrs->customKeys(); for (const auto& attr : customKeys) { - // decode attr key - auto decoded = decodeAttributeKey(attr); - - attrs[decoded] = entryAttrs->value(attr); + attrs[attr] = entryAttrs->value(attr); } // add some informative and readonly attributes @@ -134,8 +131,7 @@ namespace FdoSecrets continue; } - auto encoded = encodeAttributeKey(it.key()); - entryAttrs->set(encoded, it.value()); + entryAttrs->set(it.key(), it.value()); } m_backend->endUpdate(); @@ -354,16 +350,6 @@ namespace FdoSecrets return pathComponents.join('/'); } - QString Item::encodeAttributeKey(const QString& key) - { - return QUrl::toPercentEncoding(key, "", "_:").replace('%', '_'); - } - - QString Item::decodeAttributeKey(const QString& key) - { - return QString::fromUtf8(QByteArray::fromPercentEncoding(key.toLatin1(), '_')); - } - void setEntrySecret(Entry* entry, const QByteArray& data, const QString& contentType) { auto mimeName = contentType.split(';').takeFirst().trimmed(); diff --git a/src/fdosecrets/objects/Item.h b/src/fdosecrets/objects/Item.h index cfec77fe5..39e83de74 100644 --- a/src/fdosecrets/objects/Item.h +++ b/src/fdosecrets/objects/Item.h @@ -67,15 +67,6 @@ namespace FdoSecrets public: static const QSet ReadOnlyAttributes; - /** - * Due to the limitation in EntrySearcher, custom attr key cannot contain ':', - * Thus we encode the key when saving and decode it when returning. - * @param key - * @return - */ - static QString encodeAttributeKey(const QString& key); - static QString decodeAttributeKey(const QString& key); - DBusReturn setProperties(const QVariantMap& properties); Entry* backend() const; diff --git a/tests/TestFdoSecrets.cpp b/tests/TestFdoSecrets.cpp index 3876f9033..6994f60ab 100644 --- a/tests/TestFdoSecrets.cpp +++ b/tests/TestFdoSecrets.cpp @@ -19,8 +19,11 @@ #include "TestGlobal.h" +#include "core/EntrySearcher.h" #include "fdosecrets/GcryptMPI.h" #include "fdosecrets/objects/SessionCipher.h" +#include "fdosecrets/objects/Collection.h" +#include "fdosecrets/objects/Item.h" #include "crypto/Crypto.h" @@ -90,3 +93,22 @@ void TestFdoSecrets::testDhIetf1024Sha256Aes128CbcPkcs7() QCOMPARE(cipher->m_aesKey.toHex(), QByteArrayLiteral("6b8f5ee55138eac37118508be21e7834")); } + +void TestFdoSecrets::testCrazyAttributeKey() +{ + using FdoSecrets::Item; + using FdoSecrets::Collection; + + const QScopedPointer root(new Group()); + const QScopedPointer e1(new Entry()); + e1->setGroup(root.data()); + + const QString key = "_a:bc&-+'-e%12df_d"; + const QString value = "value"; + e1->attributes()->set(key, value); + + // search for custom entries + const auto term = Collection::attributeToTerm(key, value); + const auto res = EntrySearcher().search({term}, root.data()); + QCOMPARE(res.count(), 1); +} diff --git a/tests/TestFdoSecrets.h b/tests/TestFdoSecrets.h index eecc687e4..e108a81b9 100644 --- a/tests/TestFdoSecrets.h +++ b/tests/TestFdoSecrets.h @@ -30,6 +30,7 @@ private slots: void testGcryptMPI(); void testDhIetf1024Sha256Aes128CbcPkcs7(); + void testCrazyAttributeKey(); }; #endif // KEEPASSXC_TESTFDOSECRETS_H