diff --git a/.travis.yml b/.travis.yml index c3810b7..6cded8f 100644 --- a/.travis.yml +++ b/.travis.yml @@ -25,7 +25,7 @@ before_install: - sudo add-apt-repository ppa:beineri/opt-qt-5.14.2-xenial -y - sudo apt-get update -qq - sudo apt-get install libsodium-dev pkg-config - - sudo apt-get install qt514base libgl1-mesa-dev + - sudo apt-get install qt514base qt514websockets libgl1-mesa-dev - source /opt/qt514/bin/qt514-env.sh - chmod +x res/libsodium/buildlibsodium.sh diff --git a/LICENSE b/LICENSE index e8b36af..9bc948a 100644 --- a/LICENSE +++ b/LICENSE @@ -1,4 +1,4 @@ - Copyright 2019-2024 The Hush developers + Copyright 2019-2023 The Hush developers Copyright 2018 adityapk diff --git a/README.md b/README.md index 09df59e..b67cb66 100644 --- a/README.md +++ b/README.md @@ -49,20 +49,11 @@ rustup -V **Nothing below will work without the Linux "build-essential" package. Check that your system has it installed. If not, and you're using a Ubuntu/Debian distro, then you can install with `apt install build-essential`.** -##### Ubuntu 22.04: - -```shell script -sudo apt-get -y install build-essential qtbase5-dev qt5-qmake qtcreator qttools5-dev-tools -``` - -##### Ubuntu 18.04 and 20.04: -```shell script -sudo apt-get -y install build-essential qt5-default qt5-qmake qtcreator qttools5-dev-tools -``` - Compiling can take some time, so be patient and wait for it to finish. It will take potentially a long time for slower systems. Be Patient and please report compiler problems! +##### Ubuntu 18.04 and 20.04: ```shell script +sudo apt-get -y install build-essential qt5-default qt5-qmake libqt5websockets5-dev qtcreator qttools5-dev-tools git clone https://git.hush.is/hush/SilentDragonLite cd SilentDragonLite ./build.sh linguist diff --git a/build.sh b/build.sh index 4624f74..c435eb5 100755 --- a/build.sh +++ b/build.sh @@ -1,5 +1,5 @@ #!/bin/bash -# Copyright 2019-2024 The Hush Developers +# Copyright 2019-2023 The Hush Developers # Released under the GPLv3 UNAME=$(uname) diff --git a/contrib/debian/README.md b/contrib/debian/README.md deleted file mode 100644 index 45fd020..0000000 --- a/contrib/debian/README.md +++ /dev/null @@ -1,11 +0,0 @@ -Install build tools: - -``` -sudo apt install dh-make -``` - -To build the package from source run the following: - -``` -dpkg-buildpackage -rfakeroot -b -uc -us -``` \ No newline at end of file diff --git a/contrib/debian/changelog b/contrib/debian/changelog deleted file mode 100644 index cd59351..0000000 --- a/contrib/debian/changelog +++ /dev/null @@ -1,5 +0,0 @@ -silentdragonlite (1.5.4) stable; urgency=medium - - * 1.5.4.1 release. - - -- onryo Sat, 06 Jan 2024 10:20:30 +0200 diff --git a/contrib/debian/compat b/contrib/debian/compat deleted file mode 100644 index f11c82a..0000000 --- a/contrib/debian/compat +++ /dev/null @@ -1 +0,0 @@ -9 \ No newline at end of file diff --git a/contrib/debian/control b/contrib/debian/control deleted file mode 100644 index c57d5c1..0000000 --- a/contrib/debian/control +++ /dev/null @@ -1,13 +0,0 @@ -Source: silentdragonlite -Section: utils -Priority: optional -Maintainer: onryo -Standards-Version: 4.6.0 -Homepage: https://hush.is -Vcs-Browser: https://git.hush.is/hush/SilentDragonLite -Vcs-Git: https://git.hush.is/hush/SilentDragonLite.git - -Package: silentdragonlite -Architecture: amd64 arm64 -Depends: ${shlibs:Depends}, ${misc:Depends} -Description: SilentDragonLite is a lightwallet for HUSH which does not require you to download the full blockchain. \ No newline at end of file diff --git a/contrib/debian/copyright b/contrib/debian/copyright deleted file mode 100644 index 5128172..0000000 --- a/contrib/debian/copyright +++ /dev/null @@ -1,5 +0,0 @@ -Files: * -Copyright: 2019-2024, The Hush developers - 2018-2019, The Zcash developers -License: GPLv3 -Comment: https://hush.is/developers \ No newline at end of file diff --git a/contrib/debian/rules b/contrib/debian/rules deleted file mode 100644 index b9ce217..0000000 --- a/contrib/debian/rules +++ /dev/null @@ -1,20 +0,0 @@ -#!/usr/bin/make -f -# See debhelper(7) (uncomment to enable) -# output every command that modifies files on the build system. -#export DH_VERBOSE = 1 - -# see FEATURE AREAS in dpkg-buildflags(1) -#export DEB_BUILD_MAINT_OPTIONS = hardening=+all -# see ENVIRONMENT in dpkg-buildflags(1) -# package maintainers to append CFLAGS -#export DEB_CFLAGS_MAINT_APPEND = -Wall -pedantic -# package maintainers to append LDFLAGS -#export DEB_LDFLAGS_MAINT_APPEND = -Wl,--as-needed - -%: - dh $@ - -# dh_make generated override targets -# This is example for Cmake (See https://bugs.debian.org/641051 ) -#override_dh_auto_configure: -# dh_auto_configure -- # -DCMAKE_LIBRARY_PATH=$(DEB_HOST_MULTIARCH) \ No newline at end of file diff --git a/doc/developer.md b/doc/developer.md deleted file mode 100644 index 7824e17..0000000 --- a/doc/developer.md +++ /dev/null @@ -1,62 +0,0 @@ -# Developer Docs for SDL - -Random stuff that is useful for devs. - -# Checking return values from litelib - -There are 3 functions written in Rust that live in lib/src/lib.rs : - - * `litelib_initialize_new` - * create a new client/connection and brand new wallet - * `litelib_initialize_new_from_phrase` - * create a new client/connection from a seedphrase (restoring from seedphrase) - * `litelib_initialize_existing` - * create a new client/connection with an already existing wallet - -The Rust code calls it a "LightClient" while the C++ of SDL calls it a "Connection". - -When `litelib_initialize_existing` or `litelib_initialize_new_from_phrase` return successfully, they return the string "OK" (which is not JSON). - -When `litelib_initialize_new` returns successfully it returns JSON that looks like : - -``` -{"seed":"seed","birthday":birthday} -``` - -where "seed" is a 24 word seed and birthday is an integer block height. - -So when calling these 3 functions, which looks almost the same in the calling code, the code which checks if they worked will be different, depending on what each returns on success. - -When checking the return value of `litelib_initialize_existing` or `litelib_initialize_new_from_phrase` it should look like : - -``` -QString reply = ""; -try { - char* resp = litelib_initialize_new_from_phrase(...); - reply = litelib_process_response(resp); -} catch { - ... -} -if (reply.isEmpty())) { - // litelib_initialize_new_from_phrase failed - ... -} -``` - -Yes, `isEmpty()` is not a very strict check, we could actually check for valid-looking JSON (starts with a { and ends with a }) as well as making sure the keys "seed" and "birthday" exist. Please implement this. - -When checking the return value of `litelib_initialize_new` it should look like : - -``` -QString reply = ""; -try { - char* resp = litelib_initialize_new(...); - reply = litelib_process_response(resp); -} catch { - ... -} -if (reply.toUpper().trimmed() != "OK") { - // litelib_initialize_new failed - ... -} -``` diff --git a/doc/release-process.md b/doc/release-process.md index bc5422c..0283d0a 100644 --- a/doc/release-process.md +++ b/doc/release-process.md @@ -55,13 +55,4 @@ To update the file run `cargo vendor` as was mentioned in https://git.hush.is/hu ## Release process - * Write release notes - * Choose a release name - * Make Gitea release from master branch - * You can either manually make a git tag or let Gitea do it, which is easier - * Make binaries - * Windows exe - * Windows msi - * Linux - * Mac - * Debian package +... diff --git a/doc/relnotes.md b/doc/relnotes.md index ac78cae..c503ad5 100644 --- a/doc/relnotes.md +++ b/doc/relnotes.md @@ -1,23 +1,3 @@ -# SilentDragonLite v1.5.4 "Shielded Supersonic" - -* Mempool integration: https://git.hush.is/hush/SilentDragonLite/commit/3962b42e3098863a8b959de1b12b029c13008cbe, https://git.hush.is/hush/SilentDragonLite/pulls/126. -* Improve error handling when restoring from seedphrase: https://git.hush.is/hush/SilentDragonLite/commit/5d5447aced2c6b2a16e7dc1efd6a235c478480fb, https://git.hush.is/hush/SilentDragonLite/commit/6165733e039defc58d56fb34add5b0be43dba72d, https://git.hush.is/hush/SilentDragonLite/commit/1e6e77055b2df916af69c1c5ab16cc9294b29344. -* Remove websockets, we now have a standalone Android wallet: https://git.hush.is/hush/SilentDragonLite/commit/430a7ab47424a3b5f9af95f47913cecb7aee05d0, https://git.hush.is/hush/SilentDragonLite/commit/3b6da338c910f4a901d65cae3fad262db09c393f. -* Try another server if current is down when creating new seed: https://git.hush.is/hush/SilentDragonLite/commit/3f8ae1f9d75766331e3d1bb7689e7b18850061e1, https://git.hush.is/hush/SilentDragonLite/commit/557e10e5e8c35a102e82370517bf3a7a5ab25fca. -* Try another server if current is down when restoring during a rescan; report down server in error: https://git.hush.is/hush/SilentDragonLite/commit/f7787fe9e92ec560b48550728315e7068f8f815f. -* Report server in error when saving wallet as part of rescan: https://git.hush.is/hush/SilentDragonLite/commit/17fcb84a897ddc5b8e62241d2a3da2576200e618, https://git.hush.is/hush/SilentDragonLite/commit/51483843ac148be7d2c6956147e2fc57e144c387. -* Make sure to init from phrase when trying a new server during restore in first time wizard: https://git.hush.is/hush/SilentDragonLite/commit/ad5b294d95953bfe2f6061e20829da79919647a6. -* Initialize a new server connection from seedphrase when restoring from seed: https://git.hush.is/hush/SilentDragonLite/commit/c7e0f0fae6ea41e23ef3abc3035ecaa807201d95. -* Try another server if current is down when saving wallet via a rescan: https://git.hush.is/hush/SilentDragonLite/commit/9befa3450fdeea8a76bae324811f49b0593a151f. -* Try another server if we get an error when executing an RPC: https://git.hush.is/hush/SilentDragonLite/commit/7e54360b7215627a613a309960386ebd455a68dd, https://git.hush.is/hush/SilentDragonLite/commit/b84828604f8c9aa25acf41e90fdf5e9f4118e6bd, https://git.hush.is/hush/SilentDragonLite/commit/77ac1f99ae9a2b0b42ae752e1ce457ff9abdfcd8, https://git.hush.is/hush/SilentDragonLite/commit/f46e1b4a578b3af2d4b6cbe4754959278bbfdba9, https://git.hush.is/hush/SilentDragonLite/commit/bfdda1f1af7e4bc42dc1a4e10985e6c152dad8bd, https://git.hush.is/hush/SilentDragonLite/issues/119. (NOT READY YET) -* Update current server on info tab since it can change at run-time: https://git.hush.is/hush/SilentDragonLite/commit/a080d0ca80d757519367a38a480caee0fb1f0173. -* Misc: https://git.hush.is/hush/SilentDragonLite/commit/5508050fcca66cda38045b0f80535e3aea2aad50, https://git.hush.is/hush/SilentDragonLite/commit/cb0de2c3f6fd4b378fbfe9d37d90287c38196be4. -* Look for non-empty responses instead of the string "OK": https://git.hush.is/hush/SilentDragonLite/commit/51fe4d6cde15c1ae6b7c7930bfd4878a174f5ac5. -* Check for a non-empty response from litelib_execute: https://git.hush.is/hush/SilentDragonLite/commit/7364e21f999693825f1bd59a0814f7534e9d6f90. -* Docs: https://git.hush.is/hush/SilentDragonLite/commit/d05d8271ecc78cad6acae8d335ada7f394d72fe6, https://git.hush.is/hush/SilentDragonLite/commit/9a7e87fa1d089c2c8eb7c8abfe843d6954f384cf. -* Debug: https://git.hush.is/hush/SilentDragonLite/commit/5b33cb3638adc17f414e1f211d90b124b4f0dc69. -* deb stuff: https://git.hush.is/hush/SilentDragonLite/commit/aa58e3a4ce162e828a1ae25a2f242285296b33db, https://git.hush.is/hush/SilentDragonLite/commit/d8ff0de15d78d6daf3dc280f4f70c62adae40340, https://git.hush.is/hush/SilentDragonLite/commit/b8c18aa38b3b18d0e630423004fbf70284446a21, https://git.hush.is/hush/SilentDragonLite/commit/eca9c53ff7346f48706740443f10273a91df4475. - # SilentDragonLite v1.5.3 "Mythical Coelacanth" * Change lite server after sending a tx for improved privacy: https://git.hush.is/hush/SilentDragonLite/commit/a8fc12e0e2b2324db21407f4848f2d4aa59f4575. diff --git a/doc/win/DEVELOPING-Ubuntu-18-04.md b/doc/win/DEVELOPING-Ubuntu-18-04.md index 8aa2e54..fca6704 100644 --- a/doc/win/DEVELOPING-Ubuntu-18-04.md +++ b/doc/win/DEVELOPING-Ubuntu-18-04.md @@ -56,7 +56,7 @@ mkdir ~/git && cd ~/git git clone https://github.com/mxe/mxe.git cd mxe -make -j$(nproc) MXE_TARGETS=x86_64-w64-mingw32.static qtbase +make -j$(nproc) MXE_TARGETS=x86_64-w64-mingw32.static qtbase qtwebsockets ``` # Build SilentDragonLite .exe diff --git a/lib/Cargo.lock b/lib/Cargo.lock index a7884bb..174a16f 100644 --- a/lib/Cargo.lock +++ b/lib/Cargo.lock @@ -1849,7 +1849,7 @@ dependencies = [ [[package]] name = "silentdragonlitelib" version = "0.1.0" -source = "git+https://git.hush.is/hush/silentdragonlite-cli?rev=4ec78a01b4f35b08eff42b10e3be85de87ba2b02#4ec78a01b4f35b08eff42b10e3be85de87ba2b02" +source = "git+https://git.hush.is/hush/silentdragonlite-cli?rev=0181b16fd037f98c760e668bb6af8a41dd0d6267#0181b16fd037f98c760e668bb6af8a41dd0d6267" dependencies = [ "base58", "bellman", diff --git a/lib/Cargo.toml b/lib/Cargo.toml index a500de6..11e08b7 100644 --- a/lib/Cargo.toml +++ b/lib/Cargo.toml @@ -12,4 +12,4 @@ crate-type = ["staticlib"] libc = "0.2.58" lazy_static = "1.4.0" blake3 = "0.3.4" -silentdragonlitelib = { git = "https://git.hush.is/hush/silentdragonlite-cli", rev = "4ec78a01b4f35b08eff42b10e3be85de87ba2b02" } +silentdragonlitelib = { git = "https://git.hush.is/hush/silentdragonlite-cli", rev = "0181b16fd037f98c760e668bb6af8a41dd0d6267" } diff --git a/lib/src/lib.rs b/lib/src/lib.rs index eaa03ba..6f73c6d 100644 --- a/lib/src/lib.rs +++ b/lib/src/lib.rs @@ -92,15 +92,7 @@ pub extern fn litelib_initialize_new(dangerous: bool,server: *const c_char) -> * } }; - let lc = Arc::new(lightclient); - match LightClient::start_mempool_monitor(lc.clone()) { - Ok(_) => {println!("Starting Mempool")}, - Err(e) => { - println!("Couldnt start mempool {}", e) - } - } - - LIGHTCLIENT.lock().unwrap().replace(Some(lc)); + LIGHTCLIENT.lock().unwrap().replace(Some(Arc::new(lightclient))); // Return the wallet's seed let s_str = CString::new(seed).unwrap(); @@ -143,15 +135,7 @@ pub extern fn litelib_initialize_new_from_phrase(dangerous: bool,server: *const // Initialize logging let _ = lightclient.init_logging(); - let lc = Arc::new(lightclient); - match LightClient::start_mempool_monitor(lc.clone()) { - Ok(_) => {println!("Starting Mempool")}, - Err(e) => { - println!("Couldnt start mempool {}",e) - } - } - - LIGHTCLIENT.lock().unwrap().replace(Some(lc)); + LIGHTCLIENT.lock().unwrap().replace(Some(Arc::new(lightclient))); let c_str = CString::new("OK").unwrap(); return c_str.into_raw(); @@ -185,17 +169,8 @@ pub extern fn litelib_initialize_existing(dangerous: bool, server: *const c_char // Initialize logging let _ = lightclient.init_logging(); - - - let lc = Arc::new(lightclient); - match LightClient::start_mempool_monitor(lc.clone()) { - Ok(_) => {println!("Starting Mempool")}, - Err(e) => { - println!("Couldnt start mempool {}",e) - } - } - LIGHTCLIENT.lock().unwrap().replace(Some(lc)); + LIGHTCLIENT.lock().unwrap().replace(Some(Arc::new(lightclient))); let c_str = CString::new("OK").unwrap(); return c_str.into_raw(); diff --git a/res/css/Dark.css b/res/css/Dark.css index 9a7ffe1..9a30723 100644 --- a/res/css/Dark.css +++ b/res/css/Dark.css @@ -25,7 +25,7 @@ QTabWidget QTabBar::tab:hover { background-color:qlineargradient(x1: 0, y1: 0, x2: 0, y2: 0.25, stop: 0 #747577, stop: 1 #3E4244); color:#fff; border: 1px ridge #fff; -min-height: 20px; +min-height: 20px } QHeaderView { /* Table Header */ diff --git a/res/libsodium.a b/res/libsodium.a new file mode 100644 index 0000000..3a24a38 Binary files /dev/null and b/res/libsodium.a differ diff --git a/res/libsodium/buildlibsodium.sh b/res/libsodium/buildlibsodium.sh index 12d4412..f9f8bae 100755 --- a/res/libsodium/buildlibsodium.sh +++ b/res/libsodium/buildlibsodium.sh @@ -1,5 +1,5 @@ #!/bin/bash -# Copyright 2019-2024 The Hush developers +# Copyright 2019-2023 The Hush developers # Released under the GPLv3 VERSION=1.0.18 diff --git a/run-after-build.sh b/run-after-build.sh index f4147e4..35c5499 100755 --- a/run-after-build.sh +++ b/run-after-build.sh @@ -1,4 +1,4 @@ #!/bin/bash -# Copyright 2019-2024 The Hush Developers +# Copyright 2019-2023 The Hush Developers ./build.sh && ./SilentDragonLite diff --git a/silentdragon-lite.pro b/silentdragon-lite.pro index adf640e..3056c1c 100644 --- a/silentdragon-lite.pro +++ b/silentdragon-lite.pro @@ -3,7 +3,7 @@ # Project created by QtCreator 2018-10-05T09:54:45 # #------------------------------------------------- -# Copyright 2019-2024 The Hush Developers +# Copyright 2019-2023 The Hush Developers # Released under the GPLv3 QT += core gui network @@ -13,6 +13,7 @@ CONFIG += precompile_header PRECOMPILED_HEADER = src/precompiled.h QT += widgets +QT += websockets TARGET = SilentDragonLite TEMPLATE = app @@ -58,6 +59,8 @@ SOURCES += \ src/addressbook.cpp \ src/logger.cpp \ src/addresscombo.cpp \ + src/websockets.cpp \ + src/mobileappconnector.cpp \ src/recurring.cpp \ src/requestdialog.cpp \ src/memoedit.cpp \ @@ -101,6 +104,8 @@ HEADERS += \ src/addressbook.h \ src/logger.h \ src/addresscombo.h \ + src/websockets.h \ + src/mobileappconnector.h \ src/recurring.h \ src/requestdialog.h \ src/memoedit.h \ @@ -138,6 +143,7 @@ FORMS += \ src/connection.ui \ src/addressbook.ui \ src/memodialog.ui \ + src/mobileappconnector.ui \ src/createhushconfdialog.ui \ src/recurringdialog.ui \ src/requestContactDialog.ui \ diff --git a/src/3rdparty/sodium.h b/src/3rdparty/sodium.h index ac52ee1..ef07f1b 100644 --- a/src/3rdparty/sodium.h +++ b/src/3rdparty/sodium.h @@ -1,4 +1,4 @@ -// Copyright 2019-2024 The Hush developers +// Copyright 2019-2023 The Hush developers // Released under the GPLv3 #ifndef sodium_H diff --git a/src/Chat/Chat.cpp b/src/Chat/Chat.cpp index 08dbd08..c006ec2 100644 --- a/src/Chat/Chat.cpp +++ b/src/Chat/Chat.cpp @@ -1,4 +1,4 @@ -// Copyright 2019-2024 The Hush developers +// Copyright 2019-2023 The Hush developers // Released under the GPLv3 #include "Chat.h" diff --git a/src/Chat/Chat.h b/src/Chat/Chat.h index 231fa62..8d45fe8 100644 --- a/src/Chat/Chat.h +++ b/src/Chat/Chat.h @@ -1,4 +1,4 @@ -// Copyright 2019-2024 The Hush developers +// Copyright 2019-2023 The Hush developers // Released under the GPLv3 #ifndef CHAT_H #define CHAT_H diff --git a/src/Chat/Helper/ChatDelegator.h b/src/Chat/Helper/ChatDelegator.h index 462d959..646ba41 100644 --- a/src/Chat/Helper/ChatDelegator.h +++ b/src/Chat/Helper/ChatDelegator.h @@ -1,4 +1,4 @@ -// Copyright 2019-2024 The Hush developers +// Copyright 2019-2023 The Hush developers // GPLv3 #ifndef CHATDELEGATOR_H diff --git a/src/Crypto/FileEncryption.cpp b/src/Crypto/FileEncryption.cpp index 1b79bce..4181167 100644 --- a/src/Crypto/FileEncryption.cpp +++ b/src/Crypto/FileEncryption.cpp @@ -1,4 +1,4 @@ -// Copyright 2019-2024 The Hush developers +// Copyright 2019-2023 The Hush developers // Released under the GPLv3 #include "FileEncryption.h" diff --git a/src/Crypto/FileEncryption.h b/src/Crypto/FileEncryption.h index afb5cd6..ccbb4d8 100644 --- a/src/Crypto/FileEncryption.h +++ b/src/Crypto/FileEncryption.h @@ -1,4 +1,4 @@ -// Copyright 2019-2024 The Hush developers +// Copyright 2019-2023 The Hush developers // Released under the GPLv3 #ifndef FILEENCRYPTION_H #define FILEENCRYPTION_H diff --git a/src/Crypto/passwd.cpp b/src/Crypto/passwd.cpp index e9341ee..ced6661 100644 --- a/src/Crypto/passwd.cpp +++ b/src/Crypto/passwd.cpp @@ -1,4 +1,4 @@ -// Copyright 2019-2024 The Hush developers +// Copyright 2019-2023 The Hush developers // Released under the GPLv3 #include "passwd.h" diff --git a/src/Crypto/passwd.h b/src/Crypto/passwd.h index abfc695..5f5b01c 100644 --- a/src/Crypto/passwd.h +++ b/src/Crypto/passwd.h @@ -1,4 +1,4 @@ -// Copyright 2019-2024 The Hush developers +// Copyright 2019-2023 The Hush developers // Released under the GPLv3 #ifndef PASSWD_H #define PASSWD_H diff --git a/src/DataStore/ChatDataStore.cpp b/src/DataStore/ChatDataStore.cpp index ad1b680..b0944ec 100644 --- a/src/DataStore/ChatDataStore.cpp +++ b/src/DataStore/ChatDataStore.cpp @@ -1,4 +1,4 @@ -// Copyright 2019-2024 The Hush developers +// Copyright 2019-2023 The Hush developers // Released under the GPLv3 #include "ChatDataStore.h" diff --git a/src/DataStore/ChatDataStore.h b/src/DataStore/ChatDataStore.h index 3300631..06ca1f2 100644 --- a/src/DataStore/ChatDataStore.h +++ b/src/DataStore/ChatDataStore.h @@ -1,4 +1,4 @@ -// Copyright 2019-2024 The Hush developers +// Copyright 2019-2023 The Hush developers // Released under the GPLv3 #ifndef CHATDATASTORE_H #define CHATDATASTORE_H diff --git a/src/DataStore/ContactDataStore.cpp b/src/DataStore/ContactDataStore.cpp index bed1676..68e6aae 100644 --- a/src/DataStore/ContactDataStore.cpp +++ b/src/DataStore/ContactDataStore.cpp @@ -1,4 +1,4 @@ -// Copyright 2019-2024 The Hush developers +// Copyright 2019-2023 The Hush developers // GPLv3 #include "ContactDataStore.h" diff --git a/src/DataStore/ContactDataStore.h b/src/DataStore/ContactDataStore.h index c9bc7ff..f6a1dbf 100644 --- a/src/DataStore/ContactDataStore.h +++ b/src/DataStore/ContactDataStore.h @@ -1,4 +1,4 @@ -// Copyright 2019-2024 The Hush developers +// Copyright 2019-2023 The Hush developers // Released under the GPLv3 #ifndef CONTACTDATASTORE_H #define CONTACTDATASTORE_H diff --git a/src/DataStore/DataStore-deprecated.h b/src/DataStore/DataStore-deprecated.h index 1e3f9da..3cee754 100644 --- a/src/DataStore/DataStore-deprecated.h +++ b/src/DataStore/DataStore-deprecated.h @@ -1,4 +1,4 @@ -// Copyright 2019-2024 The Hush developers +// Copyright 2019-2023 The Hush developers // Released under the GPLv3 #ifndef DATASTORE_H #define DATASTORE_H diff --git a/src/DataStore/DataStore.cpp b/src/DataStore/DataStore.cpp index f7aa1a4..73d98e3 100644 --- a/src/DataStore/DataStore.cpp +++ b/src/DataStore/DataStore.cpp @@ -1,4 +1,4 @@ -// Copyright 2019-2024 The Hush developers +// Copyright 2019-2023 The Hush developers // Released under the GPLv3 #include "DataStore.h" diff --git a/src/DataStore/DataStore.h b/src/DataStore/DataStore.h index 14df162..def4c5d 100644 --- a/src/DataStore/DataStore.h +++ b/src/DataStore/DataStore.h @@ -1,4 +1,4 @@ -// Copyright 2019-2024 The Hush developers +// Copyright 2019-2023 The Hush developers // Released under the GPLv3 #ifndef DATASTORE_H #define DATASTORE_H diff --git a/src/DataStore/SietchDataStore.cpp b/src/DataStore/SietchDataStore.cpp index 7268e98..9c04204 100644 --- a/src/DataStore/SietchDataStore.cpp +++ b/src/DataStore/SietchDataStore.cpp @@ -1,4 +1,4 @@ -// Copyright 2019-2024 The Hush developers +// Copyright 2019-2023 The Hush developers // Released under the GPLv3 #include "SietchDataStore.h" diff --git a/src/DataStore/SietchDataStore.h b/src/DataStore/SietchDataStore.h index 70526b2..a5889bc 100644 --- a/src/DataStore/SietchDataStore.h +++ b/src/DataStore/SietchDataStore.h @@ -1,4 +1,4 @@ -// Copyright 2019-2024 The Hush developers +// Copyright 2019-2023 The Hush developers // Released under the GPLv3 #ifndef SIETCHDATASTORE_H #define SIETCHDATASTORE_H diff --git a/src/FileSystem/FileSystem.cpp b/src/FileSystem/FileSystem.cpp index 1f71a50..a598d36 100644 --- a/src/FileSystem/FileSystem.cpp +++ b/src/FileSystem/FileSystem.cpp @@ -1,4 +1,4 @@ -// Copyright 2019-2024 The Hush developers +// Copyright 2019-2023 The Hush developers // Released under the GPLv3 #include "FileSystem.h" diff --git a/src/FileSystem/FileSystem.h b/src/FileSystem/FileSystem.h index 596a57d..44d6cc6 100644 --- a/src/FileSystem/FileSystem.h +++ b/src/FileSystem/FileSystem.h @@ -1,4 +1,4 @@ -// Copyright 2019-2024 The Hush developers +// Copyright 2019-2023 The Hush developers // GPLv3 #ifndef FILESYSTEM_H #define FILESYSTEM_H diff --git a/src/Logger/LogContext.h b/src/Logger/LogContext.h index 25b1bca..7b3f4a8 100644 --- a/src/Logger/LogContext.h +++ b/src/Logger/LogContext.h @@ -1,4 +1,4 @@ -// Copyright 2019-2024 The Hush developers +// Copyright 2019-2023 The Hush developers // Released under the GPLv3 #ifndef LOGCONTEXT_H #define LOGCONTEXT_H diff --git a/src/Logger/LogCrtitical.h b/src/Logger/LogCrtitical.h index 514b6e7..0c05f4c 100644 --- a/src/Logger/LogCrtitical.h +++ b/src/Logger/LogCrtitical.h @@ -1,4 +1,4 @@ -// Copyright 2019-2024 The Hush developers +// Copyright 2019-2023 The Hush developers // Released under the GPLv3 #ifndef LOGCRITICAL_H #define LOGCRITICAL_H diff --git a/src/Logger/LogDebug.h b/src/Logger/LogDebug.h index 2df045c..3967900 100644 --- a/src/Logger/LogDebug.h +++ b/src/Logger/LogDebug.h @@ -1,4 +1,4 @@ -// Copyright 2019-2024 The Hush developers +// Copyright 2019-2023 The Hush developers // Released under the GPLv3 #ifndef LOGDEBUG_H #define LOGDEBUG_H diff --git a/src/Logger/LogError.h b/src/Logger/LogError.h index 5c8f42d..07daf70 100644 --- a/src/Logger/LogError.h +++ b/src/Logger/LogError.h @@ -1,4 +1,4 @@ -// Copyright 2019-2024 The Hush developers +// Copyright 2019-2023 The Hush developers // Released under the GPLv3 #ifndef LOGERROR_H #define LOGERROR_H diff --git a/src/Logger/LogFatal.h b/src/Logger/LogFatal.h index 719983c..cc00e65 100644 --- a/src/Logger/LogFatal.h +++ b/src/Logger/LogFatal.h @@ -1,4 +1,4 @@ -// Copyright 2019-2024 The Hush developers +// Copyright 2019-2023 The Hush developers // Released under the GPLv3 #ifndef LOGFATAL_H #define LOGFATAL_H diff --git a/src/Logger/LogInfo.h b/src/Logger/LogInfo.h index 9838a77..5fcaa02 100644 --- a/src/Logger/LogInfo.h +++ b/src/Logger/LogInfo.h @@ -1,4 +1,4 @@ -// Copyright 2019-2024 The Hush developers +// Copyright 2019-2023 The Hush developers // Released under the GPLv3 #ifndef LOGINFO_H #define LOGINFO_H diff --git a/src/Logger/LogStrategy.h b/src/Logger/LogStrategy.h index ca247ce..c17802f 100644 --- a/src/Logger/LogStrategy.h +++ b/src/Logger/LogStrategy.h @@ -1,4 +1,4 @@ -// Copyright 2019-2024 The Hush developers +// Copyright 2019-2023 The Hush developers // Released under the GPLv3 #ifndef LOGSTRATEGY_H #define LOGSTRATEGY_H diff --git a/src/Logger/LogSuccess.h b/src/Logger/LogSuccess.h index 3c39a05..1ab4e22 100644 --- a/src/Logger/LogSuccess.h +++ b/src/Logger/LogSuccess.h @@ -1,4 +1,4 @@ -// Copyright 2019-2024 The Hush developers +// Copyright 2019-2023 The Hush developers // Released under the GPLv3 #ifndef LOGSUCCESS_H #define LOGSUCCESS_H diff --git a/src/Logger/LogType.h b/src/Logger/LogType.h index 9c43c05..468a717 100644 --- a/src/Logger/LogType.h +++ b/src/Logger/LogType.h @@ -1,4 +1,4 @@ -// Copyright 2019-2024 The Hush developers +// Copyright 2019-2023 The Hush developers // Released under the GPLv3 #ifndef LOGTYPE_H #define LOGTYPE_H diff --git a/src/Logger/LogWarning.h b/src/Logger/LogWarning.h index 96d2f04..ef11b56 100644 --- a/src/Logger/LogWarning.h +++ b/src/Logger/LogWarning.h @@ -1,4 +1,4 @@ -// Copyright 2019-2024 The Hush developers +// Copyright 2019-2023 The Hush developers // Released under the GPLv3 #ifndef LOGWARNING_H #define LOGWARNING_H diff --git a/src/Logger/LogWriter.cpp b/src/Logger/LogWriter.cpp index a24cb0f..3bdeb02 100644 --- a/src/Logger/LogWriter.cpp +++ b/src/Logger/LogWriter.cpp @@ -1,4 +1,4 @@ -// Copyright 2019-2024 The Hush developers +// Copyright 2019-2023 The Hush developers // Released under the GPLv3 #include "LogWriter.h" diff --git a/src/Logger/LogWriter.h b/src/Logger/LogWriter.h index 270971c..0e026d8 100644 --- a/src/Logger/LogWriter.h +++ b/src/Logger/LogWriter.h @@ -1,4 +1,4 @@ -// Copyright 2019-2024 The Hush developers +// Copyright 2019-2023 The Hush developers // Released under the GPLv3 #ifndef LOGWRITER_H #define LOGWRITER_H diff --git a/src/Logger/Logger.h b/src/Logger/Logger.h index 5429a24..f00b637 100644 --- a/src/Logger/Logger.h +++ b/src/Logger/Logger.h @@ -1,4 +1,4 @@ -// Copyright 2019-2024 The Hush developers +// Copyright 2019-2023 The Hush developers // Released under the GPLv3 #ifndef LOGGER_H #define LOGGER_H diff --git a/src/Logger/SimpleLogger.h b/src/Logger/SimpleLogger.h index bf16db3..1529d34 100644 --- a/src/Logger/SimpleLogger.h +++ b/src/Logger/SimpleLogger.h @@ -1,4 +1,4 @@ -// Copyright 2019-2024 The Hush developers +// Copyright 2019-2023 The Hush developers // Released under the GPLv3 #ifndef SIMPLELOGGER_H #define SIMPLELOGGER_H diff --git a/src/Logger/test.cpp b/src/Logger/test.cpp index 7596878..4671f81 100644 --- a/src/Logger/test.cpp +++ b/src/Logger/test.cpp @@ -1,4 +1,4 @@ -// Copyright 2019-2024 The Hush developers +// Copyright 2019-2023 The Hush developers // Released under the GPLv3 #include "SimpleLogger.h" diff --git a/src/Model/ChatItem.cpp b/src/Model/ChatItem.cpp index bf3b3ab..19e72d4 100644 --- a/src/Model/ChatItem.cpp +++ b/src/Model/ChatItem.cpp @@ -1,4 +1,4 @@ -// Copyright 2019-2024 The Hush developers +// Copyright 2019-2023 The Hush developers // Released under the GPLv3 #include "ChatItem.h" diff --git a/src/Model/ChatItem.h b/src/Model/ChatItem.h index 2ea7471..35997fc 100644 --- a/src/Model/ChatItem.h +++ b/src/Model/ChatItem.h @@ -1,4 +1,4 @@ -// Copyright 2019-2024 The Hush developers +// Copyright 2019-2023 The Hush developers // Released under the GPLv3 #ifndef CHATITEM_H diff --git a/src/Model/ContactItem.cpp b/src/Model/ContactItem.cpp index 0e34c68..919b4d6 100644 --- a/src/Model/ContactItem.cpp +++ b/src/Model/ContactItem.cpp @@ -1,4 +1,4 @@ -// Copyright 2019-2024 The Hush developers +// Copyright 2019-2023 The Hush developers // GPLv3 #include "ContactItem.h" #include "chatmodel.h" diff --git a/src/Model/ContactItem.h b/src/Model/ContactItem.h index ea51766..9f35576 100644 --- a/src/Model/ContactItem.h +++ b/src/Model/ContactItem.h @@ -1,4 +1,4 @@ -// Copyright 2019-2024 The Hush developers +// Copyright 2019-2023 The Hush developers // Released under the GPLv3 #ifndef CONTACTITEM_H #define CONTACTITEM_H diff --git a/src/Model/ContactRequest.cpp b/src/Model/ContactRequest.cpp index f41e6d4..f9cfa4a 100644 --- a/src/Model/ContactRequest.cpp +++ b/src/Model/ContactRequest.cpp @@ -1,4 +1,4 @@ -// Copyright 2019-2024 The Hush developers +// Copyright 2019-2023 The Hush developers // GPLv3 #include "ContactRequest.h" diff --git a/src/Model/ContactRequest.h b/src/Model/ContactRequest.h index 9954936..5e8f781 100644 --- a/src/Model/ContactRequest.h +++ b/src/Model/ContactRequest.h @@ -1,4 +1,4 @@ -// Copyright 2019-2024 The Hush developers +// Copyright 2019-2023 The Hush developers // Released under the GPLv3 #ifndef CONTACTREQUEST_H #define CONTACTREQUEST_H diff --git a/src/Model/ContactRequestChatItem.cpp b/src/Model/ContactRequestChatItem.cpp index e667d4b..a254c3c 100644 --- a/src/Model/ContactRequestChatItem.cpp +++ b/src/Model/ContactRequestChatItem.cpp @@ -1,3 +1,3 @@ -// Copyright 2019-2024 The Hush developers +// Copyright 2019-2023 The Hush developers // Released under the GPLv3 #include "ContactRequestChatItem.h" diff --git a/src/Model/ContactRequestChatItem.h b/src/Model/ContactRequestChatItem.h index ce47fac..3800536 100644 --- a/src/Model/ContactRequestChatItem.h +++ b/src/Model/ContactRequestChatItem.h @@ -1,4 +1,4 @@ -// Copyright 2019-2024 The Hush developers +// Copyright 2019-2023 The Hush developers // Released under the GPLv3 #ifdef CONTACTREQUESTCHATITEM_H #define CONTACTREQUESTCHATITEM_H diff --git a/src/about.ui b/src/about.ui index ba5f54f..e236366 100644 --- a/src/about.ui +++ b/src/about.ui @@ -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-2024 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-2023 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> diff --git a/src/addressbook.cpp b/src/addressbook.cpp index e57f160..13ca5d0 100644 --- a/src/addressbook.cpp +++ b/src/addressbook.cpp @@ -1,4 +1,4 @@ -// Copyright 2019-2024 The Hush developers +// Copyright 2019-2023 The Hush developers // Released under the GPLv3 #include "addressbook.h" diff --git a/src/addressbook.h b/src/addressbook.h index 73effdc..9a5672e 100644 --- a/src/addressbook.h +++ b/src/addressbook.h @@ -1,4 +1,4 @@ -// Copyright 2019-2024 The Hush developers +// Copyright 2019-2023 The Hush developers // Released under the GPLv3 #ifndef ADDRESSBOOK_H #define ADDRESSBOOK_H diff --git a/src/addresscombo.cpp b/src/addresscombo.cpp index fb5109a..d1399cf 100644 --- a/src/addresscombo.cpp +++ b/src/addresscombo.cpp @@ -1,4 +1,4 @@ -// Copyright 2019-2024 The Hush developers +// Copyright 2019-2023 The Hush developers // Released under the GPLv3 #include "addresscombo.h" #include "addressbook.h" diff --git a/src/addresscombo.h b/src/addresscombo.h index 3f770df..437a592 100644 --- a/src/addresscombo.h +++ b/src/addresscombo.h @@ -1,4 +1,4 @@ -// Copyright 2019-2024 The Hush developers +// Copyright 2019-2023 The Hush developers // Released under the GPLv3 #ifndef ADDRESSCOMBO_H #define ADDRESSCOMBO_H diff --git a/src/balancestablemodel.cpp b/src/balancestablemodel.cpp index 5da187c..91f80b1 100644 --- a/src/balancestablemodel.cpp +++ b/src/balancestablemodel.cpp @@ -1,4 +1,4 @@ -// Copyright 2019-2024 The Hush developers +// Copyright 2019-2023 The Hush developers // Released under the GPLv3 #include "balancestablemodel.h" #include "addressbook.h" diff --git a/src/balancestablemodel.h b/src/balancestablemodel.h index f9d6aee..ee1e70f 100644 --- a/src/balancestablemodel.h +++ b/src/balancestablemodel.h @@ -1,4 +1,4 @@ -// Copyright 2019-2024 The Hush developers +// Copyright 2019-2023 The Hush developers // Released under the GPLv3 #ifndef BALANCESTABLEMODEL_H #define BALANCESTABLEMODEL_H diff --git a/src/camount.cpp b/src/camount.cpp index 90fd732..63b50dd 100644 --- a/src/camount.cpp +++ b/src/camount.cpp @@ -1,4 +1,4 @@ -// Copyright 2019-2024 The Hush developers +// Copyright 2019-2023 The Hush developers // Released under the GPLv3 #include "camount.h" #include "settings.h" diff --git a/src/camount.h b/src/camount.h index ffc853d..299f12b 100644 --- a/src/camount.h +++ b/src/camount.h @@ -1,4 +1,4 @@ -// Copyright 2019-2024 The Hush developers +// Copyright 2019-2023 The Hush developers // Released under the GPLv3 #ifndef CAMOUNT_H #define CAMOUNT_H diff --git a/src/chatbubbleme.cpp b/src/chatbubbleme.cpp index 0fe76fc..ea654fe 100644 --- a/src/chatbubbleme.cpp +++ b/src/chatbubbleme.cpp @@ -1,4 +1,4 @@ -// Copyright 2019-2024 The Hush developers +// Copyright 2019-2023 The Hush developers // Released under the GPLv3 #include "chatbubbleme.h" #include "ui_chatbubbleme.h" diff --git a/src/chatbubbleme.h b/src/chatbubbleme.h index 879f19a..153f015 100644 --- a/src/chatbubbleme.h +++ b/src/chatbubbleme.h @@ -1,4 +1,4 @@ -// Copyright 2019-2024 The Hush developers +// Copyright 2019-2023 The Hush developers // Released under the GPLv3 #ifndef CHATBUBBLEME_H #define CHATBUBBLEME_H diff --git a/src/chatbubblepartner.cpp b/src/chatbubblepartner.cpp index ee427db..1f68e9d 100644 --- a/src/chatbubblepartner.cpp +++ b/src/chatbubblepartner.cpp @@ -1,4 +1,4 @@ -// Copyright 2019-2024 The Hush developers +// Copyright 2019-2023 The Hush developers // Released under the GPLv3 #include "chatbubblepartner.h" #include "ui_chatbubblepartner.h" diff --git a/src/chatbubblepartner.h b/src/chatbubblepartner.h index e0ddf10..26058bc 100644 --- a/src/chatbubblepartner.h +++ b/src/chatbubblepartner.h @@ -1,4 +1,4 @@ -// Copyright 2019-2024 The Hush developers +// Copyright 2019-2023 The Hush developers // Released under the GPLv3 #ifndef CHATBUBBLEPARTNER_H #define CHATBUBBLEPARTNER_H diff --git a/src/chatmodel.cpp b/src/chatmodel.cpp index 4dedaa2..306b1ba 100644 --- a/src/chatmodel.cpp +++ b/src/chatmodel.cpp @@ -1,4 +1,4 @@ -// Copyright 2019-2024 The Hush developers +// Copyright 2019-2023 The Hush developers // Released under the GPLv3 #include "chatmodel.h" #include "settings.h" diff --git a/src/chatmodel.h b/src/chatmodel.h index aca73b3..af6b7c1 100644 --- a/src/chatmodel.h +++ b/src/chatmodel.h @@ -1,4 +1,4 @@ -// Copyright 2019-2024 The Hush developers +// Copyright 2019-2023 The Hush developers // Released under the GPLv3 #ifndef CHATMODEL_H diff --git a/src/connection.cpp b/src/connection.cpp index a5c3db4..bef89f8 100644 --- a/src/connection.cpp +++ b/src/connection.cpp @@ -1,4 +1,4 @@ -// Copyright 2019-2024 The Hush developers +// Copyright 2019-2023 The Hush developers // Released under the GPLv3 #include "connection.h" #include "mainwindow.h" @@ -9,8 +9,6 @@ #include "controller.h" #include "../lib/silentdragonlitelib.h" #include "precompiled.h" -#include -#include "sdl.h" using json = nlohmann::json; @@ -34,7 +32,7 @@ ConnectionLoader::ConnectionLoader(MainWindow* main, Controller* rpc) connD->setupUi(d); auto theme = Settings::getInstance()->get_theme_name(); - DEBUG("theme " << theme << " has loaded"); + qDebug() << theme << "theme " << theme << " has loaded"; auto size = QSize(512,512); if (theme == "Dark" || theme == "Midnight") { @@ -57,7 +55,6 @@ ConnectionLoader::ConnectionLoader(MainWindow* main, Controller* rpc) ConnectionLoader::~ConnectionLoader() { - DEBUG("destroying ConnectionLoader"); delete isSyncing; delete connD; delete d; @@ -65,7 +62,6 @@ ConnectionLoader::~ConnectionLoader() void ConnectionLoader::loadConnection() { - DEBUG("calling doAutoConnect"); QTimer::singleShot(1, [=]() { this->doAutoConnect(); }); if (!Settings::getInstance()->isHeadless()) d->exec(); @@ -73,22 +69,7 @@ void ConnectionLoader::loadConnection() void ConnectionLoader::loadProgress() { - 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); - - }); + QTimer::singleShot(1, [=]() { this->ShowProgress(); }); if (!Settings::getInstance()->isHeadless()) d->exec(); } @@ -102,62 +83,56 @@ void ConnectionLoader::ShowProgress() auto connection = makeConnection(config); auto me = this; - DEBUG("server=" << config->server << " connection=" << connection << " me=" << me); + qDebug() << __func__ << ": server=" << config->server << " connection=" << connection << " me=" << me; isSyncing = new QAtomicInteger(); isSyncing->store(true); - DEBUG("isSyncing"); - + main->logger->write("isSyncing"); + // Do a sync after import syncTimer = new QTimer(main); - DEBUG("Beginning sync after import wif"); - connection->doRPC("sync", "", [=](auto) { - DEBUG("finished syncing"); + main->logger->write("Beginning sync after import wif"); + connection->doRPCWithDefaultErrorHandling("sync", "", [=](auto) { 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, [=]() { - DEBUG("Check the sync status"); + // Check the sync status if (isSyncing != nullptr && isSyncing->load()) { - DEBUG("Get the sync status"); + // 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(); - qint64 total = reply["total_blocks"].get(); - 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"); - - // rethrow exception so loadProgress can catch - // it and retry the entire ShowProgress() function again - throw new std::runtime_error(std::string("syncstatus failed")); - } + connection->doRPC("syncstatus", "", [=](json reply) { + if (isSyncing != nullptr && reply.find("synced_blocks") != reply.end()) + + { + qint64 synced = reply["synced_blocks"].get(); + qint64 total = reply["total_blocks"].get(); + me->showInformation( + "Syncing... " + QString::number(synced) + " / " + QString::number(total) + ); + } + }, + [=](QString err) { + qDebug() << "Sync error" << err; + }); + }catch (...) + { + main->logger->write("catch sync progress reply"); } - }); + + } +}); + +syncTimer->setInterval(1* 1000); +syncTimer->start(); +main->logger->write("Start sync timer"); - int interval = 1*1000; - syncTimer->setInterval(interval); - syncTimer->start(); - DEBUG("Start sync timer with interval=" << interval); } void ConnectionLoader::doAutoConnect() @@ -165,53 +140,43 @@ void ConnectionLoader::doAutoConnect() auto config = std::shared_ptr(new ConnectionConfig()); config->dangerous = false; config->server = Settings::getInstance()->getSettings().server; - DEBUG(" server=" << config->server); + qDebug() << __func__ << " server=" << config->server; // Initialize the library - DEBUG("Attempting to initialize library with "<< config->server); + main->logger->write(QObject::tr("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())) { - DEBUG("using existing wallet"); + qDebug() << __func__ << ": 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); - QString response = ""; - try { - char* resp = litelib_initialize_existing( + if (response.toUpper().trimmed() != "OK") { + config->server = Settings::getRandomServer(); + + 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 { - DEBUG("Successfully connected to random server: " << config->server << " !!!"); + qDebug() << __func__ << ": Successfully connected to random server: " << config->server << " !!!"; } } else { - DEBUG("Successfully connected to " << config->server << " !!!"); + qDebug() << __func__ << ": Successfully connected to " << config->server << " !!!"; } } else { - DEBUG("no existing wallet"); + qDebug() << __func__ << ": no existing wallet"; main->logger->write(QObject::tr("Create/restore wallet.")); createOrRestore(config->dangerous, config->server); d->show(); @@ -222,77 +187,61 @@ 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 - DEBUG("Connection is online."); + main->logger->write("Connection is online."); connection->setInfo(reply); - DEBUG("getting Connection reply"); + main->logger->write("getting Connection reply"); isSyncing = new QAtomicInteger(); isSyncing->store(true); - DEBUG("isSyncing"); + main->logger->write("isSyncing"); // Do a sync at startup syncTimer = new QTimer(main); - DEBUG("Beginning sync"); - connection->doRPC("sync", "", [=](auto) { - DEBUG("finished syncing"); + main->logger->write("Beginning sync"); + connection->doRPCWithDefaultErrorHandling("sync", "", [=](auto) { 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, [=]() { - DEBUG("Check the sync status"); + // Check the sync status if (isSyncing != nullptr && isSyncing->load()) { - DEBUG("Getting the sync status"); + // Get 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(); qint64 total = reply["total_blocks"].get(); me->showInformation( "Syncing... " + QString::number(synced) + " / " + QString::number(total) ); } - }, - [=](QString err) { - DEBUG("syncstatus error" << err); - }); - } catch (const std::exception& e) { - DEBUG("caught exception from syncstatus: " << e.what()); - } + }, + [=](QString err) { + qDebug() << "Sync error" << err; + }); + }catch (...) + { + main->logger->write("catch sync progress reply"); + + } + } }); - int interval = 1*1000; - syncTimer->setInterval(interval); + syncTimer->setInterval(1* 1000); syncTimer->start(); - DEBUG("Start sync timer with interval=" << interval); + main->logger->write("Start sync timer"); }, [=](QString err) { showError(err); @@ -306,13 +255,13 @@ void ConnectionLoader::createOrRestore(bool dangerous, QString server) d->hide(); // Create a wizard FirstTimeWizard wizard(dangerous,server); - DEBUG("Start new Wallet with FirstimeWizard"); + main->logger->write("Start new Wallet with FirstimeWizard"); wizard.exec(); } void ConnectionLoader::doRPCSetConnection(Connection* conn) { - DEBUG("Connectionloader finished, setting connection"); + qDebug() << "Connectionloader finished, setting connection"; main->logger->write("Connectionloader finished, setting connection"); rpc->setConnection(conn); d->accept(); @@ -323,16 +272,17 @@ void ConnectionLoader::doRPCSetConnection(Connection* conn) main->logger->write("Path to Wallet.dat : " ); qDebug() << __func__ << ": wallet path =" << plaintextWallet; plaintextWallet.remove(); - } catch (const std::exception& e) { - DEBUG("Caught exception" << e.what() ); - DEBUG("No plaintext wallet found! file=" << plaintextWallet); + + } catch (...) { + qDebug() << "No plaintext wallet found! file=" << plaintextWallet; main->logger->write("no Plaintext wallet.dat"); } + } void ConnectionLoader::doRPCSetConnectionShield(Connection* conn) { - DEBUG("Importing finished, setting connection"); + qDebug() << "Importing finished, setting connection"; rpc->setConnection(conn); d->accept(); main->getRPC()->shield([=] (auto) {}); @@ -343,10 +293,9 @@ void ConnectionLoader::doRPCSetConnectionShield(Connection* conn) main->logger->write("Path to Wallet.dat : " ); qDebug() << __func__ << ": wallet path =" << plaintextWallet; plaintextWallet.remove(); - } catch (const std::exception& e) { - DEBUG("Caught exception" << e.what() ); + } catch (...) { main->logger->write("no Plaintext wallet.dat"); - DEBUG("No plaintext wallet found! file=" << plaintextWallet); + qDebug() << "No plaintext wallet found! file=" << plaintextWallet; } } @@ -397,50 +346,19 @@ QString litelib_process_response(char* resp) ************************************************************************************/ void Executor::run() { - auto config = std::shared_ptr(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() ); - } - - //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 - ); + 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); - 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); - } + else + emit responseReady(parsed); } void Callback::processRPCCallback(json resp) @@ -468,12 +386,11 @@ Connection::Connection(MainWindow* m, std::shared_ptr conf) void Connection::doRPC(const QString cmd, const QString args, const std::function& cb, const std::function& errCb) { - if (shutdownInProgress) { - DEBUG("Ignoring RPC because shutdown in progress"); + if (shutdownInProgress) + // Ignoring RPC because shutdown in progress return; - } - DEBUG("cmd=" << cmd << " args=" << args); + qDebug() << __func__ << ": " << cmd; // Create a runner. auto runner = new Executor(cmd, args); @@ -488,7 +405,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& cb) { - DEBUG("cmd=" << cmd << " args=" << args); + qDebug() << __func__ << ": " << cmd; doRPC(cmd, args, cb, [=] (QString err) { this->showTxError(err); }); @@ -496,7 +413,7 @@ void Connection::doRPCWithDefaultErrorHandling(const QString cmd, const QString void Connection::doRPCIgnoreError(const QString cmd, const QString args, const std::function& cb) { - DEBUG("cmd=" << cmd << " args=" << args); + qDebug() << __func__ << ": " << cmd; doRPC(cmd, args, cb, [=] (auto) { // Ignored error handling }); @@ -528,6 +445,5 @@ void Connection::showTxError(const QString& error) */ void Connection::shutdown() { - DEBUG("shutting down"); shutdownInProgress = true; } diff --git a/src/connection.h b/src/connection.h index ef62082..431cd38 100644 --- a/src/connection.h +++ b/src/connection.h @@ -1,4 +1,4 @@ -// Copyright 2019-2024 The Hush developers +// Copyright 2019-2023 The Hush developers // Released under the GPLv3 #ifndef CONNECTION_H #define CONNECTION_H @@ -6,7 +6,6 @@ #include "mainwindow.h" #include "ui_connection.h" #include "precompiled.h" -#include using json = nlohmann::json; diff --git a/src/contactmodel.cpp b/src/contactmodel.cpp index 01332f7..aea39cd 100644 --- a/src/contactmodel.cpp +++ b/src/contactmodel.cpp @@ -1,4 +1,4 @@ -// Copyright 2019-2024 The Hush developers +// Copyright 2019-2023 The Hush developers // GPLv3 #include "contactmodel.h" diff --git a/src/contactmodel.h b/src/contactmodel.h index adba846..2878e32 100644 --- a/src/contactmodel.h +++ b/src/contactmodel.h @@ -1,4 +1,4 @@ -// Copyright 2019-2024 The Hush developers +// Copyright 2019-2023 The Hush developers // Released under the GPLv3 #ifndef CONTACTMODEL_H #define CONTACTMODEL_H diff --git a/src/controller.cpp b/src/controller.cpp index e0dc505..61660cd 100644 --- a/src/controller.cpp +++ b/src/controller.cpp @@ -1,4 +1,4 @@ -// Copyright 2019-2024 The Hush developers +// Copyright 2019-2023 The Hush developers // Released under the GPLv3 #include "controller.h" @@ -7,6 +7,7 @@ #include "settings.h" #include "version.h" #include "camount.h" +#include "websockets.h" #include "Model/ChatItem.h" #include "DataStore/DataStore.h" @@ -261,12 +262,10 @@ 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(""); } @@ -299,19 +298,12 @@ 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) { @@ -740,7 +732,6 @@ void Controller::updateUIBalances() { CAmount balT = getModel()->getBalT(); CAmount balZ = getModel()->getBalZ(); - CAmount balU = getModel()->getBalU(); CAmount balVerified = getModel()->getBalVerified(); CAmount balSpendable = getModel()->getBalSpendable(); @@ -758,7 +749,6 @@ 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()); @@ -898,16 +888,17 @@ void Controller::refreshBalances() zrpc->fetchBalance([=] (json reply) { CAmount balT = CAmount::fromqint64(reply["tbalance"].get()); CAmount balZ = CAmount::fromqint64(reply["zbalance"].get()); - CAmount balU = CAmount::fromqint64(reply["unconfirmed"].get()); CAmount balVerified = CAmount::fromqint64(reply["verified_zbalance"].get()); CAmount balSpendable = CAmount::fromqint64(reply["spendable_zbalance"].get()); 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); @@ -942,26 +933,6 @@ 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()) @@ -1073,6 +1044,7 @@ 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]; @@ -1086,7 +1058,9 @@ 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 "); @@ -1108,11 +1082,15 @@ 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; @@ -1140,6 +1118,7 @@ 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, @@ -1182,13 +1161,13 @@ void Controller::refreshTransactions() { } else { { // Incoming Transaction - QString memo; - address = (it["address"].is_null() ? "" : QString::fromStdString(it["address"])); + address = (it["address"].is_null() ? "" : QString::fromStdString(it["address"])); + model->markAddressUsed(address); + QString memo; if (!it["memo"].is_null()) { memo = QString::fromStdString(it["memo"]); } - items.push_back(TransactionItemDetail{ address, CAmount::fromqint64(it["amount"].get()), memo @@ -1208,7 +1187,7 @@ void Controller::refreshTransactions() { QString contactname = ""; bool isContact = false; - if (!memo.isNull()) { + if (!it["memo"].is_null()) { if (memo.startsWith("{")) { try { @@ -1278,8 +1257,7 @@ void Controller::refreshTransactions() { if (position == 1) { chatModel->addMemo(txid, headerbytes); - } - else { + } else { // } @@ -1295,6 +1273,7 @@ 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]; @@ -1308,6 +1287,7 @@ 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) { @@ -1324,13 +1304,18 @@ 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; @@ -1358,6 +1343,7 @@ 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, @@ -1381,6 +1367,8 @@ 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( diff --git a/src/datamodel.cpp b/src/datamodel.cpp index c17629b..45d42d3 100644 --- a/src/datamodel.cpp +++ b/src/datamodel.cpp @@ -1,4 +1,4 @@ -// Copyright 2019-2024 The Hush developers +// Copyright 2019-2023 The Hush developers // Released under the GPLv3 #include "datamodel.h" diff --git a/src/datamodel.h b/src/datamodel.h index 31f38d6..0a1cf6d 100644 --- a/src/datamodel.h +++ b/src/datamodel.h @@ -1,11 +1,11 @@ -// Copyright 2019-2024 The Hush developers +// Copyright 2019-2023 The Hush developers // Released under the GPLv3 #ifndef DATAMODEL_H #define DATAMODEL_H #include "camount.h" #include "precompiled.h" -#include + struct UnspentOutput { QString address; @@ -48,9 +48,6 @@ 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; } @@ -79,7 +76,6 @@ private: CAmount balT; CAmount balZ; - CAmount balU; CAmount balVerified; CAmount balSpendable; diff --git a/src/fillediconlabel.h b/src/fillediconlabel.h index 88fe5f9..2f35269 100644 --- a/src/fillediconlabel.h +++ b/src/fillediconlabel.h @@ -1,4 +1,4 @@ -// Copyright 2019-2024 The Hush developers +// Copyright 2019-2023 The Hush developers // Released under the GPLv3 #ifndef FILLEDICONLABEL_H #define FILLEDICONLABEL_H diff --git a/src/firsttimewizard.cpp b/src/firsttimewizard.cpp index daa272e..c69632f 100644 --- a/src/firsttimewizard.cpp +++ b/src/firsttimewizard.cpp @@ -1,4 +1,4 @@ -// Copyright 2019-2024 The Hush developers +// Copyright 2019-2023 The Hush developers // Released under the GPLv3 #include "firsttimewizard.h" #include "ui_newseed.h" @@ -293,28 +293,10 @@ void NewSeedPage::initializePage() { // Call the library to create a new wallet. qDebug() << __func__; - 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(); - } - + char* resp = litelib_initialize_new(parent->dangerous,parent->server.toStdString().c_str()); + QString reply = litelib_process_response(resp); 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); @@ -625,49 +607,21 @@ bool NewSeedPage::validatePage() { dialog.exec(); - 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(); - } - - qDebug() << __func__ << ": reply=" << reply; - - // 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; + if ((verifyseed.verify->toPlainText() == seed) && (verifyseed.verifyBirthday->toPlainText() == birthday)) + { + char* resp = litelib_execute("save", ""); + QString reply = litelib_process_response(resp); - auto parsed = json::parse(reply.toStdString().c_str(), nullptr, false); - if (parsed.is_discarded() || parsed.is_null() || parsed.find("result") == parsed.end()) { + 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; - } + QMessageBox::warning(this, tr("Failed to save wallet"), + tr("Couldn't save the wallet") + "\n" + reply, + QMessageBox::Ok); + return false; + } else { + return true; + } }else{ qDebug()<<"Wrong Seed"; QFile file(dirwalletencfirst); @@ -675,7 +629,9 @@ 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; @@ -730,79 +686,32 @@ bool RestoreSeedPage::validatePage() { qint64 number = number_str.toUInt(); // 3. Attempt to restore wallet with the seed phrase { - 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; + 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); if (reply.toUpper().trimmed() != "OK") { - 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::warning(this, tr("Failed to restore wallet"), + tr("Couldn't restore the wallet") + "\n" + reply, QMessageBox::Ok); return false; - } + } } // 4. Finally attempt to save the wallet { - 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; + char* resp = litelib_execute("save", ""); + QString reply = litelib_process_response(resp); 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" + "server=" + parent->server + "\n" + reply, + QMessageBox::warning(this, tr("Failed to save wallet"), + tr("Couldn't save the wallet") + "\n" + reply, QMessageBox::Ok); return false; } else { return true; - } + } } } diff --git a/src/firsttimewizard.h b/src/firsttimewizard.h index b02015f..994b602 100644 --- a/src/firsttimewizard.h +++ b/src/firsttimewizard.h @@ -1,4 +1,4 @@ -// Copyright 2019-2024 The Hush developers +// Copyright 2019-2023 The Hush developers // Released under the GPLv3 #ifndef FIRSTTIMEWIZARD_H #define FIRSTTIMEWIZARD_H diff --git a/src/liteinterface.cpp b/src/liteinterface.cpp index 03c206d..4d7779d 100644 --- a/src/liteinterface.cpp +++ b/src/liteinterface.cpp @@ -1,4 +1,4 @@ -// Copyright 2019-2024 The Hush developers +// Copyright 2019-2023 The Hush developers // Released under the GPLv3 #include "liteinterface.h" diff --git a/src/liteinterface.h b/src/liteinterface.h index cb3ecc6..2fc500a 100644 --- a/src/liteinterface.h +++ b/src/liteinterface.h @@ -1,4 +1,4 @@ -// Copyright 2019-2024 The Hush developers +// Copyright 2019-2023 The Hush developers // Released under the GPLv3 #ifndef hushDRPC_H #define hushDRPC_H diff --git a/src/logger.cpp b/src/logger.cpp index ecfc7b2..11ffd33 100644 --- a/src/logger.cpp +++ b/src/logger.cpp @@ -1,4 +1,4 @@ -// Copyright 2019-2024 The Hush developers +// Copyright 2019-2023 The Hush developers // Released under the GPLv3 #include "logger.h" diff --git a/src/logger.h b/src/logger.h index dee5819..6fed592 100644 --- a/src/logger.h +++ b/src/logger.h @@ -1,4 +1,4 @@ -// Copyright 2019-2024 The Hush developers +// Copyright 2019-2023 The Hush developers // Released under the GPLv3 #ifndef LOGGER_H #define LOGGER_H diff --git a/src/main.cpp b/src/main.cpp index 5b4ad6d..347ee2a 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,4 +1,4 @@ -// Copyright 2019-2024 The Hush developers +// Copyright 2019-2023 The Hush developers // Released under the GPLv3 #include @@ -6,7 +6,6 @@ #include "mainwindow.h" #include "controller.h" #include "settings.h" -#include #include "version.h" diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index 234bbca..6562979 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -1,4 +1,4 @@ -// Copyright 2019-2024 The Hush developers +// Copyright 2019-2023 The Hush developers // Released under the GPLv3 #include "mainwindow.h" #include "addressbook.h" @@ -25,6 +25,7 @@ #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 @@ -37,7 +38,6 @@ #include #include #include -#include "sdl.h" using json = nlohmann::json; @@ -159,11 +159,11 @@ MainWindow::MainWindow(QWidget *parent) : // Rescan QObject::connect(ui->actionRescan, &QAction::triggered, [=]() { - DEBUG("rescan action triggered"); - Ui_Restore restoreSeed; - QDialog dialog(this); - restoreSeed.setupUi(&dialog); - Settings::saveRestore(&dialog); + + Ui_Restore restoreSeed; + QDialog dialog(this); + restoreSeed.setupUi(&dialog); + Settings::saveRestore(&dialog); rpc->fetchSeed([=](json reply) { if (isJsonError(reply)) { @@ -209,74 +209,35 @@ MainWindow::MainWindow(QWidget *parent) : config->server = Settings::getInstance()->getSettings().server; // 3. Attempt to restore wallet with the seed phrase { - 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") { - 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); - } + 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); 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::warning(this, tr("Failed to restore wallet"), + tr("Couldn't restore the wallet") + "\n" + reply, QMessageBox::Ok); - return false; - } + + } } // 4. Finally attempt to save the wallet { - 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(); - } - } - + char* resp = litelib_execute("save", ""); + QString reply = litelib_process_response(resp); 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" + "server=" + config->server + "\n" + reply, + QMessageBox::warning(this, tr("Failed to save wallet"), + tr("Couldn't save the wallet") + "\n" + reply, QMessageBox::Ok); } else { qDebug() << __func__ << ": saved wallet correctly"; - } + } dialog.close(); // To rescan, we clear the wallet state, and then reload the connection @@ -289,14 +250,15 @@ 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); @@ -332,6 +294,16 @@ 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) @@ -340,6 +312,36 @@ 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()); @@ -931,7 +933,7 @@ void MainWindow::doImport(QList* keys) { keys->pop_front(); //bool rescan = keys->isEmpty(); - if (key.startsWith("secret")) { + if (key.startsWith("SK") || 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 @@ -1095,10 +1097,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"))){ @@ -2722,6 +2724,8 @@ MainWindow::~MainWindow() delete loadingMovie; delete logger; + delete wsserver; + delete wormhole; } void MainWindow::on_givemeZaddr_clicked() { diff --git a/src/mainwindow.h b/src/mainwindow.h index 31ab6e1..6a2486e 100644 --- a/src/mainwindow.h +++ b/src/mainwindow.h @@ -1,4 +1,4 @@ -// Copyright 2019-2024 The Hush developers +// Copyright 2019-2023 The Hush developers // Released under the GPLv3 #ifndef MAINWINDOW_H #define MAINWINDOW_H @@ -14,6 +14,8 @@ using json = nlohmann::json; // Forward declare to break circular dependency. class Controller; class Settings; +class WSServer; +class WormholeClient; class ChatModel; @@ -68,6 +70,10 @@ public: + void replaceWormholeClient(WormholeClient* newClient); + bool isWebsocketListening(); + void createWebsocket(QString wormholecode); + void stopWebsocket(); void saveContact(); void saveandsendContact(); void showRequesthush(); @@ -194,6 +200,10 @@ private: bool uiPaymentsReady = false; QString pendingURIPayment; + WSServer* wsserver = nullptr; + WormholeClient* wormhole = nullptr; + + Controller* rpc = nullptr; QCompleter* labelCompleter = nullptr; diff --git a/src/mainwindow.ui b/src/mainwindow.ui index db12534..0a4b91d 100644 --- a/src/mainwindow.ui +++ b/src/mainwindow.ui @@ -641,33 +641,6 @@ - - - 0 - 0 - - - - Unconfirmed - - - - - - - - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - - - - 0 @@ -691,7 +664,7 @@ - + @@ -718,14 +691,14 @@ - + Qt::Horizontal - + @@ -762,7 +735,7 @@ - + color:red; @@ -775,7 +748,7 @@ - + @@ -794,14 +767,14 @@ - + Deposit Hush - + Qt::Vertical diff --git a/src/memoedit.cpp b/src/memoedit.cpp index 8790d8f..adf2292 100644 --- a/src/memoedit.cpp +++ b/src/memoedit.cpp @@ -1,4 +1,4 @@ -// Copyright 2019-2024 The Hush developers +// Copyright 2019-2023 The Hush developers // Released under the GPLv3 #include "memoedit.h" diff --git a/src/memoedit.h b/src/memoedit.h index b099b1d..9d4e310 100644 --- a/src/memoedit.h +++ b/src/memoedit.h @@ -1,4 +1,4 @@ -// Copyright 2019-2024 The Hush developers +// Copyright 2019-2023 The Hush developers // Released under the GPLv3 #ifndef MEMOEDIT_H #define MEMOEDIT_H diff --git a/src/mobileappconnector.cpp b/src/mobileappconnector.cpp new file mode 100644 index 0000000..98501db --- /dev/null +++ b/src/mobileappconnector.cpp @@ -0,0 +1,16 @@ +// 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; +} diff --git a/src/mobileappconnector.h b/src/mobileappconnector.h new file mode 100644 index 0000000..868a80f --- /dev/null +++ b/src/mobileappconnector.h @@ -0,0 +1,24 @@ +// Copyright 2019-2023 The Hush developers +// Released under the GPLv3 +#ifndef MOBILEAPPCONNECTOR_H +#define MOBILEAPPCONNECTOR_H + +#include + +namespace Ui { +class MobileAppConnector; +} + +class MobileAppConnector : public QDialog +{ + Q_OBJECT + +public: + explicit MobileAppConnector(QWidget *parent = nullptr); + ~MobileAppConnector(); + +private: + Ui::MobileAppConnector *ui; +}; + +#endif // MOBILEAPPCONNECTOR_H diff --git a/src/mobileappconnector.ui b/src/mobileappconnector.ui new file mode 100644 index 0000000..823a497 --- /dev/null +++ b/src/mobileappconnector.ui @@ -0,0 +1,214 @@ + + + MobileAppConnector + + + + 0 + 0 + 800 + 530 + + + + Mobile Connector App + + + + + + Qt::Horizontal + + + QDialogButtonBox::Close + + + + + + + + 0 + 0 + + + + Scan this QRCode from your silentdragon companion app to connect your phone + + + + + + + QR Code + + + + + + Connection String + + + + + + + + 9 + + + + true + + + + + + + + 0 + 0 + + + + background-color: #fff + + + + + + + + + + Allow connections over the internet via silentdragon wormhole + + + + + + + + + + silentdragon Companion App + + + + + + + 0 + 0 + + + + Disconnect + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + TextLabel + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + Last seen: + + + + + + + TextLabel + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + Connection type: + + + + + + + TextLabel + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + + + + QRCodeLabel + QLabel +
qrcodelabel.h
+
+
+ + + + buttonBox + accepted() + MobileAppConnector + accept() + + + 248 + 254 + + + 157 + 274 + + + + + buttonBox + rejected() + MobileAppConnector + reject() + + + 316 + 260 + + + 286 + 274 + + + + +
diff --git a/src/precompiled.h b/src/precompiled.h index 1eba304..25fa01f 100644 --- a/src/precompiled.h +++ b/src/precompiled.h @@ -1,4 +1,4 @@ -// Copyright 2019-2024 The Hush developers +// Copyright 2019-2023 The Hush developers // Released under the GPLv3 #if defined __cplusplus /* Add C++ includes here */ @@ -64,6 +64,7 @@ #include #include #include +#include #include #include #include diff --git a/src/qrcodelabel.cpp b/src/qrcodelabel.cpp index 5813809..6b2778c 100644 --- a/src/qrcodelabel.cpp +++ b/src/qrcodelabel.cpp @@ -1,4 +1,4 @@ -// Copyright 2019-2024 The Hush developers +// Copyright 2019-2023 The Hush developers // Released under the GPLv3 #include "qrcodelabel.h" diff --git a/src/qrcodelabel.h b/src/qrcodelabel.h index 51a40dd..313ec65 100644 --- a/src/qrcodelabel.h +++ b/src/qrcodelabel.h @@ -1,4 +1,4 @@ -// Copyright 2019-2024 The Hush developers +// Copyright 2019-2023 The Hush developers // Released under the GPLv3 #ifndef QRCODELABEL_H #define QRCODELABEL_H diff --git a/src/recurring.cpp b/src/recurring.cpp index 88dcfe7..2e94744 100644 --- a/src/recurring.cpp +++ b/src/recurring.cpp @@ -1,4 +1,4 @@ -// Copyright 2019-2024 The Hush developers +// Copyright 2019-2023 The Hush developers // Released under the GPLv3 #include "recurring.h" diff --git a/src/recurring.h b/src/recurring.h index 94e2019..2f27f45 100644 --- a/src/recurring.h +++ b/src/recurring.h @@ -1,4 +1,4 @@ -// Copyright 2019-2024 The Hush developers +// Copyright 2019-2023 The Hush developers // Released under the GPLv3 #ifndef RECURRING_H #define RECURRING_H diff --git a/src/requestdialog.cpp b/src/requestdialog.cpp index 749eb85..bb4c214 100644 --- a/src/requestdialog.cpp +++ b/src/requestdialog.cpp @@ -1,4 +1,4 @@ -// Copyright 2019-2024 The Hush developers +// Copyright 2019-2023 The Hush developers // Released under the GPLv3 #include "requestdialog.h" #include "ui_requestdialog.h" diff --git a/src/requestdialog.h b/src/requestdialog.h index 657026a..8dbeaca 100644 --- a/src/requestdialog.h +++ b/src/requestdialog.h @@ -1,4 +1,4 @@ -// Copyright 2019-2024 The Hush developers +// Copyright 2019-2023 The Hush developers // Released under the GPLv3 #ifndef REQUESTDIALOG_H #define REQUESTDIALOG_H diff --git a/src/scripts/docker/Dockerfile b/src/scripts/docker/Dockerfile index 6391c24..361d2fe 100644 --- a/src/scripts/docker/Dockerfile +++ b/src/scripts/docker/Dockerfile @@ -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 + make -j$(nproc) MXE_TARGETS=x86_64-w64-mingw32.static qtbase qtwebsockets # Add rust RUN apt install -y gcc-aarch64-linux-gnu diff --git a/src/sdl.h b/src/sdl.h deleted file mode 100644 index 68b24b3..0000000 --- a/src/sdl.h +++ /dev/null @@ -1 +0,0 @@ -#define DEBUG(x) (qDebug() << QString(__func__) << ": " << x) diff --git a/src/sendtab.cpp b/src/sendtab.cpp index 38bd5e1..61e8ad9 100644 --- a/src/sendtab.cpp +++ b/src/sendtab.cpp @@ -1,4 +1,4 @@ -// Copyright 2019-2024 The Hush developers +// Copyright 2019-2023 The Hush developers // Released under the GPLv3 #include "mainwindow.h" #include "ui_mainwindow.h" diff --git a/src/settings.cpp b/src/settings.cpp index 3389412..d6243b6 100644 --- a/src/settings.cpp +++ b/src/settings.cpp @@ -1,10 +1,9 @@ -// Copyright 2019-2024 The Hush developers +// Copyright 2019-2023 The Hush developers // Released under the GPLv3 #include "mainwindow.h" #include "settings.h" #include "camount.h" #include "../lib/silentdragonlitelib.h" -#include Settings* Settings::instance = nullptr; @@ -37,14 +36,9 @@ Config Settings::getSettings() { if (server.trimmed().isEmpty()) { server = Settings::getRandomServer(); - QString response = ""; // make sure existing server in conf is alive, otherwise choose random one - 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(); - } + char* resp = litelib_initialize_existing(false, server.toStdString().c_str()); + QString response = litelib_process_response(resp); if (response.toUpper().trimmed() != "OK") { qDebug() << "Lite server in conf " << server << " is down, getting a random one"; @@ -316,14 +310,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__ << ": caught an exception, ignoring: " << e.what(); + qDebug() << __func__ << ": litelib_process_response threw an exception, ignoring: " << e.what(); } // if we see a valid connection, return this server diff --git a/src/settings.h b/src/settings.h index 376131b..f65e4cd 100644 --- a/src/settings.h +++ b/src/settings.h @@ -1,4 +1,4 @@ -// Copyright 2019-2024 The Hush developers +// Copyright 2019-2023 The Hush developers // Released under the GPLv3 #ifndef SETTINGS_H #define SETTINGS_H diff --git a/src/txtablemodel.cpp b/src/txtablemodel.cpp index 04ea0dd..633145c 100644 --- a/src/txtablemodel.cpp +++ b/src/txtablemodel.cpp @@ -1,4 +1,4 @@ -// Copyright 2019-2024 The Hush developers +// Copyright 2019-2023 The Hush developers // Released under the GPLv3 #include "txtablemodel.h" #include "settings.h" diff --git a/src/txtablemodel.h b/src/txtablemodel.h index a0a147b..0479518 100644 --- a/src/txtablemodel.h +++ b/src/txtablemodel.h @@ -1,4 +1,4 @@ -// Copyright 2019-2024 The Hush developers +// Copyright 2019-2023 The Hush developers // Released under the GPLv3 #ifndef STRINGSTABLEMODEL_H #define STRINGSTABLEMODEL_H diff --git a/src/version.h b/src/version.h index 0f14577..514ba63 100644 --- a/src/version.h +++ b/src/version.h @@ -1,3 +1,3 @@ -// Copyright 2019-2024 The Hush developers +// Copyright 2019-2023 The Hush developers // Released under the GPLv3 -#define APP_VERSION "1.5.4" +#define APP_VERSION "1.5.3" diff --git a/src/viewalladdresses.cpp b/src/viewalladdresses.cpp index 6eb6d3c..d3fbe22 100644 --- a/src/viewalladdresses.cpp +++ b/src/viewalladdresses.cpp @@ -1,4 +1,4 @@ -// Copyright 2019-2024 The Hush developers +// Copyright 2019-2023 The Hush developers // Released under the GPLv3 #include "viewalladdresses.h" #include "camount.h" diff --git a/src/viewalladdresses.h b/src/viewalladdresses.h index 0963e3f..cafc47e 100644 --- a/src/viewalladdresses.h +++ b/src/viewalladdresses.h @@ -1,4 +1,4 @@ -// Copyright 2019-2024 The Hush developers +// Copyright 2019-2023 The Hush developers // Released under the GPLv3 #ifndef VIEWALLADDRESSES_H #define VIEWALLADDRESSES_H diff --git a/src/websockets.cpp b/src/websockets.cpp new file mode 100644 index 0000000..e09d1b0 --- /dev/null +++ b/src/websockets.cpp @@ -0,0 +1,940 @@ +// 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(sender()); + if (m_debug) + qDebug() << "Message received:" << message; + + if (pClient) { + std::shared_ptr client = std::make_shared(pClient, this); + AppDataServer::getInstance()->processMessage(message, m_mainWindow, client, AppConnectionType::DIRECT); + } +} + +void WSServer::processBinaryMessage(QByteArray message) +{ + //QWebSocket *pClient = qobject_cast(sender()); + if (m_debug) + qDebug() << "Binary Message received:" << message; + +} + +void WSServer::socketDisconnected() +{ + QWebSocket *pClient = qobject_cast(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(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="<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="< ((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="< 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 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 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> 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(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 QPaira, const QPair 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 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> 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(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 QPaira, const QPair 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 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 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; diff --git a/src/websockets.h b/src/websockets.h new file mode 100644 index 0000000..65e9311 --- /dev/null +++ b/src/websockets.h @@ -0,0 +1,179 @@ +// 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 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 pClient); + void processSendManyTx(QJsonObject sendmanyTx, MainWindow* mainwindow, std::shared_ptr pClient); + void processMessage(QString message, MainWindow* mainWindow, std::shared_ptr pClient, AppConnectionType connType); + void processGetInfo(QJsonObject jobj, MainWindow* mainWindow, std::shared_ptr pClient); + void processDecryptedMessage(QString message, MainWindow* mainWindow, std::shared_ptr pClient); + void processGetTransactions(MainWindow* mainWindow, std::shared_ptr 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 diff --git a/util/SilentDragonLite.desktop b/util/SilentDragonLite.desktop index 24b5b3d..d659ab5 100644 --- a/util/SilentDragonLite.desktop +++ b/util/SilentDragonLite.desktop @@ -1,7 +1,7 @@ [Desktop Entry] Version=1.0 Name=SilentDragonLite -Comment=Lite wallet for HUSH cryptocurrency +Comment=Full-node wallet for HUSH cryptocurrency Exec=/home/user/SilentDragonLite/SilentDragonLite Icon=/home/user/SilentDragonLite/res/SDLogo.png Terminal=false diff --git a/util/add-linux-icons.sh b/util/add-linux-icons.sh index 7fed756..a24680e 100755 --- a/util/add-linux-icons.sh +++ b/util/add-linux-icons.sh @@ -1,5 +1,5 @@ #!/bin/bash -# Copyright 2019-2024 The Hush Developers +# Copyright 2019-2023 The Hush Developers username=$(id -un) sed -i "s|\/home\/.*\/SilentDragonLite\/|\/home\/$username\/SilentDragonLite\/|g" SilentDragonLite.desktop diff --git a/util/install.sh b/util/install.sh index 8107b10..da3e59c 100755 --- a/util/install.sh +++ b/util/install.sh @@ -1,10 +1,12 @@ #!/bin/bash -# Copyright 2019-2024 The Hush Developers +# Copyright 2019-2023 The Hush Developers cd ../ && ./build.sh linguist && ./build.sh +# should be better username=$(id -un) cd util/ && sed -i "s|\/home\/.*\/SilentDragonLite\/|\/home\/$username\/SilentDragonLite\/|g" SilentDragonLite.desktop cp SilentDragonLite.desktop ~/.local/share/applications +# might be /usr/share/applications/ that requires sudo \ No newline at end of file diff --git a/util/replace.pl b/util/replace.pl index ef99cb8..51ab56d 100755 --- a/util/replace.pl +++ b/util/replace.pl @@ -1,5 +1,5 @@ #!/usr/bin/perl -# Copyright (c) 2016-2024 The Hush developers +# Copyright (c) 2016-2023 The Hush developers # Distributed under the GPLv3 software license, see the accompanying # file COPYING or https://www.gnu.org/licenses/gpl-3.0.en.html diff --git a/util/update-copyrights.sh b/util/update-copyrights.sh index 2ff3e64..293602f 100755 --- a/util/update-copyrights.sh +++ b/util/update-copyrights.sh @@ -1,22 +1,10 @@ #!/usr/bin/env bash - -# Copyright (c) 2016-2024 The Hush developers +# Copyright (c) 2016-2023 The Hush developers # Released under the GPLv3 -# Usage: update-copyrights.sh 2024 2025 +# Usage: update-copyrights.sh 2021 2022 # TODO: verify $1 and $2 exist - -if ! command -v ack &> /dev/null -then - echo "ack could not be found. Please install it and try again." - exit 1 -fi - -if ! command -v xargs &> /dev/null -then - echo "xargs could not be found. Please install it and try again." - exit 1 -fi +# TODO: verify ack and xargs exist on this system # This update comments in source code ack -l -i "20..-20..*Hush dev" | xargs ./util/replace.pl -$1 -$2 diff --git a/win-static-build.sh b/win-static-build.sh index db587a3..3c10329 100755 --- a/win-static-build.sh +++ b/win-static-build.sh @@ -1,5 +1,5 @@ #!/bin/bash -# Copyright 2019-2024 The Hush Developers +# Copyright 2019-2023 The Hush Developers VERSION=$(cat src/version.h |cut -d\" -f2) echo "Compiling SilentDragonLite $VERSION .exe with $JOBS threads..."