Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/keepassxreboot/keepassxc.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSami Vänttinen <sami.vanttinen@protonmail.com>2022-02-23 01:52:51 +0300
committerJonathan White <support@dmapps.us>2022-02-24 01:48:50 +0300
commit7284a8062a3eef681d529e2e56c3b66a82b09337 (patch)
treea8ead4f57a3e0f2abbcda8199da4a808d2a3370e
parent67910249952e4e77535d8ecde2fe589fe32f64da (diff)
Fix password generator responses (#7404)
* Respond directly to the current client instead of broadcasting * Append requestID to generate-password response
-rw-r--r--src/browser/BrowserAction.cpp333
-rw-r--r--src/browser/BrowserAction.h24
-rw-r--r--src/browser/BrowserHost.cpp25
-rw-r--r--src/browser/BrowserHost.h9
-rw-r--r--src/browser/BrowserMessageBuilder.cpp259
-rw-r--r--src/browser/BrowserMessageBuilder.h96
-rw-r--r--src/browser/BrowserService.cpp41
-rw-r--r--src/browser/BrowserService.h15
-rwxr-xr-xsrc/browser/CMakeLists.txt3
-rw-r--r--tests/TestBrowser.cpp11
10 files changed, 500 insertions, 316 deletions
diff --git a/src/browser/BrowserAction.cpp b/src/browser/BrowserAction.cpp
index 3f7665797..70a0fb588 100644
--- a/src/browser/BrowserAction.cpp
+++ b/src/browser/BrowserAction.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2021 KeePassXC Team <team@keepassxc.org>
+ * Copyright (C) 2022 KeePassXC Team <team@keepassxc.org>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -16,65 +16,22 @@
*/
#include "BrowserAction.h"
-
+#include "BrowserMessageBuilder.h"
#include "BrowserService.h"
#include "BrowserSettings.h"
#include "BrowserShared.h"
#include "config-keepassx.h"
#include "core/Global.h"
#include "core/Tools.h"
-#include "gui/PasswordGeneratorWidget.h"
#include <QJsonArray>
#include <QJsonDocument>
#include <QJsonObject>
-
-#include <botan/sodium.h>
-
-using namespace Botan::Sodium;
-
-namespace
-{
- enum
- {
- ERROR_KEEPASS_DATABASE_NOT_OPENED = 1,
- ERROR_KEEPASS_DATABASE_HASH_NOT_RECEIVED = 2,
- ERROR_KEEPASS_CLIENT_PUBLIC_KEY_NOT_RECEIVED = 3,
- ERROR_KEEPASS_CANNOT_DECRYPT_MESSAGE = 4,
- ERROR_KEEPASS_TIMEOUT_OR_NOT_CONNECTED = 5,
- ERROR_KEEPASS_ACTION_CANCELLED_OR_DENIED = 6,
- ERROR_KEEPASS_CANNOT_ENCRYPT_MESSAGE = 7,
- ERROR_KEEPASS_ASSOCIATION_FAILED = 8,
- ERROR_KEEPASS_KEY_CHANGE_FAILED = 9,
- ERROR_KEEPASS_ENCRYPTION_KEY_UNRECOGNIZED = 10,
- ERROR_KEEPASS_NO_SAVED_DATABASES_FOUND = 11,
- ERROR_KEEPASS_INCORRECT_ACTION = 12,
- ERROR_KEEPASS_EMPTY_MESSAGE_RECEIVED = 13,
- ERROR_KEEPASS_NO_URL_PROVIDED = 14,
- ERROR_KEEPASS_NO_LOGINS_FOUND = 15,
- ERROR_KEEPASS_NO_GROUPS_FOUND = 16,
- ERROR_KEEPASS_CANNOT_CREATE_NEW_GROUP = 17,
- ERROR_KEEPASS_NO_VALID_UUID_PROVIDED = 18
- };
-}
+#include <QLocalSocket>
const int BrowserAction::MaxUrlLength = 256;
-BrowserAction::BrowserAction()
-{
- QObject::connect(browserService(),
- &BrowserService::passwordGenerated,
- browserService(),
- [=](const QString& password, const QString& nonce) {
- auto newNonce = incrementNonce(nonce);
- QJsonObject message = buildMessage(newNonce);
- message["password"] = password;
-
- browserService()->sendPassword(buildResponse("generate-password", message, newNonce));
- });
-}
-
-QJsonObject BrowserAction::processClientMessage(const QJsonObject& json)
+QJsonObject BrowserAction::processClientMessage(QLocalSocket* socket, const QJsonObject& json)
{
if (json.isEmpty()) {
return getErrorReply("", ERROR_KEEPASS_EMPTY_MESSAGE_RECEIVED);
@@ -100,13 +57,13 @@ QJsonObject BrowserAction::processClientMessage(const QJsonObject& json)
}
}
- return handleAction(json);
+ return handleAction(socket, json);
}
// Private functions
///////////////////////
-QJsonObject BrowserAction::handleAction(const QJsonObject& json)
+QJsonObject BrowserAction::handleAction(QLocalSocket* socket, const QJsonObject& json)
{
QString action = json.value("action").toString();
@@ -121,7 +78,7 @@ QJsonObject BrowserAction::handleAction(const QJsonObject& json)
} else if (action.compare("get-logins") == 0) {
return handleGetLogins(json, action);
} else if (action.compare("generate-password") == 0) {
- return handleGeneratePassword(json, action);
+ return handleGeneratePassword(socket, json, action);
} else if (action.compare("set-login") == 0) {
return handleSetLogin(json, action);
} else if (action.compare("lock-database") == 0) {
@@ -152,23 +109,18 @@ QJsonObject BrowserAction::handleChangePublicKeys(const QJsonObject& json, const
}
m_associated = false;
- unsigned char pk[crypto_box_PUBLICKEYBYTES];
- unsigned char sk[crypto_box_SECRETKEYBYTES];
- crypto_box_keypair(pk, sk);
-
- const QString publicKey = getBase64FromKey(pk, crypto_box_PUBLICKEYBYTES);
- const QString secretKey = getBase64FromKey(sk, crypto_box_SECRETKEYBYTES);
- if (publicKey.isEmpty() || secretKey.isEmpty()) {
+ auto keyPair = browserMessageBuilder()->getKeyPair();
+ if (keyPair.first.isEmpty() || keyPair.second.isEmpty()) {
return getErrorReply(action, ERROR_KEEPASS_ENCRYPTION_KEY_UNRECOGNIZED);
}
m_clientPublicKey = clientPublicKey;
- m_publicKey = publicKey;
- m_secretKey = secretKey;
+ m_publicKey = keyPair.first;
+ m_secretKey = keyPair.second;
- QJsonObject response = buildMessage(incrementNonce(nonce));
+ QJsonObject response = browserMessageBuilder()->buildMessage(browserMessageBuilder()->incrementNonce(nonce));
response["action"] = action;
- response["publicKey"] = publicKey;
+ response["publicKey"] = keyPair.first;
return response;
}
@@ -190,9 +142,9 @@ QJsonObject BrowserAction::handleGetDatabaseHash(const QJsonObject& json, const
QString command = decrypted.value("action").toString();
if (!command.isEmpty() && command.compare("get-databasehash") == 0) {
- const QString newNonce = incrementNonce(nonce);
+ const QString newNonce = browserMessageBuilder()->incrementNonce(nonce);
- QJsonObject message = buildMessage(newNonce);
+ QJsonObject message = browserMessageBuilder()->buildMessage(newNonce);
message["hash"] = hash;
// Update a legacy database hash if found
@@ -236,9 +188,9 @@ QJsonObject BrowserAction::handleAssociate(const QJsonObject& json, const QStrin
}
m_associated = true;
- const QString newNonce = incrementNonce(nonce);
+ const QString newNonce = browserMessageBuilder()->incrementNonce(nonce);
- QJsonObject message = buildMessage(newNonce);
+ QJsonObject message = browserMessageBuilder()->buildMessage(newNonce);
message["hash"] = hash;
message["id"] = id;
return buildResponse(action, message, newNonce);
@@ -270,9 +222,9 @@ QJsonObject BrowserAction::handleTestAssociate(const QJsonObject& json, const QS
}
m_associated = true;
- const QString newNonce = incrementNonce(nonce);
+ const QString newNonce = browserMessageBuilder()->incrementNonce(nonce);
- QJsonObject message = buildMessage(newNonce);
+ QJsonObject message = browserMessageBuilder()->buildMessage(newNonce);
message["hash"] = hash;
message["id"] = id;
@@ -317,9 +269,9 @@ QJsonObject BrowserAction::handleGetLogins(const QJsonObject& json, const QStrin
return getErrorReply(action, ERROR_KEEPASS_NO_LOGINS_FOUND);
}
- const QString newNonce = incrementNonce(nonce);
+ const QString newNonce = browserMessageBuilder()->incrementNonce(nonce);
- QJsonObject message = buildMessage(newNonce);
+ QJsonObject message = browserMessageBuilder()->buildMessage(newNonce);
message["count"] = users.count();
message["entries"] = users;
message["hash"] = hash;
@@ -328,12 +280,33 @@ QJsonObject BrowserAction::handleGetLogins(const QJsonObject& json, const QStrin
return buildResponse(action, message, newNonce);
}
-QJsonObject BrowserAction::handleGeneratePassword(const QJsonObject& json, const QString& action)
+QJsonObject BrowserAction::handleGeneratePassword(QLocalSocket* socket, const QJsonObject& json, const QString& action)
{
auto errorMessage = getErrorReply(action, ERROR_KEEPASS_ACTION_CANCELLED_OR_DENIED);
auto nonce = json.value("nonce").toString();
+ auto incrementedNonce = browserMessageBuilder()->incrementNonce(nonce);
- browserService()->showPasswordGenerator(errorMessage, nonce);
+ const QString encrypted = json.value("message").toString();
+ const QJsonObject decrypted = decryptMessage(encrypted, nonce);
+ if (decrypted.isEmpty()) {
+ return getErrorReply(action, ERROR_KEEPASS_CANNOT_DECRYPT_MESSAGE);
+ }
+
+ auto requestId = decrypted.value("requestID").toString();
+
+ // Do not allow multiple requests from the same client
+ if (browserService()->isPasswordGeneratorRequested()) {
+ auto errorReply = getErrorReply(action, ERROR_KEEPASS_ACTION_CANCELLED_OR_DENIED);
+
+ // Append requestID to the response if found
+ if (!requestId.isEmpty()) {
+ errorReply["requestID"] = requestId;
+ }
+
+ return errorReply;
+ }
+
+ browserService()->showPasswordGenerator(socket, incrementedNonce, m_clientPublicKey, m_secretKey);
return QJsonObject();
}
@@ -379,9 +352,9 @@ QJsonObject BrowserAction::handleSetLogin(const QJsonObject& json, const QString
result = browserService()->updateEntry(id, uuid, login, password, url, submitUrl);
}
- const QString newNonce = incrementNonce(nonce);
+ const QString newNonce = browserMessageBuilder()->incrementNonce(nonce);
- QJsonObject message = buildMessage(newNonce);
+ QJsonObject message = browserMessageBuilder()->buildMessage(newNonce);
message["count"] = QJsonValue::Null;
message["entries"] = QJsonValue::Null;
message["error"] = result ? QStringLiteral("success") : QStringLiteral("error");
@@ -409,8 +382,8 @@ QJsonObject BrowserAction::handleLockDatabase(const QJsonObject& json, const QSt
if (!command.isEmpty() && command.compare("lock-database") == 0) {
browserService()->lockDatabase();
- const QString newNonce = incrementNonce(nonce);
- QJsonObject message = buildMessage(newNonce);
+ const QString newNonce = browserMessageBuilder()->incrementNonce(nonce);
+ QJsonObject message = browserMessageBuilder()->buildMessage(newNonce);
return buildResponse(action, message, newNonce);
}
@@ -443,9 +416,9 @@ QJsonObject BrowserAction::handleGetDatabaseGroups(const QJsonObject& json, cons
return getErrorReply(action, ERROR_KEEPASS_NO_GROUPS_FOUND);
}
- const QString newNonce = incrementNonce(nonce);
+ const QString newNonce = browserMessageBuilder()->incrementNonce(nonce);
- QJsonObject message = buildMessage(newNonce);
+ QJsonObject message = browserMessageBuilder()->buildMessage(newNonce);
message["groups"] = groups;
return buildResponse(action, message, newNonce);
@@ -477,9 +450,9 @@ QJsonObject BrowserAction::handleCreateNewGroup(const QJsonObject& json, const Q
return getErrorReply(action, ERROR_KEEPASS_CANNOT_CREATE_NEW_GROUP);
}
- const QString newNonce = incrementNonce(nonce);
+ const QString newNonce = browserMessageBuilder()->incrementNonce(nonce);
- QJsonObject message = buildMessage(newNonce);
+ QJsonObject message = browserMessageBuilder()->buildMessage(newNonce);
message["name"] = newGroup["name"];
message["uuid"] = newGroup["uuid"];
@@ -512,9 +485,9 @@ QJsonObject BrowserAction::handleGetTotp(const QJsonObject& json, const QString&
// Get the current TOTP
const auto totp = browserService()->getCurrentTotp(uuid);
- const QString newNonce = incrementNonce(nonce);
+ const QString newNonce = browserMessageBuilder()->incrementNonce(nonce);
- QJsonObject message = buildMessage(newNonce);
+ QJsonObject message = browserMessageBuilder()->buildMessage(newNonce);
message["totp"] = totp;
return buildResponse(action, message, newNonce);
@@ -546,8 +519,8 @@ QJsonObject BrowserAction::handleDeleteEntry(const QJsonObject& json, const QStr
const auto result = browserService()->deleteEntry(uuid);
- const QString newNonce = incrementNonce(nonce);
- QJsonObject message = buildMessage(newNonce);
+ const QString newNonce = browserMessageBuilder()->incrementNonce(nonce);
+ QJsonObject message = browserMessageBuilder()->buildMessage(newNonce);
message["success"] = result ? TRUE_STR : FALSE_STR;
return buildResponse(action, message, newNonce);
@@ -575,202 +548,22 @@ QJsonObject BrowserAction::handleGlobalAutoType(const QJsonObject& json, const Q
browserService()->requestGlobalAutoType(topLevelDomain);
- const QString newNonce = incrementNonce(nonce);
- QJsonObject message = buildMessage(newNonce);
+ const QString newNonce = browserMessageBuilder()->incrementNonce(nonce);
+ QJsonObject message = browserMessageBuilder()->buildMessage(newNonce);
return buildResponse(action, message, newNonce);
}
-QJsonObject BrowserAction::getErrorReply(const QString& action, const int errorCode) const
-{
- QJsonObject response;
- response["action"] = action;
- response["errorCode"] = QString::number(errorCode);
- response["error"] = getErrorMessage(errorCode);
- return response;
-}
-
-QJsonObject BrowserAction::buildMessage(const QString& nonce) const
-{
- QJsonObject message;
- message["version"] = KEEPASSXC_VERSION;
- message["success"] = TRUE_STR;
- message["nonce"] = nonce;
- return message;
-}
-
-QJsonObject BrowserAction::buildResponse(const QString& action, const QJsonObject& message, const QString& nonce)
-{
- QJsonObject response;
- QString encryptedMessage = encryptMessage(message, nonce);
- if (encryptedMessage.isEmpty()) {
- return getErrorReply(action, ERROR_KEEPASS_CANNOT_ENCRYPT_MESSAGE);
- }
-
- response["action"] = action;
- response["message"] = encryptedMessage;
- response["nonce"] = nonce;
- return response;
-}
-
-QString BrowserAction::getErrorMessage(const int errorCode) const
-{
- switch (errorCode) {
- case ERROR_KEEPASS_DATABASE_NOT_OPENED:
- return QObject::tr("Database not opened");
- case ERROR_KEEPASS_DATABASE_HASH_NOT_RECEIVED:
- return QObject::tr("Database hash not available");
- case ERROR_KEEPASS_CLIENT_PUBLIC_KEY_NOT_RECEIVED:
- return QObject::tr("Client public key not received");
- case ERROR_KEEPASS_CANNOT_DECRYPT_MESSAGE:
- return QObject::tr("Cannot decrypt message");
- case ERROR_KEEPASS_ACTION_CANCELLED_OR_DENIED:
- return QObject::tr("Action cancelled or denied");
- case ERROR_KEEPASS_CANNOT_ENCRYPT_MESSAGE:
- return QObject::tr("Message encryption failed.");
- case ERROR_KEEPASS_ASSOCIATION_FAILED:
- return QObject::tr("KeePassXC association failed, try again");
- case ERROR_KEEPASS_ENCRYPTION_KEY_UNRECOGNIZED:
- return QObject::tr("Encryption key is not recognized");
- case ERROR_KEEPASS_INCORRECT_ACTION:
- return QObject::tr("Incorrect action");
- case ERROR_KEEPASS_EMPTY_MESSAGE_RECEIVED:
- return QObject::tr("Empty message received");
- case ERROR_KEEPASS_NO_URL_PROVIDED:
- return QObject::tr("No URL provided");
- case ERROR_KEEPASS_NO_LOGINS_FOUND:
- return QObject::tr("No logins found");
- case ERROR_KEEPASS_NO_GROUPS_FOUND:
- return QObject::tr("No groups found");
- case ERROR_KEEPASS_CANNOT_CREATE_NEW_GROUP:
- return QObject::tr("Cannot create new group");
- case ERROR_KEEPASS_NO_VALID_UUID_PROVIDED:
- return QObject::tr("No valid UUID provided");
- default:
- return QObject::tr("Unknown error");
- }
-}
-
-QString BrowserAction::encryptMessage(const QJsonObject& message, const QString& nonce)
-{
- if (message.isEmpty() || nonce.isEmpty()) {
- return QString();
- }
-
- const QString reply(QJsonDocument(message).toJson());
- if (!reply.isEmpty()) {
- return encrypt(reply, nonce);
- }
-
- return QString();
-}
-
QJsonObject BrowserAction::decryptMessage(const QString& message, const QString& nonce)
{
- if (message.isEmpty() || nonce.isEmpty()) {
- return QJsonObject();
- }
-
- QByteArray ba = decrypt(message, nonce);
- if (ba.isEmpty()) {
- return QJsonObject();
- }
-
- return getJsonObject(ba);
+ return browserMessageBuilder()->decryptMessage(message, nonce, m_clientPublicKey, m_secretKey);
}
-QString BrowserAction::encrypt(const QString& plaintext, const QString& nonce)
-{
- const QByteArray ma = plaintext.toUtf8();
- const QByteArray na = base64Decode(nonce);
- const QByteArray ca = base64Decode(m_clientPublicKey);
- const QByteArray sa = base64Decode(m_secretKey);
-
- std::vector<unsigned char> m(ma.cbegin(), ma.cend());
- std::vector<unsigned char> n(na.cbegin(), na.cend());
- std::vector<unsigned char> ck(ca.cbegin(), ca.cend());
- std::vector<unsigned char> sk(sa.cbegin(), sa.cend());
-
- std::vector<unsigned char> e;
- e.resize(BrowserShared::NATIVEMSG_MAX_LENGTH);
-
- if (m.empty() || n.empty() || ck.empty() || sk.empty()) {
- return QString();
- }
-
- if (crypto_box_easy(e.data(), m.data(), m.size(), n.data(), ck.data(), sk.data()) == 0) {
- QByteArray res = getQByteArray(e.data(), (crypto_box_MACBYTES + ma.length()));
- return res.toBase64();
- }
-
- return QString();
-}
-
-QByteArray BrowserAction::decrypt(const QString& encrypted, const QString& nonce)
-{
- const QByteArray ma = base64Decode(encrypted);
- const QByteArray na = base64Decode(nonce);
- const QByteArray ca = base64Decode(m_clientPublicKey);
- const QByteArray sa = base64Decode(m_secretKey);
-
- std::vector<unsigned char> m(ma.cbegin(), ma.cend());
- std::vector<unsigned char> n(na.cbegin(), na.cend());
- std::vector<unsigned char> ck(ca.cbegin(), ca.cend());
- std::vector<unsigned char> sk(sa.cbegin(), sa.cend());
-
- std::vector<unsigned char> d;
- d.resize(BrowserShared::NATIVEMSG_MAX_LENGTH);
-
- if (m.empty() || n.empty() || ck.empty() || sk.empty()) {
- return QByteArray();
- }
-
- if (crypto_box_open_easy(d.data(), m.data(), ma.length(), n.data(), ck.data(), sk.data()) == 0) {
- return getQByteArray(d.data(), std::char_traits<char>::length(reinterpret_cast<const char*>(d.data())));
- }
-
- return QByteArray();
-}
-
-QString BrowserAction::getBase64FromKey(const uchar* array, const uint len)
-{
- return getQByteArray(array, len).toBase64();
-}
-
-QByteArray BrowserAction::getQByteArray(const uchar* array, const uint len) const
-{
- QByteArray qba;
- qba.reserve(len);
- for (uint i = 0; i < len; ++i) {
- qba.append(static_cast<char>(array[i]));
- }
- return qba;
-}
-
-QJsonObject BrowserAction::getJsonObject(const uchar* pArray, const uint len) const
-{
- QByteArray arr = getQByteArray(pArray, len);
- QJsonParseError err;
- QJsonDocument doc(QJsonDocument::fromJson(arr, &err));
- return doc.object();
-}
-
-QJsonObject BrowserAction::getJsonObject(const QByteArray& ba) const
-{
- QJsonParseError err;
- QJsonDocument doc(QJsonDocument::fromJson(ba, &err));
- return doc.object();
-}
-
-QByteArray BrowserAction::base64Decode(const QString& str)
+QJsonObject BrowserAction::getErrorReply(const QString& action, const int errorCode) const
{
- return QByteArray::fromBase64(str.toUtf8());
+ return browserMessageBuilder()->getErrorReply(action, errorCode);
}
-QString BrowserAction::incrementNonce(const QString& nonce)
+QJsonObject BrowserAction::buildResponse(const QString& action, const QJsonObject& message, const QString& nonce)
{
- const QByteArray nonceArray = base64Decode(nonce);
- std::vector<unsigned char> n(nonceArray.cbegin(), nonceArray.cend());
-
- sodium_increment(n.data(), n.size());
- return getQByteArray(n.data(), n.size()).toBase64();
+ return browserMessageBuilder()->buildResponse(action, message, nonce, m_clientPublicKey, m_secretKey);
}
diff --git a/src/browser/BrowserAction.h b/src/browser/BrowserAction.h
index 86b1884a2..49c66b644 100644
--- a/src/browser/BrowserAction.h
+++ b/src/browser/BrowserAction.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2021 KeePassXC Team <team@keepassxc.org>
+ * Copyright (C) 2022 KeePassXC Team <team@keepassxc.org>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -21,23 +21,24 @@
#include <QString>
class QJsonObject;
+class QLocalSocket;
class BrowserAction
{
public:
- explicit BrowserAction();
+ explicit BrowserAction() = default;
~BrowserAction() = default;
- QJsonObject processClientMessage(const QJsonObject& json);
+ QJsonObject processClientMessage(QLocalSocket* socket, const QJsonObject& json);
private:
- QJsonObject handleAction(const QJsonObject& json);
+ QJsonObject handleAction(QLocalSocket* socket, const QJsonObject& json);
QJsonObject handleChangePublicKeys(const QJsonObject& json, const QString& action);
QJsonObject handleGetDatabaseHash(const QJsonObject& json, const QString& action);
QJsonObject handleAssociate(const QJsonObject& json, const QString& action);
QJsonObject handleTestAssociate(const QJsonObject& json, const QString& action);
QJsonObject handleGetLogins(const QJsonObject& json, const QString& action);
- QJsonObject handleGeneratePassword(const QJsonObject& json, const QString& action);
+ QJsonObject handleGeneratePassword(QLocalSocket* socket, const QJsonObject& json, const QString& action);
QJsonObject handleSetLogin(const QJsonObject& json, const QString& action);
QJsonObject handleLockDatabase(const QJsonObject& json, const QString& action);
QJsonObject handleGetDatabaseGroups(const QJsonObject& json, const QString& action);
@@ -46,22 +47,11 @@ private:
QJsonObject handleDeleteEntry(const QJsonObject& json, const QString& action);
QJsonObject handleGlobalAutoType(const QJsonObject& json, const QString& action);
+private:
QJsonObject buildMessage(const QString& nonce) const;
QJsonObject buildResponse(const QString& action, const QJsonObject& message, const QString& nonce);
QJsonObject getErrorReply(const QString& action, const int errorCode) const;
- QString getErrorMessage(const int errorCode) const;
-
- QString encryptMessage(const QJsonObject& message, const QString& nonce);
QJsonObject decryptMessage(const QString& message, const QString& nonce);
- QString encrypt(const QString& plaintext, const QString& nonce);
- QByteArray decrypt(const QString& encrypted, const QString& nonce);
-
- QString getBase64FromKey(const uchar* array, const uint len);
- QByteArray getQByteArray(const uchar* array, const uint len) const;
- QJsonObject getJsonObject(const uchar* pArray, const uint len) const;
- QJsonObject getJsonObject(const QByteArray& ba) const;
- QByteArray base64Decode(const QString& str);
- QString incrementNonce(const QString& nonce);
private:
static const int MaxUrlLength;
diff --git a/src/browser/BrowserHost.cpp b/src/browser/BrowserHost.cpp
index 6ddf7e061..bc6129bf1 100644
--- a/src/browser/BrowserHost.cpp
+++ b/src/browser/BrowserHost.cpp
@@ -88,18 +88,29 @@ void BrowserHost::readProxyMessage()
return;
}
- emit clientMessageReceived(json.object());
+ emit clientMessageReceived(socket, json.object());
}
-void BrowserHost::sendClientMessage(const QJsonObject& json)
+void BrowserHost::broadcastClientMessage(const QJsonObject& json)
{
QString reply(QJsonDocument(json).toJson(QJsonDocument::Compact));
for (const auto socket : m_socketList) {
- if (socket && socket->isValid() && socket->state() == QLocalSocket::ConnectedState) {
- QByteArray arr = reply.toUtf8();
- socket->write(arr.constData(), arr.length());
- socket->flush();
- }
+ sendClientData(socket, reply);
+ }
+}
+
+void BrowserHost::sendClientMessage(QLocalSocket* socket, const QJsonObject& json)
+{
+ QString reply(QJsonDocument(json).toJson(QJsonDocument::Compact));
+ sendClientData(socket, reply);
+}
+
+void BrowserHost::sendClientData(QLocalSocket* socket, const QString& data)
+{
+ if (socket && socket->isValid() && socket->state() == QLocalSocket::ConnectedState) {
+ QByteArray arr = data.toUtf8();
+ socket->write(arr.constData(), arr.length());
+ socket->flush();
}
}
diff --git a/src/browser/BrowserHost.h b/src/browser/BrowserHost.h
index ea8e07409..86f20f1e2 100644
--- a/src/browser/BrowserHost.h
+++ b/src/browser/BrowserHost.h
@@ -24,6 +24,7 @@
class QLocalServer;
class QLocalSocket;
+class QString;
class BrowserHost : public QObject
{
@@ -36,10 +37,11 @@ public:
void start();
void stop();
- void sendClientMessage(const QJsonObject& json);
+ void broadcastClientMessage(const QJsonObject& json);
+ void sendClientMessage(QLocalSocket* socket, const QJsonObject& json);
signals:
- void clientMessageReceived(const QJsonObject& json);
+ void clientMessageReceived(QLocalSocket* socket, const QJsonObject& json);
private slots:
void proxyConnected();
@@ -47,6 +49,9 @@ private slots:
void proxyDisconnected();
private:
+ void sendClientData(QLocalSocket* socket, const QString& data);
+
+private:
QPointer<QLocalServer> m_localServer;
QList<QLocalSocket*> m_socketList;
};
diff --git a/src/browser/BrowserMessageBuilder.cpp b/src/browser/BrowserMessageBuilder.cpp
new file mode 100644
index 000000000..e537205df
--- /dev/null
+++ b/src/browser/BrowserMessageBuilder.cpp
@@ -0,0 +1,259 @@
+/*
+ * Copyright (C) 2022 KeePassXC Team <team@keepassxc.org>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "BrowserMessageBuilder.h"
+#include "BrowserShared.h"
+#include "config-keepassx.h"
+#include "core/Global.h"
+#include "core/Tools.h"
+
+#include <QJsonArray>
+#include <QJsonDocument>
+#include <QJsonObject>
+
+#include <botan/sodium.h>
+
+using namespace Botan::Sodium;
+
+Q_GLOBAL_STATIC(BrowserMessageBuilder, s_browserMessageBuilder);
+
+BrowserMessageBuilder* BrowserMessageBuilder::instance()
+{
+ return s_browserMessageBuilder;
+}
+
+QPair<QString, QString> BrowserMessageBuilder::getKeyPair()
+{
+ unsigned char pk[crypto_box_PUBLICKEYBYTES];
+ unsigned char sk[crypto_box_SECRETKEYBYTES];
+ crypto_box_keypair(pk, sk);
+
+ const QString publicKey = getBase64FromKey(pk, crypto_box_PUBLICKEYBYTES);
+ const QString secretKey = getBase64FromKey(sk, crypto_box_SECRETKEYBYTES);
+ return qMakePair(publicKey, secretKey);
+}
+
+QJsonObject BrowserMessageBuilder::getErrorReply(const QString& action, const int errorCode) const
+{
+ QJsonObject response;
+ response["action"] = action;
+ response["errorCode"] = QString::number(errorCode);
+ response["error"] = getErrorMessage(errorCode);
+ return response;
+}
+
+QJsonObject BrowserMessageBuilder::buildMessage(const QString& nonce) const
+{
+ QJsonObject message;
+ message["version"] = KEEPASSXC_VERSION;
+ message["success"] = TRUE_STR;
+ message["nonce"] = nonce;
+ return message;
+}
+
+QJsonObject BrowserMessageBuilder::buildResponse(const QString& action,
+ const QJsonObject& message,
+ const QString& nonce,
+ const QString& publicKey,
+ const QString& secretKey)
+{
+ QJsonObject response;
+ QString encryptedMessage = encryptMessage(message, nonce, publicKey, secretKey);
+ if (encryptedMessage.isEmpty()) {
+ return getErrorReply(action, ERROR_KEEPASS_CANNOT_ENCRYPT_MESSAGE);
+ }
+
+ response["action"] = action;
+ response["message"] = encryptedMessage;
+ response["nonce"] = nonce;
+ return response;
+}
+
+QString BrowserMessageBuilder::getErrorMessage(const int errorCode) const
+{
+ switch (errorCode) {
+ case ERROR_KEEPASS_DATABASE_NOT_OPENED:
+ return QObject::tr("Database not opened");
+ case ERROR_KEEPASS_DATABASE_HASH_NOT_RECEIVED:
+ return QObject::tr("Database hash not available");
+ case ERROR_KEEPASS_CLIENT_PUBLIC_KEY_NOT_RECEIVED:
+ return QObject::tr("Client public key not received");
+ case ERROR_KEEPASS_CANNOT_DECRYPT_MESSAGE:
+ return QObject::tr("Cannot decrypt message");
+ case ERROR_KEEPASS_ACTION_CANCELLED_OR_DENIED:
+ return QObject::tr("Action cancelled or denied");
+ case ERROR_KEEPASS_CANNOT_ENCRYPT_MESSAGE:
+ return QObject::tr("Message encryption failed.");
+ case ERROR_KEEPASS_ASSOCIATION_FAILED:
+ return QObject::tr("KeePassXC association failed, try again");
+ case ERROR_KEEPASS_ENCRYPTION_KEY_UNRECOGNIZED:
+ return QObject::tr("Encryption key is not recognized");
+ case ERROR_KEEPASS_INCORRECT_ACTION:
+ return QObject::tr("Incorrect action");
+ case ERROR_KEEPASS_EMPTY_MESSAGE_RECEIVED:
+ return QObject::tr("Empty message received");
+ case ERROR_KEEPASS_NO_URL_PROVIDED:
+ return QObject::tr("No URL provided");
+ case ERROR_KEEPASS_NO_LOGINS_FOUND:
+ return QObject::tr("No logins found");
+ case ERROR_KEEPASS_NO_GROUPS_FOUND:
+ return QObject::tr("No groups found");
+ case ERROR_KEEPASS_CANNOT_CREATE_NEW_GROUP:
+ return QObject::tr("Cannot create new group");
+ case ERROR_KEEPASS_NO_VALID_UUID_PROVIDED:
+ return QObject::tr("No valid UUID provided");
+ default:
+ return QObject::tr("Unknown error");
+ }
+}
+
+QString BrowserMessageBuilder::encryptMessage(const QJsonObject& message,
+ const QString& nonce,
+ const QString& publicKey,
+ const QString& secretKey)
+{
+ if (message.isEmpty() || nonce.isEmpty()) {
+ return QString();
+ }
+
+ const QString reply(QJsonDocument(message).toJson());
+ if (!reply.isEmpty()) {
+ return encrypt(reply, nonce, publicKey, secretKey);
+ }
+
+ return QString();
+}
+
+QJsonObject BrowserMessageBuilder::decryptMessage(const QString& message,
+ const QString& nonce,
+ const QString& publicKey,
+ const QString& secretKey)
+{
+ if (message.isEmpty() || nonce.isEmpty()) {
+ return QJsonObject();
+ }
+
+ QByteArray ba = decrypt(message, nonce, publicKey, secretKey);
+ if (ba.isEmpty()) {
+ return QJsonObject();
+ }
+
+ return getJsonObject(ba);
+}
+
+QString BrowserMessageBuilder::encrypt(const QString& plaintext,
+ const QString& nonce,
+ const QString& publicKey,
+ const QString& secretKey)
+{
+ const QByteArray ma = plaintext.toUtf8();
+ const QByteArray na = base64Decode(nonce);
+ const QByteArray ca = base64Decode(publicKey);
+ const QByteArray sa = base64Decode(secretKey);
+
+ std::vector<unsigned char> m(ma.cbegin(), ma.cend());
+ std::vector<unsigned char> n(na.cbegin(), na.cend());
+ std::vector<unsigned char> ck(ca.cbegin(), ca.cend());
+ std::vector<unsigned char> sk(sa.cbegin(), sa.cend());
+
+ std::vector<unsigned char> e;
+ e.resize(BrowserShared::NATIVEMSG_MAX_LENGTH);
+
+ if (m.empty() || n.empty() || ck.empty() || sk.empty()) {
+ return QString();
+ }
+
+ if (crypto_box_easy(e.data(), m.data(), m.size(), n.data(), ck.data(), sk.data()) == 0) {
+ QByteArray res = getQByteArray(e.data(), (crypto_box_MACBYTES + ma.length()));
+ return res.toBase64();
+ }
+
+ return QString();
+}
+
+QByteArray BrowserMessageBuilder::decrypt(const QString& encrypted,
+ const QString& nonce,
+ const QString& publicKey,
+ const QString& secretKey)
+{
+ const QByteArray ma = base64Decode(encrypted);
+ const QByteArray na = base64Decode(nonce);
+ const QByteArray ca = base64Decode(publicKey);
+ const QByteArray sa = base64Decode(secretKey);
+
+ std::vector<unsigned char> m(ma.cbegin(), ma.cend());
+ std::vector<unsigned char> n(na.cbegin(), na.cend());
+ std::vector<unsigned char> ck(ca.cbegin(), ca.cend());
+ std::vector<unsigned char> sk(sa.cbegin(), sa.cend());
+
+ std::vector<unsigned char> d;
+ d.resize(BrowserShared::NATIVEMSG_MAX_LENGTH);
+
+ if (m.empty() || n.empty() || ck.empty() || sk.empty()) {
+ return QByteArray();
+ }
+
+ if (crypto_box_open_easy(d.data(), m.data(), ma.length(), n.data(), ck.data(), sk.data()) == 0) {
+ return getQByteArray(d.data(), std::char_traits<char>::length(reinterpret_cast<const char*>(d.data())));
+ }
+
+ return QByteArray();
+}
+
+QString BrowserMessageBuilder::getBase64FromKey(const uchar* array, const uint len)
+{
+ return getQByteArray(array, len).toBase64();
+}
+
+QByteArray BrowserMessageBuilder::getQByteArray(const uchar* array, const uint len) const
+{
+ QByteArray qba;
+ qba.reserve(len);
+ for (uint i = 0; i < len; ++i) {
+ qba.append(static_cast<char>(array[i]));
+ }
+ return qba;
+}
+
+QJsonObject BrowserMessageBuilder::getJsonObject(const uchar* pArray, const uint len) const
+{
+ QByteArray arr = getQByteArray(pArray, len);
+ QJsonParseError err;
+ QJsonDocument doc(QJsonDocument::fromJson(arr, &err));
+ return doc.object();
+}
+
+QJsonObject BrowserMessageBuilder::getJsonObject(const QByteArray& ba) const
+{
+ QJsonParseError err;
+ QJsonDocument doc(QJsonDocument::fromJson(ba, &err));
+ return doc.object();
+}
+
+QByteArray BrowserMessageBuilder::base64Decode(const QString& str)
+{
+ return QByteArray::fromBase64(str.toUtf8());
+}
+
+QString BrowserMessageBuilder::incrementNonce(const QString& nonce)
+{
+ const QByteArray nonceArray = base64Decode(nonce);
+ std::vector<unsigned char> n(nonceArray.cbegin(), nonceArray.cend());
+
+ sodium_increment(n.data(), n.size());
+ return getQByteArray(n.data(), n.size()).toBase64();
+}
diff --git a/src/browser/BrowserMessageBuilder.h b/src/browser/BrowserMessageBuilder.h
new file mode 100644
index 000000000..9dc4f27f0
--- /dev/null
+++ b/src/browser/BrowserMessageBuilder.h
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2022 KeePassXC Team <team@keepassxc.org>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef BROWSERMESSAGEBUILDER_H
+#define BROWSERMESSAGEBUILDER_H
+
+#include <QPair>
+#include <QString>
+
+class QJsonObject;
+
+namespace
+{
+ enum
+ {
+ ERROR_KEEPASS_DATABASE_NOT_OPENED = 1,
+ ERROR_KEEPASS_DATABASE_HASH_NOT_RECEIVED = 2,
+ ERROR_KEEPASS_CLIENT_PUBLIC_KEY_NOT_RECEIVED = 3,
+ ERROR_KEEPASS_CANNOT_DECRYPT_MESSAGE = 4,
+ ERROR_KEEPASS_TIMEOUT_OR_NOT_CONNECTED = 5,
+ ERROR_KEEPASS_ACTION_CANCELLED_OR_DENIED = 6,
+ ERROR_KEEPASS_CANNOT_ENCRYPT_MESSAGE = 7,
+ ERROR_KEEPASS_ASSOCIATION_FAILED = 8,
+ ERROR_KEEPASS_KEY_CHANGE_FAILED = 9,
+ ERROR_KEEPASS_ENCRYPTION_KEY_UNRECOGNIZED = 10,
+ ERROR_KEEPASS_NO_SAVED_DATABASES_FOUND = 11,
+ ERROR_KEEPASS_INCORRECT_ACTION = 12,
+ ERROR_KEEPASS_EMPTY_MESSAGE_RECEIVED = 13,
+ ERROR_KEEPASS_NO_URL_PROVIDED = 14,
+ ERROR_KEEPASS_NO_LOGINS_FOUND = 15,
+ ERROR_KEEPASS_NO_GROUPS_FOUND = 16,
+ ERROR_KEEPASS_CANNOT_CREATE_NEW_GROUP = 17,
+ ERROR_KEEPASS_NO_VALID_UUID_PROVIDED = 18
+ };
+}
+
+class BrowserMessageBuilder
+{
+public:
+ explicit BrowserMessageBuilder() = default;
+ static BrowserMessageBuilder* instance();
+
+ QPair<QString, QString> getKeyPair();
+
+ QJsonObject buildMessage(const QString& nonce) const;
+ QJsonObject buildResponse(const QString& action,
+ const QJsonObject& message,
+ const QString& nonce,
+ const QString& publicKey,
+ const QString& secretKey);
+ QJsonObject getErrorReply(const QString& action, const int errorCode) const;
+ QString getErrorMessage(const int errorCode) const;
+
+ QString encryptMessage(const QJsonObject& message,
+ const QString& nonce,
+ const QString& publicKey,
+ const QString& secretKey);
+ QJsonObject
+ decryptMessage(const QString& message, const QString& nonce, const QString& publicKey, const QString& secretKey);
+ QString encrypt(const QString& plaintext, const QString& nonce, const QString& publicKey, const QString& secretKey);
+ QByteArray
+ decrypt(const QString& encrypted, const QString& nonce, const QString& publicKey, const QString& secretKey);
+
+ QString getBase64FromKey(const uchar* array, const uint len);
+ QByteArray getQByteArray(const uchar* array, const uint len) const;
+ QJsonObject getJsonObject(const uchar* pArray, const uint len) const;
+ QJsonObject getJsonObject(const QByteArray& ba) const;
+ QByteArray base64Decode(const QString& str);
+ QString incrementNonce(const QString& nonce);
+
+private:
+ Q_DISABLE_COPY(BrowserMessageBuilder);
+
+ friend class TestBrowser;
+};
+
+static inline BrowserMessageBuilder* browserMessageBuilder()
+{
+ return BrowserMessageBuilder::instance();
+}
+
+#endif // BROWSERMESSAGEBUILDER_H
diff --git a/src/browser/BrowserService.cpp b/src/browser/BrowserService.cpp
index 3ebf6d2b8..9f13546ad 100644
--- a/src/browser/BrowserService.cpp
+++ b/src/browser/BrowserService.cpp
@@ -23,6 +23,7 @@
#include "BrowserEntryConfig.h"
#include "BrowserEntrySaveDialog.h"
#include "BrowserHost.h"
+#include "BrowserMessageBuilder.h"
#include "BrowserSettings.h"
#include "core/Tools.h"
#include "gui/MainWindow.h"
@@ -39,6 +40,7 @@
#include <QJsonArray>
#include <QJsonObject>
#include <QListWidget>
+#include <QLocalSocket>
#include <QProgressDialog>
#include <QUrl>
@@ -64,6 +66,7 @@ BrowserService::BrowserService()
, m_browserHost(new BrowserHost)
, m_dialogActive(false)
, m_bringToFrontRequested(false)
+ , m_passwordGeneratorRequested(false)
, m_prevWindowState(WindowState::Normal)
, m_keepassBrowserUUID(Tools::hexToUuid("de887cc3036343b8974b5911b8816224"))
{
@@ -311,37 +314,55 @@ QString BrowserService::getCurrentTotp(const QString& uuid)
return {};
}
-void BrowserService::showPasswordGenerator(const QJsonObject& errorMessage, const QString& nonce)
+void BrowserService::showPasswordGenerator(QLocalSocket* socket,
+ const QString& incrementedNonce,
+ const QString& publicKey,
+ const QString& secretKey)
{
if (!m_passwordGenerator) {
m_passwordGenerator.reset(PasswordGeneratorWidget::popupGenerator());
connect(m_passwordGenerator.data(), &PasswordGeneratorWidget::closed, m_passwordGenerator.data(), [=] {
if (!m_passwordGenerator->isPasswordGenerated()) {
- m_browserHost->sendClientMessage(errorMessage);
+ auto errorMessage = browserMessageBuilder()->getErrorReply("generate-password",
+ ERROR_KEEPASS_ACTION_CANCELLED_OR_DENIED);
+ m_browserHost->sendClientMessage(socket, errorMessage);
}
m_passwordGenerator.reset();
hideWindow();
+ m_passwordGeneratorRequested = false;
});
connect(m_passwordGenerator.data(),
&PasswordGeneratorWidget::appliedPassword,
m_passwordGenerator.data(),
- [=](const QString& password) { emit passwordGenerated(password, nonce); });
+ [=](const QString& password) {
+ QJsonObject message = browserMessageBuilder()->buildMessage(incrementedNonce);
+ message["password"] = password;
+ sendPassword(socket,
+ browserMessageBuilder()->buildResponse(
+ "generate-password", message, incrementedNonce, publicKey, secretKey));
+ });
}
+ m_passwordGeneratorRequested = true;
raiseWindow();
m_passwordGenerator->raise();
m_passwordGenerator->activateWindow();
}
-void BrowserService::sendPassword(const QJsonObject& message)
+void BrowserService::sendPassword(QLocalSocket* socket, const QJsonObject& message)
{
- m_browserHost->sendClientMessage(message);
+ m_browserHost->sendClientMessage(socket, message);
hideWindow();
}
+bool BrowserService::isPasswordGeneratorRequested() const
+{
+ return m_passwordGeneratorRequested;
+}
+
QString BrowserService::storeKey(const QString& key)
{
auto db = getDatabase();
@@ -1382,7 +1403,7 @@ void BrowserService::databaseLocked(DatabaseWidget* dbWidget)
if (dbWidget) {
QJsonObject msg;
msg["action"] = QString("database-locked");
- m_browserHost->sendClientMessage(msg);
+ m_browserHost->broadcastClientMessage(msg);
}
}
@@ -1396,7 +1417,7 @@ void BrowserService::databaseUnlocked(DatabaseWidget* dbWidget)
QJsonObject msg;
msg["action"] = QString("database-unlocked");
- m_browserHost->sendClientMessage(msg);
+ m_browserHost->broadcastClientMessage(msg);
auto db = dbWidget->database();
if (checkLegacySettings(db)) {
@@ -1419,7 +1440,7 @@ void BrowserService::activeDatabaseChanged(DatabaseWidget* dbWidget)
m_currentDatabaseWidget = dbWidget;
}
-void BrowserService::processClientMessage(const QJsonObject& message)
+void BrowserService::processClientMessage(QLocalSocket* socket, const QJsonObject& message)
{
auto clientID = message["clientID"].toString();
if (clientID.isEmpty()) {
@@ -1432,6 +1453,6 @@ void BrowserService::processClientMessage(const QJsonObject& message)
}
auto& action = m_browserClients.value(clientID);
- auto response = action->processClientMessage(message);
- m_browserHost->sendClientMessage(response);
+ auto response = action->processClientMessage(socket, message);
+ m_browserHost->sendClientMessage(socket, response);
}
diff --git a/src/browser/BrowserService.h b/src/browser/BrowserService.h
index 111fe9d78..f91887cd0 100644
--- a/src/browser/BrowserService.h
+++ b/src/browser/BrowserService.h
@@ -23,6 +23,8 @@
#include "core/Entry.h"
#include "gui/PasswordGeneratorWidget.h"
+class QLocalSocket;
+
typedef QPair<QString, QString> StringPair;
typedef QList<StringPair> StringPairList;
@@ -56,8 +58,12 @@ public:
QJsonObject getDatabaseGroups();
QJsonObject createNewGroup(const QString& groupName);
QString getCurrentTotp(const QString& uuid);
- void showPasswordGenerator(const QJsonObject& errorMessage, const QString& nonce);
- void sendPassword(const QJsonObject& message);
+ void showPasswordGenerator(QLocalSocket* socket,
+ const QString& nonce,
+ const QString& publicKey,
+ const QString& secretKey);
+ void sendPassword(QLocalSocket* socket, const QJsonObject& message);
+ bool isPasswordGeneratorRequested() const;
void addEntry(const QString& dbid,
const QString& login,
@@ -97,7 +103,7 @@ public:
signals:
void requestUnlock();
- void passwordGenerated(const QString& password, const QString& nonce);
+ void passwordGenerated(QLocalSocket* socket, const QString& password, const QString& nonce);
public slots:
void databaseLocked(DatabaseWidget* dbWidget);
@@ -105,7 +111,7 @@ public slots:
void activeDatabaseChanged(DatabaseWidget* dbWidget);
private slots:
- void processClientMessage(const QJsonObject& message);
+ void processClientMessage(QLocalSocket* socket, const QJsonObject& message);
private:
enum Access
@@ -163,6 +169,7 @@ private:
bool m_dialogActive;
bool m_bringToFrontRequested;
+ bool m_passwordGeneratorRequested;
WindowState m_prevWindowState;
QUuid m_keepassBrowserUUID;
diff --git a/src/browser/CMakeLists.txt b/src/browser/CMakeLists.txt
index e2fa9d831..98715cb14 100755
--- a/src/browser/CMakeLists.txt
+++ b/src/browser/CMakeLists.txt
@@ -1,5 +1,5 @@
# Copyright (C) 2017 Sami Vänttinen <sami.vanttinen@protonmail.com>
-# Copyright (C) 2017 KeePassXC Team <team@keepassxc.org>
+# Copyright (C) 2022 KeePassXC Team <team@keepassxc.org>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@@ -23,6 +23,7 @@ if(WITH_XC_BROWSER)
BrowserEntryConfig.cpp
BrowserEntrySaveDialog.cpp
BrowserHost.cpp
+ BrowserMessageBuilder.cpp
BrowserSettingsPage.cpp
BrowserSettingsWidget.cpp
BrowserService.cpp
diff --git a/tests/TestBrowser.cpp b/tests/TestBrowser.cpp
index 71d5c8636..6dcff3b74 100644
--- a/tests/TestBrowser.cpp
+++ b/tests/TestBrowser.cpp
@@ -17,6 +17,7 @@
#include "TestBrowser.h"
+#include "browser/BrowserMessageBuilder.h"
#include "browser/BrowserSettings.h"
#include "core/Group.h"
#include "core/Tools.h"
@@ -61,7 +62,7 @@ void TestBrowser::testChangePublicKeys()
json["publicKey"] = PUBLICKEY;
json["nonce"] = NONCE;
- auto response = m_browserAction->processClientMessage(json);
+ auto response = m_browserAction->processClientMessage(nullptr, json);
QCOMPARE(response["action"].toString(), QString("change-public-keys"));
QCOMPARE(response["publicKey"].toString() == PUBLICKEY, false);
QCOMPARE(response["success"].toString(), TRUE_STR);
@@ -75,7 +76,7 @@ void TestBrowser::testEncryptMessage()
m_browserAction->m_publicKey = SERVERPUBLICKEY;
m_browserAction->m_secretKey = SERVERSECRETKEY;
m_browserAction->m_clientPublicKey = PUBLICKEY;
- auto encrypted = m_browserAction->encryptMessage(message, NONCE);
+ auto encrypted = browserMessageBuilder()->encryptMessage(message, NONCE, PUBLICKEY, SERVERSECRETKEY);
QCOMPARE(encrypted, QString("+zjtntnk4rGWSl/Ph7Vqip/swvgeupk4lNgHEm2OO3ujNr0OMz6eQtGwjtsj+/rP"));
}
@@ -86,7 +87,7 @@ void TestBrowser::testDecryptMessage()
m_browserAction->m_publicKey = SERVERPUBLICKEY;
m_browserAction->m_secretKey = SERVERSECRETKEY;
m_browserAction->m_clientPublicKey = PUBLICKEY;
- auto decrypted = m_browserAction->decryptMessage(message, NONCE);
+ auto decrypted = browserMessageBuilder()->decryptMessage(message, NONCE, PUBLICKEY, SERVERSECRETKEY);
QCOMPARE(decrypted["action"].toString(), QString("test-action"));
}
@@ -99,13 +100,13 @@ void TestBrowser::testGetBase64FromKey()
pk[i] = i;
}
- auto response = m_browserAction->getBase64FromKey(pk, crypto_box_PUBLICKEYBYTES);
+ auto response = browserMessageBuilder()->getBase64FromKey(pk, crypto_box_PUBLICKEYBYTES);
QCOMPARE(response, QString("AAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBkaGxwdHh8="));
}
void TestBrowser::testIncrementNonce()
{
- auto result = m_browserAction->incrementNonce(NONCE);
+ auto result = browserMessageBuilder()->incrementNonce(NONCE);
QCOMPARE(result, QString("zRKdvTjL5bgWaKMCTut/8soM/uoMrFoZ"));
}