mirror of
https://github.com/keepassxreboot/keepassxc.git
synced 2024-12-27 16:29:44 -05:00
Merge pull request #1174 from keepassxreboot/feature/autotype-warning-on-long-sequences
Add warning on long Auto Type sequences
This commit is contained in:
commit
cdaf25cb3e
@ -20,6 +20,7 @@
|
||||
|
||||
#include <QApplication>
|
||||
#include <QPluginLoader>
|
||||
#include <QRegularExpression>
|
||||
|
||||
#include "config-keepassx.h"
|
||||
|
||||
@ -54,17 +55,16 @@ AutoType::AutoType(QObject* parent, bool test)
|
||||
QString pluginName = "keepassx-autotype-";
|
||||
if (!test) {
|
||||
pluginName += QApplication::platformName();
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
pluginName += "test";
|
||||
}
|
||||
|
||||
QString pluginPath = filePath()->pluginPath(pluginName);
|
||||
|
||||
if (!pluginPath.isEmpty()) {
|
||||
#ifdef WITH_XC_AUTOTYPE
|
||||
#ifdef WITH_XC_AUTOTYPE
|
||||
loadPlugin(pluginPath);
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
connect(qApp, SIGNAL(aboutToQuit()), SLOT(unloadPlugin()));
|
||||
@ -91,8 +91,7 @@ void AutoType::loadPlugin(const QString& pluginPath)
|
||||
if (m_plugin->isAvailable()) {
|
||||
m_executor = m_plugin->createExecutor();
|
||||
connect(pluginInstance, SIGNAL(globalShortcutTriggered()), SIGNAL(globalShortcutTriggered()));
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
unloadPlugin();
|
||||
}
|
||||
}
|
||||
@ -128,7 +127,7 @@ QStringList AutoType::windowTitles()
|
||||
return m_plugin->windowTitles();
|
||||
}
|
||||
|
||||
void AutoType::performAutoType(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;
|
||||
@ -138,11 +137,14 @@ void AutoType::performAutoType(const Entry* entry, QWidget* hideWindow, const QS
|
||||
QString sequence;
|
||||
if (customSequence.isEmpty()) {
|
||||
sequence = autoTypeSequence(entry);
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
sequence = customSequence;
|
||||
}
|
||||
|
||||
if (!checkSyntax(sequence)) {
|
||||
return;
|
||||
}
|
||||
|
||||
sequence.replace("{{}", "{LEFTBRACE}");
|
||||
sequence.replace("{}}", "{RIGHTBRACE}");
|
||||
|
||||
@ -217,16 +219,14 @@ void AutoType::performGlobalAutoType(const QList<Database*>& dbList)
|
||||
message.append("\n\n");
|
||||
message.append(windowTitle);
|
||||
MessageBox::information(nullptr, tr("Auto-Type - KeePassXC"), message);
|
||||
}
|
||||
else if ((entryList.size() == 1) && !config()->get("security/autotypeask").toBool()) {
|
||||
} else if ((entryList.size() == 1) && !config()->get("security/autotypeask").toBool()) {
|
||||
m_inAutoType = false;
|
||||
performAutoType(entryList.first(), nullptr, sequenceHash[entryList.first()]);
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
m_windowFromGlobal = m_plugin->activeWindow();
|
||||
AutoTypeSelectDialog* selectDialog = new AutoTypeSelectDialog();
|
||||
connect(selectDialog, SIGNAL(entryActivated(Entry*,QString)),
|
||||
SLOT(performAutoTypeFromGlobal(Entry*,QString)));
|
||||
connect(
|
||||
selectDialog, SIGNAL(entryActivated(Entry*, QString)), SLOT(performAutoTypeFromGlobal(Entry*, QString)));
|
||||
connect(selectDialog, SIGNAL(rejected()), SLOT(resetInAutoType()));
|
||||
selectDialog->setEntries(entryList, sequenceHash);
|
||||
#if defined(Q_OS_MAC)
|
||||
@ -246,6 +246,7 @@ void AutoType::performAutoTypeFromGlobal(Entry* entry, const QString& sequence)
|
||||
m_plugin->raiseWindow(m_windowFromGlobal);
|
||||
|
||||
m_inAutoType = false;
|
||||
|
||||
performAutoType(entry, nullptr, sequence, m_windowFromGlobal);
|
||||
}
|
||||
|
||||
@ -294,12 +295,10 @@ bool AutoType::registerGlobalShortcut(Qt::Key key, Qt::KeyboardModifiers modifie
|
||||
m_currentGlobalKey = key;
|
||||
m_currentGlobalModifiers = modifiers;
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@ -326,30 +325,28 @@ bool AutoType::parseActions(const QString& sequence, const Entry* entry, QList<A
|
||||
bool inTmpl = false;
|
||||
m_autoTypeDelay = config()->get("AutoTypeDelay").toInt();
|
||||
|
||||
|
||||
for (const QChar& ch : sequence) {
|
||||
if (inTmpl) {
|
||||
if (ch == '{') {
|
||||
qWarning("Syntax error in auto-type sequence.");
|
||||
return false;
|
||||
}
|
||||
else if (ch == '}') {
|
||||
actions.append(createActionFromTemplate(tmpl, entry));
|
||||
} else if (ch == '}') {
|
||||
QList<AutoTypeAction*> autoType = createActionFromTemplate(tmpl, entry);
|
||||
if (autoType.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
actions.append(autoType);
|
||||
inTmpl = false;
|
||||
tmpl.clear();
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
tmpl += ch;
|
||||
}
|
||||
}
|
||||
else if (ch == '{') {
|
||||
} else if (ch == '{') {
|
||||
inTmpl = true;
|
||||
}
|
||||
else if (ch == '}') {
|
||||
} else if (ch == '}') {
|
||||
qWarning("Syntax error in auto-type sequence.");
|
||||
return false;
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
actions.append(new AutoTypeChar(ch));
|
||||
}
|
||||
}
|
||||
@ -388,120 +385,78 @@ QList<AutoTypeAction*> AutoType::createActionFromTemplate(const QString& tmpl, c
|
||||
if (num == 0) {
|
||||
return list;
|
||||
}
|
||||
// some safety checks
|
||||
else if (tmplName.compare("delay",Qt::CaseInsensitive)==0) {
|
||||
if (num > 10000) {
|
||||
return list;
|
||||
}
|
||||
}
|
||||
else if (num > 100) {
|
||||
return list;
|
||||
}
|
||||
}
|
||||
|
||||
if (tmplName.compare("tab",Qt::CaseInsensitive)==0) {
|
||||
if (tmplName.compare("tab", Qt::CaseInsensitive) == 0) {
|
||||
list.append(new AutoTypeKey(Qt::Key_Tab));
|
||||
}
|
||||
else if (tmplName.compare("enter",Qt::CaseInsensitive)==0) {
|
||||
} else if (tmplName.compare("enter", Qt::CaseInsensitive) == 0) {
|
||||
list.append(new AutoTypeKey(Qt::Key_Enter));
|
||||
}
|
||||
else if (tmplName.compare("space",Qt::CaseInsensitive)==0) {
|
||||
} else if (tmplName.compare("space", Qt::CaseInsensitive) == 0) {
|
||||
list.append(new AutoTypeKey(Qt::Key_Space));
|
||||
}
|
||||
else if (tmplName.compare("up",Qt::CaseInsensitive)==0) {
|
||||
} else if (tmplName.compare("up", Qt::CaseInsensitive) == 0) {
|
||||
list.append(new AutoTypeKey(Qt::Key_Up));
|
||||
}
|
||||
else if (tmplName.compare("down",Qt::CaseInsensitive)==0) {
|
||||
} else if (tmplName.compare("down", Qt::CaseInsensitive) == 0) {
|
||||
list.append(new AutoTypeKey(Qt::Key_Down));
|
||||
}
|
||||
else if (tmplName.compare("left",Qt::CaseInsensitive)==0) {
|
||||
} else if (tmplName.compare("left", Qt::CaseInsensitive) == 0) {
|
||||
list.append(new AutoTypeKey(Qt::Key_Left));
|
||||
}
|
||||
else if (tmplName.compare("right",Qt::CaseInsensitive)==0) {
|
||||
} else if (tmplName.compare("right", Qt::CaseInsensitive) == 0) {
|
||||
list.append(new AutoTypeKey(Qt::Key_Right));
|
||||
}
|
||||
else if (tmplName.compare("insert",Qt::CaseInsensitive)==0 ||
|
||||
tmplName.compare("ins",Qt::CaseInsensitive)==0) {
|
||||
} else if (tmplName.compare("insert", Qt::CaseInsensitive) == 0 ||
|
||||
tmplName.compare("ins", Qt::CaseInsensitive) == 0) {
|
||||
list.append(new AutoTypeKey(Qt::Key_Insert));
|
||||
}
|
||||
else if (tmplName.compare("delete",Qt::CaseInsensitive)==0 ||
|
||||
tmplName.compare("del",Qt::CaseInsensitive)==0) {
|
||||
} else if (tmplName.compare("delete", Qt::CaseInsensitive) == 0 ||
|
||||
tmplName.compare("del", Qt::CaseInsensitive) == 0) {
|
||||
list.append(new AutoTypeKey(Qt::Key_Delete));
|
||||
}
|
||||
else if (tmplName.compare("home",Qt::CaseInsensitive)==0) {
|
||||
} else if (tmplName.compare("home", Qt::CaseInsensitive) == 0) {
|
||||
list.append(new AutoTypeKey(Qt::Key_Home));
|
||||
}
|
||||
else if (tmplName.compare("end",Qt::CaseInsensitive)==0) {
|
||||
} else if (tmplName.compare("end", Qt::CaseInsensitive) == 0) {
|
||||
list.append(new AutoTypeKey(Qt::Key_End));
|
||||
}
|
||||
else if (tmplName.compare("pgup",Qt::CaseInsensitive)==0) {
|
||||
} else if (tmplName.compare("pgup", Qt::CaseInsensitive) == 0) {
|
||||
list.append(new AutoTypeKey(Qt::Key_PageUp));
|
||||
}
|
||||
else if (tmplName.compare("pgdown",Qt::CaseInsensitive)==0) {
|
||||
} else if (tmplName.compare("pgdown", Qt::CaseInsensitive) == 0) {
|
||||
list.append(new AutoTypeKey(Qt::Key_PageDown));
|
||||
}
|
||||
else if (tmplName.compare("backspace",Qt::CaseInsensitive)==0 ||
|
||||
tmplName.compare("bs",Qt::CaseInsensitive)==0 ||
|
||||
tmplName.compare("bksp",Qt::CaseInsensitive)==0) {
|
||||
} else if (tmplName.compare("backspace", Qt::CaseInsensitive) == 0 ||
|
||||
tmplName.compare("bs", Qt::CaseInsensitive) == 0 || tmplName.compare("bksp", Qt::CaseInsensitive) == 0) {
|
||||
list.append(new AutoTypeKey(Qt::Key_Backspace));
|
||||
}
|
||||
else if (tmplName.compare("break",Qt::CaseInsensitive)==0) {
|
||||
} else if (tmplName.compare("break", Qt::CaseInsensitive) == 0) {
|
||||
list.append(new AutoTypeKey(Qt::Key_Pause));
|
||||
}
|
||||
else if (tmplName.compare("capslock",Qt::CaseInsensitive)==0) {
|
||||
} else if (tmplName.compare("capslock", Qt::CaseInsensitive) == 0) {
|
||||
list.append(new AutoTypeKey(Qt::Key_CapsLock));
|
||||
}
|
||||
else if (tmplName.compare("esc",Qt::CaseInsensitive)==0) {
|
||||
} else if (tmplName.compare("esc", Qt::CaseInsensitive) == 0) {
|
||||
list.append(new AutoTypeKey(Qt::Key_Escape));
|
||||
}
|
||||
else if (tmplName.compare("help",Qt::CaseInsensitive)==0) {
|
||||
} else if (tmplName.compare("help", Qt::CaseInsensitive) == 0) {
|
||||
list.append(new AutoTypeKey(Qt::Key_Help));
|
||||
}
|
||||
else if (tmplName.compare("numlock",Qt::CaseInsensitive)==0) {
|
||||
} else if (tmplName.compare("numlock", Qt::CaseInsensitive) == 0) {
|
||||
list.append(new AutoTypeKey(Qt::Key_NumLock));
|
||||
}
|
||||
else if (tmplName.compare("ptrsc",Qt::CaseInsensitive)==0) {
|
||||
} else if (tmplName.compare("ptrsc", Qt::CaseInsensitive) == 0) {
|
||||
list.append(new AutoTypeKey(Qt::Key_Print));
|
||||
}
|
||||
else if (tmplName.compare("scrolllock",Qt::CaseInsensitive)==0) {
|
||||
} else if (tmplName.compare("scrolllock", Qt::CaseInsensitive) == 0) {
|
||||
list.append(new AutoTypeKey(Qt::Key_ScrollLock));
|
||||
}
|
||||
// Qt doesn't know about keypad keys so use the normal ones instead
|
||||
else if (tmplName.compare("add",Qt::CaseInsensitive)==0 ||
|
||||
tmplName.compare("+",Qt::CaseInsensitive)==0) {
|
||||
else if (tmplName.compare("add", Qt::CaseInsensitive) == 0 || tmplName.compare("+", Qt::CaseInsensitive) == 0) {
|
||||
list.append(new AutoTypeChar('+'));
|
||||
}
|
||||
else if (tmplName.compare("subtract",Qt::CaseInsensitive)==0) {
|
||||
} else if (tmplName.compare("subtract", Qt::CaseInsensitive) == 0) {
|
||||
list.append(new AutoTypeChar('-'));
|
||||
}
|
||||
else if (tmplName.compare("multiply",Qt::CaseInsensitive)==0) {
|
||||
} else if (tmplName.compare("multiply", Qt::CaseInsensitive) == 0) {
|
||||
list.append(new AutoTypeChar('*'));
|
||||
}
|
||||
else if (tmplName.compare("divide",Qt::CaseInsensitive)==0) {
|
||||
} else if (tmplName.compare("divide", Qt::CaseInsensitive) == 0) {
|
||||
list.append(new AutoTypeChar('/'));
|
||||
}
|
||||
else if (tmplName.compare("^",Qt::CaseInsensitive)==0) {
|
||||
} else if (tmplName.compare("^", Qt::CaseInsensitive) == 0) {
|
||||
list.append(new AutoTypeChar('^'));
|
||||
}
|
||||
else if (tmplName.compare("%",Qt::CaseInsensitive)==0) {
|
||||
} else if (tmplName.compare("%", Qt::CaseInsensitive) == 0) {
|
||||
list.append(new AutoTypeChar('%'));
|
||||
}
|
||||
else if (tmplName.compare("~",Qt::CaseInsensitive)==0) {
|
||||
} else if (tmplName.compare("~", Qt::CaseInsensitive) == 0) {
|
||||
list.append(new AutoTypeChar('~'));
|
||||
}
|
||||
else if (tmplName.compare("(",Qt::CaseInsensitive)==0) {
|
||||
} else if (tmplName.compare("(", Qt::CaseInsensitive) == 0) {
|
||||
list.append(new AutoTypeChar('('));
|
||||
}
|
||||
else if (tmplName.compare(")",Qt::CaseInsensitive)==0) {
|
||||
} else if (tmplName.compare(")", Qt::CaseInsensitive) == 0) {
|
||||
list.append(new AutoTypeChar(')'));
|
||||
}
|
||||
else if (tmplName.compare("leftbrace",Qt::CaseInsensitive)==0) {
|
||||
} else if (tmplName.compare("leftbrace", Qt::CaseInsensitive) == 0) {
|
||||
list.append(new AutoTypeChar('{'));
|
||||
}
|
||||
else if (tmplName.compare("rightbrace",Qt::CaseInsensitive)==0) {
|
||||
} 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();
|
||||
@ -515,18 +470,14 @@ QList<AutoTypeAction*> AutoType::createActionFromTemplate(const QString& tmpl, c
|
||||
for (int i = 1; i < num; i++) {
|
||||
list.append(list.at(0)->clone());
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
|
||||
if (tmplName.compare("delay",Qt::CaseInsensitive)==0 && num > 0) {
|
||||
if (tmplName.compare("delay", Qt::CaseInsensitive) == 0 && num > 0) {
|
||||
list.append(new AutoTypeDelay(num));
|
||||
}
|
||||
else if (tmplName.compare("clearfield",Qt::CaseInsensitive)==0) {
|
||||
} else if (tmplName.compare("clearfield", Qt::CaseInsensitive) == 0) {
|
||||
list.append(new AutoTypeClearField());
|
||||
}
|
||||
else if (tmplName.compare("totp", Qt::CaseInsensitive) == 0) {
|
||||
} else if (tmplName.compare("totp", Qt::CaseInsensitive) == 0) {
|
||||
QString totp = entry->totp();
|
||||
if (!totp.isEmpty()) {
|
||||
for (const QChar& ch : totp) {
|
||||
@ -545,11 +496,9 @@ QList<AutoTypeAction*> AutoType::createActionFromTemplate(const QString& tmpl, c
|
||||
for (const QChar& ch : resolved) {
|
||||
if (ch == '\n') {
|
||||
list.append(new AutoTypeKey(Qt::Key_Enter));
|
||||
}
|
||||
else if (ch == '\t') {
|
||||
} else if (ch == '\t') {
|
||||
list.append(new AutoTypeKey(Qt::Key_Tab));
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
list.append(new AutoTypeChar(ch));
|
||||
}
|
||||
}
|
||||
@ -574,8 +523,7 @@ QString AutoType::autoTypeSequence(const Entry* entry, const QString& windowTitl
|
||||
if (windowMatches(windowTitle, window)) {
|
||||
if (!assoc.sequence.isEmpty()) {
|
||||
sequence = assoc.sequence;
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
sequence = entry->defaultAutoTypeSequence();
|
||||
}
|
||||
match = true;
|
||||
@ -583,14 +531,14 @@ QString AutoType::autoTypeSequence(const Entry* entry, const QString& windowTitl
|
||||
}
|
||||
}
|
||||
|
||||
if (!match && config()->get("AutoTypeEntryTitleMatch").toBool()
|
||||
&& windowMatchesTitle(windowTitle, entry->resolvePlaceholder(entry->title()))) {
|
||||
if (!match && config()->get("AutoTypeEntryTitleMatch").toBool() &&
|
||||
windowMatchesTitle(windowTitle, entry->resolvePlaceholder(entry->title()))) {
|
||||
sequence = entry->defaultAutoTypeSequence();
|
||||
match = true;
|
||||
}
|
||||
|
||||
if (!match && config()->get("AutoTypeEntryURLMatch").toBool()
|
||||
&& windowMatchesUrl(windowTitle, entry->resolvePlaceholder(entry->url()))) {
|
||||
if (!match && config()->get("AutoTypeEntryURLMatch").toBool() &&
|
||||
windowMatchesUrl(windowTitle, entry->resolvePlaceholder(entry->url()))) {
|
||||
sequence = entry->defaultAutoTypeSequence();
|
||||
match = true;
|
||||
}
|
||||
@ -598,8 +546,7 @@ QString AutoType::autoTypeSequence(const Entry* entry, const QString& windowTitl
|
||||
if (!match) {
|
||||
return QString();
|
||||
}
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
sequence = entry->defaultAutoTypeSequence();
|
||||
}
|
||||
|
||||
@ -608,8 +555,7 @@ QString AutoType::autoTypeSequence(const Entry* entry, const QString& windowTitl
|
||||
if (!enableSet) {
|
||||
if (group->autoTypeEnabled() == Group::Disable) {
|
||||
return QString();
|
||||
}
|
||||
else if (group->autoTypeEnabled() == Group::Enable) {
|
||||
} else if (group->autoTypeEnabled() == Group::Enable) {
|
||||
enableSet = true;
|
||||
}
|
||||
}
|
||||
@ -621,14 +567,13 @@ QString AutoType::autoTypeSequence(const Entry* entry, const QString& windowTitl
|
||||
group = group->parentGroup();
|
||||
} while (group && (!enableSet || sequence.isEmpty()));
|
||||
|
||||
if (sequence.isEmpty() && (!entry->resolvePlaceholder(entry->username()).isEmpty() || !entry->resolvePlaceholder(entry->password()).isEmpty())) {
|
||||
if (sequence.isEmpty() && (!entry->resolvePlaceholder(entry->username()).isEmpty() ||
|
||||
!entry->resolvePlaceholder(entry->password()).isEmpty())) {
|
||||
if (entry->resolvePlaceholder(entry->username()).isEmpty()) {
|
||||
sequence = "{PASSWORD}{ENTER}";
|
||||
}
|
||||
else if (entry->resolvePlaceholder(entry->password()).isEmpty()) {
|
||||
} else if (entry->resolvePlaceholder(entry->password()).isEmpty()) {
|
||||
sequence = "{USERNAME}{ENTER}";
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
sequence = "{USERNAME}{TAB}{PASSWORD}{ENTER}";
|
||||
}
|
||||
}
|
||||
@ -641,8 +586,7 @@ bool AutoType::windowMatches(const QString& windowTitle, const QString& windowPa
|
||||
if (windowPattern.startsWith("//") && windowPattern.endsWith("//") && windowPattern.size() >= 4) {
|
||||
QRegExp regExp(windowPattern.mid(2, windowPattern.size() - 4), Qt::CaseInsensitive, QRegExp::RegExp2);
|
||||
return (regExp.indexIn(windowTitle) != -1);
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
return WildcardMatcher(windowTitle).match(windowPattern);
|
||||
}
|
||||
}
|
||||
@ -665,3 +609,96 @@ bool AutoType::windowMatchesUrl(const QString& windowTitle, const QString& resol
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool AutoType::checkSyntax(const QString& string)
|
||||
{
|
||||
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 numpad = "NUMPAD\\d" + allowRepetition;
|
||||
QString delay = "DELAY=\\d+";
|
||||
QString beep = "BEEP\\s\\d+\\s\\d+";
|
||||
QString vkey = "VKEY(?:-[EN]X)?\\s\\w+";
|
||||
|
||||
// these chars aren't in parentheses
|
||||
QString shortcutKeys = "[\\^\\%~\\+@]";
|
||||
// a normal string not in parentheses
|
||||
QString fixedStrings = "[^\\^\\%~\\+@\\{\\}]*";
|
||||
|
||||
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)
|
||||
{
|
||||
// 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)
|
||||
{
|
||||
// 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)
|
||||
{
|
||||
auto sequence = entry->effectiveAutoTypeSequence();
|
||||
if (verifyAutoTypeSyntax(sequence)) {
|
||||
executeAutoTypeActions(entry, hideWindow, customSequence, window);
|
||||
}
|
||||
}
|
||||
|
@ -36,13 +36,25 @@ class AutoType : public QObject
|
||||
|
||||
public:
|
||||
QStringList windowTitles();
|
||||
void performAutoType(const Entry* entry, QWidget* hideWindow = nullptr,
|
||||
const QString& customSequence = QString(), WId window = 0);
|
||||
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);
|
||||
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(),
|
||||
WId window = 0);
|
||||
|
||||
inline bool isAvailable() {
|
||||
inline bool isAvailable()
|
||||
{
|
||||
return m_plugin;
|
||||
}
|
||||
|
||||
@ -85,7 +97,8 @@ private:
|
||||
Q_DISABLE_COPY(AutoType)
|
||||
};
|
||||
|
||||
inline AutoType* autoType() {
|
||||
inline AutoType* autoType()
|
||||
{
|
||||
return AutoType::instance();
|
||||
}
|
||||
|
||||
|
@ -613,7 +613,7 @@ void DatabaseWidget::openUrlForEntry(Entry* entry)
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// otherwise ask user
|
||||
if (urlString.length() > 6) {
|
||||
QString cmdTruncated = urlString.mid(6);
|
||||
@ -627,7 +627,7 @@ void DatabaseWidget::openUrlForEntry(Entry* entry)
|
||||
this
|
||||
);
|
||||
msgbox.setDefaultButton(QMessageBox::No);
|
||||
|
||||
|
||||
QCheckBox* checkbox = new QCheckBox(tr("Remember my choice"), &msgbox);
|
||||
msgbox.setCheckBox(checkbox);
|
||||
bool remember = false;
|
||||
@ -636,12 +636,12 @@ void DatabaseWidget::openUrlForEntry(Entry* entry)
|
||||
remember = true;
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
int result = msgbox.exec();
|
||||
if (result == QMessageBox::Yes) {
|
||||
QProcess::startDetached(urlString.mid(6));
|
||||
}
|
||||
|
||||
|
||||
if (remember) {
|
||||
entry->attributes()->set(EntryAttributes::RememberCmdExecAttr,
|
||||
result == QMessageBox::Yes ? "1" : "0");
|
||||
|
@ -32,6 +32,7 @@
|
||||
#include <QMimeData>
|
||||
#include <QEvent>
|
||||
|
||||
#include "autotype/AutoType.h"
|
||||
#include "core/Config.h"
|
||||
#include "core/Database.h"
|
||||
#include "core/Entry.h"
|
||||
@ -764,7 +765,9 @@ void EditEntryWidget::updateEntryData(Entry* entry) const
|
||||
entry->setDefaultAutoTypeSequence(QString());
|
||||
}
|
||||
else {
|
||||
entry->setDefaultAutoTypeSequence(m_autoTypeUi->sequenceEdit->text());
|
||||
if (AutoType::verifyAutoTypeSyntax(m_autoTypeUi->sequenceEdit->text())) {
|
||||
entry->setDefaultAutoTypeSequence(m_autoTypeUi->sequenceEdit->text());
|
||||
}
|
||||
}
|
||||
|
||||
entry->autoTypeAssociations()->copyDataFrom(m_autoTypeAssoc);
|
||||
|
@ -282,3 +282,34 @@ void TestAutoType::testGlobalAutoTypeRegExp()
|
||||
QCOMPARE(m_test->actionChars(), QString("custom_attr_third"));
|
||||
m_test->clearActions();
|
||||
}
|
||||
|
||||
void TestAutoType::testAutoTypeSyntaxChecks()
|
||||
{
|
||||
// Huge sequence
|
||||
QCOMPARE(true, AutoType::checkSyntax("{word 23}{F1 23}{~ 23}{% 23}{^}{F12}{(}{) 23}{[}{[}{]}{Delay=23}{+}{SUBTRACT}~+%@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("{{{}}{}{}}{{}}"));
|
||||
// Good sequence
|
||||
QCOMPARE(true, AutoType::checkSyntax("{{}{}}{}}{{}"));
|
||||
QCOMPARE(true, AutoType::checkSyntax("{]}{[}{[}{]}"));
|
||||
QCOMPARE(true, 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}"));
|
||||
QCOMPARE(false, AutoType::checkHighRepetition("{delay 5000000000}"));
|
||||
}
|
@ -47,6 +47,7 @@ private slots:
|
||||
void testGlobalAutoTypeUrlSubdomainMatch();
|
||||
void testGlobalAutoTypeTitleMatchDisabled();
|
||||
void testGlobalAutoTypeRegExp();
|
||||
void testAutoTypeSyntaxChecks();
|
||||
|
||||
private:
|
||||
AutoTypePlatformInterface* m_platform;
|
||||
|
Loading…
Reference in New Issue
Block a user