Correct regex escape logic

* Fixes #7776

Implement QRegularExpression::escape within Tools::convertToRegex to allow usage on older Qt versions.

Also wrap EXACT_MODIFIER patterns in a non-capture group to prevent misinterpreted regex.
This commit is contained in:
Patrick Sean Klein
2022-05-21 16:21:33 +02:00
committed by Jonathan White
parent 924eb6dbc4
commit e16c007d43
6 changed files with 136 additions and 18 deletions

View File

@@ -224,7 +224,7 @@ void TestEntrySearcher::testSearchTermParser()
QCOMPARE(terms.length(), 2);
QCOMPARE(terms[0].field, EntrySearcher::Field::Url);
QCOMPARE(terms[0].regex.pattern(), QString("^.*\\.google\\.com$"));
QCOMPARE(terms[0].regex.pattern(), QString("^(?:.*\\.google\\.com)$"));
QCOMPARE(terms[1].field, EntrySearcher::Field::Username);
QCOMPARE(terms[1].regex.pattern(), QString("\\d+\\w{2}"));
@@ -237,7 +237,7 @@ void TestEntrySearcher::testSearchTermParser()
QCOMPARE(terms[0].field, EntrySearcher::Field::AttributeValue);
QCOMPARE(terms[0].word, QString("abc"));
QCOMPARE(terms[0].regex.pattern(), QString("^efg$"));
QCOMPARE(terms[0].regex.pattern(), QString("^(?:efg)$"));
QCOMPARE(terms[1].field, EntrySearcher::Field::AttributeValue);
QCOMPARE(terms[1].word, QString("def"));

View File

@@ -82,6 +82,11 @@ void TestFdoSecrets::testSpecialCharsInAttributeValue()
QCOMPARE(res.count(), 1);
QCOMPARE(res[0]->title(), QStringLiteral("titleB"));
}
{
const auto term = Collection::attributeToTerm("testAttribute", "v|");
const auto res = EntrySearcher().search({term}, root.data());
QCOMPARE(res.count(), 0);
}
}
void TestFdoSecrets::testDBusPathParse()

View File

@@ -165,6 +165,34 @@ void TestTools::testBackupFilePatternSubstitution()
QCOMPARE(Tools::substituteBackupFilePath(pattern, dbFilePath), expectedSubstitution);
}
void TestTools::testEscapeRegex_data()
{
QTest::addColumn<QString>("input");
QTest::addColumn<QString>("expected");
QString all_regular_characters = "0123456789";
for (char c = 'a'; c != 'z'; ++c) {
all_regular_characters += QChar::fromLatin1(c);
}
for (char c = 'A'; c != 'Z'; ++c) {
all_regular_characters += QChar::fromLatin1(c);
}
QTest::newRow("Regular characters should not be escaped") << all_regular_characters << all_regular_characters;
QTest::newRow("Special characters should be escaped") << R"(.^$*+-?()[]{}|\)"
<< R"(\.\^\$\*\+\-\?\(\)\[\]\{\}\|\\)";
QTest::newRow("Null character") << QString::fromLatin1("ab\0c", 4) << "ab\\0c";
}
void TestTools::testEscapeRegex()
{
QFETCH(QString, input);
QFETCH(QString, expected);
auto actual = Tools::escapeRegex(input);
QCOMPARE(actual, expected);
}
void TestTools::testConvertToRegex()
{
QFETCH(QString, input);
@@ -185,16 +213,29 @@ void TestTools::testConvertToRegex_data()
QTest::newRow("No Options") << input << static_cast<int>(Tools::RegexConvertOpts::DEFAULT)
<< QString(R"(te|st*t?[5]^(test);',.)");
// Escape regex
QTest::newRow("Escape Regex") << input << static_cast<int>(Tools::RegexConvertOpts::ESCAPE_REGEX)
<< Tools::escapeRegex(input);
QTest::newRow("Escape Regex and exact match")
<< input << static_cast<int>(Tools::RegexConvertOpts::ESCAPE_REGEX | Tools::RegexConvertOpts::EXACT_MATCH)
<< "^(?:" + Tools::escapeRegex(input) + ")$";
// Exact match does not escape the pattern
QTest::newRow("Exact Match") << input << static_cast<int>(Tools::RegexConvertOpts::EXACT_MATCH)
<< QString(R"(^te|st*t?[5]^(test);',.$)");
<< QString(R"(^(?:te|st*t?[5]^(test);',.)$)");
// Exact match with improper regex
QTest::newRow("Exact Match") << ")av(" << static_cast<int>(Tools::RegexConvertOpts::EXACT_MATCH)
<< QString(R"(^(?:)av()$)");
QTest::newRow("Exact Match & Wildcard")
<< input << static_cast<int>(Tools::RegexConvertOpts::EXACT_MATCH | Tools::RegexConvertOpts::WILDCARD_ALL)
<< QString(R"(^te|st.*t.\[5\]\^\(test\);'\,\.$)");
<< 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\);'\,\.)");
<< 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\);'\,\.)");
<< 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\);'\,\.)");
<< QString(R"(te\|st.*t\?\[5\]\^\(test\)\;\'\,\.)");
}

View File

@@ -31,6 +31,8 @@ private slots:
void testValidUuid();
void testBackupFilePatternSubstitution_data();
void testBackupFilePatternSubstitution();
void testEscapeRegex();
void testEscapeRegex_data();
void testConvertToRegex();
void testConvertToRegex_data();
};