Skip to content

Commit

Permalink
Support for triggering Global Auto-Type from browser extension
Browse files Browse the repository at this point in the history
  • Loading branch information
varjolintu committed Mar 13, 2021
1 parent 8b8fb95 commit c9b1c9c
Show file tree
Hide file tree
Showing 4 changed files with 54 additions and 21 deletions.
67 changes: 46 additions & 21 deletions src/browser/BrowserAction.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ QJsonObject BrowserAction::processClientMessage(const QJsonObject& json)

bool triggerUnlock = false;
const QString trigger = json.value("triggerUnlock").toString();
if (!trigger.isEmpty() && trigger.compare(TRUE_STR, Qt::CaseSensitive) == 0) {
if (!trigger.isEmpty() && trigger.compare(TRUE_STR) == 0) {
triggerUnlock = true;
}

Expand All @@ -69,7 +69,8 @@ QJsonObject BrowserAction::processClientMessage(const QJsonObject& json)
return getErrorReply(action, ERROR_KEEPASS_INCORRECT_ACTION);
}

if (action.compare("change-public-keys", Qt::CaseSensitive) != 0 && !browserService()->isDatabaseOpened()) {
if (action.compare("change-public-keys") != 0 && action.compare("perform-autotype") != 0
&& !browserService()->isDatabaseOpened()) {
if (m_clientPublicKey.isEmpty()) {
return getErrorReply(action, ERROR_KEEPASS_CLIENT_PUBLIC_KEY_NOT_RECEIVED);
} else if (!browserService()->openDatabase(triggerUnlock)) {
Expand All @@ -87,28 +88,30 @@ QJsonObject BrowserAction::handleAction(const QJsonObject& json)
{
QString action = json.value("action").toString();

if (action.compare("change-public-keys", Qt::CaseSensitive) == 0) {
if (action.compare("change-public-keys") == 0) {
return handleChangePublicKeys(json, action);
} else if (action.compare("get-databasehash", Qt::CaseSensitive) == 0) {
} else if (action.compare("get-databasehash") == 0) {
return handleGetDatabaseHash(json, action);
} else if (action.compare("associate", Qt::CaseSensitive) == 0) {
} else if (action.compare("associate") == 0) {
return handleAssociate(json, action);
} else if (action.compare("test-associate", Qt::CaseSensitive) == 0) {
} else if (action.compare("test-associate") == 0) {
return handleTestAssociate(json, action);
} else if (action.compare("get-logins", Qt::CaseSensitive) == 0) {
} else if (action.compare("get-logins") == 0) {
return handleGetLogins(json, action);
} else if (action.compare("generate-password", Qt::CaseSensitive) == 0) {
} else if (action.compare("generate-password") == 0) {
return handleGeneratePassword(json, action);
} else if (action.compare("set-login", Qt::CaseSensitive) == 0) {
} else if (action.compare("set-login") == 0) {
return handleSetLogin(json, action);
} else if (action.compare("lock-database", Qt::CaseSensitive) == 0) {
} else if (action.compare("lock-database") == 0) {
return handleLockDatabase(json, action);
} else if (action.compare("get-database-groups", Qt::CaseSensitive) == 0) {
} else if (action.compare("get-database-groups") == 0) {
return handleGetDatabaseGroups(json, action);
} else if (action.compare("create-new-group", Qt::CaseSensitive) == 0) {
} else if (action.compare("create-new-group") == 0) {
return handleCreateNewGroup(json, action);
} else if (action.compare("get-totp", Qt::CaseSensitive) == 0) {
} else if (action.compare("get-totp") == 0) {
return handleGetTotp(json, action);
} else if (action.compare("perform-autotype") == 0) {
return handleGlobalAutoType(json, action);
}

// Action was not recognized
Expand Down Expand Up @@ -162,7 +165,7 @@ QJsonObject BrowserAction::handleGetDatabaseHash(const QJsonObject& json, const
}

QString command = decrypted.value("action").toString();
if (!command.isEmpty() && command.compare("get-databasehash", Qt::CaseSensitive) == 0) {
if (!command.isEmpty() && command.compare("get-databasehash") == 0) {
const QString newNonce = incrementNonce(nonce);

QJsonObject message = buildMessage(newNonce);
Expand Down Expand Up @@ -199,7 +202,7 @@ QJsonObject BrowserAction::handleAssociate(const QJsonObject& json, const QStrin
return getErrorReply(action, ERROR_KEEPASS_ASSOCIATION_FAILED);
}

if (key.compare(m_clientPublicKey, Qt::CaseSensitive) == 0) {
if (key.compare(m_clientPublicKey) == 0) {
// Check for identification key. If it's not found, ensure backwards compatibility and use the current public
// key
const QString idKey = decrypted.value("idKey").toString();
Expand Down Expand Up @@ -238,7 +241,7 @@ QJsonObject BrowserAction::handleTestAssociate(const QJsonObject& json, const QS
}

const QString key = browserService()->getKey(id);
if (key.isEmpty() || key.compare(responseKey, Qt::CaseSensitive) != 0) {
if (key.isEmpty() || key.compare(responseKey) != 0) {
return getErrorReply(action, ERROR_KEEPASS_ASSOCIATION_FAILED);
}

Expand Down Expand Up @@ -283,7 +286,7 @@ QJsonObject BrowserAction::handleGetLogins(const QJsonObject& json, const QStrin
const QString id = decrypted.value("id").toString();
const QString formUrl = decrypted.value("submitUrl").toString();
const QString auth = decrypted.value("httpAuth").toString();
const bool httpAuth = auth.compare(TRUE_STR, Qt::CaseSensitive) == 0 ? true : false;
const bool httpAuth = auth.compare(TRUE_STR) == 0 ? true : false;
const QJsonArray users = browserService()->findMatchingEntries(id, siteUrl, formUrl, "", keyList, httpAuth);

if (users.isEmpty()) {
Expand Down Expand Up @@ -387,7 +390,7 @@ QJsonObject BrowserAction::handleLockDatabase(const QJsonObject& json, const QSt
}

QString command = decrypted.value("action").toString();
if (!command.isEmpty() && command.compare("lock-database", Qt::CaseSensitive) == 0) {
if (!command.isEmpty() && command.compare("lock-database") == 0) {
browserService()->lockDatabase();

const QString newNonce = incrementNonce(nonce);
Expand Down Expand Up @@ -415,7 +418,7 @@ QJsonObject BrowserAction::handleGetDatabaseGroups(const QJsonObject& json, cons
}

QString command = decrypted.value("action").toString();
if (command.isEmpty() || command.compare("get-database-groups", Qt::CaseSensitive) != 0) {
if (command.isEmpty() || command.compare("get-database-groups") != 0) {
return getErrorReply(action, ERROR_KEEPASS_INCORRECT_ACTION);
}

Expand Down Expand Up @@ -448,7 +451,7 @@ QJsonObject BrowserAction::handleCreateNewGroup(const QJsonObject& json, const Q
}

QString command = decrypted.value("action").toString();
if (command.isEmpty() || command.compare("create-new-group", Qt::CaseSensitive) != 0) {
if (command.isEmpty() || command.compare("create-new-group") != 0) {
return getErrorReply(action, ERROR_KEEPASS_INCORRECT_ACTION);
}

Expand Down Expand Up @@ -482,7 +485,7 @@ QJsonObject BrowserAction::handleGetTotp(const QJsonObject& json, const QString&
}

QString command = decrypted.value("action").toString();
if (command.isEmpty() || command.compare("get-totp", Qt::CaseSensitive) != 0) {
if (command.isEmpty() || command.compare("get-totp") != 0) {
return getErrorReply(action, ERROR_KEEPASS_INCORRECT_ACTION);
}

Expand All @@ -498,6 +501,28 @@ QJsonObject BrowserAction::handleGetTotp(const QJsonObject& json, const QString&
return buildResponse(action, message, newNonce);
}

QJsonObject BrowserAction::handleGlobalAutoType(const QJsonObject& json, const QString& action)
{
const QString nonce = json.value("nonce").toString();
const QString encrypted = json.value("message").toString();
const QJsonObject decrypted = decryptMessage(encrypted, nonce);

if (decrypted.isEmpty()) {
return getErrorReply(action, ERROR_KEEPASS_CANNOT_DECRYPT_MESSAGE);
}

QString command = decrypted.value("action").toString();
if (!command.isEmpty() && command.compare("perform-autotype") == 0) {
browserService()->performGlobalAutoType();

const QString newNonce = incrementNonce(nonce);
QJsonObject message = buildMessage(newNonce);
return buildResponse(action, message, newNonce);
}

return getErrorReply(action, ERROR_KEEPASS_INCORRECT_ACTION);
}

QJsonObject BrowserAction::getErrorReply(const QString& action, const int errorCode) const
{
QJsonObject response;
Expand Down
1 change: 1 addition & 0 deletions src/browser/BrowserAction.h
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ class BrowserAction
QJsonObject handleGetDatabaseGroups(const QJsonObject& json, const QString& action);
QJsonObject handleCreateNewGroup(const QJsonObject& json, const QString& action);
QJsonObject handleGetTotp(const QJsonObject& json, const QString& action);
QJsonObject handleGlobalAutoType(const QJsonObject& json, const QString& action);

QJsonObject buildMessage(const QString& nonce) const;
QJsonObject buildResponse(const QString& action, const QJsonObject& message, const QString& nonce);
Expand Down
6 changes: 6 additions & 0 deletions src/browser/BrowserService.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
#include "core/Tools.h"
#include "gui/MainWindow.h"
#include "gui/MessageBox.h"
#include "gui/osutils/OSUtils.h"
#ifdef Q_OS_MACOS
#include "gui/osutils/macutils/MacUtils.h"
#endif
Expand Down Expand Up @@ -737,6 +738,11 @@ void BrowserService::convertAttributesToCustomData(QSharedPointer<Database> db)
}
}

void BrowserService::performGlobalAutoType()
{
emit osUtils->globalShortcutTriggered("autotype");
}

QList<Entry*>
BrowserService::sortEntries(QList<Entry*>& pwEntries, const QString& siteUrlStr, const QString& formUrlStr)
{
Expand Down
1 change: 1 addition & 0 deletions src/browser/BrowserService.h
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ class BrowserService : public QObject
const StringPairList& keyList,
const bool httpAuth = false);

void performGlobalAutoType();
static void convertAttributesToCustomData(QSharedPointer<Database> db);

static const QString KEEPASSXCBROWSER_NAME;
Expand Down

0 comments on commit c9b1c9c

Please sign in to comment.