mirror of
https://github.com/keepassxreboot/keepassxc.git
synced 2025-07-26 08:15:32 -04:00
Fix password generator responses (#7404)
* Respond directly to the current client instead of broadcasting * Append requestID to generate-password response
This commit is contained in:
parent
6791024995
commit
7284a8062a
10 changed files with 500 additions and 316 deletions
|
@ -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
|
* 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
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
@ -16,65 +16,22 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "BrowserAction.h"
|
#include "BrowserAction.h"
|
||||||
|
#include "BrowserMessageBuilder.h"
|
||||||
#include "BrowserService.h"
|
#include "BrowserService.h"
|
||||||
#include "BrowserSettings.h"
|
#include "BrowserSettings.h"
|
||||||
#include "BrowserShared.h"
|
#include "BrowserShared.h"
|
||||||
#include "config-keepassx.h"
|
#include "config-keepassx.h"
|
||||||
#include "core/Global.h"
|
#include "core/Global.h"
|
||||||
#include "core/Tools.h"
|
#include "core/Tools.h"
|
||||||
#include "gui/PasswordGeneratorWidget.h"
|
|
||||||
|
|
||||||
#include <QJsonArray>
|
#include <QJsonArray>
|
||||||
#include <QJsonDocument>
|
#include <QJsonDocument>
|
||||||
#include <QJsonObject>
|
#include <QJsonObject>
|
||||||
|
#include <QLocalSocket>
|
||||||
#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
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
const int BrowserAction::MaxUrlLength = 256;
|
const int BrowserAction::MaxUrlLength = 256;
|
||||||
|
|
||||||
BrowserAction::BrowserAction()
|
QJsonObject BrowserAction::processClientMessage(QLocalSocket* socket, const QJsonObject& json)
|
||||||
{
|
|
||||||
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)
|
|
||||||
{
|
{
|
||||||
if (json.isEmpty()) {
|
if (json.isEmpty()) {
|
||||||
return getErrorReply("", ERROR_KEEPASS_EMPTY_MESSAGE_RECEIVED);
|
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
|
// Private functions
|
||||||
///////////////////////
|
///////////////////////
|
||||||
|
|
||||||
QJsonObject BrowserAction::handleAction(const QJsonObject& json)
|
QJsonObject BrowserAction::handleAction(QLocalSocket* socket, const QJsonObject& json)
|
||||||
{
|
{
|
||||||
QString action = json.value("action").toString();
|
QString action = json.value("action").toString();
|
||||||
|
|
||||||
|
@ -121,7 +78,7 @@ QJsonObject BrowserAction::handleAction(const QJsonObject& json)
|
||||||
} else if (action.compare("get-logins") == 0) {
|
} else if (action.compare("get-logins") == 0) {
|
||||||
return handleGetLogins(json, action);
|
return handleGetLogins(json, action);
|
||||||
} else if (action.compare("generate-password") == 0) {
|
} else if (action.compare("generate-password") == 0) {
|
||||||
return handleGeneratePassword(json, action);
|
return handleGeneratePassword(socket, json, action);
|
||||||
} else if (action.compare("set-login") == 0) {
|
} else if (action.compare("set-login") == 0) {
|
||||||
return handleSetLogin(json, action);
|
return handleSetLogin(json, action);
|
||||||
} else if (action.compare("lock-database") == 0) {
|
} else if (action.compare("lock-database") == 0) {
|
||||||
|
@ -152,23 +109,18 @@ QJsonObject BrowserAction::handleChangePublicKeys(const QJsonObject& json, const
|
||||||
}
|
}
|
||||||
|
|
||||||
m_associated = false;
|
m_associated = false;
|
||||||
unsigned char pk[crypto_box_PUBLICKEYBYTES];
|
auto keyPair = browserMessageBuilder()->getKeyPair();
|
||||||
unsigned char sk[crypto_box_SECRETKEYBYTES];
|
if (keyPair.first.isEmpty() || keyPair.second.isEmpty()) {
|
||||||
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()) {
|
|
||||||
return getErrorReply(action, ERROR_KEEPASS_ENCRYPTION_KEY_UNRECOGNIZED);
|
return getErrorReply(action, ERROR_KEEPASS_ENCRYPTION_KEY_UNRECOGNIZED);
|
||||||
}
|
}
|
||||||
|
|
||||||
m_clientPublicKey = clientPublicKey;
|
m_clientPublicKey = clientPublicKey;
|
||||||
m_publicKey = publicKey;
|
m_publicKey = keyPair.first;
|
||||||
m_secretKey = secretKey;
|
m_secretKey = keyPair.second;
|
||||||
|
|
||||||
QJsonObject response = buildMessage(incrementNonce(nonce));
|
QJsonObject response = browserMessageBuilder()->buildMessage(browserMessageBuilder()->incrementNonce(nonce));
|
||||||
response["action"] = action;
|
response["action"] = action;
|
||||||
response["publicKey"] = publicKey;
|
response["publicKey"] = keyPair.first;
|
||||||
|
|
||||||
return response;
|
return response;
|
||||||
}
|
}
|
||||||
|
@ -190,9 +142,9 @@ QJsonObject BrowserAction::handleGetDatabaseHash(const QJsonObject& json, const
|
||||||
|
|
||||||
QString command = decrypted.value("action").toString();
|
QString command = decrypted.value("action").toString();
|
||||||
if (!command.isEmpty() && command.compare("get-databasehash") == 0) {
|
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;
|
message["hash"] = hash;
|
||||||
|
|
||||||
// Update a legacy database hash if found
|
// Update a legacy database hash if found
|
||||||
|
@ -236,9 +188,9 @@ QJsonObject BrowserAction::handleAssociate(const QJsonObject& json, const QStrin
|
||||||
}
|
}
|
||||||
|
|
||||||
m_associated = true;
|
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["hash"] = hash;
|
||||||
message["id"] = id;
|
message["id"] = id;
|
||||||
return buildResponse(action, message, newNonce);
|
return buildResponse(action, message, newNonce);
|
||||||
|
@ -270,9 +222,9 @@ QJsonObject BrowserAction::handleTestAssociate(const QJsonObject& json, const QS
|
||||||
}
|
}
|
||||||
|
|
||||||
m_associated = true;
|
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["hash"] = hash;
|
||||||
message["id"] = id;
|
message["id"] = id;
|
||||||
|
|
||||||
|
@ -317,9 +269,9 @@ QJsonObject BrowserAction::handleGetLogins(const QJsonObject& json, const QStrin
|
||||||
return getErrorReply(action, ERROR_KEEPASS_NO_LOGINS_FOUND);
|
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["count"] = users.count();
|
||||||
message["entries"] = users;
|
message["entries"] = users;
|
||||||
message["hash"] = hash;
|
message["hash"] = hash;
|
||||||
|
@ -328,12 +280,33 @@ QJsonObject BrowserAction::handleGetLogins(const QJsonObject& json, const QStrin
|
||||||
return buildResponse(action, message, newNonce);
|
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 errorMessage = getErrorReply(action, ERROR_KEEPASS_ACTION_CANCELLED_OR_DENIED);
|
||||||
auto nonce = json.value("nonce").toString();
|
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();
|
return QJsonObject();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -379,9 +352,9 @@ QJsonObject BrowserAction::handleSetLogin(const QJsonObject& json, const QString
|
||||||
result = browserService()->updateEntry(id, uuid, login, password, url, submitUrl);
|
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["count"] = QJsonValue::Null;
|
||||||
message["entries"] = QJsonValue::Null;
|
message["entries"] = QJsonValue::Null;
|
||||||
message["error"] = result ? QStringLiteral("success") : QStringLiteral("error");
|
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) {
|
if (!command.isEmpty() && command.compare("lock-database") == 0) {
|
||||||
browserService()->lockDatabase();
|
browserService()->lockDatabase();
|
||||||
|
|
||||||
const QString newNonce = incrementNonce(nonce);
|
const QString newNonce = browserMessageBuilder()->incrementNonce(nonce);
|
||||||
QJsonObject message = buildMessage(newNonce);
|
QJsonObject message = browserMessageBuilder()->buildMessage(newNonce);
|
||||||
|
|
||||||
return buildResponse(action, message, 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);
|
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;
|
message["groups"] = groups;
|
||||||
|
|
||||||
return buildResponse(action, message, newNonce);
|
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);
|
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["name"] = newGroup["name"];
|
||||||
message["uuid"] = newGroup["uuid"];
|
message["uuid"] = newGroup["uuid"];
|
||||||
|
|
||||||
|
@ -512,9 +485,9 @@ QJsonObject BrowserAction::handleGetTotp(const QJsonObject& json, const QString&
|
||||||
|
|
||||||
// Get the current TOTP
|
// Get the current TOTP
|
||||||
const auto totp = browserService()->getCurrentTotp(uuid);
|
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;
|
message["totp"] = totp;
|
||||||
|
|
||||||
return buildResponse(action, message, newNonce);
|
return buildResponse(action, message, newNonce);
|
||||||
|
@ -546,8 +519,8 @@ QJsonObject BrowserAction::handleDeleteEntry(const QJsonObject& json, const QStr
|
||||||
|
|
||||||
const auto result = browserService()->deleteEntry(uuid);
|
const auto result = browserService()->deleteEntry(uuid);
|
||||||
|
|
||||||
const QString newNonce = incrementNonce(nonce);
|
const QString newNonce = browserMessageBuilder()->incrementNonce(nonce);
|
||||||
QJsonObject message = buildMessage(newNonce);
|
QJsonObject message = browserMessageBuilder()->buildMessage(newNonce);
|
||||||
message["success"] = result ? TRUE_STR : FALSE_STR;
|
message["success"] = result ? TRUE_STR : FALSE_STR;
|
||||||
|
|
||||||
return buildResponse(action, message, newNonce);
|
return buildResponse(action, message, newNonce);
|
||||||
|
@ -575,202 +548,22 @@ QJsonObject BrowserAction::handleGlobalAutoType(const QJsonObject& json, const Q
|
||||||
|
|
||||||
browserService()->requestGlobalAutoType(topLevelDomain);
|
browserService()->requestGlobalAutoType(topLevelDomain);
|
||||||
|
|
||||||
const QString newNonce = incrementNonce(nonce);
|
const QString newNonce = browserMessageBuilder()->incrementNonce(nonce);
|
||||||
QJsonObject message = buildMessage(newNonce);
|
QJsonObject message = browserMessageBuilder()->buildMessage(newNonce);
|
||||||
return buildResponse(action, message, 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)
|
QJsonObject BrowserAction::decryptMessage(const QString& message, const QString& nonce)
|
||||||
{
|
{
|
||||||
if (message.isEmpty() || nonce.isEmpty()) {
|
return browserMessageBuilder()->decryptMessage(message, nonce, m_clientPublicKey, m_secretKey);
|
||||||
return QJsonObject();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QByteArray ba = decrypt(message, nonce);
|
QJsonObject BrowserAction::getErrorReply(const QString& action, const int errorCode) const
|
||||||
if (ba.isEmpty()) {
|
|
||||||
return QJsonObject();
|
|
||||||
}
|
|
||||||
|
|
||||||
return getJsonObject(ba);
|
|
||||||
}
|
|
||||||
|
|
||||||
QString BrowserAction::encrypt(const QString& plaintext, const QString& nonce)
|
|
||||||
{
|
{
|
||||||
const QByteArray ma = plaintext.toUtf8();
|
return browserMessageBuilder()->getErrorReply(action, errorCode);
|
||||||
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) {
|
QJsonObject BrowserAction::buildResponse(const QString& action, const QJsonObject& message, const QString& nonce)
|
||||||
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);
|
return browserMessageBuilder()->buildResponse(action, message, nonce, m_clientPublicKey, m_secretKey);
|
||||||
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)
|
|
||||||
{
|
|
||||||
return QByteArray::fromBase64(str.toUtf8());
|
|
||||||
}
|
|
||||||
|
|
||||||
QString BrowserAction::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();
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
* 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
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
@ -21,23 +21,24 @@
|
||||||
#include <QString>
|
#include <QString>
|
||||||
|
|
||||||
class QJsonObject;
|
class QJsonObject;
|
||||||
|
class QLocalSocket;
|
||||||
|
|
||||||
class BrowserAction
|
class BrowserAction
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
explicit BrowserAction();
|
explicit BrowserAction() = default;
|
||||||
~BrowserAction() = default;
|
~BrowserAction() = default;
|
||||||
|
|
||||||
QJsonObject processClientMessage(const QJsonObject& json);
|
QJsonObject processClientMessage(QLocalSocket* socket, const QJsonObject& json);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QJsonObject handleAction(const QJsonObject& json);
|
QJsonObject handleAction(QLocalSocket* socket, const QJsonObject& json);
|
||||||
QJsonObject handleChangePublicKeys(const QJsonObject& json, const QString& action);
|
QJsonObject handleChangePublicKeys(const QJsonObject& json, const QString& action);
|
||||||
QJsonObject handleGetDatabaseHash(const QJsonObject& json, const QString& action);
|
QJsonObject handleGetDatabaseHash(const QJsonObject& json, const QString& action);
|
||||||
QJsonObject handleAssociate(const QJsonObject& json, const QString& action);
|
QJsonObject handleAssociate(const QJsonObject& json, const QString& action);
|
||||||
QJsonObject handleTestAssociate(const QJsonObject& json, const QString& action);
|
QJsonObject handleTestAssociate(const QJsonObject& json, const QString& action);
|
||||||
QJsonObject handleGetLogins(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 handleSetLogin(const QJsonObject& json, const QString& action);
|
||||||
QJsonObject handleLockDatabase(const QJsonObject& json, const QString& action);
|
QJsonObject handleLockDatabase(const QJsonObject& json, const QString& action);
|
||||||
QJsonObject handleGetDatabaseGroups(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 handleDeleteEntry(const QJsonObject& json, const QString& action);
|
||||||
QJsonObject handleGlobalAutoType(const QJsonObject& json, const QString& action);
|
QJsonObject handleGlobalAutoType(const QJsonObject& json, const QString& action);
|
||||||
|
|
||||||
|
private:
|
||||||
QJsonObject buildMessage(const QString& nonce) const;
|
QJsonObject buildMessage(const QString& nonce) const;
|
||||||
QJsonObject buildResponse(const QString& action, const QJsonObject& message, const QString& nonce);
|
QJsonObject buildResponse(const QString& action, const QJsonObject& message, const QString& nonce);
|
||||||
QJsonObject getErrorReply(const QString& action, const int errorCode) const;
|
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);
|
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:
|
private:
|
||||||
static const int MaxUrlLength;
|
static const int MaxUrlLength;
|
||||||
|
|
|
@ -88,20 +88,31 @@ void BrowserHost::readProxyMessage()
|
||||||
return;
|
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));
|
QString reply(QJsonDocument(json).toJson(QJsonDocument::Compact));
|
||||||
for (const auto socket : m_socketList) {
|
for (const auto socket : m_socketList) {
|
||||||
|
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) {
|
if (socket && socket->isValid() && socket->state() == QLocalSocket::ConnectedState) {
|
||||||
QByteArray arr = reply.toUtf8();
|
QByteArray arr = data.toUtf8();
|
||||||
socket->write(arr.constData(), arr.length());
|
socket->write(arr.constData(), arr.length());
|
||||||
socket->flush();
|
socket->flush();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
void BrowserHost::proxyDisconnected()
|
void BrowserHost::proxyDisconnected()
|
||||||
{
|
{
|
||||||
|
|
|
@ -24,6 +24,7 @@
|
||||||
|
|
||||||
class QLocalServer;
|
class QLocalServer;
|
||||||
class QLocalSocket;
|
class QLocalSocket;
|
||||||
|
class QString;
|
||||||
|
|
||||||
class BrowserHost : public QObject
|
class BrowserHost : public QObject
|
||||||
{
|
{
|
||||||
|
@ -36,16 +37,20 @@ public:
|
||||||
void start();
|
void start();
|
||||||
void stop();
|
void stop();
|
||||||
|
|
||||||
void sendClientMessage(const QJsonObject& json);
|
void broadcastClientMessage(const QJsonObject& json);
|
||||||
|
void sendClientMessage(QLocalSocket* socket, const QJsonObject& json);
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void clientMessageReceived(const QJsonObject& json);
|
void clientMessageReceived(QLocalSocket* socket, const QJsonObject& json);
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void proxyConnected();
|
void proxyConnected();
|
||||||
void readProxyMessage();
|
void readProxyMessage();
|
||||||
void proxyDisconnected();
|
void proxyDisconnected();
|
||||||
|
|
||||||
|
private:
|
||||||
|
void sendClientData(QLocalSocket* socket, const QString& data);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QPointer<QLocalServer> m_localServer;
|
QPointer<QLocalServer> m_localServer;
|
||||||
QList<QLocalSocket*> m_socketList;
|
QList<QLocalSocket*> m_socketList;
|
||||||
|
|
259
src/browser/BrowserMessageBuilder.cpp
Normal file
259
src/browser/BrowserMessageBuilder.cpp
Normal file
|
@ -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();
|
||||||
|
}
|
96
src/browser/BrowserMessageBuilder.h
Normal file
96
src/browser/BrowserMessageBuilder.h
Normal file
|
@ -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
|
|
@ -23,6 +23,7 @@
|
||||||
#include "BrowserEntryConfig.h"
|
#include "BrowserEntryConfig.h"
|
||||||
#include "BrowserEntrySaveDialog.h"
|
#include "BrowserEntrySaveDialog.h"
|
||||||
#include "BrowserHost.h"
|
#include "BrowserHost.h"
|
||||||
|
#include "BrowserMessageBuilder.h"
|
||||||
#include "BrowserSettings.h"
|
#include "BrowserSettings.h"
|
||||||
#include "core/Tools.h"
|
#include "core/Tools.h"
|
||||||
#include "gui/MainWindow.h"
|
#include "gui/MainWindow.h"
|
||||||
|
@ -39,6 +40,7 @@
|
||||||
#include <QJsonArray>
|
#include <QJsonArray>
|
||||||
#include <QJsonObject>
|
#include <QJsonObject>
|
||||||
#include <QListWidget>
|
#include <QListWidget>
|
||||||
|
#include <QLocalSocket>
|
||||||
#include <QProgressDialog>
|
#include <QProgressDialog>
|
||||||
#include <QUrl>
|
#include <QUrl>
|
||||||
|
|
||||||
|
@ -64,6 +66,7 @@ BrowserService::BrowserService()
|
||||||
, m_browserHost(new BrowserHost)
|
, m_browserHost(new BrowserHost)
|
||||||
, m_dialogActive(false)
|
, m_dialogActive(false)
|
||||||
, m_bringToFrontRequested(false)
|
, m_bringToFrontRequested(false)
|
||||||
|
, m_passwordGeneratorRequested(false)
|
||||||
, m_prevWindowState(WindowState::Normal)
|
, m_prevWindowState(WindowState::Normal)
|
||||||
, m_keepassBrowserUUID(Tools::hexToUuid("de887cc3036343b8974b5911b8816224"))
|
, m_keepassBrowserUUID(Tools::hexToUuid("de887cc3036343b8974b5911b8816224"))
|
||||||
{
|
{
|
||||||
|
@ -311,37 +314,55 @@ QString BrowserService::getCurrentTotp(const QString& uuid)
|
||||||
return {};
|
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) {
|
if (!m_passwordGenerator) {
|
||||||
m_passwordGenerator.reset(PasswordGeneratorWidget::popupGenerator());
|
m_passwordGenerator.reset(PasswordGeneratorWidget::popupGenerator());
|
||||||
|
|
||||||
connect(m_passwordGenerator.data(), &PasswordGeneratorWidget::closed, m_passwordGenerator.data(), [=] {
|
connect(m_passwordGenerator.data(), &PasswordGeneratorWidget::closed, m_passwordGenerator.data(), [=] {
|
||||||
if (!m_passwordGenerator->isPasswordGenerated()) {
|
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();
|
m_passwordGenerator.reset();
|
||||||
hideWindow();
|
hideWindow();
|
||||||
|
m_passwordGeneratorRequested = false;
|
||||||
});
|
});
|
||||||
|
|
||||||
connect(m_passwordGenerator.data(),
|
connect(m_passwordGenerator.data(),
|
||||||
&PasswordGeneratorWidget::appliedPassword,
|
&PasswordGeneratorWidget::appliedPassword,
|
||||||
m_passwordGenerator.data(),
|
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();
|
raiseWindow();
|
||||||
m_passwordGenerator->raise();
|
m_passwordGenerator->raise();
|
||||||
m_passwordGenerator->activateWindow();
|
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();
|
hideWindow();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool BrowserService::isPasswordGeneratorRequested() const
|
||||||
|
{
|
||||||
|
return m_passwordGeneratorRequested;
|
||||||
|
}
|
||||||
|
|
||||||
QString BrowserService::storeKey(const QString& key)
|
QString BrowserService::storeKey(const QString& key)
|
||||||
{
|
{
|
||||||
auto db = getDatabase();
|
auto db = getDatabase();
|
||||||
|
@ -1382,7 +1403,7 @@ void BrowserService::databaseLocked(DatabaseWidget* dbWidget)
|
||||||
if (dbWidget) {
|
if (dbWidget) {
|
||||||
QJsonObject msg;
|
QJsonObject msg;
|
||||||
msg["action"] = QString("database-locked");
|
msg["action"] = QString("database-locked");
|
||||||
m_browserHost->sendClientMessage(msg);
|
m_browserHost->broadcastClientMessage(msg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1396,7 +1417,7 @@ void BrowserService::databaseUnlocked(DatabaseWidget* dbWidget)
|
||||||
|
|
||||||
QJsonObject msg;
|
QJsonObject msg;
|
||||||
msg["action"] = QString("database-unlocked");
|
msg["action"] = QString("database-unlocked");
|
||||||
m_browserHost->sendClientMessage(msg);
|
m_browserHost->broadcastClientMessage(msg);
|
||||||
|
|
||||||
auto db = dbWidget->database();
|
auto db = dbWidget->database();
|
||||||
if (checkLegacySettings(db)) {
|
if (checkLegacySettings(db)) {
|
||||||
|
@ -1419,7 +1440,7 @@ void BrowserService::activeDatabaseChanged(DatabaseWidget* dbWidget)
|
||||||
m_currentDatabaseWidget = dbWidget;
|
m_currentDatabaseWidget = dbWidget;
|
||||||
}
|
}
|
||||||
|
|
||||||
void BrowserService::processClientMessage(const QJsonObject& message)
|
void BrowserService::processClientMessage(QLocalSocket* socket, const QJsonObject& message)
|
||||||
{
|
{
|
||||||
auto clientID = message["clientID"].toString();
|
auto clientID = message["clientID"].toString();
|
||||||
if (clientID.isEmpty()) {
|
if (clientID.isEmpty()) {
|
||||||
|
@ -1432,6 +1453,6 @@ void BrowserService::processClientMessage(const QJsonObject& message)
|
||||||
}
|
}
|
||||||
|
|
||||||
auto& action = m_browserClients.value(clientID);
|
auto& action = m_browserClients.value(clientID);
|
||||||
auto response = action->processClientMessage(message);
|
auto response = action->processClientMessage(socket, message);
|
||||||
m_browserHost->sendClientMessage(response);
|
m_browserHost->sendClientMessage(socket, response);
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,6 +23,8 @@
|
||||||
#include "core/Entry.h"
|
#include "core/Entry.h"
|
||||||
#include "gui/PasswordGeneratorWidget.h"
|
#include "gui/PasswordGeneratorWidget.h"
|
||||||
|
|
||||||
|
class QLocalSocket;
|
||||||
|
|
||||||
typedef QPair<QString, QString> StringPair;
|
typedef QPair<QString, QString> StringPair;
|
||||||
typedef QList<StringPair> StringPairList;
|
typedef QList<StringPair> StringPairList;
|
||||||
|
|
||||||
|
@ -56,8 +58,12 @@ public:
|
||||||
QJsonObject getDatabaseGroups();
|
QJsonObject getDatabaseGroups();
|
||||||
QJsonObject createNewGroup(const QString& groupName);
|
QJsonObject createNewGroup(const QString& groupName);
|
||||||
QString getCurrentTotp(const QString& uuid);
|
QString getCurrentTotp(const QString& uuid);
|
||||||
void showPasswordGenerator(const QJsonObject& errorMessage, const QString& nonce);
|
void showPasswordGenerator(QLocalSocket* socket,
|
||||||
void sendPassword(const QJsonObject& message);
|
const QString& nonce,
|
||||||
|
const QString& publicKey,
|
||||||
|
const QString& secretKey);
|
||||||
|
void sendPassword(QLocalSocket* socket, const QJsonObject& message);
|
||||||
|
bool isPasswordGeneratorRequested() const;
|
||||||
|
|
||||||
void addEntry(const QString& dbid,
|
void addEntry(const QString& dbid,
|
||||||
const QString& login,
|
const QString& login,
|
||||||
|
@ -97,7 +103,7 @@ public:
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void requestUnlock();
|
void requestUnlock();
|
||||||
void passwordGenerated(const QString& password, const QString& nonce);
|
void passwordGenerated(QLocalSocket* socket, const QString& password, const QString& nonce);
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void databaseLocked(DatabaseWidget* dbWidget);
|
void databaseLocked(DatabaseWidget* dbWidget);
|
||||||
|
@ -105,7 +111,7 @@ public slots:
|
||||||
void activeDatabaseChanged(DatabaseWidget* dbWidget);
|
void activeDatabaseChanged(DatabaseWidget* dbWidget);
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void processClientMessage(const QJsonObject& message);
|
void processClientMessage(QLocalSocket* socket, const QJsonObject& message);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
enum Access
|
enum Access
|
||||||
|
@ -163,6 +169,7 @@ private:
|
||||||
|
|
||||||
bool m_dialogActive;
|
bool m_dialogActive;
|
||||||
bool m_bringToFrontRequested;
|
bool m_bringToFrontRequested;
|
||||||
|
bool m_passwordGeneratorRequested;
|
||||||
WindowState m_prevWindowState;
|
WindowState m_prevWindowState;
|
||||||
QUuid m_keepassBrowserUUID;
|
QUuid m_keepassBrowserUUID;
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
# Copyright (C) 2017 Sami Vänttinen <sami.vanttinen@protonmail.com>
|
# 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
|
# 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
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
@ -23,6 +23,7 @@ if(WITH_XC_BROWSER)
|
||||||
BrowserEntryConfig.cpp
|
BrowserEntryConfig.cpp
|
||||||
BrowserEntrySaveDialog.cpp
|
BrowserEntrySaveDialog.cpp
|
||||||
BrowserHost.cpp
|
BrowserHost.cpp
|
||||||
|
BrowserMessageBuilder.cpp
|
||||||
BrowserSettingsPage.cpp
|
BrowserSettingsPage.cpp
|
||||||
BrowserSettingsWidget.cpp
|
BrowserSettingsWidget.cpp
|
||||||
BrowserService.cpp
|
BrowserService.cpp
|
||||||
|
|
|
@ -17,6 +17,7 @@
|
||||||
|
|
||||||
#include "TestBrowser.h"
|
#include "TestBrowser.h"
|
||||||
|
|
||||||
|
#include "browser/BrowserMessageBuilder.h"
|
||||||
#include "browser/BrowserSettings.h"
|
#include "browser/BrowserSettings.h"
|
||||||
#include "core/Group.h"
|
#include "core/Group.h"
|
||||||
#include "core/Tools.h"
|
#include "core/Tools.h"
|
||||||
|
@ -61,7 +62,7 @@ void TestBrowser::testChangePublicKeys()
|
||||||
json["publicKey"] = PUBLICKEY;
|
json["publicKey"] = PUBLICKEY;
|
||||||
json["nonce"] = NONCE;
|
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["action"].toString(), QString("change-public-keys"));
|
||||||
QCOMPARE(response["publicKey"].toString() == PUBLICKEY, false);
|
QCOMPARE(response["publicKey"].toString() == PUBLICKEY, false);
|
||||||
QCOMPARE(response["success"].toString(), TRUE_STR);
|
QCOMPARE(response["success"].toString(), TRUE_STR);
|
||||||
|
@ -75,7 +76,7 @@ void TestBrowser::testEncryptMessage()
|
||||||
m_browserAction->m_publicKey = SERVERPUBLICKEY;
|
m_browserAction->m_publicKey = SERVERPUBLICKEY;
|
||||||
m_browserAction->m_secretKey = SERVERSECRETKEY;
|
m_browserAction->m_secretKey = SERVERSECRETKEY;
|
||||||
m_browserAction->m_clientPublicKey = PUBLICKEY;
|
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"));
|
QCOMPARE(encrypted, QString("+zjtntnk4rGWSl/Ph7Vqip/swvgeupk4lNgHEm2OO3ujNr0OMz6eQtGwjtsj+/rP"));
|
||||||
}
|
}
|
||||||
|
@ -86,7 +87,7 @@ void TestBrowser::testDecryptMessage()
|
||||||
m_browserAction->m_publicKey = SERVERPUBLICKEY;
|
m_browserAction->m_publicKey = SERVERPUBLICKEY;
|
||||||
m_browserAction->m_secretKey = SERVERSECRETKEY;
|
m_browserAction->m_secretKey = SERVERSECRETKEY;
|
||||||
m_browserAction->m_clientPublicKey = PUBLICKEY;
|
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"));
|
QCOMPARE(decrypted["action"].toString(), QString("test-action"));
|
||||||
}
|
}
|
||||||
|
@ -99,13 +100,13 @@ void TestBrowser::testGetBase64FromKey()
|
||||||
pk[i] = i;
|
pk[i] = i;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto response = m_browserAction->getBase64FromKey(pk, crypto_box_PUBLICKEYBYTES);
|
auto response = browserMessageBuilder()->getBase64FromKey(pk, crypto_box_PUBLICKEYBYTES);
|
||||||
QCOMPARE(response, QString("AAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBkaGxwdHh8="));
|
QCOMPARE(response, QString("AAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBkaGxwdHh8="));
|
||||||
}
|
}
|
||||||
|
|
||||||
void TestBrowser::testIncrementNonce()
|
void TestBrowser::testIncrementNonce()
|
||||||
{
|
{
|
||||||
auto result = m_browserAction->incrementNonce(NONCE);
|
auto result = browserMessageBuilder()->incrementNonce(NONCE);
|
||||||
QCOMPARE(result, QString("zRKdvTjL5bgWaKMCTut/8soM/uoMrFoZ"));
|
QCOMPARE(result, QString("zRKdvTjL5bgWaKMCTut/8soM/uoMrFoZ"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue