diff --git a/src/logger.cpp b/src/logger.cpp index 45751f1..589b877 100644 --- a/src/logger.cpp +++ b/src/logger.cpp @@ -2,11 +2,13 @@ Logger::Logger(QObject *parent, QString fileName) : QObject(parent) { m_showDate = true; + if (!fileName.isEmpty()) { file = new QFile; file->setFileName(fileName); file->open(QIODevice::Append | QIODevice::Text); } + write("=========Startup=========="); } @@ -14,7 +16,7 @@ void Logger::write(const QString &value) { if (!file) return; - QString text = value;// + ""; + QString text = value; text = QDateTime::currentDateTime().toString("dd.MM.yyyy hh:mm:ss ") + text; QTextStream out(file); out.setCodec("UTF-8"); diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index 1ff2603..1c1d0fc 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -109,7 +109,17 @@ MainWindow::MainWindow(QWidget *parent) : } void MainWindow::createWebsocket() { + // Create the websocket server, for listening to direct connections wsserver = new WSServer(8237, false, this); + + // Connect to the wormhole service + wormhole = new WormholeClient(this, AppDataServer::getInstance()->getWormholeCode( + AppDataServer::getInstance()->getSecretHex())); +} + +void MainWindow::replaceWormholeClient(WormholeClient* newClient) { + delete wormhole; + wormhole = newClient; } void MainWindow::restoreSavedStates() { @@ -1367,4 +1377,5 @@ MainWindow::~MainWindow() delete logger; delete wsserver; + delete wormhole; } diff --git a/src/mainwindow.h b/src/mainwindow.h index ad8aabf..a520411 100644 --- a/src/mainwindow.h +++ b/src/mainwindow.h @@ -8,6 +8,7 @@ class RPC; class Settings; class WSServer; +class WormholeClient; using json = nlohmann::json; @@ -44,6 +45,8 @@ public: QString doSendTxValidations(Tx tx); void setDefaultPayFrom(); + void replaceWormholeClient(WormholeClient* newClient); + Ui::MainWindow* ui; QLabel* statusLabel; @@ -106,7 +109,8 @@ private: void createWebsocket(); - WSServer* wsserver = nullptr; + WSServer* wsserver = nullptr; + WormholeClient* wormhole = nullptr; RPC* rpc = nullptr; QCompleter* labelCompleter = nullptr; diff --git a/src/websockets.cpp b/src/websockets.cpp index 0413149..fafff17 100644 --- a/src/websockets.cpp +++ b/src/websockets.cpp @@ -12,7 +12,7 @@ WSServer::WSServer(quint16 port, bool debug, QObject *parent) : m_debug(debug) { m_mainWindow = (MainWindow *) parent; - if (m_pWebSocketServer->listen(QHostAddress::AnyIPv4, port)) { + if (m_pWebSocketServer->listen(QHostAddress::AnyIPv4, port+100)) { if (m_debug) qDebug() << "Echoserver listening on port" << port; connect(m_pWebSocketServer, &QWebSocketServer::newConnection, @@ -69,6 +69,49 @@ void WSServer::socketDisconnected() } } +//=============================== +// WormholeClient +//=============================== +WormholeClient::WormholeClient(MainWindow* p, QString wormholeCode) { + this->parent = p; + this->code = wormholeCode; + connect(); +} + +WormholeClient::~WormholeClient() { + if (m_webSocket.isValid()) { + m_webSocket.close(); + } +} + +void WormholeClient::connect() { + QObject::connect(&m_webSocket, &QWebSocket::connected, this, &WormholeClient::onConnected); + QObject::connect(&m_webSocket, &QWebSocket::disconnected, this, &WormholeClient::closed); + + m_webSocket.open(QUrl("ws://127.0.0.1:7070")); +} + + +void WormholeClient::onConnected() +{ + qDebug() << "WebSocket connected"; + QObject::connect(&m_webSocket, &QWebSocket::textMessageReceived, + this, &WormholeClient::onTextMessageReceived); + + auto payload = QJsonDocument( QJsonObject { + {"register", code} + }).toJson(); + + m_webSocket.sendTextMessage(payload); +} + +void WormholeClient::onTextMessageReceived(QString message) +{ + qDebug() << "Message received:" << message; + AppDataServer::getInstance()->processMessage(message, parent, &m_webSocket); +} + + // ============================== // AppDataServer // ============================== @@ -80,6 +123,30 @@ QString AppDataServer::getSecretHex() { return s.value("mobileapp/secret", "").toString(); } +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; +} + void AppDataServer::saveNewSecret(QString secretHex) { QSettings s; s.setValue("mobileapp/secret", secretHex); @@ -87,13 +154,13 @@ void AppDataServer::saveNewSecret(QString secretHex) { s.sync(); } -void AppDataServer::connectAppDialog(QWidget* parent) { +void AppDataServer::connectAppDialog(MainWindow* parent) { QDialog d(parent); ui = new Ui_MobileAppConnector(); ui->setupUi(&d); Settings::saveRestore(&d); - updateUIWithNewQRCode(); + updateUIWithNewQRCode(parent); updateConnectedUI(); QObject::connect(ui->btnDisconnect, &QPushButton::clicked, [=] () { @@ -108,11 +175,12 @@ void AppDataServer::connectAppDialog(QWidget* parent) { // Cleanup tempSecret = ""; + delete tempWormholeClient; delete ui; ui = nullptr; } -void AppDataServer::updateUIWithNewQRCode() { +void AppDataServer::updateUIWithNewQRCode(MainWindow* mainwindow) { // Get the address of the localhost auto addrList = QNetworkInterface::allAddresses(); @@ -138,7 +206,7 @@ void AppDataServer::updateUIWithNewQRCode() { sodium_bin2hex(secretHex, crypto_secretbox_KEYBYTES*2+1, secretBin, crypto_secretbox_KEYBYTES); QString secretStr(secretHex); - tempSecret = secretStr; + registerNewTempSecret(secretStr, mainwindow); QString codeStr = uri + "," + secretStr; @@ -146,6 +214,12 @@ void AppDataServer::updateUIWithNewQRCode() { ui->txtConnStr->setText(codeStr); } +void AppDataServer::registerNewTempSecret(QString tmpSecretHex, MainWindow* main) { + tempSecret = tmpSecretHex; + + tempWormholeClient = new WormholeClient(main, getWormholeCode(tempSecret)); +} + void AppDataServer::updateConnectedUI() { if (ui == nullptr) return; @@ -222,7 +296,8 @@ QString AppDataServer::encryptOutgoing(QString msg) { auto json = QJsonDocument(QJsonObject{ {"nonce", QString(newLocalNonce)}, - {"payload", QString(encryptedHex)} + {"payload", QString(encryptedHex)}, + {"to", getWormholeCode(getSecretHex())} }); delete[] noncebin; @@ -345,13 +420,17 @@ void AppDataServer::processMessage(QString message, MainWindow* mainWindow, QWeb // decryptMessage() saveNewSecret(tempSecret); + // Swap out the wormhole connection + mainWindow->replaceWormholeClient(tempWormholeClient); + tempWormholeClient = nullptr; + // 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(); + updateUIWithNewQRCode(mainWindow); } processDecryptedMessage(decrypted, mainWindow, pClient); diff --git a/src/websockets.h b/src/websockets.h index 0919ff1..2590317 100644 --- a/src/websockets.h +++ b/src/websockets.h @@ -33,6 +33,28 @@ private: bool m_debug; }; +class WormholeClient : public QObject { + Q_OBJECT + +Q_SIGNALS: + void closed(); + +private Q_SLOTS: + void onConnected(); + void onTextMessageReceived(QString message); + +public: + WormholeClient(MainWindow* parent, QString wormholeCode); + ~WormholeClient(); + + void connect(); + +private: + MainWindow* parent = nullptr; + QWebSocket m_webSocket; + QString code; +}; + enum NonceType { LOCAL = 1, REMOTE @@ -47,9 +69,9 @@ public: return instance; } - void connectAppDialog(QWidget* parent); + void connectAppDialog(MainWindow* parent); void updateConnectedUI(); - void updateUIWithNewQRCode(); + void updateUIWithNewQRCode(MainWindow* mainwindow); void processSendTx(QJsonObject sendTx, MainWindow* mainwindow, QWebSocket* pClient); void processMessage(QString message, MainWindow* mainWindow, QWebSocket* pClient); @@ -60,9 +82,12 @@ public: 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, MainWindow* main); + QString getNonceHex(NonceType nt); void saveNonceHex(NonceType nt, QString noncehex); @@ -70,8 +95,10 @@ private: AppDataServer() = default; static AppDataServer* instance; - QString tempSecret; Ui_MobileAppConnector* ui; + + QString tempSecret; + WormholeClient* tempWormholeClient = nullptr; }; class AppDataModel { @@ -105,4 +132,6 @@ private: static AppDataModel* instance; }; + + #endif // WEBSOCKETS_H \ No newline at end of file