diff options
author | Sami Vänttinen <sami.vanttinen@protonmail.com> | 2022-02-23 01:52:51 +0300 |
---|---|---|
committer | Jonathan White <support@dmapps.us> | 2022-02-24 01:48:50 +0300 |
commit | 7284a8062a3eef681d529e2e56c3b66a82b09337 (patch) | |
tree | a8ead4f57a3e0f2abbcda8199da4a808d2a3370e | |
parent | 67910249952e4e77535d8ecde2fe589fe32f64da (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.cpp | 333 | ||||
-rw-r--r-- | src/browser/BrowserAction.h | 24 | ||||
-rw-r--r-- | src/browser/BrowserHost.cpp | 25 | ||||
-rw-r--r-- | src/browser/BrowserHost.h | 9 | ||||
-rw-r--r-- | src/browser/BrowserMessageBuilder.cpp | 259 | ||||
-rw-r--r-- | src/browser/BrowserMessageBuilder.h | 96 | ||||
-rw-r--r-- | src/browser/BrowserService.cpp | 41 | ||||
-rw-r--r-- | src/browser/BrowserService.h | 15 | ||||
-rwxr-xr-x | src/browser/CMakeLists.txt | 3 | ||||
-rw-r--r-- | tests/TestBrowser.cpp | 11 |
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")); } |