From 5e0df62d7adc951aa05bdb064eddd23f50ab87be Mon Sep 17 00:00:00 2001 From: frostasm Date: Sat, 14 Oct 2017 15:41:45 +0300 Subject: [PATCH] Add processing of the url placeholders --- src/core/Entry.cpp | 92 ++++++++++++++++++++++++++++++++++++++------- src/core/Entry.h | 17 +++++++++ tests/TestEntry.cpp | 32 ++++++++++++++++ tests/TestEntry.h | 1 + 4 files changed, 128 insertions(+), 14 deletions(-) diff --git a/src/core/Entry.cpp b/src/core/Entry.cpp index 464628dc..867e68ea 100644 --- a/src/core/Entry.cpp +++ b/src/core/Entry.cpp @@ -755,23 +755,28 @@ QString Entry::resolvePlaceholder(const QString& str) const { QString result = str; - const QList keyList = attributes()->keys(); - for (const QString& key : keyList) { - Qt::CaseSensitivity cs = Qt::CaseInsensitive; - QString k = key; + const UrlPlaceholderType placeholderType = urlPlaceholderType(str); + if (placeholderType != UrlPlaceholderType::NotUrl) { + return resolveUrlPlaceholder(url(), placeholderType); + } else { + const QList keyList = attributes()->keys(); + for (const QString& key : keyList) { + Qt::CaseSensitivity cs = Qt::CaseInsensitive; + QString k = key; - if (!EntryAttributes::isDefaultAttribute(key)) { - cs = Qt::CaseSensitive; - k.prepend("{S:"); - } else { - k.prepend("{"); - } + if (!EntryAttributes::isDefaultAttribute(key)) { + cs = Qt::CaseSensitive; + k.prepend("{S:"); + } else { + k.prepend("{"); + } - k.append("}"); - if (result.compare(k,cs)==0) { - result.replace(result,attributes()->value(key)); - break; + k.append("}"); + if (result.compare(k,cs)==0) { + result.replace(result,attributes()->value(key)); + break; + } } } @@ -829,3 +834,62 @@ QString Entry::resolveUrl(const QString& url) const // No valid http URL's found return QString(""); } + +QString Entry::resolveUrlPlaceholder(const QString &strUrl, Entry::UrlPlaceholderType placeholderType) const +{ + QUrl qurl(strUrl); + if (!qurl.isValid()) + return QString(); + + switch (placeholderType) { + case UrlPlaceholderType::FullUrl: + return strUrl; + case UrlPlaceholderType::WithoutScheme: + return qurl.toString(QUrl::RemoveScheme | QUrl::FullyDecoded); + case UrlPlaceholderType::Scheme: + return qurl.scheme(); + case UrlPlaceholderType::Host: + return qurl.host(); + case UrlPlaceholderType::Port: + return QString::number(qurl.port()); + case UrlPlaceholderType::Path: + return qurl.path(); + case UrlPlaceholderType::Query: + return qurl.query(); + case UrlPlaceholderType::Fragment: + return qurl.fragment(); + case UrlPlaceholderType::UserInfo: + return qurl.userInfo(); + case UrlPlaceholderType::UserName: + return qurl.userName(); + case UrlPlaceholderType::Password: + return qurl.password(); + default: + Q_ASSERT(false); + break; + } + + return QString(); +} + +Entry::UrlPlaceholderType Entry::urlPlaceholderType(const QString &placeholder) const +{ + static const QMap urlPlaceholders { + { QStringLiteral("{URL}"), UrlPlaceholderType::FullUrl }, + { QStringLiteral("{URL:RMVSCM}"), UrlPlaceholderType::WithoutScheme }, + { QStringLiteral("{URL:WITHOUTSCHEME}"), UrlPlaceholderType::WithoutScheme }, + { QStringLiteral("{URL:SCM}"), UrlPlaceholderType::Scheme }, + { QStringLiteral("{URL:SCHEME}"), UrlPlaceholderType::Scheme }, + { QStringLiteral("{URL:HOST}"), UrlPlaceholderType::Host }, + { QStringLiteral("{URL:PORT}"), UrlPlaceholderType::Port }, + { QStringLiteral("{URL:PATH}"), UrlPlaceholderType::Path }, + { QStringLiteral("{URL:QUERY}"), UrlPlaceholderType::Query }, + { QStringLiteral("{URL:FRAGMENT}"), UrlPlaceholderType::Fragment }, + { QStringLiteral("{URL:USERINFO}"), UrlPlaceholderType::UserInfo }, + { QStringLiteral("{URL:USERNAME}"), UrlPlaceholderType::UserName }, + { QStringLiteral("{URL:PASSWORD}"), UrlPlaceholderType::Password } + }; + + UrlPlaceholderType result = urlPlaceholders.value(placeholder.toUpper(), UrlPlaceholderType::NotUrl); + return result; +} diff --git a/src/core/Entry.h b/src/core/Entry.h index a37637c2..51208c9e 100644 --- a/src/core/Entry.h +++ b/src/core/Entry.h @@ -134,6 +134,21 @@ public: }; Q_DECLARE_FLAGS(CloneFlags, CloneFlag) + enum class UrlPlaceholderType { + NotUrl, + FullUrl, + WithoutScheme, + Scheme, + Host, + Port, + Path, + Query, + Fragment, + UserInfo, + UserName, + Password, + }; + /** * Creates a duplicate of this entry except that the returned entry isn't * part of any group. @@ -145,6 +160,8 @@ public: QString maskPasswordPlaceholders(const QString& str) const; QString resolveMultiplePlaceholders(const QString& str) const; QString resolvePlaceholder(const QString& str) const; + QString resolveUrlPlaceholder(const QString& url, UrlPlaceholderType placeholderType) const; + UrlPlaceholderType urlPlaceholderType(const QString& placeholder) const; QString resolveUrl(const QString& url) const; /** diff --git a/tests/TestEntry.cpp b/tests/TestEntry.cpp index 84ad0318..056dbc93 100644 --- a/tests/TestEntry.cpp +++ b/tests/TestEntry.cpp @@ -158,3 +158,35 @@ void TestEntry::testResolveUrl() delete entry; } + +void TestEntry::testResolveUrlPlaceholders() +{ + Entry* entry = new Entry(); + entry->setUrl("https://user:pw@keepassxc.org:80/path/example.php?q=e&s=t+2#fragment"); + + QString rmvscm("//user:pw@keepassxc.org:80/path/example.php?q=e&s=t+2#fragment"); // Entry URL without scheme name. + QString scm("https"); // Scheme name of the entry URL. + QString host("keepassxc.org"); // Host component of the entry URL. + QString port("80"); // Port number of the entry URL. + QString path("/path/example.php"); // Path component of the entry URL. + QString query("q=e&s=t+2"); // Query information of the entry URL. + QString userinfo("user:pw"); // User information of the entry URL. + QString username("user"); // User name of the entry URL. + QString password("pw"); // Password of the entry URL. + QString fragment("fragment"); // Password of the entry URL. + + QCOMPARE(entry->resolvePlaceholder("{URL:RMVSCM}"), rmvscm); + QCOMPARE(entry->resolvePlaceholder("{URL:WITHOUTSCHEME}"), rmvscm); + QCOMPARE(entry->resolvePlaceholder("{URL:SCM}"), scm); + QCOMPARE(entry->resolvePlaceholder("{URL:SCHEME}"), scm); + QCOMPARE(entry->resolvePlaceholder("{URL:HOST}"), host); + QCOMPARE(entry->resolvePlaceholder("{URL:PORT}"), port); + QCOMPARE(entry->resolvePlaceholder("{URL:PATH}"), path); + QCOMPARE(entry->resolvePlaceholder("{URL:QUERY}"), query); + QCOMPARE(entry->resolvePlaceholder("{URL:USERINFO}"), userinfo); + QCOMPARE(entry->resolvePlaceholder("{URL:USERNAME}"), username); + QCOMPARE(entry->resolvePlaceholder("{URL:PASSWORD}"), password); + QCOMPARE(entry->resolvePlaceholder("{URL:FRAGMENT}"), fragment); + + delete entry; +} diff --git a/tests/TestEntry.h b/tests/TestEntry.h index 3f6d20ee..febdf085 100644 --- a/tests/TestEntry.h +++ b/tests/TestEntry.h @@ -32,6 +32,7 @@ private slots: void testCopyDataFrom(); void testClone(); void testResolveUrl(); + void testResolveUrlPlaceholders(); }; #endif // KEEPASSX_TESTENTRY_H