diff --git a/src/autotype/AutoType.cpp b/src/autotype/AutoType.cpp index fc098afd3..a3d8b0533 100644 --- a/src/autotype/AutoType.cpp +++ b/src/autotype/AutoType.cpp @@ -20,8 +20,7 @@ #include #include -#include -#include +#include #include "config-keepassx.h" @@ -128,7 +127,7 @@ QStringList AutoType::windowTitles() return m_plugin->windowTitles(); } -void AutoType::executeAutoType(const Entry* entry, QWidget* hideWindow, const QString& customSequence, WId window) +void AutoType::executeAutoTypeActions(const Entry* entry, QWidget* hideWindow, const QString& customSequence, WId window) { if (m_inAutoType || !m_plugin) { return; @@ -457,9 +456,7 @@ QList AutoType::createActionFromTemplate(const QString& tmpl, c list.append(new AutoTypeChar('{')); } else if (tmplName.compare("rightbrace", Qt::CaseInsensitive) == 0) { list.append(new AutoTypeChar('}')); - } - - else { + } else { QRegExp fnRegexp("f(\\d+)", Qt::CaseInsensitive, QRegExp::RegExp2); if (fnRegexp.exactMatch(tmplName)) { int fnNo = fnRegexp.cap(1).toInt(); @@ -615,67 +612,93 @@ bool AutoType::windowMatchesUrl(const QString& windowTitle, const QString& resol bool AutoType::checkSyntax(const QString& string) { - // checks things like {word 23}{F1 23}{~ 23}{% 23}{^}{F12}{(}{) 23}{[}{[}{]}{Delay=23}{+}{-}~+%@fixedstring - QString allowRepetition = "(\\s\\d*){0,1}"; - QString normalCommands = "[A-Z:]*" + allowRepetition; // the ":" allows custom commands + QString allowRepetition = "(?:\\s\\d+)?"; + // the ":" allows custom commands with syntax S:Field + // exclude BEEP otherwise will be checked as valid + QString normalCommands = "(?!BEEP\\s)[A-Z:]*" + allowRepetition; QString specialLiterals = "[\\^\\%\\(\\)~\\{\\}\\[\\]\\+-]" + allowRepetition; - QString functionKeys = "(F[1-9]" + allowRepetition + "|F1[0-2])" + allowRepetition; + QString functionKeys = "(?:F[1-9]" + allowRepetition + "|F1[0-2])" + allowRepetition; QString numpad = "NUMPAD\\d" + allowRepetition; QString delay = "DELAY=\\d+"; - QString beep = "BEEP\\s\\d*\\s\\d*"; - QString vkey = "VKEY(-[EN]X){0,1}" + allowRepetition; + QString beep = "BEEP\\s\\d+\\s\\d+"; + QString vkey = "VKEY(?:-[EN]X)?\\s\\w+"; - // these arent in parenthesis + // these chars aren't in parentheses QString shortcutKeys = "[\\^\\%~\\+@]"; + // a normal string not in parentheses QString fixedStrings = "[^\\^\\%~\\+@\\{\\}]*"; - QRegExp autoTypeSyntax("(" + shortcutKeys + "|" + fixedStrings + "|\\{(" + normalCommands + "|" + specialLiterals + - "|" + functionKeys + "|" + numpad + "|" + delay + "|" + beep + "|" + vkey + ")\\})*"); - autoTypeSyntax.setCaseSensitivity(Qt::CaseInsensitive); - autoTypeSyntax.setPatternSyntax(QRegExp::RegExp); - return autoTypeSyntax.exactMatch(string); + QRegularExpression autoTypeSyntax("^(?:" + shortcutKeys + "|" + fixedStrings + "|\\{(?:" + normalCommands + "|" + specialLiterals + + "|" + functionKeys + "|" + numpad + "|" + delay + "|" + beep + "|" + vkey + ")\\})*$", + QRegularExpression::CaseInsensitiveOption); + QRegularExpressionMatch match = autoTypeSyntax.match(string); + return match.hasMatch(); } bool AutoType::checkHighDelay(const QString& string) { - QRegExp highDelay("\\{DELAY\\s\\d{5,}\\}"); // 5 digit numbers(10 seconds) are too much - highDelay.setCaseSensitivity(Qt::CaseInsensitive); - highDelay.setPatternSyntax(QRegExp::RegExp); - return highDelay.exactMatch(string); + // 5 digit numbers(10 seconds) are too much + QRegularExpression highDelay("\\{DELAY\\s\\d{5,}\\}", QRegularExpression::CaseInsensitiveOption); + QRegularExpressionMatch match = highDelay.match(string); + return match.hasMatch(); +} + +bool AutoType::checkSlowKeypress(const QString& string) +{ + // 3 digit numbers(100 milliseconds) are too much + QRegularExpression slowKeypress("\\{DELAY=\\d{3,}\\}", QRegularExpression::CaseInsensitiveOption); + QRegularExpressionMatch match = slowKeypress.match(string); + return match.hasMatch(); } bool AutoType::checkHighRepetition(const QString& string) { - QRegExp highRepetition("\\{(?!DELAY\\s)\\w*\\s\\d{3,}\\}"); // 3 digit numbers are too much - highRepetition.setCaseSensitivity(Qt::CaseInsensitive); - highRepetition.setPatternSyntax(QRegExp::RegExp); - return highRepetition.exactMatch(string); + // 3 digit numbers are too much + QRegularExpression highRepetition("\\{(?!DELAY\\s)\\w+\\s\\d{3,}\\}", QRegularExpression::CaseInsensitiveOption); + QRegularExpressionMatch match = highRepetition.match(string); + return match.hasMatch(); } +bool AutoType::verifyAutoTypeSyntax(const QString& sequence) +{ + if (!AutoType::checkSyntax(sequence)) { + QMessageBox messageBox; + messageBox.critical(0, tr("Auto-Type"), tr("The Syntax of your AutoType statement is incorrect!")); + return false; + } else if (AutoType::checkHighDelay(sequence)) { + QMessageBox::StandardButton reply; + reply = QMessageBox::question(0, tr("Auto-Type"), + tr("This AutoType command contains a very long delay. Do you really want to proceed?")); + + if (reply == QMessageBox::No) { + return false; + } + } else if (AutoType::checkSlowKeypress(sequence)) { + QMessageBox::StandardButton reply; + reply = QMessageBox::question(0, tr("Auto-Type"), + tr("This AutoType command contains very slow key-press. Do you really want to proceed?")); + + if (reply == QMessageBox::No) { + return false; + } + } else if (AutoType::checkHighRepetition(sequence)) { + QMessageBox::StandardButton reply; + reply = QMessageBox::question(0, tr("Auto-Type"), + tr("This AutoType command contains arguments which are " + "repeated very often. Do you really want to proceed?")); + + if (reply == QMessageBox::No) { + return false; + } + } + return true; +} + + void AutoType::performAutoType(const Entry* entry, QWidget* hideWindow, const QString& customSequence, WId window) { - if (!AutoType::checkSyntax(entry->effectiveAutoTypeSequence())) { - QMessageBox messageBox; - messageBox.critical(0, tr("AutoType"), tr("The Syntax of your AutoType statement is incorrect!")); - return; - } else if (AutoType::checkHighDelay(entry->effectiveAutoTypeSequence())) { - QMessageBox::StandardButton reply; - reply = QMessageBox::question( - 0, - tr("AutoType"), - tr("This AutoType command contains a very long delay. Do you really want to execute it?")); - - if (reply == QMessageBox::No) { - return; - } - } else if (AutoType::checkHighRepetition(entry->effectiveAutoTypeSequence())) { - QMessageBox::StandardButton reply; - reply = QMessageBox::question(0, tr("AutoType"), tr("This AutoType command contains arguments which are " - "repeated very often. Do you really want to execute it?")); - - if (reply == QMessageBox::No) { - return; - } + auto sequence = entry->effectiveAutoTypeSequence(); + if (verifyAutoTypeSyntax(sequence)) { + executeAutoTypeActions(entry, hideWindow, customSequence, window); } - executeAutoType(entry, hideWindow, customSequence, window); } diff --git a/src/autotype/AutoType.h b/src/autotype/AutoType.h index f800ab1e6..eb366ae9c 100644 --- a/src/autotype/AutoType.h +++ b/src/autotype/AutoType.h @@ -36,7 +36,7 @@ class AutoType : public QObject public: QStringList windowTitles(); - void executeAutoType(const Entry* entry, + void executeAutoTypeActions(const Entry* entry, QWidget* hideWindow = nullptr, const QString& customSequence = QString(), WId window = 0); @@ -45,7 +45,9 @@ public: int callEventFilter(void* event); static bool checkSyntax(const QString& string); static bool checkHighRepetition(const QString& string); + static bool checkSlowKeypress(const QString& string); static bool checkHighDelay(const QString& string); + static bool verifyAutoTypeSyntax(const QString& sequence); void performAutoType(const Entry* entry, QWidget* hideWindow = nullptr, const QString& customSequence = QString(), diff --git a/src/gui/entry/EditEntryWidget.cpp b/src/gui/entry/EditEntryWidget.cpp index fdb8aa142..2c65d3ec8 100644 --- a/src/gui/entry/EditEntryWidget.cpp +++ b/src/gui/entry/EditEntryWidget.cpp @@ -766,40 +766,9 @@ void EditEntryWidget::updateEntryData(Entry* entry) const entry->setDefaultAutoTypeSequence(QString()); } else { - if (!AutoType::checkSyntax(m_autoTypeUi->sequenceEdit->text())) { - //handle wrong syntax - QMessageBox messageBox; - messageBox.critical(0, - "AutoType", - tr("The Syntax of your AutoType statement is incorrect! It won't be saved!")); - - } - else if (AutoType::checkHighDelay(m_autoTypeUi->sequenceEdit->text())) { - //handle too long delay - QMessageBox::StandardButton reply; - reply = QMessageBox::question(0, - "AutoType", - tr("This AutoType command contains a very long delay. Do you really want to save it?")); - - if (reply == QMessageBox::Yes) { - entry->setDefaultAutoTypeSequence(m_autoTypeUi->sequenceEdit->text()); - } - } - else if (AutoType::checkHighRepetition(m_autoTypeUi->sequenceEdit->text())) { - //handle too much repetition - QMessageBox::StandardButton reply; - reply = QMessageBox::question(0, - "AutoType", - tr("This AutoType command contains arguments which are repeated very often. Do you really want to save it?")); - - if (reply == QMessageBox::Yes) { - entry->setDefaultAutoTypeSequence(m_autoTypeUi->sequenceEdit->text()); - } - } - else { + if (AutoType::verifyAutoTypeSyntax(m_autoTypeUi->sequenceEdit->text())) { entry->setDefaultAutoTypeSequence(m_autoTypeUi->sequenceEdit->text()); } - } entry->autoTypeAssociations()->copyDataFrom(m_autoTypeAssoc); diff --git a/tests/TestAutoType.cpp b/tests/TestAutoType.cpp index d1c09c263..da245d8cb 100644 --- a/tests/TestAutoType.cpp +++ b/tests/TestAutoType.cpp @@ -287,11 +287,23 @@ void TestAutoType::testAutoTypeSyntaxChecks() { // Huge sequence QCOMPARE(true, AutoType::checkSyntax("{word 23}{F1 23}{~ 23}{% 23}{^}{F12}{(}{) 23}{[}{[}{]}{Delay=23}{+}{-}~+%@fixedstring")); + + QCOMPARE(true, AutoType::checkSyntax("{NUMPAD1 3}")); + + QCOMPARE(true, AutoType::checkSyntax("{BEEP 3 3}")); + QCOMPARE(false, AutoType::checkSyntax("{BEEP 3}")); + + QCOMPARE(true, AutoType::checkSyntax("{VKEY 0x01}")); + QCOMPARE(true, AutoType::checkSyntax("{VKEY VK_LBUTTON}")); + QCOMPARE(true, AutoType::checkSyntax("{VKEY-EX 0x01}")); // Bad sequence QCOMPARE(false, AutoType::checkSyntax("{{{}}{}{}}{{}}")); // High DelAY / low delay QCOMPARE(true, AutoType::checkHighDelay("{DelAY 50000}")); QCOMPARE(false, AutoType::checkHighDelay("{delay 50}")); + // Slow typing + QCOMPARE(true, AutoType::checkSlowKeypress("{DelAY=50000}")); + QCOMPARE(false, AutoType::checkSlowKeypress("{delay=50}")); // Many repetition / few repetition / delay not repetition QCOMPARE(true, AutoType::checkHighRepetition("{LEFT 50000000}")); QCOMPARE(false, AutoType::checkHighRepetition("{SPACE 10}{TAB 3}{RIGHT 50}"));