2
src/3rdparty/sodium.h
vendored
2
src/3rdparty/sodium.h
vendored
@@ -1,4 +1,4 @@
|
||||
// Copyright 2019-2023 The Hush developers
|
||||
// Copyright 2019-2024 The Hush developers
|
||||
// Released under the GPLv3
|
||||
|
||||
#ifndef sodium_H
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2019-2023 The Hush developers
|
||||
// Copyright 2019-2024 The Hush developers
|
||||
// Released under the GPLv3
|
||||
|
||||
#include "Chat.h"
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2019-2023 The Hush developers
|
||||
// Copyright 2019-2024 The Hush developers
|
||||
// Released under the GPLv3
|
||||
#ifndef CHAT_H
|
||||
#define CHAT_H
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2019-2023 The Hush developers
|
||||
// Copyright 2019-2024 The Hush developers
|
||||
// GPLv3
|
||||
|
||||
#ifndef CHATDELEGATOR_H
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2019-2023 The Hush developers
|
||||
// Copyright 2019-2024 The Hush developers
|
||||
// Released under the GPLv3
|
||||
#include "FileEncryption.h"
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2019-2023 The Hush developers
|
||||
// Copyright 2019-2024 The Hush developers
|
||||
// Released under the GPLv3
|
||||
#ifndef FILEENCRYPTION_H
|
||||
#define FILEENCRYPTION_H
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2019-2023 The Hush developers
|
||||
// Copyright 2019-2024 The Hush developers
|
||||
// Released under the GPLv3
|
||||
#include "passwd.h"
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2019-2023 The Hush developers
|
||||
// Copyright 2019-2024 The Hush developers
|
||||
// Released under the GPLv3
|
||||
#ifndef PASSWD_H
|
||||
#define PASSWD_H
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2019-2023 The Hush developers
|
||||
// Copyright 2019-2024 The Hush developers
|
||||
// Released under the GPLv3
|
||||
|
||||
#include "ChatDataStore.h"
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2019-2023 The Hush developers
|
||||
// Copyright 2019-2024 The Hush developers
|
||||
// Released under the GPLv3
|
||||
#ifndef CHATDATASTORE_H
|
||||
#define CHATDATASTORE_H
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2019-2023 The Hush developers
|
||||
// Copyright 2019-2024 The Hush developers
|
||||
// GPLv3
|
||||
|
||||
#include "ContactDataStore.h"
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2019-2023 The Hush developers
|
||||
// Copyright 2019-2024 The Hush developers
|
||||
// Released under the GPLv3
|
||||
#ifndef CONTACTDATASTORE_H
|
||||
#define CONTACTDATASTORE_H
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2019-2023 The Hush developers
|
||||
// Copyright 2019-2024 The Hush developers
|
||||
// Released under the GPLv3
|
||||
#ifndef DATASTORE_H
|
||||
#define DATASTORE_H
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2019-2023 The Hush developers
|
||||
// Copyright 2019-2024 The Hush developers
|
||||
// Released under the GPLv3
|
||||
#include "DataStore.h"
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2019-2023 The Hush developers
|
||||
// Copyright 2019-2024 The Hush developers
|
||||
// Released under the GPLv3
|
||||
#ifndef DATASTORE_H
|
||||
#define DATASTORE_H
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2019-2023 The Hush developers
|
||||
// Copyright 2019-2024 The Hush developers
|
||||
// Released under the GPLv3
|
||||
#include "SietchDataStore.h"
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2019-2023 The Hush developers
|
||||
// Copyright 2019-2024 The Hush developers
|
||||
// Released under the GPLv3
|
||||
#ifndef SIETCHDATASTORE_H
|
||||
#define SIETCHDATASTORE_H
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2019-2023 The Hush developers
|
||||
// Copyright 2019-2024 The Hush developers
|
||||
// Released under the GPLv3
|
||||
#include "FileSystem.h"
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2019-2023 The Hush developers
|
||||
// Copyright 2019-2024 The Hush developers
|
||||
// GPLv3
|
||||
#ifndef FILESYSTEM_H
|
||||
#define FILESYSTEM_H
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2019-2023 The Hush developers
|
||||
// Copyright 2019-2024 The Hush developers
|
||||
// Released under the GPLv3
|
||||
#ifndef LOGCONTEXT_H
|
||||
#define LOGCONTEXT_H
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2019-2023 The Hush developers
|
||||
// Copyright 2019-2024 The Hush developers
|
||||
// Released under the GPLv3
|
||||
#ifndef LOGCRITICAL_H
|
||||
#define LOGCRITICAL_H
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2019-2023 The Hush developers
|
||||
// Copyright 2019-2024 The Hush developers
|
||||
// Released under the GPLv3
|
||||
#ifndef LOGDEBUG_H
|
||||
#define LOGDEBUG_H
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2019-2023 The Hush developers
|
||||
// Copyright 2019-2024 The Hush developers
|
||||
// Released under the GPLv3
|
||||
#ifndef LOGERROR_H
|
||||
#define LOGERROR_H
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2019-2023 The Hush developers
|
||||
// Copyright 2019-2024 The Hush developers
|
||||
// Released under the GPLv3
|
||||
#ifndef LOGFATAL_H
|
||||
#define LOGFATAL_H
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2019-2023 The Hush developers
|
||||
// Copyright 2019-2024 The Hush developers
|
||||
// Released under the GPLv3
|
||||
#ifndef LOGINFO_H
|
||||
#define LOGINFO_H
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2019-2023 The Hush developers
|
||||
// Copyright 2019-2024 The Hush developers
|
||||
// Released under the GPLv3
|
||||
#ifndef LOGSTRATEGY_H
|
||||
#define LOGSTRATEGY_H
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2019-2023 The Hush developers
|
||||
// Copyright 2019-2024 The Hush developers
|
||||
// Released under the GPLv3
|
||||
#ifndef LOGSUCCESS_H
|
||||
#define LOGSUCCESS_H
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2019-2023 The Hush developers
|
||||
// Copyright 2019-2024 The Hush developers
|
||||
// Released under the GPLv3
|
||||
#ifndef LOGTYPE_H
|
||||
#define LOGTYPE_H
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2019-2023 The Hush developers
|
||||
// Copyright 2019-2024 The Hush developers
|
||||
// Released under the GPLv3
|
||||
#ifndef LOGWARNING_H
|
||||
#define LOGWARNING_H
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2019-2023 The Hush developers
|
||||
// Copyright 2019-2024 The Hush developers
|
||||
// Released under the GPLv3
|
||||
#include "LogWriter.h"
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2019-2023 The Hush developers
|
||||
// Copyright 2019-2024 The Hush developers
|
||||
// Released under the GPLv3
|
||||
#ifndef LOGWRITER_H
|
||||
#define LOGWRITER_H
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2019-2023 The Hush developers
|
||||
// Copyright 2019-2024 The Hush developers
|
||||
// Released under the GPLv3
|
||||
#ifndef LOGGER_H
|
||||
#define LOGGER_H
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2019-2023 The Hush developers
|
||||
// Copyright 2019-2024 The Hush developers
|
||||
// Released under the GPLv3
|
||||
#ifndef SIMPLELOGGER_H
|
||||
#define SIMPLELOGGER_H
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2019-2023 The Hush developers
|
||||
// Copyright 2019-2024 The Hush developers
|
||||
// Released under the GPLv3
|
||||
#include "SimpleLogger.h"
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2019-2023 The Hush developers
|
||||
// Copyright 2019-2024 The Hush developers
|
||||
// Released under the GPLv3
|
||||
|
||||
#include "ChatItem.h"
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2019-2023 The Hush developers
|
||||
// Copyright 2019-2024 The Hush developers
|
||||
// Released under the GPLv3
|
||||
|
||||
#ifndef CHATITEM_H
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2019-2023 The Hush developers
|
||||
// Copyright 2019-2024 The Hush developers
|
||||
// GPLv3
|
||||
#include "ContactItem.h"
|
||||
#include "chatmodel.h"
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2019-2023 The Hush developers
|
||||
// Copyright 2019-2024 The Hush developers
|
||||
// Released under the GPLv3
|
||||
#ifndef CONTACTITEM_H
|
||||
#define CONTACTITEM_H
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2019-2023 The Hush developers
|
||||
// Copyright 2019-2024 The Hush developers
|
||||
// GPLv3
|
||||
|
||||
#include "ContactRequest.h"
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2019-2023 The Hush developers
|
||||
// Copyright 2019-2024 The Hush developers
|
||||
// Released under the GPLv3
|
||||
#ifndef CONTACTREQUEST_H
|
||||
#define CONTACTREQUEST_H
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
// Copyright 2019-2023 The Hush developers
|
||||
// Copyright 2019-2024 The Hush developers
|
||||
// Released under the GPLv3
|
||||
#include "ContactRequestChatItem.h"
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2019-2023 The Hush developers
|
||||
// Copyright 2019-2024 The Hush developers
|
||||
// Released under the GPLv3
|
||||
#ifdef CONTACTREQUESTCHATITEM_H
|
||||
#define CONTACTREQUESTCHATITEM_H
|
||||
|
||||
@@ -63,7 +63,7 @@
|
||||
<html><head><meta name="qrichtext" content="1" /><style type="text/css">
|
||||
p, li { white-space: pre-wrap; }
|
||||
</style></head><body style=" font-family:'Ubuntu'; font-size:11pt; font-weight:400; font-style:normal;">
|
||||
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Copyright (c) 2019-2023 The Hush developers GNU Public License V3</p>
|
||||
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Copyright (c) 2019-2024 The Hush developers GNU Public License V3</p>
|
||||
<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p>
|
||||
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Copyright (c) 2018-2019 Aditya Kulkarni, Duke Leto, Jane Mercer </p>
|
||||
<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2019-2023 The Hush developers
|
||||
// Copyright 2019-2024 The Hush developers
|
||||
// Released under the GPLv3
|
||||
|
||||
#include "addressbook.h"
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2019-2023 The Hush developers
|
||||
// Copyright 2019-2024 The Hush developers
|
||||
// Released under the GPLv3
|
||||
#ifndef ADDRESSBOOK_H
|
||||
#define ADDRESSBOOK_H
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2019-2023 The Hush developers
|
||||
// Copyright 2019-2024 The Hush developers
|
||||
// Released under the GPLv3
|
||||
#include "addresscombo.h"
|
||||
#include "addressbook.h"
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2019-2023 The Hush developers
|
||||
// Copyright 2019-2024 The Hush developers
|
||||
// Released under the GPLv3
|
||||
#ifndef ADDRESSCOMBO_H
|
||||
#define ADDRESSCOMBO_H
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2019-2023 The Hush developers
|
||||
// Copyright 2019-2024 The Hush developers
|
||||
// Released under the GPLv3
|
||||
#include "balancestablemodel.h"
|
||||
#include "addressbook.h"
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2019-2023 The Hush developers
|
||||
// Copyright 2019-2024 The Hush developers
|
||||
// Released under the GPLv3
|
||||
#ifndef BALANCESTABLEMODEL_H
|
||||
#define BALANCESTABLEMODEL_H
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2019-2023 The Hush developers
|
||||
// Copyright 2019-2024 The Hush developers
|
||||
// Released under the GPLv3
|
||||
#include "camount.h"
|
||||
#include "settings.h"
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2019-2023 The Hush developers
|
||||
// Copyright 2019-2024 The Hush developers
|
||||
// Released under the GPLv3
|
||||
#ifndef CAMOUNT_H
|
||||
#define CAMOUNT_H
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2019-2023 The Hush developers
|
||||
// Copyright 2019-2024 The Hush developers
|
||||
// Released under the GPLv3
|
||||
#include "chatbubbleme.h"
|
||||
#include "ui_chatbubbleme.h"
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2019-2023 The Hush developers
|
||||
// Copyright 2019-2024 The Hush developers
|
||||
// Released under the GPLv3
|
||||
#ifndef CHATBUBBLEME_H
|
||||
#define CHATBUBBLEME_H
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2019-2023 The Hush developers
|
||||
// Copyright 2019-2024 The Hush developers
|
||||
// Released under the GPLv3
|
||||
#include "chatbubblepartner.h"
|
||||
#include "ui_chatbubblepartner.h"
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2019-2023 The Hush developers
|
||||
// Copyright 2019-2024 The Hush developers
|
||||
// Released under the GPLv3
|
||||
#ifndef CHATBUBBLEPARTNER_H
|
||||
#define CHATBUBBLEPARTNER_H
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2019-2023 The Hush developers
|
||||
// Copyright 2019-2024 The Hush developers
|
||||
// Released under the GPLv3
|
||||
#include "chatmodel.h"
|
||||
#include "settings.h"
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2019-2023 The Hush developers
|
||||
// Copyright 2019-2024 The Hush developers
|
||||
// Released under the GPLv3
|
||||
|
||||
#ifndef CHATMODEL_H
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2019-2023 The Hush developers
|
||||
// Copyright 2019-2024 The Hush developers
|
||||
// Released under the GPLv3
|
||||
#include "connection.h"
|
||||
#include "mainwindow.h"
|
||||
@@ -9,6 +9,8 @@
|
||||
#include "controller.h"
|
||||
#include "../lib/silentdragonlitelib.h"
|
||||
#include "precompiled.h"
|
||||
#include <QThreadPool>
|
||||
#include "sdl.h"
|
||||
|
||||
using json = nlohmann::json;
|
||||
|
||||
@@ -32,7 +34,7 @@ ConnectionLoader::ConnectionLoader(MainWindow* main, Controller* rpc)
|
||||
connD->setupUi(d);
|
||||
|
||||
auto theme = Settings::getInstance()->get_theme_name();
|
||||
qDebug() << theme << "theme " << theme << " has loaded";
|
||||
DEBUG("theme " << theme << " has loaded");
|
||||
auto size = QSize(512,512);
|
||||
|
||||
if (theme == "Dark" || theme == "Midnight") {
|
||||
@@ -55,6 +57,7 @@ ConnectionLoader::ConnectionLoader(MainWindow* main, Controller* rpc)
|
||||
|
||||
ConnectionLoader::~ConnectionLoader()
|
||||
{
|
||||
DEBUG("destroying ConnectionLoader");
|
||||
delete isSyncing;
|
||||
delete connD;
|
||||
delete d;
|
||||
@@ -62,6 +65,7 @@ ConnectionLoader::~ConnectionLoader()
|
||||
|
||||
void ConnectionLoader::loadConnection()
|
||||
{
|
||||
DEBUG("calling doAutoConnect");
|
||||
QTimer::singleShot(1, [=]() { this->doAutoConnect(); });
|
||||
if (!Settings::getInstance()->isHeadless())
|
||||
d->exec();
|
||||
@@ -69,7 +73,22 @@ void ConnectionLoader::loadConnection()
|
||||
|
||||
void ConnectionLoader::loadProgress()
|
||||
{
|
||||
QTimer::singleShot(1, [=]() { this->ShowProgress(); });
|
||||
bool failed = false;
|
||||
QTimer::singleShot(1, [=]() mutable {
|
||||
DEBUG("failed=" << failed);
|
||||
// continually retry ShowProgress() until it succeeds
|
||||
// by running without an exception
|
||||
do {
|
||||
try {
|
||||
this->ShowProgress();
|
||||
failed = false;
|
||||
} catch (const std::exception& e) {
|
||||
DEBUG("caught exception " << e.what() );
|
||||
failed = true;
|
||||
}
|
||||
} while (failed);
|
||||
|
||||
});
|
||||
if (!Settings::getInstance()->isHeadless())
|
||||
d->exec();
|
||||
}
|
||||
@@ -83,56 +102,62 @@ void ConnectionLoader::ShowProgress()
|
||||
|
||||
auto connection = makeConnection(config);
|
||||
auto me = this;
|
||||
qDebug() << __func__ << ": server=" << config->server << " connection=" << connection << " me=" << me;
|
||||
DEBUG("server=" << config->server << " connection=" << connection << " me=" << me);
|
||||
|
||||
isSyncing = new QAtomicInteger<bool>();
|
||||
isSyncing->store(true);
|
||||
main->logger->write("isSyncing");
|
||||
|
||||
DEBUG("isSyncing");
|
||||
|
||||
// Do a sync after import
|
||||
syncTimer = new QTimer(main);
|
||||
main->logger->write("Beginning sync after import wif");
|
||||
connection->doRPCWithDefaultErrorHandling("sync", "", [=](auto) {
|
||||
DEBUG("Beginning sync after import wif");
|
||||
connection->doRPC("sync", "", [=](auto) {
|
||||
DEBUG("finished syncing");
|
||||
isSyncing->store(false);
|
||||
// Cancel the timer
|
||||
syncTimer->deleteLater();
|
||||
// When sync is done, set the connection
|
||||
this->doRPCSetConnectionShield(connection);
|
||||
}, [=](auto) {
|
||||
DEBUG("sync rpc error! server=" << config->server);
|
||||
});
|
||||
|
||||
|
||||
// While it is syncing, we'll show the status updates while it is alive.
|
||||
QObject::connect(syncTimer, &QTimer::timeout, [=]() {
|
||||
// Check the sync status
|
||||
DEBUG("Check the sync status");
|
||||
if (isSyncing != nullptr && isSyncing->load()) {
|
||||
// Get the sync status
|
||||
|
||||
DEBUG("Get the sync status");
|
||||
try {
|
||||
connection->doRPC("syncstatus", "", [=](json reply) {
|
||||
if (isSyncing != nullptr && reply.find("synced_blocks") != reply.end())
|
||||
|
||||
{
|
||||
qint64 synced = reply["synced_blocks"].get<json::number_unsigned_t>();
|
||||
qint64 total = reply["total_blocks"].get<json::number_unsigned_t>();
|
||||
me->showInformation(
|
||||
"Syncing... " + QString::number(synced) + " / " + QString::number(total)
|
||||
);
|
||||
}
|
||||
},
|
||||
[=](QString err) {
|
||||
qDebug() << "Sync error" << err;
|
||||
});
|
||||
}catch (...)
|
||||
{
|
||||
main->logger->write("catch sync progress reply");
|
||||
}
|
||||
|
||||
}
|
||||
});
|
||||
connection->doRPC("syncstatus", "", [=](json reply) {
|
||||
if (isSyncing != nullptr && reply.find("synced_blocks") != reply.end()) {
|
||||
qint64 synced = reply["synced_blocks"].get<json::number_unsigned_t>();
|
||||
qint64 total = reply["total_blocks"].get<json::number_unsigned_t>();
|
||||
me->showInformation(
|
||||
"Syncing... " + QString::number(synced) + " / " + QString::number(total)
|
||||
);
|
||||
}
|
||||
}, [=](QString err) {
|
||||
DEBUG("Sync error " << err);
|
||||
// We may have gotten "Unexpected compression flag: 60"
|
||||
// or some other error, so let's try another server
|
||||
config->server = Settings::getRandomServer();
|
||||
DEBUG("Changed server to " << config->server );
|
||||
});
|
||||
} catch (const std::exception& e) {
|
||||
DEBUG("syncstatus exception: " << e.what() );
|
||||
main->logger->write("catch sync progress reply");
|
||||
|
||||
syncTimer->setInterval(1* 1000);
|
||||
syncTimer->start();
|
||||
main->logger->write("Start sync timer");
|
||||
// rethrow exception so loadProgress can catch
|
||||
// it and retry the entire ShowProgress() function again
|
||||
throw new std::runtime_error(std::string("syncstatus failed"));
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
int interval = 1*1000;
|
||||
syncTimer->setInterval(interval);
|
||||
syncTimer->start();
|
||||
DEBUG("Start sync timer with interval=" << interval);
|
||||
}
|
||||
|
||||
void ConnectionLoader::doAutoConnect()
|
||||
@@ -140,43 +165,53 @@ void ConnectionLoader::doAutoConnect()
|
||||
auto config = std::shared_ptr<ConnectionConfig>(new ConnectionConfig());
|
||||
config->dangerous = false;
|
||||
config->server = Settings::getInstance()->getSettings().server;
|
||||
qDebug() << __func__ << " server=" << config->server;
|
||||
DEBUG(" server=" << config->server);
|
||||
|
||||
// Initialize the library
|
||||
main->logger->write(QObject::tr("Attempting to initialize library with ") + config->server);
|
||||
DEBUG("Attempting to initialize library with "<< config->server);
|
||||
|
||||
// Check to see if there's an existing wallet
|
||||
if (litelib_wallet_exists(Settings::getDefaultChainName().toStdString().c_str())) {
|
||||
qDebug() << __func__ << ": using existing wallet";
|
||||
DEBUG("using existing wallet");
|
||||
main->logger->write(QObject::tr("Using existing wallet."));
|
||||
char* resp = litelib_initialize_existing(
|
||||
config->dangerous,
|
||||
config->server.toStdString().c_str()
|
||||
);
|
||||
QString response = litelib_process_response(resp);
|
||||
|
||||
if (response.toUpper().trimmed() != "OK") {
|
||||
config->server = Settings::getRandomServer();
|
||||
|
||||
resp = litelib_initialize_existing(
|
||||
QString response = "";
|
||||
try {
|
||||
char* resp = litelib_initialize_existing(
|
||||
config->dangerous,
|
||||
config->server.toStdString().c_str()
|
||||
);
|
||||
response = litelib_process_response(resp);
|
||||
} catch (const std::exception& e) {
|
||||
DEBUG("caught an exception, ignoring: " << e.what());
|
||||
}
|
||||
|
||||
if (response.toUpper().trimmed() != "OK") {
|
||||
config->server = Settings::getRandomServer();
|
||||
|
||||
try {
|
||||
char* resp = litelib_initialize_existing(
|
||||
config->dangerous,
|
||||
config->server.toStdString().c_str()
|
||||
);
|
||||
response = litelib_process_response(resp);
|
||||
} catch (const std::exception& e) {
|
||||
DEBUG("caught an exception, ignoring: " << e.what());
|
||||
}
|
||||
|
||||
if (response.toUpper().trimmed() != "OK") {
|
||||
QString resp = "Error when connecting to " + config->server + ": " + response;
|
||||
showError(resp);
|
||||
return;
|
||||
} else {
|
||||
qDebug() << __func__ << ": Successfully connected to random server: " << config->server << " !!!";
|
||||
DEBUG("Successfully connected to random server: " << config->server << " !!!");
|
||||
}
|
||||
} else {
|
||||
qDebug() << __func__ << ": Successfully connected to " << config->server << " !!!";
|
||||
DEBUG("Successfully connected to " << config->server << " !!!");
|
||||
}
|
||||
|
||||
} else {
|
||||
qDebug() << __func__ << ": no existing wallet";
|
||||
DEBUG("no existing wallet");
|
||||
main->logger->write(QObject::tr("Create/restore wallet."));
|
||||
createOrRestore(config->dangerous, config->server);
|
||||
d->show();
|
||||
@@ -187,61 +222,77 @@ void ConnectionLoader::doAutoConnect()
|
||||
qDebug() << __func__ << ": server=" << config->server
|
||||
<< " connection=" << connection << " me=" << me << endl;
|
||||
|
||||
|
||||
// After the lib is initialized, try to do get info
|
||||
connection->doRPC("info", "", [=](auto reply) {
|
||||
// If success, set the connection
|
||||
main->logger->write("Connection is online.");
|
||||
DEBUG("Connection is online.");
|
||||
connection->setInfo(reply);
|
||||
main->logger->write("getting Connection reply");
|
||||
DEBUG("getting Connection reply");
|
||||
isSyncing = new QAtomicInteger<bool>();
|
||||
isSyncing->store(true);
|
||||
main->logger->write("isSyncing");
|
||||
DEBUG("isSyncing");
|
||||
|
||||
// Do a sync at startup
|
||||
syncTimer = new QTimer(main);
|
||||
main->logger->write("Beginning sync");
|
||||
connection->doRPCWithDefaultErrorHandling("sync", "", [=](auto) {
|
||||
DEBUG("Beginning sync");
|
||||
connection->doRPC("sync", "", [=](auto) {
|
||||
DEBUG("finished syncing");
|
||||
isSyncing->store(false);
|
||||
// Cancel the timer
|
||||
syncTimer->deleteLater();
|
||||
// When sync is done, set the connection
|
||||
this->doRPCSetConnection(connection);
|
||||
}, [=](auto) mutable {
|
||||
DEBUG("sync rpc error! server=" << config->server);
|
||||
// continually retry sync RPC until it succeeds
|
||||
// don't change server each time it fails
|
||||
bool failed = true;
|
||||
do {
|
||||
// config->server = Settings::getRandomServer();
|
||||
// auto connection = makeConnection(config);
|
||||
// DEBUG("changed server to " << config->server);
|
||||
connection->doRPC("sync", "", [=](auto) mutable {
|
||||
DEBUG("sync success with server=" << config->server);
|
||||
failed = false;
|
||||
isSyncing->store(false);
|
||||
// Cancel the timer
|
||||
syncTimer->deleteLater();
|
||||
// When sync is done, set the connection
|
||||
this->doRPCSetConnection(connection);
|
||||
}, [=](auto) {
|
||||
DEBUG("sync failed with server=" << config->server << " . continuing sync loop" );
|
||||
});
|
||||
} while (failed);
|
||||
});
|
||||
|
||||
// While it is syncing, we'll show the status updates while it is alive.
|
||||
QObject::connect(syncTimer, &QTimer::timeout, [=]() {
|
||||
// Check the sync status
|
||||
DEBUG("Check the sync status");
|
||||
if (isSyncing != nullptr && isSyncing->load()) {
|
||||
// Get the sync status
|
||||
|
||||
DEBUG("Getting the sync status");
|
||||
try {
|
||||
connection->doRPC("syncstatus", "", [=](json reply) {
|
||||
if (isSyncing != nullptr && reply.find("synced_blocks") != reply.end())
|
||||
|
||||
{
|
||||
if (isSyncing != nullptr && reply.find("synced_blocks") != reply.end()) {
|
||||
qint64 synced = reply["synced_blocks"].get<json::number_unsigned_t>();
|
||||
qint64 total = reply["total_blocks"].get<json::number_unsigned_t>();
|
||||
me->showInformation(
|
||||
"Syncing... " + QString::number(synced) + " / " + QString::number(total)
|
||||
);
|
||||
}
|
||||
},
|
||||
[=](QString err) {
|
||||
qDebug() << "Sync error" << err;
|
||||
});
|
||||
}catch (...)
|
||||
{
|
||||
main->logger->write("catch sync progress reply");
|
||||
|
||||
}
|
||||
|
||||
},
|
||||
[=](QString err) {
|
||||
DEBUG("syncstatus error" << err);
|
||||
});
|
||||
} catch (const std::exception& e) {
|
||||
DEBUG("caught exception from syncstatus: " << e.what());
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
syncTimer->setInterval(1* 1000);
|
||||
int interval = 1*1000;
|
||||
syncTimer->setInterval(interval);
|
||||
syncTimer->start();
|
||||
main->logger->write("Start sync timer");
|
||||
DEBUG("Start sync timer with interval=" << interval);
|
||||
|
||||
}, [=](QString err) {
|
||||
showError(err);
|
||||
@@ -255,13 +306,13 @@ void ConnectionLoader::createOrRestore(bool dangerous, QString server)
|
||||
d->hide();
|
||||
// Create a wizard
|
||||
FirstTimeWizard wizard(dangerous,server);
|
||||
main->logger->write("Start new Wallet with FirstimeWizard");
|
||||
DEBUG("Start new Wallet with FirstimeWizard");
|
||||
wizard.exec();
|
||||
}
|
||||
|
||||
void ConnectionLoader::doRPCSetConnection(Connection* conn)
|
||||
{
|
||||
qDebug() << "Connectionloader finished, setting connection";
|
||||
DEBUG("Connectionloader finished, setting connection");
|
||||
main->logger->write("Connectionloader finished, setting connection");
|
||||
rpc->setConnection(conn);
|
||||
d->accept();
|
||||
@@ -272,17 +323,16 @@ void ConnectionLoader::doRPCSetConnection(Connection* conn)
|
||||
main->logger->write("Path to Wallet.dat : " );
|
||||
qDebug() << __func__ << ": wallet path =" << plaintextWallet;
|
||||
plaintextWallet.remove();
|
||||
|
||||
} catch (...) {
|
||||
qDebug() << "No plaintext wallet found! file=" << plaintextWallet;
|
||||
} catch (const std::exception& e) {
|
||||
DEBUG("Caught exception" << e.what() );
|
||||
DEBUG("No plaintext wallet found! file=" << plaintextWallet);
|
||||
main->logger->write("no Plaintext wallet.dat");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void ConnectionLoader::doRPCSetConnectionShield(Connection* conn)
|
||||
{
|
||||
qDebug() << "Importing finished, setting connection";
|
||||
DEBUG("Importing finished, setting connection");
|
||||
rpc->setConnection(conn);
|
||||
d->accept();
|
||||
main->getRPC()->shield([=] (auto) {});
|
||||
@@ -293,9 +343,10 @@ void ConnectionLoader::doRPCSetConnectionShield(Connection* conn)
|
||||
main->logger->write("Path to Wallet.dat : " );
|
||||
qDebug() << __func__ << ": wallet path =" << plaintextWallet;
|
||||
plaintextWallet.remove();
|
||||
} catch (...) {
|
||||
} catch (const std::exception& e) {
|
||||
DEBUG("Caught exception" << e.what() );
|
||||
main->logger->write("no Plaintext wallet.dat");
|
||||
qDebug() << "No plaintext wallet found! file=" << plaintextWallet;
|
||||
DEBUG("No plaintext wallet found! file=" << plaintextWallet);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -346,19 +397,50 @@ QString litelib_process_response(char* resp)
|
||||
************************************************************************************/
|
||||
void Executor::run()
|
||||
{
|
||||
char* resp = litelib_execute(this->cmd.toStdString().c_str(), this->args.toStdString().c_str());
|
||||
QString reply = litelib_process_response(resp);
|
||||
auto parsed = json::parse(
|
||||
reply.toStdString().c_str(),
|
||||
nullptr,
|
||||
false
|
||||
);
|
||||
if (parsed.is_discarded() || parsed.is_null())
|
||||
emit handleError(reply);
|
||||
auto config = std::shared_ptr<ConnectionConfig>(new ConnectionConfig());
|
||||
DEBUG("cmd=" << cmd << " args=" << args << " server=" << config->server);
|
||||
QString response = "";
|
||||
try {
|
||||
char* resp = litelib_execute(this->cmd.toStdString().c_str(), this->args.toStdString().c_str());
|
||||
response = litelib_process_response(resp);
|
||||
} catch (const std::exception& e) {
|
||||
DEBUG("ignoring exception: " << e.what() );
|
||||
}
|
||||
|
||||
else
|
||||
//TODO: we can do stricter error checking
|
||||
if (response.isEmpty()) {
|
||||
config->server = Settings::getRandomServer();
|
||||
|
||||
try {
|
||||
char* resp = litelib_initialize_existing(
|
||||
config->dangerous,
|
||||
config->server.toStdString().c_str()
|
||||
);
|
||||
response = litelib_process_response(resp);
|
||||
resp = litelib_execute(this->cmd.toStdString().c_str(), this->args.toStdString().c_str());
|
||||
response = litelib_process_response(resp);
|
||||
} catch (const std::exception& e) {
|
||||
DEBUG("server= " << config->server << " gave exception: " << e.what() );
|
||||
emit handleError(response);
|
||||
}
|
||||
}
|
||||
try {
|
||||
auto parsed = json::parse(
|
||||
response.toStdString().c_str(),
|
||||
nullptr,
|
||||
false
|
||||
);
|
||||
|
||||
if (parsed.is_discarded() || parsed.is_null()) {
|
||||
emit handleError(response);
|
||||
} else {
|
||||
emit responseReady(parsed);
|
||||
}
|
||||
} catch (const std::exception& e) {
|
||||
DEBUG("exception when parsing json: " << e.what() );
|
||||
emit handleError(response);
|
||||
}
|
||||
|
||||
emit responseReady(parsed);
|
||||
}
|
||||
|
||||
void Callback::processRPCCallback(json resp)
|
||||
@@ -386,11 +468,12 @@ Connection::Connection(MainWindow* m, std::shared_ptr<ConnectionConfig> conf)
|
||||
|
||||
void Connection::doRPC(const QString cmd, const QString args, const std::function<void(json)>& cb, const std::function<void(QString)>& errCb)
|
||||
{
|
||||
if (shutdownInProgress)
|
||||
// Ignoring RPC because shutdown in progress
|
||||
if (shutdownInProgress) {
|
||||
DEBUG("Ignoring RPC because shutdown in progress");
|
||||
return;
|
||||
}
|
||||
|
||||
qDebug() << __func__ << ": " << cmd;
|
||||
DEBUG("cmd=" << cmd << " args=" << args);
|
||||
|
||||
// Create a runner.
|
||||
auto runner = new Executor(cmd, args);
|
||||
@@ -405,7 +488,7 @@ void Connection::doRPC(const QString cmd, const QString args, const std::functio
|
||||
|
||||
void Connection::doRPCWithDefaultErrorHandling(const QString cmd, const QString args, const std::function<void(json)>& cb)
|
||||
{
|
||||
qDebug() << __func__ << ": " << cmd;
|
||||
DEBUG("cmd=" << cmd << " args=" << args);
|
||||
doRPC(cmd, args, cb, [=] (QString err) {
|
||||
this->showTxError(err);
|
||||
});
|
||||
@@ -413,7 +496,7 @@ void Connection::doRPCWithDefaultErrorHandling(const QString cmd, const QString
|
||||
|
||||
void Connection::doRPCIgnoreError(const QString cmd, const QString args, const std::function<void(json)>& cb)
|
||||
{
|
||||
qDebug() << __func__ << ": " << cmd;
|
||||
DEBUG("cmd=" << cmd << " args=" << args);
|
||||
doRPC(cmd, args, cb, [=] (auto) {
|
||||
// Ignored error handling
|
||||
});
|
||||
@@ -445,5 +528,6 @@ void Connection::showTxError(const QString& error)
|
||||
*/
|
||||
void Connection::shutdown()
|
||||
{
|
||||
DEBUG("shutting down");
|
||||
shutdownInProgress = true;
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2019-2023 The Hush developers
|
||||
// Copyright 2019-2024 The Hush developers
|
||||
// Released under the GPLv3
|
||||
#ifndef CONNECTION_H
|
||||
#define CONNECTION_H
|
||||
@@ -6,6 +6,7 @@
|
||||
#include "mainwindow.h"
|
||||
#include "ui_connection.h"
|
||||
#include "precompiled.h"
|
||||
#include <QRunnable>
|
||||
|
||||
using json = nlohmann::json;
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2019-2023 The Hush developers
|
||||
// Copyright 2019-2024 The Hush developers
|
||||
// GPLv3
|
||||
|
||||
#include "contactmodel.h"
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2019-2023 The Hush developers
|
||||
// Copyright 2019-2024 The Hush developers
|
||||
// Released under the GPLv3
|
||||
#ifndef CONTACTMODEL_H
|
||||
#define CONTACTMODEL_H
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2019-2023 The Hush developers
|
||||
// Copyright 2019-2024 The Hush developers
|
||||
// Released under the GPLv3
|
||||
|
||||
#include "controller.h"
|
||||
@@ -7,7 +7,6 @@
|
||||
#include "settings.h"
|
||||
#include "version.h"
|
||||
#include "camount.h"
|
||||
#include "websockets.h"
|
||||
#include "Model/ChatItem.h"
|
||||
#include "DataStore/DataStore.h"
|
||||
|
||||
@@ -262,10 +261,12 @@ void Controller::noConnection()
|
||||
|
||||
// Clear balances
|
||||
ui->balSheilded->setText("");
|
||||
ui->balUnconfirmed->setText("");
|
||||
ui->balTransparent->setText("");
|
||||
ui->balTotal->setText("");
|
||||
|
||||
ui->balSheilded->setToolTip("");
|
||||
ui->balUnconfirmed->setToolTip("");
|
||||
ui->balTransparent->setToolTip("");
|
||||
ui->balTotal->setToolTip("");
|
||||
}
|
||||
@@ -298,12 +299,19 @@ void Controller::processInfo(const json& info)
|
||||
main->disableRecurring();
|
||||
}
|
||||
|
||||
void Controller::getInfoThenRefresh(bool force)
|
||||
void Controller::getInfoThenRefresh(bool force)
|
||||
{
|
||||
qDebug()<< __func__;
|
||||
if (!zrpc->haveConnection())
|
||||
if (!zrpc->haveConnection())
|
||||
return noConnection();
|
||||
|
||||
// Update current server in Info Tab
|
||||
auto current_server = Settings::getInstance()->getSettings().server;
|
||||
ui->current_server->setText(current_server);
|
||||
|
||||
// no need to update sticky server because currently there is no
|
||||
// way to change that at run-time via GUI
|
||||
|
||||
static bool prevCallSucceeded = false;
|
||||
|
||||
zrpc->fetchInfo([=] (const json& reply) {
|
||||
@@ -732,6 +740,7 @@ void Controller::updateUIBalances()
|
||||
{
|
||||
CAmount balT = getModel()->getBalT();
|
||||
CAmount balZ = getModel()->getBalZ();
|
||||
CAmount balU = getModel()->getBalU();
|
||||
CAmount balVerified = getModel()->getBalVerified();
|
||||
CAmount balSpendable = getModel()->getBalSpendable();
|
||||
|
||||
@@ -749,6 +758,7 @@ void Controller::updateUIBalances()
|
||||
// Balances table
|
||||
ui->balSheilded->setText(balZ.toDecimalhushString());
|
||||
ui->balVerified->setText(balVerified.toDecimalhushString());
|
||||
ui->balUnconfirmed->setText(balU.toDecimalhushString());
|
||||
ui->balTransparent->setText(balT.toDecimalhushString());
|
||||
ui->balSpendable->setText(balSpendable.toDecimalhushString());
|
||||
ui->balTotal->setText(balTotal.toDecimalhushString());
|
||||
@@ -888,17 +898,16 @@ void Controller::refreshBalances()
|
||||
zrpc->fetchBalance([=] (json reply) {
|
||||
CAmount balT = CAmount::fromqint64(reply["tbalance"].get<json::number_unsigned_t>());
|
||||
CAmount balZ = CAmount::fromqint64(reply["zbalance"].get<json::number_unsigned_t>());
|
||||
CAmount balU = CAmount::fromqint64(reply["unconfirmed"].get<json::number_unsigned_t>());
|
||||
CAmount balVerified = CAmount::fromqint64(reply["verified_zbalance"].get<json::number_unsigned_t>());
|
||||
CAmount balSpendable = CAmount::fromqint64(reply["spendable_zbalance"].get<json::number_unsigned_t>());
|
||||
|
||||
model->setBalT(balT);
|
||||
model->setBalZ(balZ);
|
||||
model->setBalU(balU);
|
||||
model->setBalVerified(balVerified);
|
||||
model->setBalSpendable(balSpendable);
|
||||
|
||||
// This is for the websockets
|
||||
AppDataModel::getInstance()->setBalances(balT, balZ);
|
||||
|
||||
// This is for the datamodel
|
||||
CAmount balAvailable = balT + balVerified;
|
||||
model->setAvailableBalance(balAvailable);
|
||||
@@ -933,6 +942,26 @@ void Controller::refreshBalances()
|
||||
});
|
||||
}
|
||||
|
||||
void printJsonValue(QTextStream& out, const nlohmann::json& j, int depth = 0) {
|
||||
if (j.is_array()) {
|
||||
for (auto& elem : j) {
|
||||
printJsonValue(out, elem, depth + 1);
|
||||
}
|
||||
} else if (j.is_object()) {
|
||||
for (auto it = j.begin(); it != j.end(); ++it) {
|
||||
std::string key = it.key();
|
||||
const nlohmann::json& value = it.value();
|
||||
out << QString::fromStdString(std::string(depth * 4, ' '))
|
||||
<< QString::fromStdString(key) << ": ";
|
||||
printJsonValue(out, value, depth + 1);
|
||||
}
|
||||
} else {
|
||||
out << QString::fromStdString(j.dump(4)) << "\n";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void Controller::refreshTransactions() {
|
||||
qDebug()<< __func__;
|
||||
if (!zrpc->haveConnection())
|
||||
@@ -1044,7 +1073,6 @@ void Controller::refreshTransactions() {
|
||||
|
||||
#define MESSAGEAS1 ((const unsigned char *) hashEncryptionKeyraw) ///////////
|
||||
#define MESSAGEAS1_LEN length
|
||||
|
||||
unsigned char sk[crypto_kx_SECRETKEYBYTES];
|
||||
unsigned char pk[crypto_kx_PUBLICKEYBYTES];
|
||||
|
||||
@@ -1058,9 +1086,7 @@ void Controller::refreshTransactions() {
|
||||
unsigned char server_rx[crypto_kx_SESSIONKEYBYTES], server_tx[crypto_kx_SESSIONKEYBYTES];
|
||||
|
||||
////////////////Get the pubkey from Bob, so we can create the share key
|
||||
|
||||
/////Create the shared key for sending the message
|
||||
|
||||
if (crypto_kx_server_session_keys(server_rx, server_tx, pk, sk, pubkeyBob) != 0)
|
||||
{
|
||||
main->logger->write("Suspicious client public outgoing key, bail out ");
|
||||
@@ -1082,15 +1108,11 @@ void Controller::refreshTransactions() {
|
||||
{
|
||||
//////unsigned char* as message from QString
|
||||
#define MESSAGE2 (const unsigned char *) encryptedMemo
|
||||
|
||||
///////// length of the encrypted message
|
||||
#define CIPHERTEXT1_LEN encryptedMemoSize1
|
||||
|
||||
///////Message length is smaller then the encrypted message
|
||||
#define MESSAGE1_LEN encryptedMemoSize1 - crypto_secretstream_xchacha20poly1305_ABYTES
|
||||
|
||||
//////Set the length of the decrypted message
|
||||
|
||||
unsigned char decrypted[MESSAGE1_LEN];
|
||||
unsigned char tag[crypto_secretstream_xchacha20poly1305_TAG_FINAL];
|
||||
crypto_secretstream_xchacha20poly1305_state state;
|
||||
@@ -1118,7 +1140,6 @@ void Controller::refreshTransactions() {
|
||||
|
||||
/////Now we can convert it to QString
|
||||
//////////////Give us the output of the decrypted message as debug to see if it was successfully
|
||||
|
||||
ChatItem item = ChatItem(
|
||||
datetime,
|
||||
address,
|
||||
@@ -1161,13 +1182,13 @@ void Controller::refreshTransactions() {
|
||||
} else {
|
||||
|
||||
{ // Incoming Transaction
|
||||
address = (it["address"].is_null() ? "" : QString::fromStdString(it["address"]));
|
||||
model->markAddressUsed(address);
|
||||
QString memo;
|
||||
address = (it["address"].is_null() ? "" : QString::fromStdString(it["address"]));
|
||||
|
||||
QString memo;
|
||||
if (!it["memo"].is_null()) {
|
||||
memo = QString::fromStdString(it["memo"]);
|
||||
}
|
||||
|
||||
items.push_back(TransactionItemDetail{ address,
|
||||
CAmount::fromqint64(it["amount"].get<json::number_integer_t>()),
|
||||
memo
|
||||
@@ -1187,7 +1208,7 @@ void Controller::refreshTransactions() {
|
||||
QString contactname = "";
|
||||
bool isContact = false;
|
||||
|
||||
if (!it["memo"].is_null()) {
|
||||
if (!memo.isNull()) {
|
||||
|
||||
if (memo.startsWith("{")) {
|
||||
try {
|
||||
@@ -1257,7 +1278,8 @@ void Controller::refreshTransactions() {
|
||||
if (position == 1)
|
||||
{
|
||||
chatModel->addMemo(txid, headerbytes);
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
//
|
||||
}
|
||||
|
||||
@@ -1273,7 +1295,6 @@ void Controller::refreshTransactions() {
|
||||
|
||||
#define MESSAGEAS1 ((const unsigned char *) hashEncryptionKeyraw)///////////
|
||||
#define MESSAGEAS1_LEN length
|
||||
|
||||
unsigned char sk[crypto_kx_SECRETKEYBYTES];
|
||||
unsigned char pk[crypto_kx_PUBLICKEYBYTES];
|
||||
|
||||
@@ -1287,7 +1308,6 @@ void Controller::refreshTransactions() {
|
||||
unsigned char client_rx[crypto_kx_SESSIONKEYBYTES], client_tx[crypto_kx_SESSIONKEYBYTES];
|
||||
|
||||
////////////////Get the pubkey from Bob, so we can create the share key
|
||||
|
||||
/////Create the shared key for sending the message
|
||||
if (crypto_kx_client_session_keys(client_rx, client_tx, pk, sk, pubkeyBob) != 0)
|
||||
{
|
||||
@@ -1304,18 +1324,13 @@ void Controller::refreshTransactions() {
|
||||
|
||||
int encryptedMemoSize1 = ba.length();
|
||||
//int headersize = ba1.length();
|
||||
|
||||
//////unsigned char* as message from QString
|
||||
#define MESSAGE2 (const unsigned char *) encryptedMemo
|
||||
|
||||
///////// length of the encrypted message
|
||||
#define CIPHERTEXT1_LEN encryptedMemoSize1
|
||||
|
||||
///////Message length is smaller then the encrypted message
|
||||
#define MESSAGE1_LEN encryptedMemoSize1 - crypto_secretstream_xchacha20poly1305_ABYTES
|
||||
|
||||
//////Set the length of the decrypted message
|
||||
|
||||
unsigned char decrypted[MESSAGE1_LEN+1];
|
||||
unsigned char tag[crypto_secretstream_xchacha20poly1305_TAG_FINAL];
|
||||
crypto_secretstream_xchacha20poly1305_state state;
|
||||
@@ -1343,7 +1358,6 @@ void Controller::refreshTransactions() {
|
||||
memodecrypt = QString::fromUtf8( decryptedMemo.data(), decryptedMemo.size());
|
||||
|
||||
////Give us the output of the decrypted message as debug to see if it was successfully
|
||||
|
||||
ChatItem item = ChatItem(
|
||||
datetime,
|
||||
address,
|
||||
@@ -1367,8 +1381,6 @@ void Controller::refreshTransactions() {
|
||||
qDebug() << __func__ << ": ignoring txid="<< txid;
|
||||
}
|
||||
|
||||
//} else if (memo.startsWith("{")) {
|
||||
//qDebug() << __func__ << ": ignoring a header memo";
|
||||
} else {
|
||||
// Add a chatitem for the initial CR
|
||||
ChatItem item = ChatItem(
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2019-2023 The Hush developers
|
||||
// Copyright 2019-2024 The Hush developers
|
||||
// Released under the GPLv3
|
||||
#include "datamodel.h"
|
||||
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
// Copyright 2019-2023 The Hush developers
|
||||
// Copyright 2019-2024 The Hush developers
|
||||
// Released under the GPLv3
|
||||
#ifndef DATAMODEL_H
|
||||
#define DATAMODEL_H
|
||||
|
||||
#include "camount.h"
|
||||
#include "precompiled.h"
|
||||
|
||||
#include <QReadLocker>
|
||||
|
||||
struct UnspentOutput {
|
||||
QString address;
|
||||
@@ -48,6 +48,9 @@ public:
|
||||
CAmount getBalZ() { QReadLocker locker(lock); return balZ; }
|
||||
void setBalZ(CAmount a) { QReadLocker locker(lock); this->balZ = a; }
|
||||
|
||||
CAmount getBalU() { QReadLocker locker(lock); return balU; }
|
||||
void setBalU(CAmount a) { QReadLocker locker(lock); this->balU = a; }
|
||||
|
||||
CAmount getBalVerified() { QReadLocker locker(lock); return balVerified; }
|
||||
void setBalVerified(CAmount a) { QReadLocker locker(lock); this->balVerified = a; }
|
||||
|
||||
@@ -76,6 +79,7 @@ private:
|
||||
|
||||
CAmount balT;
|
||||
CAmount balZ;
|
||||
CAmount balU;
|
||||
CAmount balVerified;
|
||||
CAmount balSpendable;
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2019-2023 The Hush developers
|
||||
// Copyright 2019-2024 The Hush developers
|
||||
// Released under the GPLv3
|
||||
#ifndef FILLEDICONLABEL_H
|
||||
#define FILLEDICONLABEL_H
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2019-2023 The Hush developers
|
||||
// Copyright 2019-2024 The Hush developers
|
||||
// Released under the GPLv3
|
||||
#include "firsttimewizard.h"
|
||||
#include "ui_newseed.h"
|
||||
@@ -293,10 +293,28 @@ void NewSeedPage::initializePage() {
|
||||
// Call the library to create a new wallet.
|
||||
qDebug() << __func__;
|
||||
|
||||
char* resp = litelib_initialize_new(parent->dangerous,parent->server.toStdString().c_str());
|
||||
QString reply = litelib_process_response(resp);
|
||||
QString reply = "";
|
||||
try {
|
||||
char* resp = litelib_initialize_new(parent->dangerous,parent->server.toStdString().c_str());
|
||||
reply = litelib_process_response(resp);
|
||||
} catch (const std::exception& e) {
|
||||
qDebug() << __func__ << ": caught an exception, ignoring: " << e.what();
|
||||
}
|
||||
|
||||
qDebug() << __func__ << ": reply=" << reply;
|
||||
|
||||
if (reply.isEmpty()) {
|
||||
qDebug() << "Lite server " << parent->server << " is down, getting a random one";
|
||||
parent->server = Settings::getRandomServer();
|
||||
qDebug() << __func__ << ": new server is " << parent->server;
|
||||
|
||||
// retry with the new server
|
||||
// we use litelib_initialize_existing because the call to litelib_initialize_new above
|
||||
// has already created a wallet on disk
|
||||
char* resp = litelib_initialize_existing(parent->dangerous,parent->server.toStdString().c_str());
|
||||
reply = litelib_process_response(resp);
|
||||
}
|
||||
|
||||
auto parsed = json::parse(reply.toStdString().c_str(), nullptr, false);
|
||||
if (parsed.is_discarded() || parsed.is_null() || parsed.find("seed") == parsed.end()) {
|
||||
form.txtSeed->setPlainText(tr("Error creating a wallet") + "\n" + reply);
|
||||
@@ -607,21 +625,49 @@ bool NewSeedPage::validatePage() {
|
||||
|
||||
dialog.exec();
|
||||
|
||||
if ((verifyseed.verify->toPlainText() == seed) && (verifyseed.verifyBirthday->toPlainText() == birthday))
|
||||
{
|
||||
char* resp = litelib_execute("save", "");
|
||||
QString reply = litelib_process_response(resp);
|
||||
QString reply = "";
|
||||
if ((verifyseed.verify->toPlainText() == seed) && (verifyseed.verifyBirthday->toPlainText() == birthday)) {
|
||||
try {
|
||||
char* resp = litelib_execute("save", "");
|
||||
reply = litelib_process_response(resp);
|
||||
} catch (const std::exception& e) {
|
||||
qDebug() << __func__ << ": caught an exception, ignoring: " << e.what();
|
||||
}
|
||||
|
||||
auto parsed = json::parse(reply.toStdString().c_str(), nullptr, false);
|
||||
if (parsed.is_discarded() || parsed.is_null() || parsed.find("result") == parsed.end()) {
|
||||
qDebug() << __func__ << ": reply=" << reply;
|
||||
|
||||
QMessageBox::warning(this, tr("Failed to save wallet"),
|
||||
tr("Couldn't save the wallet") + "\n" + reply,
|
||||
QMessageBox::Ok);
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
// TODO: this is duplicated code that should be refactored
|
||||
// into a dedicated function
|
||||
if (reply.isEmpty()) {
|
||||
qDebug() << "Lite server " << parent->server << " is down, getting a random one";
|
||||
parent->server = Settings::getRandomServer();
|
||||
qDebug() << __func__ << ": new server is " << parent->server;
|
||||
|
||||
// make a new connection to the new server
|
||||
char* resp = litelib_initialize_new(parent->dangerous,parent->server.toStdString().c_str());
|
||||
reply = litelib_process_response(resp);
|
||||
|
||||
// retry with the new server
|
||||
try {
|
||||
resp = litelib_execute("save", "");
|
||||
reply = litelib_process_response(resp);
|
||||
} catch (const std::exception& e) {
|
||||
qDebug() << __func__ << ": caught an exception with new server, something is fucky: " << e.what();
|
||||
}
|
||||
}
|
||||
|
||||
qDebug() << __func__ << ": reply=" << reply;
|
||||
|
||||
auto parsed = json::parse(reply.toStdString().c_str(), nullptr, false);
|
||||
if (parsed.is_discarded() || parsed.is_null() || parsed.find("result") == parsed.end()) {
|
||||
|
||||
QMessageBox::warning(this, tr("Failed to save wallet"),
|
||||
tr("Couldn't save the wallet") + "\n" + "server=" + parent->server + "\n" + reply,
|
||||
QMessageBox::Ok);
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}else{
|
||||
qDebug()<<"Wrong Seed";
|
||||
QFile file(dirwalletencfirst);
|
||||
@@ -629,9 +675,7 @@ bool NewSeedPage::validatePage() {
|
||||
|
||||
file.remove();
|
||||
file1.remove();
|
||||
QMessageBox::warning(this, tr("Wrong Seed"),
|
||||
tr("Please try again") + "\n" ,
|
||||
QMessageBox::Ok);
|
||||
QMessageBox::warning(this, tr("Wrong Seed"), tr("Please try again") + "\n" , QMessageBox::Ok);
|
||||
form.birthday->setVisible(true);
|
||||
form.txtSeed->setVisible(true);
|
||||
return false;
|
||||
@@ -686,32 +730,79 @@ bool RestoreSeedPage::validatePage() {
|
||||
qint64 number = number_str.toUInt();
|
||||
// 3. Attempt to restore wallet with the seed phrase
|
||||
{
|
||||
char* resp = litelib_initialize_new_from_phrase(parent->dangerous, parent->server.toStdString().c_str(),
|
||||
seed.toStdString().c_str(), birthday, number);
|
||||
QString reply = litelib_process_response(resp);
|
||||
QString reply = "";
|
||||
try {
|
||||
char* resp = litelib_initialize_new_from_phrase(parent->dangerous, parent->server.toStdString().c_str(),
|
||||
seed.toStdString().c_str(), birthday, number);
|
||||
reply = litelib_process_response(resp);
|
||||
} catch (const std::exception& e) {
|
||||
qDebug() << __func__ << ": caught an exception, ignoring: " << e.what();
|
||||
}
|
||||
|
||||
qDebug() << __func__ << ": reply=" << reply;
|
||||
|
||||
if (reply.toUpper().trimmed() != "OK") {
|
||||
QMessageBox::warning(this, tr("Failed to restore wallet"),
|
||||
tr("Couldn't restore the wallet") + "\n" + reply,
|
||||
qDebug() << "Lite server " << parent->server << " is down, getting a random one";
|
||||
parent->server = Settings::getRandomServer();
|
||||
qDebug() << __func__ << ": new server is " << parent->server;
|
||||
|
||||
// retry with the new server
|
||||
char* resp = litelib_initialize_new_from_phrase(parent->dangerous, parent->server.toStdString().c_str(),
|
||||
seed.toStdString().c_str(), birthday, number);
|
||||
reply = litelib_process_response(resp);
|
||||
}
|
||||
|
||||
|
||||
if (reply.toUpper().trimmed() != "OK") {
|
||||
QMessageBox::warning(this, tr("Failed to restore wallet"),
|
||||
tr("Couldn't restore the wallet") + "\n" + "server=" + parent->server + "\n" + reply,
|
||||
QMessageBox::Ok);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 4. Finally attempt to save the wallet
|
||||
{
|
||||
char* resp = litelib_execute("save", "");
|
||||
QString reply = litelib_process_response(resp);
|
||||
QString reply = "";
|
||||
try {
|
||||
char* resp = litelib_execute("save", "");
|
||||
reply = litelib_process_response(resp);
|
||||
} catch (const std::exception& e) {
|
||||
qDebug() << __func__ << ": caught an exception, ignoring: " << e.what();
|
||||
}
|
||||
|
||||
// TODO: this is duplicated code that should be refactored
|
||||
// into a dedicated function
|
||||
if (reply.isEmpty()) {
|
||||
qDebug() << "Lite server " << parent->server << " is down, getting a random one";
|
||||
parent->server = Settings::getRandomServer();
|
||||
qDebug() << __func__ << ": new server is " << parent->server;
|
||||
|
||||
// make a new connection to the new server
|
||||
char* resp = litelib_initialize_new_from_phrase(parent->dangerous, parent->server.toStdString().c_str(),
|
||||
seed.toStdString().c_str(), birthday, number);
|
||||
reply = litelib_process_response(resp);
|
||||
|
||||
// retry with the new server
|
||||
try {
|
||||
resp = litelib_execute("save", "");
|
||||
reply = litelib_process_response(resp);
|
||||
} catch (const std::exception& e) {
|
||||
qDebug() << __func__ << ": caught an exception with new server, something is fucky: " << e.what();
|
||||
}
|
||||
}
|
||||
|
||||
qDebug() << __func__ << ": reply=" << reply;
|
||||
|
||||
auto parsed = json::parse(reply.toStdString().c_str(), nullptr, false);
|
||||
if (parsed.is_discarded() || parsed.is_null() || parsed.find("result") == parsed.end()) {
|
||||
qDebug() << __func__ << ": Failed to save wallet, reply=" << reply;
|
||||
QMessageBox::warning(this, tr("Failed to save wallet"),
|
||||
tr("Couldn't save the wallet") + "\n" + reply,
|
||||
QMessageBox::warning(this, tr("Failed to save wallet"),
|
||||
tr("Couldn't save the wallet") + "\n" + "server=" + parent->server + "\n" + reply,
|
||||
QMessageBox::Ok);
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2019-2023 The Hush developers
|
||||
// Copyright 2019-2024 The Hush developers
|
||||
// Released under the GPLv3
|
||||
#ifndef FIRSTTIMEWIZARD_H
|
||||
#define FIRSTTIMEWIZARD_H
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2019-2023 The Hush developers
|
||||
// Copyright 2019-2024 The Hush developers
|
||||
// Released under the GPLv3
|
||||
#include "liteinterface.h"
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2019-2023 The Hush developers
|
||||
// Copyright 2019-2024 The Hush developers
|
||||
// Released under the GPLv3
|
||||
#ifndef hushDRPC_H
|
||||
#define hushDRPC_H
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2019-2023 The Hush developers
|
||||
// Copyright 2019-2024 The Hush developers
|
||||
// Released under the GPLv3
|
||||
#include "logger.h"
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2019-2023 The Hush developers
|
||||
// Copyright 2019-2024 The Hush developers
|
||||
// Released under the GPLv3
|
||||
#ifndef LOGGER_H
|
||||
#define LOGGER_H
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2019-2023 The Hush developers
|
||||
// Copyright 2019-2024 The Hush developers
|
||||
// Released under the GPLv3
|
||||
#include <singleapplication.h>
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
#include "mainwindow.h"
|
||||
#include "controller.h"
|
||||
#include "settings.h"
|
||||
#include <QCommandLineParser>
|
||||
|
||||
#include "version.h"
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2019-2023 The Hush developers
|
||||
// Copyright 2019-2024 The Hush developers
|
||||
// Released under the GPLv3
|
||||
#include "mainwindow.h"
|
||||
#include "addressbook.h"
|
||||
@@ -25,7 +25,6 @@
|
||||
#include "ui_startupencryption.h"
|
||||
#include "ui_removeencryption.h"
|
||||
#include "ui_seedrestore.h"
|
||||
#include "websockets.h"
|
||||
#include "sodium.h"
|
||||
#include "sodium/crypto_generichash_blake2b.h"
|
||||
#include <QRegularExpression>
|
||||
@@ -38,6 +37,7 @@
|
||||
#include <QCoreApplication>
|
||||
#include <QGuiApplication>
|
||||
#include <QKeyEvent>
|
||||
#include "sdl.h"
|
||||
|
||||
using json = nlohmann::json;
|
||||
|
||||
@@ -159,11 +159,11 @@ MainWindow::MainWindow(QWidget *parent) :
|
||||
|
||||
// Rescan
|
||||
QObject::connect(ui->actionRescan, &QAction::triggered, [=]() {
|
||||
|
||||
Ui_Restore restoreSeed;
|
||||
QDialog dialog(this);
|
||||
restoreSeed.setupUi(&dialog);
|
||||
Settings::saveRestore(&dialog);
|
||||
DEBUG("rescan action triggered");
|
||||
Ui_Restore restoreSeed;
|
||||
QDialog dialog(this);
|
||||
restoreSeed.setupUi(&dialog);
|
||||
Settings::saveRestore(&dialog);
|
||||
|
||||
rpc->fetchSeed([=](json reply) {
|
||||
if (isJsonError(reply)) {
|
||||
@@ -209,35 +209,74 @@ MainWindow::MainWindow(QWidget *parent) :
|
||||
config->server = Settings::getInstance()->getSettings().server;
|
||||
// 3. Attempt to restore wallet with the seed phrase
|
||||
{
|
||||
char* resp = litelib_initialize_new_from_phrase(config->dangerous, config->server.toStdString().c_str(),
|
||||
seed.toStdString().c_str(), birthday, number);
|
||||
QString reply = litelib_process_response(resp);
|
||||
QString reply = "";
|
||||
try {
|
||||
char* resp = litelib_initialize_new_from_phrase(config->dangerous, config->server.toStdString().c_str(),
|
||||
seed.toStdString().c_str(), birthday, number);
|
||||
reply = litelib_process_response(resp);
|
||||
} catch (const std::exception& e) {
|
||||
qDebug() << __func__ << ": caught an exception, ignoring: " << e.what();
|
||||
}
|
||||
|
||||
if (reply.toUpper().trimmed() != "OK") {
|
||||
QMessageBox::warning(this, tr("Failed to restore wallet"),
|
||||
tr("Couldn't restore the wallet") + "\n" + reply,
|
||||
qDebug() << "Lite server " << config->server << " is down, getting a random one";
|
||||
config->server = Settings::getRandomServer();
|
||||
qDebug() << __func__ << ": new server is " << config->server;
|
||||
// retry with the new server
|
||||
char* resp = litelib_initialize_new_from_phrase(config->dangerous,config->server.toStdString().c_str(),
|
||||
seed.toStdString().c_str(), birthday, number);
|
||||
reply = litelib_process_response(resp);
|
||||
}
|
||||
|
||||
if (reply.toUpper().trimmed() != "OK") {
|
||||
QMessageBox::warning(this, tr("Failed to restore wallet"),
|
||||
tr("Couldn't restore the wallet") + "\n" + "server=" + config->server + "\n" + reply,
|
||||
QMessageBox::Ok);
|
||||
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// 4. Finally attempt to save the wallet
|
||||
{
|
||||
char* resp = litelib_execute("save", "");
|
||||
QString reply = litelib_process_response(resp);
|
||||
QString reply = "";
|
||||
try {
|
||||
char* resp = litelib_execute("save", "");
|
||||
QString reply = litelib_process_response(resp);
|
||||
} catch (const std::exception& e) {
|
||||
qDebug() << __func__ << ": caught an exception, ignoring: " << e.what();
|
||||
}
|
||||
|
||||
if (reply.isEmpty()) {
|
||||
qDebug() << "Lite server " << config->server << " is down, getting a random one";
|
||||
config->server = Settings::getRandomServer();
|
||||
qDebug() << __func__ << ": new server is " << config->server;
|
||||
// make a new connection to the new server
|
||||
char* resp = litelib_initialize_new_from_phrase(config->dangerous,config->server.toStdString().c_str(),
|
||||
seed.toStdString().c_str(), birthday, number);
|
||||
reply = litelib_process_response(resp);
|
||||
|
||||
// retry with the new server
|
||||
try {
|
||||
resp = litelib_execute("save", "");
|
||||
reply = litelib_process_response(resp);
|
||||
} catch (const std::exception& e) {
|
||||
qDebug() << __func__ << ": caught an exception with new server, something is fucky: " << e.what();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
QByteArray ba_reply = reply.toUtf8();
|
||||
QJsonDocument jd_reply = QJsonDocument::fromJson(ba_reply);
|
||||
QJsonObject parsed = jd_reply.object();
|
||||
|
||||
if (parsed.isEmpty() || parsed["result"].isNull()) {
|
||||
QMessageBox::warning(this, tr("Failed to save wallet"),
|
||||
tr("Couldn't save the wallet") + "\n" + reply,
|
||||
QMessageBox::warning(this, tr("Failed to save wallet"),
|
||||
tr("Couldn't save the wallet") + "\n" + "server=" + config->server + "\n" + reply,
|
||||
QMessageBox::Ok);
|
||||
|
||||
} else {
|
||||
qDebug() << __func__ << ": saved wallet correctly";
|
||||
}
|
||||
}
|
||||
|
||||
dialog.close();
|
||||
// To rescan, we clear the wallet state, and then reload the connection
|
||||
@@ -250,15 +289,14 @@ MainWindow::MainWindow(QWidget *parent) :
|
||||
// Then reload the connection. The ConnectionLoader deletes itself.
|
||||
auto cl = new ConnectionLoader(this, rpc);
|
||||
cl->loadConnection();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
dialog.exec();
|
||||
});
|
||||
}); // actionReason
|
||||
|
||||
// Import Privkey
|
||||
QObject::connect(ui->actionImport_Privatkey, &QAction::triggered, this, &MainWindow::importPrivKey);
|
||||
@@ -294,16 +332,6 @@ MainWindow::MainWindow(QWidget *parent) :
|
||||
|
||||
restoreSavedStates();
|
||||
|
||||
if (AppDataServer::getInstance()->isAppConnected()) {
|
||||
qDebug() << __func__ << ": app is connected to wormhole";
|
||||
auto ads = AppDataServer::getInstance();
|
||||
|
||||
QString wormholecode = "";
|
||||
if (ads->getAllowInternetConnection())
|
||||
wormholecode = ads->getWormholeCode(ads->getSecretHex());
|
||||
|
||||
createWebsocket(wormholecode);
|
||||
}
|
||||
}
|
||||
|
||||
bool MainWindow::fileExists(QString path)
|
||||
@@ -312,36 +340,6 @@ bool MainWindow::fileExists(QString path)
|
||||
return (check_file.exists() && check_file.isFile());
|
||||
}
|
||||
|
||||
void MainWindow::createWebsocket(QString wormholecode) {
|
||||
qDebug() << "Listening for app connections on port 8777";
|
||||
// Create the websocket server, for listening to direct connections
|
||||
wsserver = new WSServer(8777, false, this);
|
||||
|
||||
if (!wormholecode.isEmpty()) {
|
||||
// Connect to the wormhole service
|
||||
wormhole = new WormholeClient(this, wormholecode);
|
||||
}
|
||||
}
|
||||
|
||||
void MainWindow::stopWebsocket() {
|
||||
delete wsserver;
|
||||
wsserver = nullptr;
|
||||
|
||||
delete wormhole;
|
||||
wormhole = nullptr;
|
||||
|
||||
qDebug() << "Websockets for app connections shut down";
|
||||
}
|
||||
|
||||
bool MainWindow::isWebsocketListening() {
|
||||
return wsserver != nullptr;
|
||||
}
|
||||
|
||||
void MainWindow::replaceWormholeClient(WormholeClient* newClient) {
|
||||
delete wormhole;
|
||||
wormhole = newClient;
|
||||
}
|
||||
|
||||
void MainWindow::restoreSavedStates() {
|
||||
QSettings s;
|
||||
restoreGeometry(s.value("geometry").toByteArray());
|
||||
@@ -933,7 +931,7 @@ void MainWindow::doImport(QList<QString>* keys) {
|
||||
keys->pop_front();
|
||||
//bool rescan = keys->isEmpty();
|
||||
|
||||
if (key.startsWith("SK") || key.startsWith("secret")) {
|
||||
if (key.startsWith("secret")) {
|
||||
rpc->importZPrivKey(key, [=] (auto) { this->doImport(keys); });
|
||||
} else if (key.startsWith("U") || key.startsWith("5") || key.startsWith("L") || key.startsWith("K")) {
|
||||
// 5 = uncompressed, len=51
|
||||
@@ -1097,10 +1095,10 @@ void MainWindow::payhushURI(QString uri, QString myAddr) {
|
||||
// Save the wallet
|
||||
this->getRPC()->saveWallet([=] (auto) {
|
||||
// Then reload the connection. The ConnectionLoader deletes itself.
|
||||
auto cl = new ConnectionLoader(this, rpc);
|
||||
auto cl = new ConnectionLoader(this, rpc);
|
||||
cl->loadProgress();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
}else if ((pui.rescan->isChecked() == true) && (pui.privKeyTxt->toPlainText().startsWith("secret"))){
|
||||
|
||||
@@ -2724,8 +2722,6 @@ MainWindow::~MainWindow()
|
||||
delete loadingMovie;
|
||||
delete logger;
|
||||
|
||||
delete wsserver;
|
||||
delete wormhole;
|
||||
}
|
||||
void MainWindow::on_givemeZaddr_clicked()
|
||||
{
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2019-2023 The Hush developers
|
||||
// Copyright 2019-2024 The Hush developers
|
||||
// Released under the GPLv3
|
||||
#ifndef MAINWINDOW_H
|
||||
#define MAINWINDOW_H
|
||||
@@ -14,8 +14,6 @@ using json = nlohmann::json;
|
||||
// Forward declare to break circular dependency.
|
||||
class Controller;
|
||||
class Settings;
|
||||
class WSServer;
|
||||
class WormholeClient;
|
||||
class ChatModel;
|
||||
|
||||
|
||||
@@ -70,10 +68,6 @@ public:
|
||||
|
||||
|
||||
|
||||
void replaceWormholeClient(WormholeClient* newClient);
|
||||
bool isWebsocketListening();
|
||||
void createWebsocket(QString wormholecode);
|
||||
void stopWebsocket();
|
||||
void saveContact();
|
||||
void saveandsendContact();
|
||||
void showRequesthush();
|
||||
@@ -200,10 +194,6 @@ private:
|
||||
bool uiPaymentsReady = false;
|
||||
QString pendingURIPayment;
|
||||
|
||||
WSServer* wsserver = nullptr;
|
||||
WormholeClient* wormhole = nullptr;
|
||||
|
||||
|
||||
Controller* rpc = nullptr;
|
||||
|
||||
QCompleter* labelCompleter = nullptr;
|
||||
|
||||
@@ -641,6 +641,33 @@
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
||||
<item>
|
||||
<widget class="QLabel" name="label_2">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Minimum" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Unconfirmed</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="balUnconfirmed">
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="3" column="0">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_2_1">
|
||||
<item>
|
||||
<widget class="QLabel" name="label_2_1">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Minimum" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
@@ -664,7 +691,7 @@
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="3" column="0">
|
||||
<item row="4" column="0">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_20">
|
||||
<item>
|
||||
<widget class="QLabel" name="label_40">
|
||||
@@ -691,14 +718,14 @@
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="4" column="0">
|
||||
<item row="5" column="0">
|
||||
<widget class="Line" name="line">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="0">
|
||||
<item row="6" column="0">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_3">
|
||||
<item>
|
||||
<widget class="QLabel" name="label_3">
|
||||
@@ -735,7 +762,7 @@
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="6" column="0">
|
||||
<item row="7" column="0">
|
||||
<widget class="QLabel" name="lblSyncWarning">
|
||||
<property name="styleSheet">
|
||||
<string notr="true">color:red;</string>
|
||||
@@ -748,7 +775,7 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="7" column="0">
|
||||
<item row="8" column="0">
|
||||
<widget class="QLabel" name="unconfirmedWarning">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Minimum" vsizetype="Preferred">
|
||||
@@ -767,14 +794,14 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="8" column="0">
|
||||
<item row="9" column="0">
|
||||
<widget class="QPushButton" name="depositHushButton">
|
||||
<property name="text">
|
||||
<string>Deposit Hush</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="9" column="0">
|
||||
<item row="10" column="0">
|
||||
<spacer name="verticalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2019-2023 The Hush developers
|
||||
// Copyright 2019-2024 The Hush developers
|
||||
// Released under the GPLv3
|
||||
#include "memoedit.h"
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2019-2023 The Hush developers
|
||||
// Copyright 2019-2024 The Hush developers
|
||||
// Released under the GPLv3
|
||||
#ifndef MEMOEDIT_H
|
||||
#define MEMOEDIT_H
|
||||
|
||||
@@ -1,16 +0,0 @@
|
||||
// Copyright 2019-2023 The Hush developers
|
||||
// Released under the GPLv3
|
||||
#include "mobileappconnector.h"
|
||||
#include "ui_mobileappconnector.h"
|
||||
|
||||
MobileAppConnector::MobileAppConnector(QWidget *parent) :
|
||||
QDialog(parent),
|
||||
ui(new Ui::MobileAppConnector)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
}
|
||||
|
||||
MobileAppConnector::~MobileAppConnector()
|
||||
{
|
||||
delete ui;
|
||||
}
|
||||
@@ -1,24 +0,0 @@
|
||||
// Copyright 2019-2023 The Hush developers
|
||||
// Released under the GPLv3
|
||||
#ifndef MOBILEAPPCONNECTOR_H
|
||||
#define MOBILEAPPCONNECTOR_H
|
||||
|
||||
#include <QDialog>
|
||||
|
||||
namespace Ui {
|
||||
class MobileAppConnector;
|
||||
}
|
||||
|
||||
class MobileAppConnector : public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit MobileAppConnector(QWidget *parent = nullptr);
|
||||
~MobileAppConnector();
|
||||
|
||||
private:
|
||||
Ui::MobileAppConnector *ui;
|
||||
};
|
||||
|
||||
#endif // MOBILEAPPCONNECTOR_H
|
||||
@@ -1,214 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>MobileAppConnector</class>
|
||||
<widget class="QDialog" name="MobileAppConnector">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>800</width>
|
||||
<height>530</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Mobile Connector App</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<item row="4" column="1" colspan="2">
|
||||
<widget class="QDialogButtonBox" name="buttonBox">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="standardButtons">
|
||||
<set>QDialogButtonBox::Close</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0" colspan="3">
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Minimum">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Scan this QRCode from your silentdragon companion app to connect your phone</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0" colspan="2">
|
||||
<widget class="QGroupBox" name="groupBox_2">
|
||||
<property name="title">
|
||||
<string>QR Code</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout_3">
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="label_2">
|
||||
<property name="text">
|
||||
<string>Connection String</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QLineEdit" name="txtConnStr">
|
||||
<property name="font">
|
||||
<font>
|
||||
<pointsize>9</pointsize>
|
||||
</font>
|
||||
</property>
|
||||
<property name="readOnly">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0">
|
||||
<widget class="QRCodeLabel" name="qrcode">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="MinimumExpanding">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="styleSheet">
|
||||
<string notr="true">background-color: #fff</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="0">
|
||||
<widget class="QCheckBox" name="chkInternetConn">
|
||||
<property name="text">
|
||||
<string>Allow connections over the internet via silentdragon wormhole</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="2" rowspan="2">
|
||||
<widget class="QGroupBox" name="groupBox">
|
||||
<property name="title">
|
||||
<string>silentdragon Companion App</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout_2">
|
||||
<item row="5" column="0">
|
||||
<widget class="QPushButton" name="btnDisconnect">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Disconnect</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="6" column="0">
|
||||
<spacer name="verticalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>40</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QLabel" name="lblLastSeen">
|
||||
<property name="text">
|
||||
<string>TextLabel</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="label_3">
|
||||
<property name="text">
|
||||
<string>Last seen:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="lblRemoteName">
|
||||
<property name="text">
|
||||
<string notr="true">TextLabel</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="0">
|
||||
<widget class="QLabel" name="label_4">
|
||||
<property name="text">
|
||||
<string>Connection type:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="0">
|
||||
<widget class="QLabel" name="lblConnectionType">
|
||||
<property name="text">
|
||||
<string>TextLabel</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<customwidgets>
|
||||
<customwidget>
|
||||
<class>QRCodeLabel</class>
|
||||
<extends>QLabel</extends>
|
||||
<header>qrcodelabel.h</header>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
<resources/>
|
||||
<connections>
|
||||
<connection>
|
||||
<sender>buttonBox</sender>
|
||||
<signal>accepted()</signal>
|
||||
<receiver>MobileAppConnector</receiver>
|
||||
<slot>accept()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>248</x>
|
||||
<y>254</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>157</x>
|
||||
<y>274</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>buttonBox</sender>
|
||||
<signal>rejected()</signal>
|
||||
<receiver>MobileAppConnector</receiver>
|
||||
<slot>reject()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>316</x>
|
||||
<y>260</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>286</x>
|
||||
<y>274</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
</connections>
|
||||
</ui>
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2019-2023 The Hush developers
|
||||
// Copyright 2019-2024 The Hush developers
|
||||
// Released under the GPLv3
|
||||
#if defined __cplusplus
|
||||
/* Add C++ includes here */
|
||||
@@ -64,7 +64,6 @@
|
||||
#include <QtNetwork/QNetworkRequest>
|
||||
#include <QtNetwork/QNetworkAccessManager>
|
||||
#include <QtNetwork/QNetworkReply>
|
||||
#include <QtWebSockets/QtWebSockets>
|
||||
#include <QJsonDocument>
|
||||
#include <QJsonArray>
|
||||
#include <QJsonObject>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2019-2023 The Hush developers
|
||||
// Copyright 2019-2024 The Hush developers
|
||||
// Released under the GPLv3
|
||||
#include "qrcodelabel.h"
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2019-2023 The Hush developers
|
||||
// Copyright 2019-2024 The Hush developers
|
||||
// Released under the GPLv3
|
||||
#ifndef QRCODELABEL_H
|
||||
#define QRCODELABEL_H
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2019-2023 The Hush developers
|
||||
// Copyright 2019-2024 The Hush developers
|
||||
// Released under the GPLv3
|
||||
#include "recurring.h"
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2019-2023 The Hush developers
|
||||
// Copyright 2019-2024 The Hush developers
|
||||
// Released under the GPLv3
|
||||
#ifndef RECURRING_H
|
||||
#define RECURRING_H
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2019-2023 The Hush developers
|
||||
// Copyright 2019-2024 The Hush developers
|
||||
// Released under the GPLv3
|
||||
#include "requestdialog.h"
|
||||
#include "ui_requestdialog.h"
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2019-2023 The Hush developers
|
||||
// Copyright 2019-2024 The Hush developers
|
||||
// Released under the GPLv3
|
||||
#ifndef REQUESTDIALOG_H
|
||||
#define REQUESTDIALOG_H
|
||||
|
||||
@@ -40,7 +40,7 @@ RUN cd /opt && rm qt-everywhere-src-5.11.2.tar.xz && rm -rf qt-everywhere-src-5.
|
||||
RUN cd /opt && \
|
||||
git clone https://github.com/mxe/mxe.git && \
|
||||
cd /opt/mxe && \
|
||||
make -j$(nproc) MXE_TARGETS=x86_64-w64-mingw32.static qtbase qtwebsockets
|
||||
make -j$(nproc) MXE_TARGETS=x86_64-w64-mingw32.static qtbase
|
||||
|
||||
# Add rust
|
||||
RUN apt install -y gcc-aarch64-linux-gnu
|
||||
|
||||
1
src/sdl.h
Normal file
1
src/sdl.h
Normal file
@@ -0,0 +1 @@
|
||||
#define DEBUG(x) (qDebug() << QString(__func__) << ": " << x)
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2019-2023 The Hush developers
|
||||
// Copyright 2019-2024 The Hush developers
|
||||
// Released under the GPLv3
|
||||
#include "mainwindow.h"
|
||||
#include "ui_mainwindow.h"
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
// Copyright 2019-2023 The Hush developers
|
||||
// Copyright 2019-2024 The Hush developers
|
||||
// Released under the GPLv3
|
||||
#include "mainwindow.h"
|
||||
#include "settings.h"
|
||||
#include "camount.h"
|
||||
#include "../lib/silentdragonlitelib.h"
|
||||
#include <QUrlQuery>
|
||||
|
||||
Settings* Settings::instance = nullptr;
|
||||
|
||||
@@ -36,9 +37,14 @@ Config Settings::getSettings() {
|
||||
if (server.trimmed().isEmpty()) {
|
||||
server = Settings::getRandomServer();
|
||||
|
||||
QString response = "";
|
||||
// make sure existing server in conf is alive, otherwise choose random one
|
||||
char* resp = litelib_initialize_existing(false, server.toStdString().c_str());
|
||||
QString response = litelib_process_response(resp);
|
||||
try {
|
||||
char* resp = litelib_initialize_existing(false, server.toStdString().c_str());
|
||||
response = litelib_process_response(resp);
|
||||
} catch (const std::exception& e) {
|
||||
qDebug() << __func__ << ": caught an exception, ignoring: " << e.what();
|
||||
}
|
||||
|
||||
if (response.toUpper().trimmed() != "OK") {
|
||||
qDebug() << "Lite server in conf " << server << " is down, getting a random one";
|
||||
@@ -310,14 +316,14 @@ QString Settings::getRandomServer() {
|
||||
// We try every server,in order, starting from a random place in the list
|
||||
while (tries < servers.size() ) {
|
||||
qDebug() << "Checking if lite server " << server << " is a alive, try=" << tries;
|
||||
char* resp = litelib_initialize_existing(false, server.toStdString().c_str());
|
||||
|
||||
QString response = "";
|
||||
|
||||
try {
|
||||
char* resp = litelib_initialize_existing(false, server.toStdString().c_str());
|
||||
response = litelib_process_response(resp);
|
||||
} catch (const std::exception& e) {
|
||||
qDebug() << __func__ << ": litelib_process_response threw an exception, ignoring: " << e.what();
|
||||
qDebug() << __func__ << ": caught an exception, ignoring: " << e.what();
|
||||
}
|
||||
|
||||
// if we see a valid connection, return this server
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2019-2023 The Hush developers
|
||||
// Copyright 2019-2024 The Hush developers
|
||||
// Released under the GPLv3
|
||||
#ifndef SETTINGS_H
|
||||
#define SETTINGS_H
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2019-2023 The Hush developers
|
||||
// Copyright 2019-2024 The Hush developers
|
||||
// Released under the GPLv3
|
||||
#include "txtablemodel.h"
|
||||
#include "settings.h"
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2019-2023 The Hush developers
|
||||
// Copyright 2019-2024 The Hush developers
|
||||
// Released under the GPLv3
|
||||
#ifndef STRINGSTABLEMODEL_H
|
||||
#define STRINGSTABLEMODEL_H
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
// Copyright 2019-2023 The Hush developers
|
||||
// Copyright 2019-2024 The Hush developers
|
||||
// Released under the GPLv3
|
||||
#define APP_VERSION "1.5.3"
|
||||
#define APP_VERSION "1.5.4"
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2019-2023 The Hush developers
|
||||
// Copyright 2019-2024 The Hush developers
|
||||
// Released under the GPLv3
|
||||
#include "viewalladdresses.h"
|
||||
#include "camount.h"
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2019-2023 The Hush developers
|
||||
// Copyright 2019-2024 The Hush developers
|
||||
// Released under the GPLv3
|
||||
#ifndef VIEWALLADDRESSES_H
|
||||
#define VIEWALLADDRESSES_H
|
||||
|
||||
@@ -1,940 +0,0 @@
|
||||
// Copyright 2019-2023 The Hush developers
|
||||
// Released under the GPLv3
|
||||
#include "websockets.h"
|
||||
#include "controller.h"
|
||||
#include "settings.h"
|
||||
#include "ui_mobileappconnector.h"
|
||||
#include "version.h"
|
||||
|
||||
// Weap the sendTextMessage to check if the connection is valid and that the parent WebServer didn't close this connection
|
||||
// for some reason.
|
||||
void ClientWebSocket::sendTextMessage(QString m) {
|
||||
if (client) {
|
||||
if (server && !server->isValidConnection(client)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (client->isValid())
|
||||
client->sendTextMessage(m);
|
||||
}
|
||||
}
|
||||
|
||||
WSServer::WSServer(quint16 port, bool debug, QObject *parent) :
|
||||
QObject(parent),
|
||||
m_pWebSocketServer(new QWebSocketServer(QStringLiteral("Direct Connection Server"),
|
||||
QWebSocketServer::NonSecureMode, this)),
|
||||
m_debug(debug)
|
||||
{
|
||||
m_mainWindow = (MainWindow *) parent;
|
||||
if (m_pWebSocketServer->listen(QHostAddress::AnyIPv4, port)) {
|
||||
if (m_debug)
|
||||
qDebug() << "Echoserver listening on port" << port;
|
||||
connect(m_pWebSocketServer, &QWebSocketServer::newConnection,
|
||||
this, &WSServer::onNewConnection);
|
||||
connect(m_pWebSocketServer, &QWebSocketServer::closed, this, &WSServer::closed);
|
||||
}
|
||||
}
|
||||
|
||||
WSServer::~WSServer()
|
||||
{
|
||||
qDebug() << "Closing websocket server";
|
||||
m_pWebSocketServer->close();
|
||||
qDeleteAll(m_clients.begin(), m_clients.end());
|
||||
qDebug() << "Deleted all websocket clients";
|
||||
}
|
||||
|
||||
void WSServer::onNewConnection()
|
||||
{
|
||||
qDebug() << "Websocket server: new connection";
|
||||
QWebSocket *pSocket = m_pWebSocketServer->nextPendingConnection();
|
||||
|
||||
connect(pSocket, &QWebSocket::textMessageReceived, this, &WSServer::processTextMessage);
|
||||
connect(pSocket, &QWebSocket::binaryMessageReceived, this, &WSServer::processBinaryMessage);
|
||||
connect(pSocket, &QWebSocket::disconnected, this, &WSServer::socketDisconnected);
|
||||
|
||||
m_clients << pSocket;
|
||||
}
|
||||
|
||||
void WSServer::processTextMessage(QString message)
|
||||
{
|
||||
QWebSocket *pClient = qobject_cast<QWebSocket *>(sender());
|
||||
if (m_debug)
|
||||
qDebug() << "Message received:" << message;
|
||||
|
||||
if (pClient) {
|
||||
std::shared_ptr<ClientWebSocket> client = std::make_shared<ClientWebSocket>(pClient, this);
|
||||
AppDataServer::getInstance()->processMessage(message, m_mainWindow, client, AppConnectionType::DIRECT);
|
||||
}
|
||||
}
|
||||
|
||||
void WSServer::processBinaryMessage(QByteArray message)
|
||||
{
|
||||
//QWebSocket *pClient = qobject_cast<QWebSocket *>(sender());
|
||||
if (m_debug)
|
||||
qDebug() << "Binary Message received:" << message;
|
||||
|
||||
}
|
||||
|
||||
void WSServer::socketDisconnected()
|
||||
{
|
||||
QWebSocket *pClient = qobject_cast<QWebSocket *>(sender());
|
||||
if (m_debug)
|
||||
qDebug() << "socketDisconnected:" << pClient;
|
||||
if (pClient) {
|
||||
m_clients.removeAll(pClient);
|
||||
pClient->deleteLater();
|
||||
}
|
||||
}
|
||||
|
||||
//===============================
|
||||
// WormholeClient
|
||||
//===============================
|
||||
WormholeClient::WormholeClient(MainWindow* p, QString wormholeCode) {
|
||||
this->parent = p;
|
||||
this->code = wormholeCode;
|
||||
connect();
|
||||
qDebug() << "New wormhole client after connect()";
|
||||
}
|
||||
|
||||
WormholeClient::~WormholeClient() {
|
||||
qDebug() << "WormholeClient destructor";
|
||||
shuttingDown = true;
|
||||
|
||||
if (m_webSocket && m_webSocket->isValid()) {
|
||||
qDebug() << "Wormhole closing!";
|
||||
m_webSocket->close();
|
||||
|
||||
}
|
||||
|
||||
if (timer) {
|
||||
qDebug() << "Wormhole timer stopping";
|
||||
timer->stop();
|
||||
}
|
||||
|
||||
delete timer;
|
||||
qDebug() << "Wormhole timer deleted";
|
||||
}
|
||||
|
||||
void WormholeClient::connect() {
|
||||
qDebug() << "Wormhole::connect";
|
||||
delete m_webSocket;
|
||||
m_webSocket = new QWebSocket();
|
||||
|
||||
if (m_webSocket) {
|
||||
QObject::connect(m_webSocket, &QWebSocket::connected, this, &WormholeClient::onConnected);
|
||||
QObject::connect(m_webSocket, &QWebSocket::disconnected, this, &WormholeClient::closed);
|
||||
} else {
|
||||
qDebug() << "Invalid websocket object!";
|
||||
}
|
||||
|
||||
m_webSocket->open(QUrl("wss://wormhole.hush.is:443"));
|
||||
//m_webSocket->open(QUrl("ws://127.0.0.1:7070"));
|
||||
}
|
||||
|
||||
void WormholeClient::retryConnect() {
|
||||
QTimer::singleShot(5 * 1000 * pow(2, retryCount), [=]() {
|
||||
if (retryCount < 10) {
|
||||
qDebug() << "Retrying websocket connection";
|
||||
this->retryCount++;
|
||||
connect();
|
||||
} else {
|
||||
qDebug() << "Retry count exceeded, will not attempt retry any more";
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Called when the websocket is closed. If this was closed without our explicitly closing it,
|
||||
// then we need to try and reconnect
|
||||
void WormholeClient::closed() {
|
||||
if (!shuttingDown) {
|
||||
retryConnect();
|
||||
}
|
||||
}
|
||||
|
||||
void WormholeClient::onConnected()
|
||||
{
|
||||
qDebug() << "WebSocket connected";
|
||||
retryCount = 0;
|
||||
qDebug() << "WebSocket connected, retryCount=" << retryCount;
|
||||
QObject::connect(m_webSocket, &QWebSocket::textMessageReceived,
|
||||
this, &WormholeClient::onTextMessageReceived);
|
||||
|
||||
auto payload = QJsonDocument( QJsonObject {
|
||||
{"register", code}
|
||||
}).toJson();
|
||||
|
||||
m_webSocket->sendTextMessage(payload);
|
||||
|
||||
// On connected, we'll also create a timer to ping it every 4 minutes, since the websocket
|
||||
// will timeout after 5 minutes
|
||||
if (m_webSocket && m_webSocket->isValid()) {
|
||||
m_webSocket->sendTextMessage(payload);
|
||||
qDebug() << "Sent registration message with code=" << code;
|
||||
|
||||
// On connected, we'll also create a timer to ping it every 4 minutes, since the websocket
|
||||
// will timeout after 5 minutes
|
||||
timer = new QTimer(parent);
|
||||
qDebug() << "Created QTimer";
|
||||
QObject::connect(timer, &QTimer::timeout, [=]() {
|
||||
qDebug() << "Timer timeout!";
|
||||
if (!shuttingDown && m_webSocket && m_webSocket->isValid()) {
|
||||
auto payload = QJsonDocument(QJsonObject { {"ping", "ping"} }).toJson();
|
||||
qint64 bytes = m_webSocket->sendTextMessage(payload);
|
||||
qDebug() << "Sent ping, " << bytes << " bytes";
|
||||
}
|
||||
});
|
||||
unsigned int interval = 4*60*1000;
|
||||
timer->start(interval); // 4 minutes
|
||||
qDebug() << "Started timer with interval=" << interval;
|
||||
} else {
|
||||
qDebug() << "Invalid websocket object onConnected!";
|
||||
}
|
||||
}
|
||||
|
||||
void WormholeClient::onTextMessageReceived(QString message)
|
||||
{
|
||||
AppDataServer::getInstance()->processMessage(message, parent, std::make_shared<ClientWebSocket>(m_webSocket), AppConnectionType::INTERNET);
|
||||
qDebug() << "Destroyed tempWormholeClient and ui";
|
||||
}
|
||||
|
||||
|
||||
// ==============================
|
||||
// AppDataServer
|
||||
// ==============================
|
||||
AppDataServer* AppDataServer::instance = nullptr;
|
||||
|
||||
QString AppDataServer::getWormholeCode(QString secretHex) {
|
||||
unsigned char* secret = new unsigned char[crypto_secretbox_KEYBYTES];
|
||||
sodium_hex2bin(secret, crypto_secretbox_KEYBYTES, secretHex.toStdString().c_str(), crypto_secretbox_KEYBYTES*2,
|
||||
NULL, NULL, NULL);
|
||||
|
||||
unsigned char* out1 = new unsigned char[crypto_hash_sha256_BYTES];
|
||||
crypto_hash_sha256(out1, secret, crypto_secretbox_KEYBYTES);
|
||||
|
||||
unsigned char* out2 = new unsigned char[crypto_hash_sha256_BYTES];
|
||||
crypto_hash_sha256(out2, out1, crypto_hash_sha256_BYTES);
|
||||
|
||||
char* wmcode = new char[crypto_hash_sha256_BYTES*2 + 1];
|
||||
sodium_bin2hex(wmcode, crypto_hash_sha256_BYTES*2 + 1, out2, crypto_hash_sha256_BYTES);
|
||||
|
||||
QString wmcodehex(wmcode);
|
||||
|
||||
delete[] wmcode;
|
||||
delete[] out2;
|
||||
delete[] out1;
|
||||
delete[] secret;
|
||||
|
||||
return wmcodehex;
|
||||
}
|
||||
|
||||
QString AppDataServer::getSecretHex() {
|
||||
QSettings s;
|
||||
|
||||
return s.value("mobileapp/secret", "").toString();
|
||||
}
|
||||
|
||||
void AppDataServer::saveNewSecret(QString secretHex) {
|
||||
QSettings().setValue("mobileapp/secret", secretHex);
|
||||
|
||||
if (secretHex.isEmpty())
|
||||
setAllowInternetConnection(false);
|
||||
}
|
||||
|
||||
bool AppDataServer::getAllowInternetConnection() {
|
||||
return QSettings().value("mobileapp/allowinternet", false).toBool();
|
||||
}
|
||||
|
||||
void AppDataServer::setAllowInternetConnection(bool allow) {
|
||||
QSettings().setValue("mobileapp/allowinternet", allow);
|
||||
}
|
||||
|
||||
void AppDataServer::saveLastConnectedOver(AppConnectionType type) {
|
||||
QSettings().setValue("mobileapp/lastconnectedover", type);
|
||||
}
|
||||
|
||||
AppConnectionType AppDataServer::getLastConnectionType() {
|
||||
return (AppConnectionType) QSettings().value("mobileapp/lastconnectedover", AppConnectionType::DIRECT).toInt();
|
||||
}
|
||||
|
||||
void AppDataServer::saveLastSeenTime() {
|
||||
QSettings().setValue("mobileapp/lastseentime", QDateTime::currentSecsSinceEpoch());
|
||||
}
|
||||
|
||||
QDateTime AppDataServer::getLastSeenTime() {
|
||||
return QDateTime::fromSecsSinceEpoch(QSettings().value("mobileapp/lastseentime", 0).toLongLong());
|
||||
}
|
||||
|
||||
void AppDataServer::setConnectedName(QString name) {
|
||||
QSettings().setValue("mobileapp/connectedname", name);
|
||||
}
|
||||
|
||||
QString AppDataServer::getConnectedName() {
|
||||
return QSettings().value("mobileapp/connectedname", "").toString();
|
||||
}
|
||||
|
||||
bool AppDataServer::isAppConnected() {
|
||||
return !getConnectedName().isEmpty() &&
|
||||
getLastSeenTime().daysTo(QDateTime::currentDateTime()) < 14;
|
||||
}
|
||||
|
||||
void AppDataServer::connectAppDialog(MainWindow* parent) {
|
||||
QDialog d(parent);
|
||||
ui = new Ui_MobileAppConnector();
|
||||
ui->setupUi(&d);
|
||||
Settings::saveRestore(&d);
|
||||
|
||||
updateUIWithNewQRCode(parent);
|
||||
updateConnectedUI();
|
||||
|
||||
QObject::connect(ui->btnDisconnect, &QPushButton::clicked, [=] () {
|
||||
QSettings().setValue("mobileapp/connectedname", "");
|
||||
saveNewSecret("");
|
||||
|
||||
updateConnectedUI();
|
||||
});
|
||||
|
||||
QObject::connect(ui->txtConnStr, &QLineEdit::cursorPositionChanged, [=](int, int) {
|
||||
ui->txtConnStr->selectAll();
|
||||
});
|
||||
|
||||
QObject::connect(ui->chkInternetConn, &QCheckBox::stateChanged, [=] (int state) {
|
||||
if (state == Qt::Checked) {
|
||||
|
||||
}
|
||||
updateUIWithNewQRCode(parent);
|
||||
});
|
||||
|
||||
// If we're not listening for the app, then start the websockets
|
||||
if (!parent->isWebsocketListening()) {
|
||||
QString wormholecode = "";
|
||||
if (getAllowInternetConnection())
|
||||
wormholecode = AppDataServer::getInstance()->getWormholeCode(AppDataServer::getInstance()->getSecretHex());
|
||||
|
||||
parent->createWebsocket(wormholecode);
|
||||
}
|
||||
|
||||
d.exec();
|
||||
|
||||
// If there is nothing connected when the dialog exits, then shutdown the websockets
|
||||
if (!isAppConnected()) {
|
||||
parent->stopWebsocket();
|
||||
}
|
||||
|
||||
// Cleanup
|
||||
tempSecret = "";
|
||||
|
||||
delete tempWormholeClient;
|
||||
tempWormholeClient = nullptr;
|
||||
|
||||
delete ui;
|
||||
ui = nullptr;
|
||||
}
|
||||
|
||||
void AppDataServer::updateUIWithNewQRCode(MainWindow* mainwindow) {
|
||||
// Get the address of the localhost
|
||||
auto addrList = QNetworkInterface::allAddresses();
|
||||
|
||||
// Find a suitable address
|
||||
QString ipv4Addr;
|
||||
for (auto addr : addrList) {
|
||||
if (addr.isLoopback() || addr.protocol() == QAbstractSocket::IPv6Protocol)
|
||||
continue;
|
||||
|
||||
ipv4Addr = addr.toString();
|
||||
break;
|
||||
}
|
||||
|
||||
if (ipv4Addr.isEmpty())
|
||||
return;
|
||||
|
||||
QString uri = "ws://" + ipv4Addr + ":8777";
|
||||
qDebug() << "Websocket URI: " << uri;
|
||||
|
||||
// Get a new secret
|
||||
unsigned char* secretBin = new unsigned char[crypto_secretbox_KEYBYTES];
|
||||
randombytes_buf(secretBin, crypto_secretbox_KEYBYTES);
|
||||
char* secretHex = new char[crypto_secretbox_KEYBYTES*2 + 1];
|
||||
sodium_bin2hex(secretHex, crypto_secretbox_KEYBYTES*2+1, secretBin, crypto_secretbox_KEYBYTES);
|
||||
|
||||
QString secretStr(secretHex);
|
||||
QString codeStr = uri + "," + secretStr;
|
||||
|
||||
if (ui->chkInternetConn->isChecked()) {
|
||||
codeStr = codeStr + ",1";
|
||||
}
|
||||
|
||||
registerNewTempSecret(secretStr, ui->chkInternetConn->isChecked(), mainwindow);
|
||||
|
||||
ui->qrcode->setQrcodeString(codeStr);
|
||||
ui->txtConnStr->setText(codeStr);
|
||||
qDebug() << "New QR="<<codeStr;
|
||||
}
|
||||
|
||||
void AppDataServer::registerNewTempSecret(QString tmpSecretHex, bool allowInternet, MainWindow* main) {
|
||||
qDebug() << "Registering new tempSecret, allowInternet=" << allowInternet;
|
||||
tempSecret = tmpSecretHex;
|
||||
|
||||
delete tempWormholeClient;
|
||||
tempWormholeClient = nullptr;
|
||||
|
||||
if (allowInternet)
|
||||
tempWormholeClient = new WormholeClient(main, getWormholeCode(tempSecret));
|
||||
qDebug() << "Created new wormhole client";
|
||||
}
|
||||
|
||||
|
||||
QString AppDataServer::connDesc(AppConnectionType t) {
|
||||
if (t == AppConnectionType::DIRECT) {
|
||||
return QObject::tr("Connected directly");
|
||||
}
|
||||
else {
|
||||
return QObject::tr("Connected over the internet via silentdragon wormhole service");
|
||||
}
|
||||
}
|
||||
|
||||
void AppDataServer::updateConnectedUI() {
|
||||
if (ui == nullptr)
|
||||
return;
|
||||
|
||||
auto remoteName = getConnectedName();
|
||||
|
||||
ui->lblRemoteName->setText(remoteName.isEmpty() ? "(Not connected to any device)" : remoteName);
|
||||
ui->lblLastSeen->setText(remoteName.isEmpty() ? "" : getLastSeenTime().toString(Qt::SystemLocaleLongDate));
|
||||
ui->lblConnectionType->setText(remoteName.isEmpty() ? "" : connDesc(getLastConnectionType()));
|
||||
|
||||
ui->btnDisconnect->setEnabled(!remoteName.isEmpty());
|
||||
}
|
||||
|
||||
QString AppDataServer::getNonceHex(NonceType nt) {
|
||||
QSettings s;
|
||||
QString hex;
|
||||
if (nt == NonceType::LOCAL) {
|
||||
// The default local nonce starts from 1, to always keep it odd
|
||||
auto defaultLocalNonce = "01" + QString("00").repeated(crypto_secretbox_NONCEBYTES-1);
|
||||
hex = s.value("mobileapp/localnoncehex", defaultLocalNonce).toString();
|
||||
}
|
||||
else {
|
||||
hex = s.value("mobileapp/remotenoncehex", QString("00").repeated(crypto_secretbox_NONCEBYTES)).toString();
|
||||
}
|
||||
return hex;
|
||||
}
|
||||
|
||||
void AppDataServer::saveNonceHex(NonceType nt, QString noncehex) {
|
||||
QSettings s;
|
||||
assert(noncehex.length() == crypto_secretbox_NONCEBYTES * 2);
|
||||
if (nt == NonceType::LOCAL) {
|
||||
s.setValue("mobileapp/localnoncehex", noncehex);
|
||||
}
|
||||
else {
|
||||
s.setValue("mobileapp/remotenoncehex", noncehex);
|
||||
}
|
||||
s.sync();
|
||||
}
|
||||
|
||||
// Encrypt an outgoing message with the stored secret key.
|
||||
QString AppDataServer::encryptOutgoing(QString msg) {
|
||||
int padding = 16*1024;
|
||||
qDebug() << "Encrypt msg(pad="<<padding<<") prepad len=" << msg.length();
|
||||
if (msg.length() % padding > 0) {
|
||||
msg = msg + QString(" ").repeated(padding - (msg.length() % padding));
|
||||
}
|
||||
qDebug() << "Encrypt msg postpad len=" << msg.length();
|
||||
|
||||
QString localNonceHex = getNonceHex(NonceType::LOCAL);
|
||||
|
||||
unsigned char* noncebin = new unsigned char[crypto_secretbox_NONCEBYTES];
|
||||
sodium_hex2bin(noncebin, crypto_secretbox_NONCEBYTES, localNonceHex.toStdString().c_str(), localNonceHex.length(),
|
||||
NULL, NULL, NULL);
|
||||
|
||||
// Increment the nonce +2 and save
|
||||
sodium_increment(noncebin, crypto_secretbox_NONCEBYTES);
|
||||
sodium_increment(noncebin, crypto_secretbox_NONCEBYTES);
|
||||
|
||||
char* newLocalNonce = new char[crypto_secretbox_NONCEBYTES*2 + 1];
|
||||
sodium_memzero(newLocalNonce, crypto_secretbox_NONCEBYTES*2 + 1);
|
||||
sodium_bin2hex(newLocalNonce, crypto_secretbox_NONCEBYTES*2+1, noncebin, crypto_box_NONCEBYTES);
|
||||
|
||||
saveNonceHex(NonceType::LOCAL, QString(newLocalNonce));
|
||||
|
||||
unsigned char* secret = new unsigned char[crypto_secretbox_KEYBYTES];
|
||||
sodium_hex2bin(secret, crypto_secretbox_KEYBYTES, getSecretHex().toStdString().c_str(), crypto_secretbox_KEYBYTES*2,
|
||||
NULL, NULL, NULL);
|
||||
|
||||
int msgSize = strlen(msg.toStdString().c_str());
|
||||
unsigned char* encrpyted = new unsigned char[ msgSize + crypto_secretbox_MACBYTES];
|
||||
|
||||
crypto_secretbox_easy(encrpyted, (const unsigned char *)msg.toStdString().c_str(), msgSize, noncebin, secret);
|
||||
|
||||
int encryptedHexSize = (msgSize + crypto_secretbox_MACBYTES) * 2 + 1;
|
||||
char * encryptedHex = new char[encryptedHexSize];
|
||||
sodium_memzero(encryptedHex, encryptedHexSize);
|
||||
sodium_bin2hex(encryptedHex, encryptedHexSize, encrpyted, msgSize + crypto_secretbox_MACBYTES);
|
||||
|
||||
auto json = QJsonDocument(QJsonObject{
|
||||
{"nonce", QString(newLocalNonce)},
|
||||
{"payload", QString(encryptedHex)},
|
||||
{"to", getWormholeCode(getSecretHex())}
|
||||
});
|
||||
|
||||
delete[] noncebin;
|
||||
delete[] newLocalNonce;
|
||||
delete[] secret;
|
||||
delete[] encrpyted;
|
||||
delete[] encryptedHex;
|
||||
|
||||
return json.toJson();
|
||||
}
|
||||
|
||||
/**
|
||||
Attempt to decrypt a message. If the decryption fails, it returns the string "error", the decrypted message otherwise.
|
||||
It will use the given secret to attempt decryption. In addition, it will enforce that the nonce is greater than the last seen nonce,
|
||||
unless the skipNonceCheck = true, which is used when attempting decrtption with a temp secret key.
|
||||
*/
|
||||
QString AppDataServer::decryptMessage(QJsonDocument msg, QString secretHex, QString lastRemoteNonceHex) {
|
||||
// Decrypt and then process
|
||||
QString noncehex = msg.object().value("nonce").toString();
|
||||
QString encryptedhex = msg.object().value("payload").toString();
|
||||
|
||||
// Enforce limits on the size of the message
|
||||
if (noncehex.length() > ((int)crypto_secretbox_NONCEBYTES * 2) ||
|
||||
encryptedhex.length() > 2 * 50 * 1024 /*50kb*/) {
|
||||
return "error";
|
||||
}
|
||||
|
||||
// Check to make sure that the nonce is greater than the last known remote nonce
|
||||
unsigned char* lastRemoteBin = new unsigned char[crypto_secretbox_NONCEBYTES];
|
||||
sodium_hex2bin(lastRemoteBin, crypto_secretbox_NONCEBYTES, lastRemoteNonceHex.toStdString().c_str(), lastRemoteNonceHex.length(),
|
||||
NULL, NULL, NULL);
|
||||
|
||||
unsigned char* noncebin = new unsigned char[crypto_secretbox_NONCEBYTES];
|
||||
sodium_hex2bin(noncebin, crypto_secretbox_NONCEBYTES, noncehex.toStdString().c_str(), noncehex.length(),
|
||||
NULL, NULL, NULL);
|
||||
|
||||
assert(crypto_secretbox_KEYBYTES == crypto_hash_sha256_BYTES);
|
||||
if (sodium_compare(lastRemoteBin, noncebin, crypto_secretbox_NONCEBYTES) != -1) {
|
||||
// Refuse to accept a lower nonce, return an error
|
||||
delete[] lastRemoteBin;
|
||||
delete[] noncebin;
|
||||
return "error";
|
||||
}
|
||||
|
||||
unsigned char* secret = new unsigned char[crypto_secretbox_KEYBYTES];
|
||||
sodium_hex2bin(secret, crypto_secretbox_KEYBYTES, secretHex.toStdString().c_str(), crypto_secretbox_KEYBYTES*2,
|
||||
NULL, NULL, NULL);
|
||||
|
||||
unsigned char* encrypted = new unsigned char[encryptedhex.length() / 2];
|
||||
sodium_hex2bin(encrypted, encryptedhex.length() / 2, encryptedhex.toStdString().c_str(), encryptedhex.length(),
|
||||
NULL, NULL, NULL);
|
||||
|
||||
int decryptedLen = encryptedhex.length() / 2 - crypto_secretbox_MACBYTES;
|
||||
unsigned char* decrypted = new unsigned char[decryptedLen];
|
||||
int result = crypto_secretbox_open_easy(decrypted, encrypted, encryptedhex.length() / 2, noncebin, secret);
|
||||
|
||||
QString payload;
|
||||
if (result == -1) {
|
||||
payload = "error";
|
||||
} else {
|
||||
// Update the last seen remote hex
|
||||
saveNonceHex(NonceType::REMOTE, noncehex);
|
||||
saveLastSeenTime();
|
||||
|
||||
char* decryptedStr = new char[decryptedLen + 1];
|
||||
sodium_memzero(decryptedStr, decryptedLen + 1);
|
||||
memcpy(decryptedStr, decrypted, decryptedLen);
|
||||
|
||||
payload = QString(decryptedStr);
|
||||
|
||||
delete[] decryptedStr;
|
||||
}
|
||||
|
||||
delete[] secret;
|
||||
delete[] lastRemoteBin;
|
||||
delete[] noncebin;
|
||||
delete[] encrypted;
|
||||
delete[] decrypted;
|
||||
|
||||
qDebug() << "Returning decrypted payload="<<payload;
|
||||
return payload;
|
||||
}
|
||||
|
||||
// Process an incoming text message. The message has to be encrypted with the secret key (or the temporary secret key)
|
||||
void AppDataServer::processMessage(QString message, MainWindow* mainWindow, std::shared_ptr<ClientWebSocket> pClient, AppConnectionType connType) {
|
||||
qDebug() << "processMessage message";
|
||||
//qDebug() << "processMessage message=" << message; // this can log sensitive info
|
||||
auto replyWithError = [=]() {
|
||||
auto r = QJsonDocument(QJsonObject{
|
||||
{"error", "Encryption error"},
|
||||
{"to", getWormholeCode(getSecretHex())}
|
||||
}).toJson();
|
||||
pClient->sendTextMessage(r);
|
||||
return;
|
||||
};
|
||||
|
||||
// First, extract the command from the message
|
||||
auto msg = QJsonDocument::fromJson(message.toUtf8());
|
||||
|
||||
// Check if we got an error from the websocket
|
||||
if (msg.object().contains("error")) {
|
||||
qDebug() << "Error:" << msg.toJson();
|
||||
return;
|
||||
}
|
||||
|
||||
// If the message is a ping, just ignore it
|
||||
if (msg.object().contains("ping")) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Then, check if the message is encrpted
|
||||
if (!msg.object().contains("nonce")) {
|
||||
replyWithError();
|
||||
return;
|
||||
}
|
||||
|
||||
auto decrypted = decryptMessage(msg, getSecretHex(), getNonceHex(NonceType::REMOTE));
|
||||
|
||||
// If the decryption failed, maybe this is a new connection, so see if the dialog is open and a
|
||||
// temp secret is in place
|
||||
if (decrypted == "error") {
|
||||
// If the dialog is open, then there might be a temporary, new secret key. Attempt to decrypt
|
||||
// with that.
|
||||
if (!tempSecret.isEmpty()) {
|
||||
// Since this is a temp secret, the last seen nonce will be "0", so basically we'll accept any nonce
|
||||
QString zeroNonce = QString("00").repeated(crypto_secretbox_NONCEBYTES);
|
||||
decrypted = decryptMessage(msg, tempSecret, zeroNonce);
|
||||
if (decrypted == "error") {
|
||||
// Oh, well. Just return an error
|
||||
replyWithError();
|
||||
return;
|
||||
}
|
||||
else {
|
||||
// This is a new connection. So, update the the secret. Note the last seen remote nonce has already been updated by
|
||||
// decryptMessage()
|
||||
saveNewSecret(tempSecret);
|
||||
setAllowInternetConnection(tempWormholeClient != nullptr);
|
||||
|
||||
// Swap out the wormhole connection
|
||||
mainWindow->replaceWormholeClient(tempWormholeClient);
|
||||
tempWormholeClient = nullptr;
|
||||
|
||||
saveLastConnectedOver(connType);
|
||||
processDecryptedMessage(decrypted, mainWindow, pClient);
|
||||
|
||||
// If the Connection UI is showing, we have to update the UI as well
|
||||
if (ui != nullptr) {
|
||||
// Update the connected phone information
|
||||
updateConnectedUI();
|
||||
|
||||
// Update with a new QR Code for safety, so this secret isn't used by anyone else
|
||||
updateUIWithNewQRCode(mainWindow);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
else {
|
||||
replyWithError();
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
saveLastConnectedOver(connType);
|
||||
processDecryptedMessage(decrypted, mainWindow, pClient);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Decrypted method will be executed here.
|
||||
void AppDataServer::processDecryptedMessage(QString message, MainWindow* mainWindow, std::shared_ptr<ClientWebSocket> pClient) {
|
||||
//qDebug() << "processDecryptedMessage message=" << message;
|
||||
// First, extract the command from the message
|
||||
auto msg = QJsonDocument::fromJson(message.toUtf8());
|
||||
|
||||
if (!msg.object().contains("command")) {
|
||||
auto r = QJsonDocument(QJsonObject{
|
||||
{"errorCode", -1},
|
||||
{"errorMessage", "Unknown JSON format"}
|
||||
}).toJson();
|
||||
pClient->sendTextMessage(encryptOutgoing(r));
|
||||
return;
|
||||
}
|
||||
|
||||
if (msg.object()["command"] == "getInfo") {
|
||||
processGetInfo(msg.object(), mainWindow, pClient);
|
||||
}
|
||||
else if (msg.object()["command"] == "getTransactions") {
|
||||
processGetTransactions(mainWindow, pClient);
|
||||
}
|
||||
else if (msg.object()["command"] == "sendTx") {
|
||||
processSendTx(msg.object()["tx"].toObject(), mainWindow, pClient);
|
||||
}
|
||||
else if (msg.object()["command"] == "sendmanyTx") {
|
||||
processSendManyTx(msg.object()["tx"].toObject(), mainWindow, pClient);
|
||||
}
|
||||
else {
|
||||
auto r = QJsonDocument(QJsonObject{
|
||||
{"errorCode", -1},
|
||||
{"errorMessage", "Command not found:" + msg.object()["command"].toString()}
|
||||
}).toJson();
|
||||
pClient->sendTextMessage(encryptOutgoing(r));
|
||||
}
|
||||
}
|
||||
|
||||
// "sendTx" command. This method will actually send money, so be careful with everything
|
||||
void AppDataServer::processSendTx(QJsonObject sendTx, MainWindow* mainwindow, std::shared_ptr<ClientWebSocket> pClient) {
|
||||
qDebug() << "processSendTx with to=" << sendTx["to"].toString();
|
||||
auto error = [=](QString reason) {
|
||||
auto r = QJsonDocument(QJsonObject{
|
||||
{"errorCode", -1},
|
||||
{"errorMessage", "Couldn't send Tx:" + reason}
|
||||
}).toJson();
|
||||
pClient->sendTextMessage(encryptOutgoing(r));
|
||||
return;
|
||||
};
|
||||
|
||||
// Refuse to send if the node is still syncing
|
||||
if (Settings::getInstance()->isSyncing()) {
|
||||
error(QObject::tr("Node is still syncing."));
|
||||
return;
|
||||
}
|
||||
|
||||
// Create a Tx Object
|
||||
Tx tx;
|
||||
tx.fee = Settings::getMinerFee();
|
||||
|
||||
// Find a from address that has at least the sending amout
|
||||
CAmount amt = CAmount::fromDecimalString(sendTx["amount"].toString());
|
||||
auto allBalances = mainwindow->getRPC()->getModel()->getAllBalances();
|
||||
QList<QPair<QString, CAmount>> bals;
|
||||
for (auto i : allBalances.keys()) {
|
||||
// Filter out balances that don't have the requisite amount
|
||||
if (allBalances.value(i) < amt)
|
||||
continue;
|
||||
|
||||
bals.append(QPair<QString, CAmount>(i, allBalances.value(i)));
|
||||
}
|
||||
|
||||
if (bals.isEmpty()) {
|
||||
error(QObject::tr("No sapling or transparent addresses with enough balance to spend."));
|
||||
return;
|
||||
}
|
||||
|
||||
std::sort(bals.begin(), bals.end(), [=](const QPair<QString, CAmount>a, const QPair<QString, CAmount> b) -> bool {
|
||||
// Sort z addresses first
|
||||
return a.first > b.first;
|
||||
});
|
||||
|
||||
tx.fromAddr = bals[0].first;
|
||||
tx.toAddrs = { ToFields{ sendTx["to"].toString(), amt, sendTx["memo"].toString()} };
|
||||
|
||||
// TODO: Respect the autoshield change setting
|
||||
|
||||
QString validation = mainwindow->doSendTxValidations(tx);
|
||||
if (!validation.isEmpty()) {
|
||||
error(validation);
|
||||
return;
|
||||
}
|
||||
|
||||
json params = json::array();
|
||||
mainwindow->getRPC()->fillTxJsonParams(params, tx);
|
||||
std::cout << std::setw(2) << params << std::endl;
|
||||
|
||||
// And send the Tx
|
||||
mainwindow->getRPC()->executeTransaction(tx,
|
||||
[=] (QString txid) {
|
||||
auto r = QJsonDocument(QJsonObject{
|
||||
{"version", 1.0},
|
||||
{"command", "sendTxSubmitted"},
|
||||
{"txid", txid}
|
||||
}).toJson();
|
||||
pClient->sendTextMessage(encryptOutgoing(r));
|
||||
},
|
||||
// Errored while submitting Tx
|
||||
[=] (QString, QString errStr) {
|
||||
auto r = QJsonDocument(QJsonObject{
|
||||
{"version", 1.0},
|
||||
{"command", "sendTxFailed"},
|
||||
{"err", errStr}
|
||||
}).toJson();
|
||||
pClient->sendTextMessage(encryptOutgoing(r));
|
||||
}
|
||||
);
|
||||
|
||||
auto r = QJsonDocument(QJsonObject{
|
||||
{"version", 1.0},
|
||||
{"command", "sendTx"},
|
||||
{"result", "success"}
|
||||
}).toJson();
|
||||
pClient->sendTextMessage(encryptOutgoing(r));
|
||||
}
|
||||
|
||||
// "sendmanyTx" command. This method will actually send money, so be careful with everything
|
||||
void AppDataServer::processSendManyTx(QJsonObject sendmanyTx, MainWindow* mainwindow, std::shared_ptr<ClientWebSocket> pClient) {
|
||||
qDebug() << "processSendManyTx with to=" << sendmanyTx["to"].toString();
|
||||
auto error = [=](QString reason) {
|
||||
auto r = QJsonDocument(QJsonObject{
|
||||
{"errorCode", -1},
|
||||
{"errorMessage", "Couldn't send Tx:" + reason}
|
||||
}).toJson();
|
||||
pClient->sendTextMessage(encryptOutgoing(r));
|
||||
return;
|
||||
};
|
||||
|
||||
// Refuse to send if the node is still syncing
|
||||
if (Settings::getInstance()->isSyncing()) {
|
||||
error(QObject::tr("Node is still syncing."));
|
||||
return;
|
||||
}
|
||||
|
||||
// Create a Tx Object
|
||||
Tx tx;
|
||||
tx.fee = Settings::getMinerFee();
|
||||
|
||||
// Find a from address that has at least the sending amout
|
||||
CAmount amt = CAmount::fromDecimalString(sendmanyTx["amount"].toString());
|
||||
auto allBalances = mainwindow->getRPC()->getModel()->getAllBalances();
|
||||
QList<QPair<QString, CAmount>> bals;
|
||||
for (auto i : allBalances.keys()) {
|
||||
// Filter out balances that don't have the requisite amount
|
||||
if (allBalances.value(i) < amt)
|
||||
continue;
|
||||
|
||||
bals.append(QPair<QString, CAmount>(i, allBalances.value(i)));
|
||||
}
|
||||
|
||||
if (bals.isEmpty()) {
|
||||
error(QObject::tr("No sapling or transparent addresses with enough balance to spend."));
|
||||
return;
|
||||
}
|
||||
|
||||
std::sort(bals.begin(), bals.end(), [=](const QPair<QString, CAmount>a, const QPair<QString, CAmount> b) -> bool {
|
||||
// Sort z addresses first
|
||||
return a.first > b.first;
|
||||
});
|
||||
|
||||
//send to more then one Receipent
|
||||
|
||||
int totalSendManyItems = sendmanyTx.size();
|
||||
for (int i=0; i < totalSendManyItems; i++) {
|
||||
|
||||
amt = CAmount::fromDecimalString(sendmanyTx["amount"].toString() % QString::number(i+1));
|
||||
QString addr = sendmanyTx["to"].toString() % QString::number(i+1);
|
||||
QString memo = sendmanyTx["memo"].toString() % QString::number(i+1);
|
||||
|
||||
tx.fromAddr = bals[0].first;
|
||||
tx.toAddrs = { ToFields{ addr, amt, memo} };
|
||||
}
|
||||
// TODO: Respect the autoshield change setting
|
||||
|
||||
QString validation = mainwindow->doSendTxValidations(tx);
|
||||
if (!validation.isEmpty()) {
|
||||
error(validation);
|
||||
return;
|
||||
}
|
||||
|
||||
json params = json::array();
|
||||
mainwindow->getRPC()->fillTxJsonParams(params, tx);
|
||||
std::cout << std::setw(2) << params << std::endl;
|
||||
|
||||
// And send the Tx
|
||||
mainwindow->getRPC()->executeTransaction(tx,
|
||||
[=] (QString txid) {
|
||||
auto r = QJsonDocument(QJsonObject{
|
||||
{"version", 1.0},
|
||||
{"command", "sendTxSubmitted"},
|
||||
{"txid", txid}
|
||||
}).toJson();
|
||||
pClient->sendTextMessage(encryptOutgoing(r));
|
||||
},
|
||||
// Errored while submitting Tx
|
||||
[=] (QString, QString errStr) {
|
||||
auto r = QJsonDocument(QJsonObject{
|
||||
{"version", 1.0},
|
||||
{"command", "sendTxFailed"},
|
||||
{"err", errStr}
|
||||
}).toJson();
|
||||
pClient->sendTextMessage(encryptOutgoing(r));
|
||||
}
|
||||
);
|
||||
|
||||
auto r = QJsonDocument(QJsonObject{
|
||||
{"version", 1.0},
|
||||
{"command", "sendTx"},
|
||||
{"result", "success"}
|
||||
}).toJson();
|
||||
pClient->sendTextMessage(encryptOutgoing(r));
|
||||
}
|
||||
|
||||
|
||||
// "getInfo" command
|
||||
void AppDataServer::processGetInfo(QJsonObject jobj, MainWindow* mainWindow, std::shared_ptr<ClientWebSocket> pClient) {
|
||||
auto connectedName = jobj["name"].toString();
|
||||
|
||||
if (mainWindow == nullptr || mainWindow->getRPC() == nullptr) {
|
||||
pClient->close(QWebSocketProtocol::CloseCodeNormal, "Not yet ready");
|
||||
return;
|
||||
}
|
||||
|
||||
// Max spendable safely from a z address and from any address
|
||||
CAmount maxZSpendable;
|
||||
CAmount maxSpendable;
|
||||
for (auto a : mainWindow->getRPC()->getModel()->getAllBalances().keys()) {
|
||||
if (Settings::getInstance()->isSaplingAddress(a)) {
|
||||
if (mainWindow->getRPC()->getModel()->getAllBalances().value(a) > maxZSpendable) {
|
||||
maxZSpendable = mainWindow->getRPC()->getModel()->getAllBalances().value(a);
|
||||
}
|
||||
}
|
||||
if (mainWindow->getRPC()->getModel()->getAllBalances().value(a) > maxSpendable) {
|
||||
maxSpendable = mainWindow->getRPC()->getModel()->getAllBalances().value(a);
|
||||
}
|
||||
}
|
||||
|
||||
setConnectedName(connectedName);
|
||||
|
||||
auto r = QJsonDocument(QJsonObject {
|
||||
{"version", 1.0},
|
||||
{"command", "getInfo"},
|
||||
{"saplingAddress", mainWindow->getRPC()->getDefaultSaplingAddress()},
|
||||
{"tAddress", mainWindow->getRPC()->getDefaultTAddress()},
|
||||
{"balance", AppDataModel::getInstance()->getTotalBalance().toDecimalDouble()},
|
||||
{"maxspendable", maxSpendable.toDecimalDouble()},
|
||||
{"maxzspendable", maxZSpendable.toDecimalDouble()},
|
||||
{"tokenName", Settings::getTokenName()},
|
||||
// changing this to hushprice is a backward incompatible change that requires
|
||||
// changing SDL, litewalletd and SDA in unison, and would break older clients
|
||||
// so we just leave it for now
|
||||
{"zecprice", Settings::getInstance()->getHUSHPrice()},
|
||||
{"serverversion", QString(APP_VERSION)}
|
||||
}).toJson();
|
||||
pClient->sendTextMessage(encryptOutgoing(r));
|
||||
}
|
||||
|
||||
void AppDataServer::processGetTransactions(MainWindow* mainWindow, std::shared_ptr<ClientWebSocket> pClient) {
|
||||
QJsonArray txns;
|
||||
auto model = mainWindow->getRPC()->getTransactionsModel();
|
||||
qDebug() << "processGetTransactions";
|
||||
|
||||
|
||||
// Add transactions
|
||||
for (int i = 0; i < model->rowCount(QModelIndex()) && i < Settings::getMaxMobileAppTxns(); i++) {
|
||||
txns.append(QJsonObject{
|
||||
{"type", model->getType(i)},
|
||||
{"datetime", model->getDate(i)},
|
||||
{"amount", model->getAmt(i)},
|
||||
{"txid", model->getTxId(i)},
|
||||
{"address", model->getAddr(i)},
|
||||
// {"memo", model->getMemo(i)},
|
||||
{"confirmations", model->getConfirmations(i)}
|
||||
});
|
||||
}
|
||||
|
||||
auto r = QJsonDocument(QJsonObject{
|
||||
{"version", 1.0},
|
||||
{"command", "getTransactions"},
|
||||
{"transactions", txns}
|
||||
}).toJson();
|
||||
pClient->sendTextMessage(encryptOutgoing(r));
|
||||
}
|
||||
|
||||
// ==============================
|
||||
// AppDataModel
|
||||
// ==============================
|
||||
AppDataModel* AppDataModel::instance = nullptr;
|
||||
179
src/websockets.h
179
src/websockets.h
@@ -1,179 +0,0 @@
|
||||
// Copyright 2019-2023 The Hush developers
|
||||
// Released under the GPLv3
|
||||
#ifndef WEBSOCKETS_H
|
||||
#define WEBSOCKETS_H
|
||||
|
||||
#include "precompiled.h"
|
||||
#include "camount.h"
|
||||
#include "mainwindow.h"
|
||||
#include "ui_mobileappconnector.h"
|
||||
|
||||
QT_FORWARD_DECLARE_CLASS(QWebSocketServer)
|
||||
QT_FORWARD_DECLARE_CLASS(QWebSocket)
|
||||
|
||||
class WSServer;
|
||||
|
||||
// We're going to wrap the websocket in this class, because the underlying QWebSocket might get closed
|
||||
// or deleted while a callback is waiting to get the data back. Therefore, we write a custom "sendTextMessage"
|
||||
// class that checks all this before sending.
|
||||
class ClientWebSocket {
|
||||
public:
|
||||
ClientWebSocket(QWebSocket* c, WSServer* s = nullptr) { client = c; server = s; }
|
||||
|
||||
void sendTextMessage(QString m);
|
||||
void close(QWebSocketProtocol::CloseCode code, const QString& msg) { client->close(code, msg); }
|
||||
private:
|
||||
QWebSocket* client;
|
||||
WSServer* server;
|
||||
};
|
||||
|
||||
class WSServer : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit WSServer(quint16 port, bool debug = false, QObject *parent = nullptr);
|
||||
bool isValidConnection(QWebSocket* c) { return m_clients.contains(c); }
|
||||
~WSServer();
|
||||
|
||||
Q_SIGNALS:
|
||||
void closed();
|
||||
|
||||
private Q_SLOTS:
|
||||
void onNewConnection();
|
||||
void processTextMessage(QString message);
|
||||
void processBinaryMessage(QByteArray message);
|
||||
void socketDisconnected();
|
||||
|
||||
private:
|
||||
QWebSocketServer *m_pWebSocketServer;
|
||||
MainWindow *m_mainWindow;
|
||||
QList<QWebSocket *> m_clients;
|
||||
bool m_debug;
|
||||
};
|
||||
|
||||
class WormholeClient : public QObject {
|
||||
Q_OBJECT
|
||||
|
||||
private Q_SLOTS:
|
||||
void onConnected();
|
||||
void onTextMessageReceived(QString message);
|
||||
void closed();
|
||||
|
||||
public:
|
||||
WormholeClient(MainWindow* parent, QString wormholeCode);
|
||||
~WormholeClient();
|
||||
|
||||
void connect();
|
||||
void retryConnect();
|
||||
|
||||
private:
|
||||
MainWindow* parent = nullptr;
|
||||
QWebSocket* m_webSocket = nullptr;
|
||||
|
||||
QTimer* timer = nullptr;
|
||||
|
||||
QString code;
|
||||
int retryCount = 0;
|
||||
bool shuttingDown = false;
|
||||
};
|
||||
|
||||
enum NonceType {
|
||||
LOCAL = 1,
|
||||
REMOTE
|
||||
};
|
||||
|
||||
enum AppConnectionType {
|
||||
DIRECT = 1,
|
||||
INTERNET
|
||||
};
|
||||
|
||||
class AppDataServer {
|
||||
public:
|
||||
static AppDataServer* getInstance() {
|
||||
if (instance == nullptr) {
|
||||
instance = new AppDataServer();
|
||||
}
|
||||
return instance;
|
||||
}
|
||||
|
||||
void connectAppDialog(MainWindow* parent);
|
||||
void updateConnectedUI();
|
||||
void updateUIWithNewQRCode(MainWindow* mainwindow);
|
||||
|
||||
void processSendTx(QJsonObject sendTx, MainWindow* mainwindow, std::shared_ptr<ClientWebSocket> pClient);
|
||||
void processSendManyTx(QJsonObject sendmanyTx, MainWindow* mainwindow, std::shared_ptr<ClientWebSocket> pClient);
|
||||
void processMessage(QString message, MainWindow* mainWindow, std::shared_ptr<ClientWebSocket> pClient, AppConnectionType connType);
|
||||
void processGetInfo(QJsonObject jobj, MainWindow* mainWindow, std::shared_ptr<ClientWebSocket> pClient);
|
||||
void processDecryptedMessage(QString message, MainWindow* mainWindow, std::shared_ptr<ClientWebSocket> pClient);
|
||||
void processGetTransactions(MainWindow* mainWindow, std::shared_ptr<ClientWebSocket> pClient);
|
||||
|
||||
QString decryptMessage(QJsonDocument msg, QString secretHex, QString lastRemoteNonceHex);
|
||||
QString encryptOutgoing(QString msg);
|
||||
|
||||
QString getWormholeCode(QString secretHex);
|
||||
QString getSecretHex();
|
||||
void saveNewSecret(QString secretHex);
|
||||
|
||||
void registerNewTempSecret(QString tmpSecretHex, bool allowInternet, MainWindow* main);
|
||||
|
||||
QString getNonceHex(NonceType nt);
|
||||
void saveNonceHex(NonceType nt, QString noncehex);
|
||||
|
||||
bool getAllowInternetConnection();
|
||||
void setAllowInternetConnection(bool allow);
|
||||
|
||||
void saveLastSeenTime();
|
||||
QDateTime getLastSeenTime();
|
||||
|
||||
void setConnectedName(QString name);
|
||||
QString getConnectedName();
|
||||
bool isAppConnected();
|
||||
|
||||
QString connDesc(AppConnectionType t);
|
||||
|
||||
void saveLastConnectedOver(AppConnectionType type);
|
||||
AppConnectionType getLastConnectionType();
|
||||
|
||||
private:
|
||||
AppDataServer() = default;
|
||||
|
||||
static AppDataServer* instance;
|
||||
Ui_MobileAppConnector* ui;
|
||||
|
||||
QString tempSecret;
|
||||
WormholeClient* tempWormholeClient = nullptr;
|
||||
};
|
||||
|
||||
class AppDataModel {
|
||||
public:
|
||||
static AppDataModel* getInstance() {
|
||||
if (instance == NULL)
|
||||
instance = new AppDataModel();
|
||||
|
||||
return instance;
|
||||
}
|
||||
|
||||
CAmount getTBalance() { return balTransparent; }
|
||||
CAmount getZBalance() { return balShielded; }
|
||||
CAmount getTotalBalance() { return balTotal; }
|
||||
|
||||
void setBalances(CAmount transparent, CAmount shielded) {
|
||||
balTransparent = transparent;
|
||||
balShielded = shielded;
|
||||
balTotal = balTransparent + balShielded;
|
||||
}
|
||||
|
||||
private:
|
||||
AppDataModel() = default; // Private, for singleton
|
||||
|
||||
CAmount balTransparent;
|
||||
CAmount balShielded;
|
||||
CAmount balTotal;
|
||||
|
||||
QString saplingAddress;
|
||||
|
||||
static AppDataModel* instance;
|
||||
};
|
||||
|
||||
|
||||
#endif // WEBSOCKETS_H
|
||||
Reference in New Issue
Block a user