diff --git a/src/autotype/AutoType.cpp b/src/autotype/AutoType.cpp index e3b5b54c0..c72b61ef6 100644 --- a/src/autotype/AutoType.cpp +++ b/src/autotype/AutoType.cpp @@ -128,31 +128,16 @@ QStringList AutoType::windowTitles() return m_plugin->windowTitles(); } -void AutoType::executeAutoTypeActions(const Entry* entry, QWidget* hideWindow, const QString& customSequence, WId window) +/** + * Core Autotype function that will execute actions + */ +void AutoType::executeAutoTypeActions(const Entry* entry, QWidget* hideWindow, const QString& sequence, WId window) { - if (m_inAutoType || !m_plugin) { + // no edit to the sequence beyond this point + if (!verifyAutoTypeSyntax(sequence)) { + m_inAutoType = false; // TODO: make this automatic return; } - m_inAutoType = true; - - QString sequence; - if (customSequence.isEmpty()) { - QList sequences = autoTypeSequences(entry); - if(sequences.isEmpty()) { - sequence = ""; - } else { - sequence = sequences.first(); - } - } else { - sequence = customSequence; - } - - if (!checkSyntax(sequence)) { - return; - } - - sequence.replace("{{}", "{LEFTBRACE}"); - sequence.replace("{}}", "{RIGHTBRACE}"); QList actions; ListDeleter actionsDeleter(&actions); @@ -191,6 +176,30 @@ void AutoType::executeAutoTypeActions(const Entry* entry, QWidget* hideWindow, c m_inAutoType = false; } +/** + * Single Autotype entry-point function + * Perfom autotype sequence in the active window + */ +void AutoType::performAutoType(const Entry* entry, QWidget* hideWindow) +{ + if (m_inAutoType || !m_plugin) { + return; + } + + QList sequences = autoTypeSequences(entry); + if(sequences.isEmpty()) { + return; + } + + m_inAutoType = true; + + executeAutoTypeActions(entry, hideWindow, sequences.first()); +} + +/** + * Global Autotype entry-point funcion + * Perform global autotype on the active window + */ void AutoType::performGlobalAutoType(const QList& dbList) { if (m_inAutoType || !m_plugin) { @@ -227,7 +236,7 @@ void AutoType::performGlobalAutoType(const QList& dbList) MessageBox::information(nullptr, tr("Auto-Type - KeePassXC"), message); } else if ((matchList.size() == 1) && !config()->get("security/autotypeask").toBool()) { m_inAutoType = false; - performAutoType(matchList.first().entry, nullptr, matchList.first().sequence); + executeAutoTypeActions(matchList.first().entry, nullptr, matchList.first().sequence); } else { m_windowFromGlobal = m_plugin->activeWindow(); AutoTypeSelectDialog* selectDialog = new AutoTypeSelectDialog(); @@ -253,7 +262,7 @@ void AutoType::performAutoTypeFromGlobal(AutoTypeMatch match) m_inAutoType = false; - performAutoType(match.entry, nullptr, match.sequence, m_windowFromGlobal); + executeAutoTypeActions(match.entry, nullptr, match.sequence, m_windowFromGlobal); } void AutoType::resetInAutoType() @@ -283,6 +292,7 @@ void AutoType::unloadPlugin() } } + bool AutoType::registerGlobalShortcut(Qt::Key key, Qt::KeyboardModifiers modifiers) { Q_ASSERT(key); @@ -325,12 +335,19 @@ int AutoType::callEventFilter(void* event) return m_plugin->platformEventFilter(event); } -bool AutoType::parseActions(const QString& sequence, const Entry* entry, QList& actions) +/** + * Parse an autotype sequence and resolve its Template/command inside as AutoTypeActions + */ +bool AutoType::parseActions(const QString& actionSequence, const Entry* entry, QList& actions) { QString tmpl; bool inTmpl = false; m_autoTypeDelay = config()->get("AutoTypeDelay").toInt(); + QString sequence = actionSequence; + sequence.replace("{{}", "{LEFTBRACE}"); + sequence.replace("{}}", "{RIGHTBRACE}"); + for (const QChar& ch : sequence) { if (inTmpl) { if (ch == '{') { @@ -369,6 +386,9 @@ bool AutoType::parseActions(const QString& sequence, const Entry* entry, QList AutoType::createActionFromTemplate(const QString& tmpl, const Entry* entry) { QString tmplName = tmpl; @@ -512,6 +532,9 @@ QList AutoType::createActionFromTemplate(const QString& tmpl, c return list; } +/** + * Retrive the autotype sequences matches for a given windowTitle + */ QList AutoType::autoTypeSequences(const Entry* entry, const QString& windowTitle) { QList sequenceList; @@ -564,6 +587,9 @@ QList AutoType::autoTypeSequences(const Entry* entry, const QString& wi return sequenceList; } +/** + * Checks if a window title matches a pattern + */ bool AutoType::windowMatches(const QString& windowTitle, const QString& windowPattern) { if (windowPattern.startsWith("//") && windowPattern.endsWith("//") && windowPattern.size() >= 4) { @@ -574,11 +600,19 @@ bool AutoType::windowMatches(const QString& windowTitle, const QString& windowPa } } +/** + * Checks if a window title matches an entry Title + * The entry title should be Spr-compiled by the caller + */ bool AutoType::windowMatchesTitle(const QString& windowTitle, const QString& resolvedTitle) { return !resolvedTitle.isEmpty() && windowTitle.contains(resolvedTitle, Qt::CaseInsensitive); } +/** + * Checks if a window title matches an entry URL + * The entry URL should be Spr-compiled by the caller + */ bool AutoType::windowMatchesUrl(const QString& windowTitle, const QString& resolvedUrl) { if (!resolvedUrl.isEmpty() && windowTitle.contains(resolvedUrl, Qt::CaseInsensitive)) { @@ -593,6 +627,9 @@ bool AutoType::windowMatchesUrl(const QString& windowTitle, const QString& resol return false; } +/** + * Checks if the overall syntax of an autotype sequence is fine + */ bool AutoType::checkSyntax(const QString& string) { QString allowRepetition = "(?:\\s\\d+)?"; @@ -618,6 +655,9 @@ bool AutoType::checkSyntax(const QString& string) return match.hasMatch(); } +/** + * Checks an autotype sequence for high delay + */ bool AutoType::checkHighDelay(const QString& string) { // 5 digit numbers(10 seconds) are too much @@ -626,6 +666,9 @@ bool AutoType::checkHighDelay(const QString& string) return match.hasMatch(); } +/** + * Checks an autotype sequence for slow keypress + */ bool AutoType::checkSlowKeypress(const QString& string) { // 3 digit numbers(100 milliseconds) are too much @@ -634,6 +677,9 @@ bool AutoType::checkSlowKeypress(const QString& string) return match.hasMatch(); } +/** + * Checks an autotype sequence for high repetition command + */ bool AutoType::checkHighRepetition(const QString& string) { // 3 digit numbers are too much @@ -642,6 +688,9 @@ bool AutoType::checkHighRepetition(const QString& string) return match.hasMatch(); } +/** + * Verify if the syntax of an autotype sequence is correct and doesn't have silly parameters + */ bool AutoType::verifyAutoTypeSyntax(const QString& sequence) { if (!AutoType::checkSyntax(sequence)) { @@ -675,12 +724,3 @@ bool AutoType::verifyAutoTypeSyntax(const QString& sequence) } return true; } - - -void AutoType::performAutoType(const Entry* entry, QWidget* hideWindow, const QString& customSequence, WId window) -{ - auto sequence = entry->effectiveAutoTypeSequence(); - if (verifyAutoTypeSyntax(sequence)) { - executeAutoTypeActions(entry, hideWindow, customSequence, window); - } -} diff --git a/src/autotype/AutoType.h b/src/autotype/AutoType.h index 5c89b4fa6..db60133ae 100644 --- a/src/autotype/AutoType.h +++ b/src/autotype/AutoType.h @@ -38,10 +38,6 @@ class AutoType : public QObject public: QStringList windowTitles(); - void executeAutoTypeActions(const Entry* entry, - QWidget* hideWindow = nullptr, - const QString& customSequence = QString(), - WId window = 0); bool registerGlobalShortcut(Qt::Key key, Qt::KeyboardModifiers modifiers); void unregisterGlobalShortcut(); int callEventFilter(void* event); @@ -51,9 +47,7 @@ public: static bool checkHighDelay(const QString& string); static bool verifyAutoTypeSyntax(const QString& sequence); void performAutoType(const Entry* entry, - QWidget* hideWindow = nullptr, - const QString& customSequence = QString(), - WId window = 0); + QWidget* hideWindow = nullptr); inline bool isAvailable() { @@ -79,6 +73,10 @@ private: explicit AutoType(QObject* parent = nullptr, bool test = false); ~AutoType(); void loadPlugin(const QString& pluginPath); + void executeAutoTypeActions(const Entry* entry, + QWidget* hideWindow = nullptr, + const QString& customSequence = QString(), + WId window = 0); bool parseActions(const QString& sequence, const Entry* entry, QList& actions); QList createActionFromTemplate(const QString& tmpl, const Entry* entry); QList autoTypeSequences(const Entry* entry, const QString& windowTitle = QString()); diff --git a/src/core/Entry.cpp b/src/core/Entry.cpp index 951c2184b..e4c9e720e 100644 --- a/src/core/Entry.cpp +++ b/src/core/Entry.cpp @@ -29,6 +29,8 @@ const int Entry::DefaultIconNumber = 0; const int Entry::ResolveMaximumDepth = 10; +const QString Entry::AutoTypeSequenceUsername = "{USERNAME}{ENTER}"; +const QString Entry::AutoTypeSequencePassword = "{PASSWORD}{ENTER}"; Entry::Entry() @@ -232,7 +234,7 @@ QString Entry::effectiveAutoTypeSequence() const if (!parent) { return QString(); } - + QString sequence = parent->effectiveAutoTypeSequence(); if (sequence.isEmpty()) { return QString(); @@ -242,6 +244,15 @@ QString Entry::effectiveAutoTypeSequence() const return m_data.defaultAutoTypeSequence; } + if (sequence == Group::RootAutoTypeSequence && (!username().isEmpty() || !password().isEmpty())) { + if (username().isEmpty()) { + return AutoTypeSequencePassword; + } else if (password().isEmpty()) { + return AutoTypeSequenceUsername; + } + return Group::RootAutoTypeSequence; + } + return sequence; } diff --git a/src/core/Entry.h b/src/core/Entry.h index 7b995b7ae..8579f9533 100644 --- a/src/core/Entry.h +++ b/src/core/Entry.h @@ -85,6 +85,7 @@ public: int autoTypeObfuscation() const; QString defaultAutoTypeSequence() const; QString effectiveAutoTypeSequence() const; + QString effectiveNewAutoTypeSequence() const; AutoTypeAssociations* autoTypeAssociations(); const AutoTypeAssociations* autoTypeAssociations() const; QString title() const; @@ -109,6 +110,8 @@ public: static const int DefaultIconNumber; static const int ResolveMaximumDepth; + static const QString AutoTypeSequenceUsername; + static const QString AutoTypeSequencePassword; void setUuid(const Uuid& uuid); void setIcon(int iconNumber); diff --git a/src/core/Group.cpp b/src/core/Group.cpp index e75f45268..51b24c199 100644 --- a/src/core/Group.cpp +++ b/src/core/Group.cpp @@ -25,6 +25,7 @@ const int Group::DefaultIconNumber = 48; const int Group::RecycleBinIconNumber = 43; +const QString Group::RootAutoTypeSequence = "{USERNAME}{TAB}{PASSWORD}{ENTER}"; Group::CloneFlags Group::DefaultCloneFlags = static_cast( Group::CloneNewUuid | Group::CloneResetTimeInfo | Group::CloneIncludeEntries); @@ -211,7 +212,7 @@ QString Group::effectiveAutoTypeSequence() const } while (group && sequence.isEmpty()); if (sequence.isEmpty()) { - sequence = "{USERNAME}{TAB}{PASSWORD}{ENTER}"; + sequence = RootAutoTypeSequence; } return sequence; diff --git a/src/core/Group.h b/src/core/Group.h index 70f033196..b1654a236 100644 --- a/src/core/Group.h +++ b/src/core/Group.h @@ -88,6 +88,7 @@ public: static const int RecycleBinIconNumber; static CloneFlags DefaultCloneFlags; static Entry::CloneFlags DefaultEntryCloneFlags; + static const QString RootAutoTypeSequence; Group* findChildByName(const QString& name); Group* findChildByUuid(const Uuid& uuid); diff --git a/tests/TestAutoType.cpp b/tests/TestAutoType.cpp index 7d26a6afe..53f455ce6 100644 --- a/tests/TestAutoType.cpp +++ b/tests/TestAutoType.cpp @@ -136,7 +136,7 @@ void TestAutoType::testInternal() QCOMPARE(m_platform->activeWindowTitle(), QString("Test")); } -void TestAutoType::testAutoTypeWithoutSequence() +void TestAutoType::testSingleAutoType() { m_autoType->performAutoType(m_entry1, nullptr); @@ -147,17 +147,6 @@ void TestAutoType::testAutoTypeWithoutSequence() .arg(m_test->keyToString(Qt::Key_Enter))); } -void TestAutoType::testAutoTypeWithSequence() -{ - m_autoType->performAutoType(m_entry1, nullptr, "{Username}abc{PaSsWoRd}"); - - QCOMPARE(m_test->actionCount(), 15); - QCOMPARE(m_test->actionChars(), - QString("%1abc%2") - .arg(m_entry1->username()) - .arg(m_entry1->password())); -} - void TestAutoType::testGlobalAutoTypeWithNoMatch() { m_test->setActiveWindowTitle("nomatch"); diff --git a/tests/TestAutoType.h b/tests/TestAutoType.h index 516481282..93a7d682c 100644 --- a/tests/TestAutoType.h +++ b/tests/TestAutoType.h @@ -38,8 +38,7 @@ private slots: void cleanup(); void testInternal(); - void testAutoTypeWithoutSequence(); - void testAutoTypeWithSequence(); + void testSingleAutoType(); void testGlobalAutoTypeWithNoMatch(); void testGlobalAutoTypeWithOneMatch(); void testGlobalAutoTypeTitleMatch();