Skip to content

Commit

Permalink
Auto-Type support for T-CONV, T-REPLACE-RX, and Comments
Browse files Browse the repository at this point in the history
* Close #1825 - Add full support for T-CONV and T-REPLACE-RX placeholders. Exception is support for the "raw" type in T-CONV.

* Close #5333 - Allow comment syntax to be present in the Auto-Type sequence
  • Loading branch information
droidmonkey committed Dec 24, 2020
1 parent 50697ab commit 7360f13
Show file tree
Hide file tree
Showing 3 changed files with 106 additions and 1 deletion.
61 changes: 60 additions & 1 deletion src/autotype/AutoType.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -586,8 +586,67 @@ AutoType::parseActions(const QString& entrySequence, const Entry* entry, QString
}
}
}
} else if (placeholder.startsWith("t-conv:")) {
// Reset to the original capture to preserve case
placeholder = match.captured(3);
placeholder.replace("t-conv:", "", Qt::CaseInsensitive);
if (!placeholder.isEmpty()) {
auto sep = placeholder[0];
auto parts = placeholder.split(sep);
if (parts.size() >= 4) {
auto resolved = entry->resolveMultiplePlaceholders(parts[1]);
auto type = parts[2].toLower();

if (type == "base64") {
resolved = resolved.toUtf8().toBase64();
} else if (type == "hex") {
resolved = resolved.toUtf8().toHex();
} else if (type == "uri") {
resolved = QUrl::toPercentEncoding(resolved.toUtf8());
} else if (type == "uri-dec") {
resolved = QUrl::fromPercentEncoding(resolved.toUtf8());
} else if (type.startsWith("u")) {
resolved = resolved.toUpper();
} else if (type.startsWith("l")) {
resolved = resolved.toLower();
} else if (error) {
*error = tr("Invalid conversion type: %1").arg(type);
continue;
}
for (const QChar& ch : resolved) {
actions << QSharedPointer<AutoTypeKey>::create(ch);
}
} else if (error) {
*error = tr("Invalid conversion syntax: %1").arg(fullPlaceholder);
}
} else if (error) {
*error = tr("Invalid conversion syntax: %1").arg(fullPlaceholder);
}
} else if (placeholder.startsWith("t-replace-rx:")) {
// Reset to the original capture to preserve case
placeholder = match.captured(3);
placeholder.replace("t-replace-rx:", "", Qt::CaseInsensitive);
if (!placeholder.isEmpty()) {
auto sep = placeholder[0];
auto parts = placeholder.split(sep);
if (parts.size() >= 5) {
auto resolvedText = entry->resolveMultiplePlaceholders(parts[1]);
auto resolvedSearch = entry->resolveMultiplePlaceholders(parts[2]);
auto resolvedReplace = entry->resolveMultiplePlaceholders(parts[3]);
// Replace $<num> with \<num>s to support Qt substitutions
resolvedReplace.replace(QRegularExpression("\\$(\\d+)"), "\\\\1");
auto resolved = resolvedText.replace(QRegularExpression(resolvedSearch), resolvedReplace);
for (const QChar& ch : resolved) {
actions << QSharedPointer<AutoTypeKey>::create(ch);
}
} else if (error) {
*error = tr("Invalid conversion syntax: %1").arg(fullPlaceholder);
}
} else if (error) {
*error = tr("Invalid conversion syntax: %1").arg(fullPlaceholder);
}
} else if (placeholder == "beep" || placeholder.startsWith("vkey")
|| placeholder.startsWith("appactivate")) {
|| placeholder.startsWith("appactivate") || placeholder.startsWith("c:")) {
// Ignore these commands
} else {
// Attempt to resolve an entry attribute
Expand Down
44 changes: 44 additions & 0 deletions tests/TestAutoType.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -278,6 +278,43 @@ void TestAutoType::testGlobalAutoTypeRegExp()
m_test->clearActions();
}

void TestAutoType::testAutoTypeResults()
{
QScopedPointer<Entry> entry(new Entry());
entry->setUsername("Username");
entry->setPassword("Password@1");
entry->setUrl("https://example.com");
entry->attributes()->set("attr1", "value1");
entry->attributes()->set("attr2", "decode%20me");

QFETCH(QString, sequence);
QFETCH(QString, expectedResult);

m_autoType->performAutoTypeWithSequence(entry.data(), sequence);
QCOMPARE(m_test->actionChars(), expectedResult);
}

void TestAutoType::testAutoTypeResults_data()
{
QTest::addColumn<QString>("sequence");
QTest::addColumn<QString>("expectedResult");

// Normal Sequences
QTest::newRow("Sequence with Attributes") << QString("{USERNAME} {PASSWORD} {URL} {S:attr1}")
<< QString("Username Password@1 https://example.com value1");
QTest::newRow("Sequence with Comment") << QString("{USERNAME}{TAB}{C:Extra Tab}{TAB}{S:attr1}")
<< QString("Username[Key0x1000001][Key0x1000001]value1");

// Conversions and Replacements
QTest::newRow("T-CONV UPPER") << QString("{T-CONV:/{USERNAME}/UPPER/}") << QString("USERNAME");
QTest::newRow("T-CONV LOWER") << QString("{T-CONV:/{USERNAME}/LOWER/}") << QString("username");
QTest::newRow("T-CONV BASE64") << QString("{T-CONV:/{USERNAME}/BASE64/}") << QString("VXNlcm5hbWU=");
QTest::newRow("T-CONV HEX") << QString("{T-CONV:/{USERNAME}/HEX/}") << QString("557365726e616d65");
QTest::newRow("T-CONV URI ENCODE") << QString("{T-CONV:/{URL}/URI/}") << QString("https%3A%2F%2Fexample.com");
QTest::newRow("T-CONV URI DECODE") << QString("{T-CONV:/{S:attr2}/URI-DEC/}") << QString("decode me");
QTest::newRow("T-REPLACE-RX") << QString("{T-REPLACE-RX:/{USERNAME}/User/Pass/}") << QString("Passname");
}

void TestAutoType::testAutoTypeSyntaxChecks()
{
auto entry = new Entry();
Expand Down Expand Up @@ -321,6 +358,13 @@ void TestAutoType::testAutoTypeSyntaxChecks()
QVERIFY2(!AutoType::verifyAutoTypeSyntax("{LEFT 50000000}", entry, error), error.toLatin1());
QVERIFY2(AutoType::verifyAutoTypeSyntax("{SPACE 10}{TAB 3}{RIGHT 50}", entry, error), error.toLatin1());
QVERIFY2(AutoType::verifyAutoTypeSyntax("{delay 5000000000}", entry, error), error.toLatin1());
// Conversion and Regex
QVERIFY2(AutoType::verifyAutoTypeSyntax("{T-CONV:/{USERNAME}/base64/}", entry, error), error.toLatin1());
QVERIFY2(!AutoType::verifyAutoTypeSyntax("{T-CONV:/{USERNAME}/junk/}", entry, error), error.toLatin1());
QVERIFY2(!AutoType::verifyAutoTypeSyntax("{T-CONV:}", entry, error), error.toLatin1());
QVERIFY2(AutoType::verifyAutoTypeSyntax("{T-REPLACE-RX:/{USERNAME}/a/b/}", entry, error), error.toLatin1());
QVERIFY2(!AutoType::verifyAutoTypeSyntax("{T-REPLACE-RX:/{USERNAME}/a/}", entry, error), error.toLatin1());
QVERIFY2(!AutoType::verifyAutoTypeSyntax("{T-REPLACE-RX:}", entry, error), error.toLatin1());
}

void TestAutoType::testAutoTypeEffectiveSequences()
Expand Down
2 changes: 2 additions & 0 deletions tests/TestAutoType.h
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,8 @@ private slots:
void testGlobalAutoTypeUrlSubdomainMatch();
void testGlobalAutoTypeTitleMatchDisabled();
void testGlobalAutoTypeRegExp();
void testAutoTypeResults();
void testAutoTypeResults_data();
void testAutoTypeSyntaxChecks();
void testAutoTypeEffectiveSequences();

Expand Down

0 comments on commit 7360f13

Please sign in to comment.