Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/keepassxreboot/keepassxc.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJonathan White <support@dmapps.us>2021-12-30 17:19:07 +0300
committerJonathan White <support@dmapps.us>2022-01-29 03:38:30 +0300
commit7f92504a2d0fbd04d9ec811804b8a633dddde4b1 (patch)
treeb05bf42a30b9ffae7cfad43ce5f1d3db148094cd
parent4a21cee98c30cb841790c13d5a6956224233fedc (diff)
Fix wildcard window title matching in Auto-Type
* Fixes #6413
-rw-r--r--src/core/Entry.cpp11
-rw-r--r--src/core/EntrySearcher.cpp9
-rw-r--r--src/core/Tools.cpp24
-rw-r--r--src/core/Tools.h18
-rw-r--r--src/fdosecrets/objects/Collection.cpp9
-rw-r--r--tests/TestTools.cpp35
-rw-r--r--tests/TestTools.h2
7 files changed, 85 insertions, 23 deletions
diff --git a/src/core/Entry.cpp b/src/core/Entry.cpp
index 650a26ad1..c90760765 100644
--- a/src/core/Entry.cpp
+++ b/src/core/Entry.cpp
@@ -281,7 +281,7 @@ QString Entry::effectiveAutoTypeSequence() const
}
/**
- * Retrive the autotype sequences matches for a given windowTitle
+ * Retrieve the Auto-Type sequences matches for a given windowTitle
* This returns a list with priority ordering. If you don't want duplicates call .toSet() on it.
*/
QList<QString> Entry::autoTypeSequences(const QString& windowTitle) const
@@ -295,13 +295,14 @@ QList<QString> Entry::autoTypeSequences(const QString& windowTitle) const
auto windowMatches = [&](const QString& pattern) {
// Regex searching
if (pattern.startsWith("//") && pattern.endsWith("//") && pattern.size() >= 4) {
- QRegExp regExp(pattern.mid(2, pattern.size() - 4), Qt::CaseInsensitive, QRegExp::RegExp2);
- return (regExp.indexIn(windowTitle) != -1);
+ QRegularExpression regExp(pattern.mid(2, pattern.size() - 4), QRegularExpression::CaseInsensitiveOption);
+ return regExp.match(windowTitle).hasMatch();
}
// Wildcard searching
- auto regex = Tools::convertToRegex(pattern, true, false, false);
- return windowTitle.contains(regex);
+ const auto regExp = Tools::convertToRegex(
+ pattern, Tools::RegexConvertOpts::EXACT_MATCH | Tools::RegexConvertOpts::WILDCARD_UNLIMITED_MATCH);
+ return regExp.match(windowTitle).hasMatch();
};
auto windowMatchesTitle = [&](const QString& entryTitle) {
diff --git a/src/core/EntrySearcher.cpp b/src/core/EntrySearcher.cpp
index 2dde80698..e52033a04 100644
--- a/src/core/EntrySearcher.cpp
+++ b/src/core/EntrySearcher.cpp
@@ -277,7 +277,14 @@ void EntrySearcher::parseSearchTerms(const QString& searchString)
auto mods = result.captured(1);
// Convert term to regex
- term.regex = Tools::convertToRegex(term.word, !mods.contains("*"), mods.contains("+"), m_caseSensitive);
+ int opts = m_caseSensitive ? Tools::RegexConvertOpts::CASE_SENSITIVE : Tools::RegexConvertOpts::DEFAULT;
+ if (!mods.contains("*")) {
+ opts |= Tools::RegexConvertOpts::WILDCARD_ALL;
+ }
+ if (mods.contains("+")) {
+ opts |= Tools::RegexConvertOpts::EXACT_MATCH;
+ }
+ term.regex = Tools::convertToRegex(term.word, opts);
// Exclude modifier
term.exclude = mods.contains("-") || mods.contains("!");
diff --git a/src/core/Tools.cpp b/src/core/Tools.cpp
index 7495952f7..5d3dff602 100644
--- a/src/core/Tools.cpp
+++ b/src/core/Tools.cpp
@@ -296,27 +296,35 @@ namespace Tools
return true;
}
- // Escape common regex symbols except for *, ?, and |
- auto regexEscape = QRegularExpression(R"re(([-[\]{}()+.,\\\/^$#]))re");
+ // Escape regex symbols
+ auto regexEscape = QRegularExpression(R"re(([-[\]{}()+.,\\\/^$#|*?]))re");
- QRegularExpression convertToRegex(const QString& string, bool useWildcards, bool exactMatch, bool caseSensitive)
+ QRegularExpression convertToRegex(const QString& string, int opts)
{
QString pattern = string;
// Wildcard support (*, ?, |)
- if (useWildcards) {
+ if (opts & RegexConvertOpts::WILDCARD_ALL || opts & RegexConvertOpts::ESCAPE_REGEX) {
pattern.replace(regexEscape, "\\\\1");
- pattern.replace("*", ".*");
- pattern.replace("?", ".");
+
+ if (opts & RegexConvertOpts::WILDCARD_UNLIMITED_MATCH) {
+ pattern.replace("\\*", ".*");
+ }
+ if (opts & RegexConvertOpts::WILDCARD_SINGLE_MATCH) {
+ pattern.replace("\\?", ".");
+ }
+ if (opts & RegexConvertOpts::WILDCARD_LOGICAL_OR) {
+ pattern.replace("\\|", "|");
+ }
}
// Exact modifier
- if (exactMatch) {
+ if (opts & RegexConvertOpts::EXACT_MATCH) {
pattern = "^" + pattern + "$";
}
auto regex = QRegularExpression(pattern);
- if (!caseSensitive) {
+ if ((opts & RegexConvertOpts::CASE_SENSITIVE) != RegexConvertOpts::CASE_SENSITIVE) {
regex.setPatternOptions(QRegularExpression::CaseInsensitiveOption);
}
diff --git a/src/core/Tools.h b/src/core/Tools.h
index c605143b7..d8a1371f1 100644
--- a/src/core/Tools.h
+++ b/src/core/Tools.h
@@ -42,13 +42,23 @@ namespace Tools
QString uuidToHex(const QUuid& uuid);
QUuid hexToUuid(const QString& uuid);
bool isValidUuid(const QString& uuidStr);
- QRegularExpression convertToRegex(const QString& string,
- bool useWildcards = false,
- bool exactMatch = false,
- bool caseSensitive = false);
QString envSubstitute(const QString& filepath,
QProcessEnvironment environment = QProcessEnvironment::systemEnvironment());
+ enum RegexConvertOpts
+ {
+ DEFAULT = 0,
+ WILDCARD_UNLIMITED_MATCH = 0x1,
+ WILDCARD_SINGLE_MATCH = 0x2,
+ WILDCARD_LOGICAL_OR = 0x4,
+ WILDCARD_ALL = WILDCARD_UNLIMITED_MATCH | WILDCARD_SINGLE_MATCH | WILDCARD_LOGICAL_OR,
+ EXACT_MATCH = 0x8,
+ CASE_SENSITIVE = 0x16,
+ ESCAPE_REGEX = 0x32,
+ };
+
+ QRegularExpression convertToRegex(const QString& string, int opts = RegexConvertOpts::DEFAULT);
+
template <typename RandomAccessIterator, typename T>
RandomAccessIterator binaryFind(RandomAccessIterator begin, RandomAccessIterator end, const T& value)
{
diff --git a/src/fdosecrets/objects/Collection.cpp b/src/fdosecrets/objects/Collection.cpp
index 610a4b99e..1c870beaa 100644
--- a/src/fdosecrets/objects/Collection.cpp
+++ b/src/fdosecrets/objects/Collection.cpp
@@ -294,11 +294,10 @@ namespace FdoSecrets
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(QRegularExpression::escape(value), useWildcards, exactMatch, caseSensitive);
+ term.regex =
+ Tools::convertToRegex(value,
+ Tools::RegexConvertOpts::EXACT_MATCH | Tools::RegexConvertOpts::CASE_SENSITIVE
+ | Tools::RegexConvertOpts::ESCAPE_REGEX);
return term;
}
diff --git a/tests/TestTools.cpp b/tests/TestTools.cpp
index 9e3dadc45..438606c7e 100644
--- a/tests/TestTools.cpp
+++ b/tests/TestTools.cpp
@@ -19,6 +19,7 @@
#include "core/Clock.h"
+#include <QRegularExpression>
#include <QTest>
#include <QUuid>
@@ -163,3 +164,37 @@ void TestTools::testBackupFilePatternSubstitution()
QCOMPARE(Tools::substituteBackupFilePath(pattern, dbFilePath), expectedSubstitution);
}
+
+void TestTools::testConvertToRegex()
+{
+ QFETCH(QString, input);
+ QFETCH(int, options);
+ QFETCH(QString, expected);
+
+ auto regex = Tools::convertToRegex(input, options).pattern();
+ QCOMPARE(regex, expected);
+}
+
+void TestTools::testConvertToRegex_data()
+{
+ const QString input = R"(te|st*t?[5]^(test);',.)";
+
+ QTest::addColumn<QString>("input");
+ QTest::addColumn<int>("options");
+ QTest::addColumn<QString>("expected");
+
+ QTest::newRow("No Options") << input << static_cast<int>(Tools::RegexConvertOpts::DEFAULT)
+ << QString(R"(te|st*t?[5]^(test);',.)");
+ QTest::newRow("Exact Match") << input << static_cast<int>(Tools::RegexConvertOpts::EXACT_MATCH)
+ << QString(R"(^te|st*t?[5]^(test);',.$)");
+ QTest::newRow("Exact Match & Wildcard")
+ << input << static_cast<int>(Tools::RegexConvertOpts::EXACT_MATCH | Tools::RegexConvertOpts::WILDCARD_ALL)
+ << QString(R"(^te|st.*t.\[5\]\^\(test\);'\,\.$)");
+ QTest::newRow("Wildcard Single Match") << input << static_cast<int>(Tools::RegexConvertOpts::WILDCARD_SINGLE_MATCH)
+ << QString(R"(te\|st\*t.\[5\]\^\(test\);'\,\.)");
+ QTest::newRow("Wildcard OR") << input << static_cast<int>(Tools::RegexConvertOpts::WILDCARD_LOGICAL_OR)
+ << QString(R"(te|st\*t\?\[5\]\^\(test\);'\,\.)");
+ QTest::newRow("Wildcard Unlimited Match")
+ << input << static_cast<int>(Tools::RegexConvertOpts::WILDCARD_UNLIMITED_MATCH)
+ << QString(R"(te\|st.*t\?\[5\]\^\(test\);'\,\.)");
+}
diff --git a/tests/TestTools.h b/tests/TestTools.h
index 29f2bf0f5..f590a53a1 100644
--- a/tests/TestTools.h
+++ b/tests/TestTools.h
@@ -31,6 +31,8 @@ private slots:
void testValidUuid();
void testBackupFilePatternSubstitution_data();
void testBackupFilePatternSubstitution();
+ void testConvertToRegex();
+ void testConvertToRegex_data();
};
#endif // KEEPASSX_TESTTOOLS_H