mirror of
https://github.com/keepassxreboot/keepassxc.git
synced 2024-10-01 01:26:01 -04:00
refactor autotype sequences and entry-point functions
This commit is contained in:
parent
b5cabbeb43
commit
a9479fd662
@ -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<QString> 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<AutoTypeAction*> actions;
|
||||
ListDeleter<AutoTypeAction*> 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<QString> 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<Database*>& dbList)
|
||||
{
|
||||
if (m_inAutoType || !m_plugin) {
|
||||
@ -227,7 +236,7 @@ void AutoType::performGlobalAutoType(const QList<Database*>& 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<AutoTypeAction*>& actions)
|
||||
/**
|
||||
* Parse an autotype sequence and resolve its Template/command inside as AutoTypeActions
|
||||
*/
|
||||
bool AutoType::parseActions(const QString& actionSequence, const Entry* entry, QList<AutoTypeAction*>& 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<A
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert an autotype Template/command to its AutoTypeAction that will be executed by the plugin executor
|
||||
*/
|
||||
QList<AutoTypeAction*> AutoType::createActionFromTemplate(const QString& tmpl, const Entry* entry)
|
||||
{
|
||||
QString tmplName = tmpl;
|
||||
@ -512,6 +532,9 @@ QList<AutoTypeAction*> AutoType::createActionFromTemplate(const QString& tmpl, c
|
||||
return list;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrive the autotype sequences matches for a given windowTitle
|
||||
*/
|
||||
QList<QString> AutoType::autoTypeSequences(const Entry* entry, const QString& windowTitle)
|
||||
{
|
||||
QList<QString> sequenceList;
|
||||
@ -564,6 +587,9 @@ QList<QString> 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);
|
||||
}
|
||||
}
|
||||
|
@ -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<AutoTypeAction*>& actions);
|
||||
QList<AutoTypeAction*> createActionFromTemplate(const QString& tmpl, const Entry* entry);
|
||||
QList<QString> autoTypeSequences(const Entry* entry, const QString& windowTitle = QString());
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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::CloneFlags>(
|
||||
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;
|
||||
|
@ -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);
|
||||
|
@ -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");
|
||||
|
@ -38,8 +38,7 @@ private slots:
|
||||
void cleanup();
|
||||
|
||||
void testInternal();
|
||||
void testAutoTypeWithoutSequence();
|
||||
void testAutoTypeWithSequence();
|
||||
void testSingleAutoType();
|
||||
void testGlobalAutoTypeWithNoMatch();
|
||||
void testGlobalAutoTypeWithOneMatch();
|
||||
void testGlobalAutoTypeTitleMatch();
|
||||
|
Loading…
Reference in New Issue
Block a user