diff --git a/.travis.yml b/.travis.yml index 6cded8f..c3810b7 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 qt514websockets libgl1-mesa-dev + - sudo apt-get install qt514base libgl1-mesa-dev - source /opt/qt514/bin/qt514-env.sh - chmod +x res/libsodium/buildlibsodium.sh diff --git a/LICENSE b/LICENSE index 9bc948a..e8b36af 100644 --- a/LICENSE +++ b/LICENSE @@ -1,4 +1,4 @@ - Copyright 2019-2023 The Hush developers + Copyright 2019-2024 The Hush developers Copyright 2018 adityapk diff --git a/README.md b/README.md index b67cb66..09df59e 100644 --- a/README.md +++ b/README.md @@ -49,11 +49,20 @@ 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`.** -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 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 libqt5websockets5-dev qtcreator qttools5-dev-tools +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! + +```shell script git clone https://git.hush.is/hush/SilentDragonLite cd SilentDragonLite ./build.sh linguist diff --git a/build.sh b/build.sh index c435eb5..4624f74 100755 --- a/build.sh +++ b/build.sh @@ -1,5 +1,5 @@ #!/bin/bash -# Copyright 2019-2023 The Hush Developers +# Copyright 2019-2024 The Hush Developers # Released under the GPLv3 UNAME=$(uname) diff --git a/contrib/debian/README.md b/contrib/debian/README.md new file mode 100644 index 0000000..45fd020 --- /dev/null +++ b/contrib/debian/README.md @@ -0,0 +1,11 @@ +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 new file mode 100644 index 0000000..cd59351 --- /dev/null +++ b/contrib/debian/changelog @@ -0,0 +1,5 @@ +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 new file mode 100644 index 0000000..f11c82a --- /dev/null +++ b/contrib/debian/compat @@ -0,0 +1 @@ +9 \ No newline at end of file diff --git a/contrib/debian/control b/contrib/debian/control new file mode 100644 index 0000000..c57d5c1 --- /dev/null +++ b/contrib/debian/control @@ -0,0 +1,13 @@ +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 new file mode 100644 index 0000000..5128172 --- /dev/null +++ b/contrib/debian/copyright @@ -0,0 +1,5 @@ +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 new file mode 100644 index 0000000..b9ce217 --- /dev/null +++ b/contrib/debian/rules @@ -0,0 +1,20 @@ +#!/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 new file mode 100644 index 0000000..7824e17 --- /dev/null +++ b/doc/developer.md @@ -0,0 +1,62 @@ +# 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 0283d0a..bc5422c 100644 --- a/doc/release-process.md +++ b/doc/release-process.md @@ -55,4 +55,13 @@ 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 c503ad5..ac78cae 100644 --- a/doc/relnotes.md +++ b/doc/relnotes.md @@ -1,3 +1,23 @@ +# 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 fca6704..8aa2e54 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 qtwebsockets +make -j$(nproc) MXE_TARGETS=x86_64-w64-mingw32.static qtbase ``` # Build SilentDragonLite .exe diff --git a/lib/Cargo.lock b/lib/Cargo.lock index 174a16f..a7884bb 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=0181b16fd037f98c760e668bb6af8a41dd0d6267#0181b16fd037f98c760e668bb6af8a41dd0d6267" +source = "git+https://git.hush.is/hush/silentdragonlite-cli?rev=4ec78a01b4f35b08eff42b10e3be85de87ba2b02#4ec78a01b4f35b08eff42b10e3be85de87ba2b02" dependencies = [ "base58", "bellman", diff --git a/lib/Cargo.toml b/lib/Cargo.toml index 11e08b7..a500de6 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 = "0181b16fd037f98c760e668bb6af8a41dd0d6267" } +silentdragonlitelib = { git = "https://git.hush.is/hush/silentdragonlite-cli", rev = "4ec78a01b4f35b08eff42b10e3be85de87ba2b02" } diff --git a/lib/src/lib.rs b/lib/src/lib.rs index 6f73c6d..eaa03ba 100644 --- a/lib/src/lib.rs +++ b/lib/src/lib.rs @@ -92,7 +92,15 @@ pub extern fn litelib_initialize_new(dangerous: bool,server: *const c_char) -> * } }; - LIGHTCLIENT.lock().unwrap().replace(Some(Arc::new(lightclient))); + 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)); // Return the wallet's seed let s_str = CString::new(seed).unwrap(); @@ -135,7 +143,15 @@ pub extern fn litelib_initialize_new_from_phrase(dangerous: bool,server: *const // Initialize logging let _ = lightclient.init_logging(); - LIGHTCLIENT.lock().unwrap().replace(Some(Arc::new(lightclient))); + 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)); let c_str = CString::new("OK").unwrap(); return c_str.into_raw(); @@ -169,8 +185,17 @@ 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(Arc::new(lightclient))); + LIGHTCLIENT.lock().unwrap().replace(Some(lc)); 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 9a30723..9a7ffe1 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 deleted file mode 100644 index 3a24a38..0000000 Binary files a/res/libsodium.a and /dev/null differ diff --git a/res/libsodium/buildlibsodium.sh b/res/libsodium/buildlibsodium.sh index f9f8bae..12d4412 100755 --- a/res/libsodium/buildlibsodium.sh +++ b/res/libsodium/buildlibsodium.sh @@ -1,5 +1,5 @@ #!/bin/bash -# Copyright 2019-2023 The Hush developers +# Copyright 2019-2024 The Hush developers # Released under the GPLv3 VERSION=1.0.18 diff --git a/run-after-build.sh b/run-after-build.sh index 35c5499..f4147e4 100755 --- a/run-after-build.sh +++ b/run-after-build.sh @@ -1,4 +1,4 @@ #!/bin/bash -# Copyright 2019-2023 The Hush Developers +# Copyright 2019-2024 The Hush Developers ./build.sh && ./SilentDragonLite diff --git a/silentdragon-lite.pro b/silentdragon-lite.pro index 3056c1c..adf640e 100644 --- a/silentdragon-lite.pro +++ b/silentdragon-lite.pro @@ -3,7 +3,7 @@ # Project created by QtCreator 2018-10-05T09:54:45 # #------------------------------------------------- -# Copyright 2019-2023 The Hush Developers +# Copyright 2019-2024 The Hush Developers # Released under the GPLv3 QT += core gui network @@ -13,7 +13,6 @@ CONFIG += precompile_header PRECOMPILED_HEADER = src/precompiled.h QT += widgets -QT += websockets TARGET = SilentDragonLite TEMPLATE = app @@ -59,8 +58,6 @@ 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 \ @@ -104,8 +101,6 @@ 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 \ @@ -143,7 +138,6 @@ 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 ef07f1b..ac52ee1 100644 --- a/src/3rdparty/sodium.h +++ b/src/3rdparty/sodium.h @@ -1,4 +1,4 @@ -// Copyright 2019-2023 The Hush developers +// Copyright 2019-2024 The Hush developers // Released under the GPLv3 #ifndef sodium_H diff --git a/src/Chat/Chat.cpp b/src/Chat/Chat.cpp index c006ec2..08dbd08 100644 --- a/src/Chat/Chat.cpp +++ b/src/Chat/Chat.cpp @@ -1,4 +1,4 @@ -// Copyright 2019-2023 The Hush developers +// Copyright 2019-2024 The Hush developers // Released under the GPLv3 #include "Chat.h" diff --git a/src/Chat/Chat.h b/src/Chat/Chat.h index 8d45fe8..231fa62 100644 --- a/src/Chat/Chat.h +++ b/src/Chat/Chat.h @@ -1,4 +1,4 @@ -// Copyright 2019-2023 The Hush developers +// Copyright 2019-2024 The Hush developers // Released under the GPLv3 #ifndef CHAT_H #define CHAT_H diff --git a/src/Chat/Helper/ChatDelegator.h b/src/Chat/Helper/ChatDelegator.h index 646ba41..462d959 100644 --- a/src/Chat/Helper/ChatDelegator.h +++ b/src/Chat/Helper/ChatDelegator.h @@ -1,4 +1,4 @@ -// Copyright 2019-2023 The Hush developers +// Copyright 2019-2024 The Hush developers // GPLv3 #ifndef CHATDELEGATOR_H diff --git a/src/Crypto/FileEncryption.cpp b/src/Crypto/FileEncryption.cpp index 4181167..1b79bce 100644 --- a/src/Crypto/FileEncryption.cpp +++ b/src/Crypto/FileEncryption.cpp @@ -1,4 +1,4 @@ -// Copyright 2019-2023 The Hush developers +// Copyright 2019-2024 The Hush developers // Released under the GPLv3 #include "FileEncryption.h" diff --git a/src/Crypto/FileEncryption.h b/src/Crypto/FileEncryption.h index ccbb4d8..afb5cd6 100644 --- a/src/Crypto/FileEncryption.h +++ b/src/Crypto/FileEncryption.h @@ -1,4 +1,4 @@ -// Copyright 2019-2023 The Hush developers +// Copyright 2019-2024 The Hush developers // Released under the GPLv3 #ifndef FILEENCRYPTION_H #define FILEENCRYPTION_H diff --git a/src/Crypto/passwd.cpp b/src/Crypto/passwd.cpp index ced6661..e9341ee 100644 --- a/src/Crypto/passwd.cpp +++ b/src/Crypto/passwd.cpp @@ -1,4 +1,4 @@ -// Copyright 2019-2023 The Hush developers +// Copyright 2019-2024 The Hush developers // Released under the GPLv3 #include "passwd.h" diff --git a/src/Crypto/passwd.h b/src/Crypto/passwd.h index 5f5b01c..abfc695 100644 --- a/src/Crypto/passwd.h +++ b/src/Crypto/passwd.h @@ -1,4 +1,4 @@ -// Copyright 2019-2023 The Hush developers +// Copyright 2019-2024 The Hush developers // Released under the GPLv3 #ifndef PASSWD_H #define PASSWD_H diff --git a/src/DataStore/ChatDataStore.cpp b/src/DataStore/ChatDataStore.cpp index b0944ec..ad1b680 100644 --- a/src/DataStore/ChatDataStore.cpp +++ b/src/DataStore/ChatDataStore.cpp @@ -1,4 +1,4 @@ -// Copyright 2019-2023 The Hush developers +// Copyright 2019-2024 The Hush developers // Released under the GPLv3 #include "ChatDataStore.h" diff --git a/src/DataStore/ChatDataStore.h b/src/DataStore/ChatDataStore.h index 06ca1f2..3300631 100644 --- a/src/DataStore/ChatDataStore.h +++ b/src/DataStore/ChatDataStore.h @@ -1,4 +1,4 @@ -// Copyright 2019-2023 The Hush developers +// Copyright 2019-2024 The Hush developers // Released under the GPLv3 #ifndef CHATDATASTORE_H #define CHATDATASTORE_H diff --git a/src/DataStore/ContactDataStore.cpp b/src/DataStore/ContactDataStore.cpp index 68e6aae..bed1676 100644 --- a/src/DataStore/ContactDataStore.cpp +++ b/src/DataStore/ContactDataStore.cpp @@ -1,4 +1,4 @@ -// Copyright 2019-2023 The Hush developers +// Copyright 2019-2024 The Hush developers // GPLv3 #include "ContactDataStore.h" diff --git a/src/DataStore/ContactDataStore.h b/src/DataStore/ContactDataStore.h index f6a1dbf..c9bc7ff 100644 --- a/src/DataStore/ContactDataStore.h +++ b/src/DataStore/ContactDataStore.h @@ -1,4 +1,4 @@ -// Copyright 2019-2023 The Hush developers +// Copyright 2019-2024 The Hush developers // Released under the GPLv3 #ifndef CONTACTDATASTORE_H #define CONTACTDATASTORE_H diff --git a/src/DataStore/DataStore-deprecated.h b/src/DataStore/DataStore-deprecated.h index 3cee754..1e3f9da 100644 --- a/src/DataStore/DataStore-deprecated.h +++ b/src/DataStore/DataStore-deprecated.h @@ -1,4 +1,4 @@ -// Copyright 2019-2023 The Hush developers +// Copyright 2019-2024 The Hush developers // Released under the GPLv3 #ifndef DATASTORE_H #define DATASTORE_H diff --git a/src/DataStore/DataStore.cpp b/src/DataStore/DataStore.cpp index 73d98e3..f7aa1a4 100644 --- a/src/DataStore/DataStore.cpp +++ b/src/DataStore/DataStore.cpp @@ -1,4 +1,4 @@ -// Copyright 2019-2023 The Hush developers +// Copyright 2019-2024 The Hush developers // Released under the GPLv3 #include "DataStore.h" diff --git a/src/DataStore/DataStore.h b/src/DataStore/DataStore.h index def4c5d..14df162 100644 --- a/src/DataStore/DataStore.h +++ b/src/DataStore/DataStore.h @@ -1,4 +1,4 @@ -// Copyright 2019-2023 The Hush developers +// Copyright 2019-2024 The Hush developers // Released under the GPLv3 #ifndef DATASTORE_H #define DATASTORE_H diff --git a/src/DataStore/SietchDataStore.cpp b/src/DataStore/SietchDataStore.cpp index 9c04204..7268e98 100644 --- a/src/DataStore/SietchDataStore.cpp +++ b/src/DataStore/SietchDataStore.cpp @@ -1,4 +1,4 @@ -// Copyright 2019-2023 The Hush developers +// Copyright 2019-2024 The Hush developers // Released under the GPLv3 #include "SietchDataStore.h" diff --git a/src/DataStore/SietchDataStore.h b/src/DataStore/SietchDataStore.h index a5889bc..70526b2 100644 --- a/src/DataStore/SietchDataStore.h +++ b/src/DataStore/SietchDataStore.h @@ -1,4 +1,4 @@ -// Copyright 2019-2023 The Hush developers +// Copyright 2019-2024 The Hush developers // Released under the GPLv3 #ifndef SIETCHDATASTORE_H #define SIETCHDATASTORE_H diff --git a/src/FileSystem/FileSystem.cpp b/src/FileSystem/FileSystem.cpp index a598d36..1f71a50 100644 --- a/src/FileSystem/FileSystem.cpp +++ b/src/FileSystem/FileSystem.cpp @@ -1,4 +1,4 @@ -// Copyright 2019-2023 The Hush developers +// Copyright 2019-2024 The Hush developers // Released under the GPLv3 #include "FileSystem.h" diff --git a/src/FileSystem/FileSystem.h b/src/FileSystem/FileSystem.h index 44d6cc6..596a57d 100644 --- a/src/FileSystem/FileSystem.h +++ b/src/FileSystem/FileSystem.h @@ -1,4 +1,4 @@ -// Copyright 2019-2023 The Hush developers +// Copyright 2019-2024 The Hush developers // GPLv3 #ifndef FILESYSTEM_H #define FILESYSTEM_H diff --git a/src/Logger/LogContext.h b/src/Logger/LogContext.h index 7b3f4a8..25b1bca 100644 --- a/src/Logger/LogContext.h +++ b/src/Logger/LogContext.h @@ -1,4 +1,4 @@ -// Copyright 2019-2023 The Hush developers +// Copyright 2019-2024 The Hush developers // Released under the GPLv3 #ifndef LOGCONTEXT_H #define LOGCONTEXT_H diff --git a/src/Logger/LogCrtitical.h b/src/Logger/LogCrtitical.h index 0c05f4c..514b6e7 100644 --- a/src/Logger/LogCrtitical.h +++ b/src/Logger/LogCrtitical.h @@ -1,4 +1,4 @@ -// Copyright 2019-2023 The Hush developers +// Copyright 2019-2024 The Hush developers // Released under the GPLv3 #ifndef LOGCRITICAL_H #define LOGCRITICAL_H diff --git a/src/Logger/LogDebug.h b/src/Logger/LogDebug.h index 3967900..2df045c 100644 --- a/src/Logger/LogDebug.h +++ b/src/Logger/LogDebug.h @@ -1,4 +1,4 @@ -// Copyright 2019-2023 The Hush developers +// Copyright 2019-2024 The Hush developers // Released under the GPLv3 #ifndef LOGDEBUG_H #define LOGDEBUG_H diff --git a/src/Logger/LogError.h b/src/Logger/LogError.h index 07daf70..5c8f42d 100644 --- a/src/Logger/LogError.h +++ b/src/Logger/LogError.h @@ -1,4 +1,4 @@ -// Copyright 2019-2023 The Hush developers +// Copyright 2019-2024 The Hush developers // Released under the GPLv3 #ifndef LOGERROR_H #define LOGERROR_H diff --git a/src/Logger/LogFatal.h b/src/Logger/LogFatal.h index cc00e65..719983c 100644 --- a/src/Logger/LogFatal.h +++ b/src/Logger/LogFatal.h @@ -1,4 +1,4 @@ -// Copyright 2019-2023 The Hush developers +// Copyright 2019-2024 The Hush developers // Released under the GPLv3 #ifndef LOGFATAL_H #define LOGFATAL_H diff --git a/src/Logger/LogInfo.h b/src/Logger/LogInfo.h index 5fcaa02..9838a77 100644 --- a/src/Logger/LogInfo.h +++ b/src/Logger/LogInfo.h @@ -1,4 +1,4 @@ -// Copyright 2019-2023 The Hush developers +// Copyright 2019-2024 The Hush developers // Released under the GPLv3 #ifndef LOGINFO_H #define LOGINFO_H diff --git a/src/Logger/LogStrategy.h b/src/Logger/LogStrategy.h index c17802f..ca247ce 100644 --- a/src/Logger/LogStrategy.h +++ b/src/Logger/LogStrategy.h @@ -1,4 +1,4 @@ -// Copyright 2019-2023 The Hush developers +// Copyright 2019-2024 The Hush developers // Released under the GPLv3 #ifndef LOGSTRATEGY_H #define LOGSTRATEGY_H diff --git a/src/Logger/LogSuccess.h b/src/Logger/LogSuccess.h index 1ab4e22..3c39a05 100644 --- a/src/Logger/LogSuccess.h +++ b/src/Logger/LogSuccess.h @@ -1,4 +1,4 @@ -// Copyright 2019-2023 The Hush developers +// Copyright 2019-2024 The Hush developers // Released under the GPLv3 #ifndef LOGSUCCESS_H #define LOGSUCCESS_H diff --git a/src/Logger/LogType.h b/src/Logger/LogType.h index 468a717..9c43c05 100644 --- a/src/Logger/LogType.h +++ b/src/Logger/LogType.h @@ -1,4 +1,4 @@ -// Copyright 2019-2023 The Hush developers +// Copyright 2019-2024 The Hush developers // Released under the GPLv3 #ifndef LOGTYPE_H #define LOGTYPE_H diff --git a/src/Logger/LogWarning.h b/src/Logger/LogWarning.h index ef11b56..96d2f04 100644 --- a/src/Logger/LogWarning.h +++ b/src/Logger/LogWarning.h @@ -1,4 +1,4 @@ -// Copyright 2019-2023 The Hush developers +// Copyright 2019-2024 The Hush developers // Released under the GPLv3 #ifndef LOGWARNING_H #define LOGWARNING_H diff --git a/src/Logger/LogWriter.cpp b/src/Logger/LogWriter.cpp index 3bdeb02..a24cb0f 100644 --- a/src/Logger/LogWriter.cpp +++ b/src/Logger/LogWriter.cpp @@ -1,4 +1,4 @@ -// Copyright 2019-2023 The Hush developers +// Copyright 2019-2024 The Hush developers // Released under the GPLv3 #include "LogWriter.h" diff --git a/src/Logger/LogWriter.h b/src/Logger/LogWriter.h index 0e026d8..270971c 100644 --- a/src/Logger/LogWriter.h +++ b/src/Logger/LogWriter.h @@ -1,4 +1,4 @@ -// Copyright 2019-2023 The Hush developers +// Copyright 2019-2024 The Hush developers // Released under the GPLv3 #ifndef LOGWRITER_H #define LOGWRITER_H diff --git a/src/Logger/Logger.h b/src/Logger/Logger.h index f00b637..5429a24 100644 --- a/src/Logger/Logger.h +++ b/src/Logger/Logger.h @@ -1,4 +1,4 @@ -// Copyright 2019-2023 The Hush developers +// Copyright 2019-2024 The Hush developers // Released under the GPLv3 #ifndef LOGGER_H #define LOGGER_H diff --git a/src/Logger/SimpleLogger.h b/src/Logger/SimpleLogger.h index 1529d34..bf16db3 100644 --- a/src/Logger/SimpleLogger.h +++ b/src/Logger/SimpleLogger.h @@ -1,4 +1,4 @@ -// Copyright 2019-2023 The Hush developers +// Copyright 2019-2024 The Hush developers // Released under the GPLv3 #ifndef SIMPLELOGGER_H #define SIMPLELOGGER_H diff --git a/src/Logger/test.cpp b/src/Logger/test.cpp index 4671f81..7596878 100644 --- a/src/Logger/test.cpp +++ b/src/Logger/test.cpp @@ -1,4 +1,4 @@ -// Copyright 2019-2023 The Hush developers +// Copyright 2019-2024 The Hush developers // Released under the GPLv3 #include "SimpleLogger.h" diff --git a/src/Model/ChatItem.cpp b/src/Model/ChatItem.cpp index 19e72d4..bf3b3ab 100644 --- a/src/Model/ChatItem.cpp +++ b/src/Model/ChatItem.cpp @@ -1,4 +1,4 @@ -// Copyright 2019-2023 The Hush developers +// Copyright 2019-2024 The Hush developers // Released under the GPLv3 #include "ChatItem.h" diff --git a/src/Model/ChatItem.h b/src/Model/ChatItem.h index 35997fc..2ea7471 100644 --- a/src/Model/ChatItem.h +++ b/src/Model/ChatItem.h @@ -1,4 +1,4 @@ -// Copyright 2019-2023 The Hush developers +// Copyright 2019-2024 The Hush developers // Released under the GPLv3 #ifndef CHATITEM_H diff --git a/src/Model/ContactItem.cpp b/src/Model/ContactItem.cpp index 919b4d6..0e34c68 100644 --- a/src/Model/ContactItem.cpp +++ b/src/Model/ContactItem.cpp @@ -1,4 +1,4 @@ -// Copyright 2019-2023 The Hush developers +// Copyright 2019-2024 The Hush developers // GPLv3 #include "ContactItem.h" #include "chatmodel.h" diff --git a/src/Model/ContactItem.h b/src/Model/ContactItem.h index 9f35576..ea51766 100644 --- a/src/Model/ContactItem.h +++ b/src/Model/ContactItem.h @@ -1,4 +1,4 @@ -// Copyright 2019-2023 The Hush developers +// Copyright 2019-2024 The Hush developers // Released under the GPLv3 #ifndef CONTACTITEM_H #define CONTACTITEM_H diff --git a/src/Model/ContactRequest.cpp b/src/Model/ContactRequest.cpp index f9cfa4a..f41e6d4 100644 --- a/src/Model/ContactRequest.cpp +++ b/src/Model/ContactRequest.cpp @@ -1,4 +1,4 @@ -// Copyright 2019-2023 The Hush developers +// Copyright 2019-2024 The Hush developers // GPLv3 #include "ContactRequest.h" diff --git a/src/Model/ContactRequest.h b/src/Model/ContactRequest.h index 5e8f781..9954936 100644 --- a/src/Model/ContactRequest.h +++ b/src/Model/ContactRequest.h @@ -1,4 +1,4 @@ -// Copyright 2019-2023 The Hush developers +// Copyright 2019-2024 The Hush developers // Released under the GPLv3 #ifndef CONTACTREQUEST_H #define CONTACTREQUEST_H diff --git a/src/Model/ContactRequestChatItem.cpp b/src/Model/ContactRequestChatItem.cpp index a254c3c..e667d4b 100644 --- a/src/Model/ContactRequestChatItem.cpp +++ b/src/Model/ContactRequestChatItem.cpp @@ -1,3 +1,3 @@ -// Copyright 2019-2023 The Hush developers +// Copyright 2019-2024 The Hush developers // Released under the GPLv3 #include "ContactRequestChatItem.h" diff --git a/src/Model/ContactRequestChatItem.h b/src/Model/ContactRequestChatItem.h index 3800536..ce47fac 100644 --- a/src/Model/ContactRequestChatItem.h +++ b/src/Model/ContactRequestChatItem.h @@ -1,4 +1,4 @@ -// Copyright 2019-2023 The Hush developers +// Copyright 2019-2024 The Hush developers // Released under the GPLv3 #ifdef CONTACTREQUESTCHATITEM_H #define CONTACTREQUESTCHATITEM_H diff --git a/src/about.ui b/src/about.ui index e236366..ba5f54f 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-2023 The Hush developers GNU Public License V3</p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Copyright (c) 2019-2024 The Hush developers GNU Public License V3</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Copyright (c) 2018-2019 Aditya Kulkarni, Duke Leto, Jane Mercer </p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> diff --git a/src/addressbook.cpp b/src/addressbook.cpp index 13ca5d0..e57f160 100644 --- a/src/addressbook.cpp +++ b/src/addressbook.cpp @@ -1,4 +1,4 @@ -// Copyright 2019-2023 The Hush developers +// Copyright 2019-2024 The Hush developers // Released under the GPLv3 #include "addressbook.h" diff --git a/src/addressbook.h b/src/addressbook.h index 9a5672e..73effdc 100644 --- a/src/addressbook.h +++ b/src/addressbook.h @@ -1,4 +1,4 @@ -// Copyright 2019-2023 The Hush developers +// Copyright 2019-2024 The Hush developers // Released under the GPLv3 #ifndef ADDRESSBOOK_H #define ADDRESSBOOK_H diff --git a/src/addresscombo.cpp b/src/addresscombo.cpp index d1399cf..fb5109a 100644 --- a/src/addresscombo.cpp +++ b/src/addresscombo.cpp @@ -1,4 +1,4 @@ -// Copyright 2019-2023 The Hush developers +// Copyright 2019-2024 The Hush developers // Released under the GPLv3 #include "addresscombo.h" #include "addressbook.h" diff --git a/src/addresscombo.h b/src/addresscombo.h index 437a592..3f770df 100644 --- a/src/addresscombo.h +++ b/src/addresscombo.h @@ -1,4 +1,4 @@ -// Copyright 2019-2023 The Hush developers +// Copyright 2019-2024 The Hush developers // Released under the GPLv3 #ifndef ADDRESSCOMBO_H #define ADDRESSCOMBO_H diff --git a/src/balancestablemodel.cpp b/src/balancestablemodel.cpp index 91f80b1..5da187c 100644 --- a/src/balancestablemodel.cpp +++ b/src/balancestablemodel.cpp @@ -1,4 +1,4 @@ -// Copyright 2019-2023 The Hush developers +// Copyright 2019-2024 The Hush developers // Released under the GPLv3 #include "balancestablemodel.h" #include "addressbook.h" diff --git a/src/balancestablemodel.h b/src/balancestablemodel.h index ee1e70f..f9d6aee 100644 --- a/src/balancestablemodel.h +++ b/src/balancestablemodel.h @@ -1,4 +1,4 @@ -// Copyright 2019-2023 The Hush developers +// Copyright 2019-2024 The Hush developers // Released under the GPLv3 #ifndef BALANCESTABLEMODEL_H #define BALANCESTABLEMODEL_H diff --git a/src/camount.cpp b/src/camount.cpp index 63b50dd..90fd732 100644 --- a/src/camount.cpp +++ b/src/camount.cpp @@ -1,4 +1,4 @@ -// Copyright 2019-2023 The Hush developers +// Copyright 2019-2024 The Hush developers // Released under the GPLv3 #include "camount.h" #include "settings.h" diff --git a/src/camount.h b/src/camount.h index 299f12b..ffc853d 100644 --- a/src/camount.h +++ b/src/camount.h @@ -1,4 +1,4 @@ -// Copyright 2019-2023 The Hush developers +// Copyright 2019-2024 The Hush developers // Released under the GPLv3 #ifndef CAMOUNT_H #define CAMOUNT_H diff --git a/src/chatbubbleme.cpp b/src/chatbubbleme.cpp index ea654fe..0fe76fc 100644 --- a/src/chatbubbleme.cpp +++ b/src/chatbubbleme.cpp @@ -1,4 +1,4 @@ -// Copyright 2019-2023 The Hush developers +// Copyright 2019-2024 The Hush developers // Released under the GPLv3 #include "chatbubbleme.h" #include "ui_chatbubbleme.h" diff --git a/src/chatbubbleme.h b/src/chatbubbleme.h index 153f015..879f19a 100644 --- a/src/chatbubbleme.h +++ b/src/chatbubbleme.h @@ -1,4 +1,4 @@ -// Copyright 2019-2023 The Hush developers +// Copyright 2019-2024 The Hush developers // Released under the GPLv3 #ifndef CHATBUBBLEME_H #define CHATBUBBLEME_H diff --git a/src/chatbubblepartner.cpp b/src/chatbubblepartner.cpp index 1f68e9d..ee427db 100644 --- a/src/chatbubblepartner.cpp +++ b/src/chatbubblepartner.cpp @@ -1,4 +1,4 @@ -// Copyright 2019-2023 The Hush developers +// Copyright 2019-2024 The Hush developers // Released under the GPLv3 #include "chatbubblepartner.h" #include "ui_chatbubblepartner.h" diff --git a/src/chatbubblepartner.h b/src/chatbubblepartner.h index 26058bc..e0ddf10 100644 --- a/src/chatbubblepartner.h +++ b/src/chatbubblepartner.h @@ -1,4 +1,4 @@ -// Copyright 2019-2023 The Hush developers +// Copyright 2019-2024 The Hush developers // Released under the GPLv3 #ifndef CHATBUBBLEPARTNER_H #define CHATBUBBLEPARTNER_H diff --git a/src/chatmodel.cpp b/src/chatmodel.cpp index 306b1ba..4dedaa2 100644 --- a/src/chatmodel.cpp +++ b/src/chatmodel.cpp @@ -1,4 +1,4 @@ -// Copyright 2019-2023 The Hush developers +// Copyright 2019-2024 The Hush developers // Released under the GPLv3 #include "chatmodel.h" #include "settings.h" diff --git a/src/chatmodel.h b/src/chatmodel.h index af6b7c1..aca73b3 100644 --- a/src/chatmodel.h +++ b/src/chatmodel.h @@ -1,4 +1,4 @@ -// Copyright 2019-2023 The Hush developers +// Copyright 2019-2024 The Hush developers // Released under the GPLv3 #ifndef CHATMODEL_H diff --git a/src/connection.cpp b/src/connection.cpp index bef89f8..a5c3db4 100644 --- a/src/connection.cpp +++ b/src/connection.cpp @@ -1,4 +1,4 @@ -// Copyright 2019-2023 The Hush developers +// Copyright 2019-2024 The Hush developers // Released under the GPLv3 #include "connection.h" #include "mainwindow.h" @@ -9,6 +9,8 @@ #include "controller.h" #include "../lib/silentdragonlitelib.h" #include "precompiled.h" +#include +#include "sdl.h" using json = nlohmann::json; @@ -32,7 +34,7 @@ ConnectionLoader::ConnectionLoader(MainWindow* main, Controller* rpc) connD->setupUi(d); auto theme = Settings::getInstance()->get_theme_name(); - qDebug() << theme << "theme " << theme << " has loaded"; + DEBUG("theme " << theme << " has loaded"); auto size = QSize(512,512); if (theme == "Dark" || theme == "Midnight") { @@ -55,6 +57,7 @@ ConnectionLoader::ConnectionLoader(MainWindow* main, Controller* rpc) ConnectionLoader::~ConnectionLoader() { + DEBUG("destroying ConnectionLoader"); delete isSyncing; delete connD; delete d; @@ -62,6 +65,7 @@ ConnectionLoader::~ConnectionLoader() void ConnectionLoader::loadConnection() { + DEBUG("calling doAutoConnect"); QTimer::singleShot(1, [=]() { this->doAutoConnect(); }); if (!Settings::getInstance()->isHeadless()) d->exec(); @@ -69,7 +73,22 @@ void ConnectionLoader::loadConnection() void ConnectionLoader::loadProgress() { - QTimer::singleShot(1, [=]() { this->ShowProgress(); }); + bool failed = false; + QTimer::singleShot(1, [=]() mutable { + DEBUG("failed=" << failed); + // continually retry ShowProgress() until it succeeds + // by running without an exception + do { + try { + this->ShowProgress(); + failed = false; + } catch (const std::exception& e) { + DEBUG("caught exception " << e.what() ); + failed = true; + } + } while (failed); + + }); if (!Settings::getInstance()->isHeadless()) d->exec(); } @@ -83,56 +102,62 @@ void ConnectionLoader::ShowProgress() auto connection = makeConnection(config); auto me = this; - qDebug() << __func__ << ": server=" << config->server << " connection=" << connection << " me=" << me; + DEBUG("server=" << config->server << " connection=" << connection << " me=" << me); isSyncing = new QAtomicInteger(); isSyncing->store(true); - main->logger->write("isSyncing"); - + DEBUG("isSyncing"); + // Do a sync after import syncTimer = new QTimer(main); - main->logger->write("Beginning sync after import wif"); - connection->doRPCWithDefaultErrorHandling("sync", "", [=](auto) { + DEBUG("Beginning sync after import wif"); + connection->doRPC("sync", "", [=](auto) { + DEBUG("finished syncing"); isSyncing->store(false); // Cancel the timer syncTimer->deleteLater(); // When sync is done, set the connection this->doRPCSetConnectionShield(connection); + }, [=](auto) { + DEBUG("sync rpc error! server=" << config->server); }); - + // While it is syncing, we'll show the status updates while it is alive. QObject::connect(syncTimer, &QTimer::timeout, [=]() { - // Check the sync status + DEBUG("Check the sync status"); if (isSyncing != nullptr && isSyncing->load()) { - // Get the sync status - + DEBUG("Get the sync status"); try { - connection->doRPC("syncstatus", "", [=](json reply) { - if (isSyncing != nullptr && reply.find("synced_blocks") != reply.end()) - - { - qint64 synced = reply["synced_blocks"].get(); - 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"); - } - - } -}); + 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"); -syncTimer->setInterval(1* 1000); -syncTimer->start(); -main->logger->write("Start sync timer"); + // rethrow exception so loadProgress can catch + // it and retry the entire ShowProgress() function again + throw new std::runtime_error(std::string("syncstatus failed")); + } + } + }); + int interval = 1*1000; + syncTimer->setInterval(interval); + syncTimer->start(); + DEBUG("Start sync timer with interval=" << interval); } void ConnectionLoader::doAutoConnect() @@ -140,43 +165,53 @@ void ConnectionLoader::doAutoConnect() auto config = std::shared_ptr(new ConnectionConfig()); config->dangerous = false; config->server = Settings::getInstance()->getSettings().server; - qDebug() << __func__ << " server=" << config->server; + DEBUG(" server=" << config->server); // Initialize the library - main->logger->write(QObject::tr("Attempting to initialize library with ") + config->server); + DEBUG("Attempting to initialize library with "<< config->server); // Check to see if there's an existing wallet if (litelib_wallet_exists(Settings::getDefaultChainName().toStdString().c_str())) { - qDebug() << __func__ << ": using existing wallet"; + DEBUG("using existing wallet"); main->logger->write(QObject::tr("Using existing wallet.")); - char* resp = litelib_initialize_existing( - config->dangerous, - config->server.toStdString().c_str() - ); - QString response = litelib_process_response(resp); - if (response.toUpper().trimmed() != "OK") { - config->server = Settings::getRandomServer(); - - resp = litelib_initialize_existing( + QString response = ""; + try { + char* resp = litelib_initialize_existing( config->dangerous, config->server.toStdString().c_str() ); response = litelib_process_response(resp); + } catch (const std::exception& e) { + DEBUG("caught an exception, ignoring: " << e.what()); + } + + if (response.toUpper().trimmed() != "OK") { + config->server = Settings::getRandomServer(); + + try { + char* resp = litelib_initialize_existing( + config->dangerous, + config->server.toStdString().c_str() + ); + response = litelib_process_response(resp); + } catch (const std::exception& e) { + DEBUG("caught an exception, ignoring: " << e.what()); + } if (response.toUpper().trimmed() != "OK") { QString resp = "Error when connecting to " + config->server + ": " + response; showError(resp); return; } else { - qDebug() << __func__ << ": Successfully connected to random server: " << config->server << " !!!"; + DEBUG("Successfully connected to random server: " << config->server << " !!!"); } } else { - qDebug() << __func__ << ": Successfully connected to " << config->server << " !!!"; + DEBUG("Successfully connected to " << config->server << " !!!"); } } else { - qDebug() << __func__ << ": no existing wallet"; + DEBUG("no existing wallet"); main->logger->write(QObject::tr("Create/restore wallet.")); createOrRestore(config->dangerous, config->server); d->show(); @@ -187,61 +222,77 @@ void ConnectionLoader::doAutoConnect() qDebug() << __func__ << ": server=" << config->server << " connection=" << connection << " me=" << me << endl; - // After the lib is initialized, try to do get info connection->doRPC("info", "", [=](auto reply) { // If success, set the connection - main->logger->write("Connection is online."); + DEBUG("Connection is online."); connection->setInfo(reply); - main->logger->write("getting Connection reply"); + DEBUG("getting Connection reply"); isSyncing = new QAtomicInteger(); isSyncing->store(true); - main->logger->write("isSyncing"); + DEBUG("isSyncing"); // Do a sync at startup syncTimer = new QTimer(main); - main->logger->write("Beginning sync"); - connection->doRPCWithDefaultErrorHandling("sync", "", [=](auto) { + DEBUG("Beginning sync"); + connection->doRPC("sync", "", [=](auto) { + DEBUG("finished syncing"); isSyncing->store(false); // Cancel the timer syncTimer->deleteLater(); // When sync is done, set the connection this->doRPCSetConnection(connection); + }, [=](auto) mutable { + DEBUG("sync rpc error! server=" << config->server); + // continually retry sync RPC until it succeeds + // don't change server each time it fails + bool failed = true; + do { + // config->server = Settings::getRandomServer(); + // auto connection = makeConnection(config); + // DEBUG("changed server to " << config->server); + connection->doRPC("sync", "", [=](auto) mutable { + DEBUG("sync success with server=" << config->server); + failed = false; + isSyncing->store(false); + // Cancel the timer + syncTimer->deleteLater(); + // When sync is done, set the connection + this->doRPCSetConnection(connection); + }, [=](auto) { + DEBUG("sync failed with server=" << config->server << " . continuing sync loop" ); + }); + } while (failed); }); // While it is syncing, we'll show the status updates while it is alive. QObject::connect(syncTimer, &QTimer::timeout, [=]() { - // Check the sync status + DEBUG("Check the sync status"); if (isSyncing != nullptr && isSyncing->load()) { - // Get the sync status - + DEBUG("Getting the sync status"); try { connection->doRPC("syncstatus", "", [=](json reply) { - if (isSyncing != nullptr && reply.find("synced_blocks") != reply.end()) - - { + if (isSyncing != nullptr && reply.find("synced_blocks") != reply.end()) { qint64 synced = reply["synced_blocks"].get(); 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"); - - } - + }, + [=](QString err) { + DEBUG("syncstatus error" << err); + }); + } catch (const std::exception& e) { + DEBUG("caught exception from syncstatus: " << e.what()); + } } }); - syncTimer->setInterval(1* 1000); + int interval = 1*1000; + syncTimer->setInterval(interval); syncTimer->start(); - main->logger->write("Start sync timer"); + DEBUG("Start sync timer with interval=" << interval); }, [=](QString err) { showError(err); @@ -255,13 +306,13 @@ void ConnectionLoader::createOrRestore(bool dangerous, QString server) d->hide(); // Create a wizard FirstTimeWizard wizard(dangerous,server); - main->logger->write("Start new Wallet with FirstimeWizard"); + DEBUG("Start new Wallet with FirstimeWizard"); wizard.exec(); } void ConnectionLoader::doRPCSetConnection(Connection* conn) { - qDebug() << "Connectionloader finished, setting connection"; + DEBUG("Connectionloader finished, setting connection"); main->logger->write("Connectionloader finished, setting connection"); rpc->setConnection(conn); d->accept(); @@ -272,17 +323,16 @@ void ConnectionLoader::doRPCSetConnection(Connection* conn) main->logger->write("Path to Wallet.dat : " ); qDebug() << __func__ << ": wallet path =" << plaintextWallet; plaintextWallet.remove(); - - } catch (...) { - qDebug() << "No plaintext wallet found! file=" << plaintextWallet; + } catch (const std::exception& e) { + DEBUG("Caught exception" << e.what() ); + DEBUG("No plaintext wallet found! file=" << plaintextWallet); main->logger->write("no Plaintext wallet.dat"); } - } void ConnectionLoader::doRPCSetConnectionShield(Connection* conn) { - qDebug() << "Importing finished, setting connection"; + DEBUG("Importing finished, setting connection"); rpc->setConnection(conn); d->accept(); main->getRPC()->shield([=] (auto) {}); @@ -293,9 +343,10 @@ void ConnectionLoader::doRPCSetConnectionShield(Connection* conn) main->logger->write("Path to Wallet.dat : " ); qDebug() << __func__ << ": wallet path =" << plaintextWallet; plaintextWallet.remove(); - } catch (...) { + } catch (const std::exception& e) { + DEBUG("Caught exception" << e.what() ); main->logger->write("no Plaintext wallet.dat"); - qDebug() << "No plaintext wallet found! file=" << plaintextWallet; + DEBUG("No plaintext wallet found! file=" << plaintextWallet); } } @@ -346,19 +397,50 @@ QString litelib_process_response(char* resp) ************************************************************************************/ void Executor::run() { - char* resp = litelib_execute(this->cmd.toStdString().c_str(), this->args.toStdString().c_str()); - QString reply = litelib_process_response(resp); - auto parsed = json::parse( - reply.toStdString().c_str(), - nullptr, - false - ); - if (parsed.is_discarded() || parsed.is_null()) - emit handleError(reply); + auto config = std::shared_ptr(new ConnectionConfig()); + DEBUG("cmd=" << cmd << " args=" << args << " server=" << config->server); + QString response = ""; + try { + char* resp = litelib_execute(this->cmd.toStdString().c_str(), this->args.toStdString().c_str()); + response = litelib_process_response(resp); + } catch (const std::exception& e) { + DEBUG("ignoring exception: " << e.what() ); + } - else + //TODO: we can do stricter error checking + if (response.isEmpty()) { + config->server = Settings::getRandomServer(); + + try { + char* resp = litelib_initialize_existing( + config->dangerous, + config->server.toStdString().c_str() + ); + response = litelib_process_response(resp); + resp = litelib_execute(this->cmd.toStdString().c_str(), this->args.toStdString().c_str()); + response = litelib_process_response(resp); + } catch (const std::exception& e) { + DEBUG("server= " << config->server << " gave exception: " << e.what() ); + emit handleError(response); + } + } + try { + auto parsed = json::parse( + response.toStdString().c_str(), + nullptr, + false + ); + + if (parsed.is_discarded() || parsed.is_null()) { + emit handleError(response); + } else { + emit responseReady(parsed); + } + } catch (const std::exception& e) { + DEBUG("exception when parsing json: " << e.what() ); + emit handleError(response); + } - emit responseReady(parsed); } void Callback::processRPCCallback(json resp) @@ -386,11 +468,12 @@ Connection::Connection(MainWindow* m, std::shared_ptr conf) void Connection::doRPC(const QString cmd, const QString args, const std::function& cb, const std::function& errCb) { - if (shutdownInProgress) - // Ignoring RPC because shutdown in progress + if (shutdownInProgress) { + DEBUG("Ignoring RPC because shutdown in progress"); return; + } - qDebug() << __func__ << ": " << cmd; + DEBUG("cmd=" << cmd << " args=" << args); // Create a runner. auto runner = new Executor(cmd, args); @@ -405,7 +488,7 @@ void Connection::doRPC(const QString cmd, const QString args, const std::functio void Connection::doRPCWithDefaultErrorHandling(const QString cmd, const QString args, const std::function& cb) { - qDebug() << __func__ << ": " << cmd; + DEBUG("cmd=" << cmd << " args=" << args); doRPC(cmd, args, cb, [=] (QString err) { this->showTxError(err); }); @@ -413,7 +496,7 @@ void Connection::doRPCWithDefaultErrorHandling(const QString cmd, const QString void Connection::doRPCIgnoreError(const QString cmd, const QString args, const std::function& cb) { - qDebug() << __func__ << ": " << cmd; + DEBUG("cmd=" << cmd << " args=" << args); doRPC(cmd, args, cb, [=] (auto) { // Ignored error handling }); @@ -445,5 +528,6 @@ void Connection::showTxError(const QString& error) */ void Connection::shutdown() { + DEBUG("shutting down"); shutdownInProgress = true; } diff --git a/src/connection.h b/src/connection.h index 431cd38..ef62082 100644 --- a/src/connection.h +++ b/src/connection.h @@ -1,4 +1,4 @@ -// Copyright 2019-2023 The Hush developers +// Copyright 2019-2024 The Hush developers // Released under the GPLv3 #ifndef CONNECTION_H #define CONNECTION_H @@ -6,6 +6,7 @@ #include "mainwindow.h" #include "ui_connection.h" #include "precompiled.h" +#include using json = nlohmann::json; diff --git a/src/contactmodel.cpp b/src/contactmodel.cpp index aea39cd..01332f7 100644 --- a/src/contactmodel.cpp +++ b/src/contactmodel.cpp @@ -1,4 +1,4 @@ -// Copyright 2019-2023 The Hush developers +// Copyright 2019-2024 The Hush developers // GPLv3 #include "contactmodel.h" diff --git a/src/contactmodel.h b/src/contactmodel.h index 2878e32..adba846 100644 --- a/src/contactmodel.h +++ b/src/contactmodel.h @@ -1,4 +1,4 @@ -// Copyright 2019-2023 The Hush developers +// Copyright 2019-2024 The Hush developers // Released under the GPLv3 #ifndef CONTACTMODEL_H #define CONTACTMODEL_H diff --git a/src/controller.cpp b/src/controller.cpp index 61660cd..e0dc505 100644 --- a/src/controller.cpp +++ b/src/controller.cpp @@ -1,4 +1,4 @@ -// Copyright 2019-2023 The Hush developers +// Copyright 2019-2024 The Hush developers // Released under the GPLv3 #include "controller.h" @@ -7,7 +7,6 @@ #include "settings.h" #include "version.h" #include "camount.h" -#include "websockets.h" #include "Model/ChatItem.h" #include "DataStore/DataStore.h" @@ -262,10 +261,12 @@ void Controller::noConnection() // Clear balances ui->balSheilded->setText(""); + ui->balUnconfirmed->setText(""); ui->balTransparent->setText(""); ui->balTotal->setText(""); ui->balSheilded->setToolTip(""); + ui->balUnconfirmed->setToolTip(""); ui->balTransparent->setToolTip(""); ui->balTotal->setToolTip(""); } @@ -298,12 +299,19 @@ void Controller::processInfo(const json& info) main->disableRecurring(); } -void Controller::getInfoThenRefresh(bool force) +void Controller::getInfoThenRefresh(bool force) { qDebug()<< __func__; - if (!zrpc->haveConnection()) + if (!zrpc->haveConnection()) return noConnection(); + // Update current server in Info Tab + auto current_server = Settings::getInstance()->getSettings().server; + ui->current_server->setText(current_server); + + // no need to update sticky server because currently there is no + // way to change that at run-time via GUI + static bool prevCallSucceeded = false; zrpc->fetchInfo([=] (const json& reply) { @@ -732,6 +740,7 @@ void Controller::updateUIBalances() { CAmount balT = getModel()->getBalT(); CAmount balZ = getModel()->getBalZ(); + CAmount balU = getModel()->getBalU(); CAmount balVerified = getModel()->getBalVerified(); CAmount balSpendable = getModel()->getBalSpendable(); @@ -749,6 +758,7 @@ void Controller::updateUIBalances() // Balances table ui->balSheilded->setText(balZ.toDecimalhushString()); ui->balVerified->setText(balVerified.toDecimalhushString()); + ui->balUnconfirmed->setText(balU.toDecimalhushString()); ui->balTransparent->setText(balT.toDecimalhushString()); ui->balSpendable->setText(balSpendable.toDecimalhushString()); ui->balTotal->setText(balTotal.toDecimalhushString()); @@ -888,17 +898,16 @@ void Controller::refreshBalances() zrpc->fetchBalance([=] (json reply) { CAmount balT = CAmount::fromqint64(reply["tbalance"].get()); 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); @@ -933,6 +942,26 @@ void Controller::refreshBalances() }); } +void printJsonValue(QTextStream& out, const nlohmann::json& j, int depth = 0) { + if (j.is_array()) { + for (auto& elem : j) { + printJsonValue(out, elem, depth + 1); + } + } else if (j.is_object()) { + for (auto it = j.begin(); it != j.end(); ++it) { + std::string key = it.key(); + const nlohmann::json& value = it.value(); + out << QString::fromStdString(std::string(depth * 4, ' ')) + << QString::fromStdString(key) << ": "; + printJsonValue(out, value, depth + 1); + } + } else { + out << QString::fromStdString(j.dump(4)) << "\n"; + } +} + + + void Controller::refreshTransactions() { qDebug()<< __func__; if (!zrpc->haveConnection()) @@ -1044,7 +1073,6 @@ void Controller::refreshTransactions() { #define MESSAGEAS1 ((const unsigned char *) hashEncryptionKeyraw) /////////// #define MESSAGEAS1_LEN length - unsigned char sk[crypto_kx_SECRETKEYBYTES]; unsigned char pk[crypto_kx_PUBLICKEYBYTES]; @@ -1058,9 +1086,7 @@ void Controller::refreshTransactions() { unsigned char server_rx[crypto_kx_SESSIONKEYBYTES], server_tx[crypto_kx_SESSIONKEYBYTES]; ////////////////Get the pubkey from Bob, so we can create the share key - /////Create the shared key for sending the message - if (crypto_kx_server_session_keys(server_rx, server_tx, pk, sk, pubkeyBob) != 0) { main->logger->write("Suspicious client public outgoing key, bail out "); @@ -1082,15 +1108,11 @@ void Controller::refreshTransactions() { { //////unsigned char* as message from QString #define MESSAGE2 (const unsigned char *) encryptedMemo - ///////// length of the encrypted message #define CIPHERTEXT1_LEN encryptedMemoSize1 - ///////Message length is smaller then the encrypted message #define MESSAGE1_LEN encryptedMemoSize1 - crypto_secretstream_xchacha20poly1305_ABYTES - //////Set the length of the decrypted message - unsigned char decrypted[MESSAGE1_LEN]; unsigned char tag[crypto_secretstream_xchacha20poly1305_TAG_FINAL]; crypto_secretstream_xchacha20poly1305_state state; @@ -1118,7 +1140,6 @@ void Controller::refreshTransactions() { /////Now we can convert it to QString //////////////Give us the output of the decrypted message as debug to see if it was successfully - ChatItem item = ChatItem( datetime, address, @@ -1161,13 +1182,13 @@ void Controller::refreshTransactions() { } else { { // Incoming Transaction - address = (it["address"].is_null() ? "" : QString::fromStdString(it["address"])); - model->markAddressUsed(address); + QString memo; + address = (it["address"].is_null() ? "" : QString::fromStdString(it["address"])); - QString memo; if (!it["memo"].is_null()) { memo = QString::fromStdString(it["memo"]); } + items.push_back(TransactionItemDetail{ address, CAmount::fromqint64(it["amount"].get()), memo @@ -1187,7 +1208,7 @@ void Controller::refreshTransactions() { QString contactname = ""; bool isContact = false; - if (!it["memo"].is_null()) { + if (!memo.isNull()) { if (memo.startsWith("{")) { try { @@ -1257,7 +1278,8 @@ void Controller::refreshTransactions() { if (position == 1) { chatModel->addMemo(txid, headerbytes); - } else { + } + else { // } @@ -1273,7 +1295,6 @@ void Controller::refreshTransactions() { #define MESSAGEAS1 ((const unsigned char *) hashEncryptionKeyraw)/////////// #define MESSAGEAS1_LEN length - unsigned char sk[crypto_kx_SECRETKEYBYTES]; unsigned char pk[crypto_kx_PUBLICKEYBYTES]; @@ -1287,7 +1308,6 @@ void Controller::refreshTransactions() { unsigned char client_rx[crypto_kx_SESSIONKEYBYTES], client_tx[crypto_kx_SESSIONKEYBYTES]; ////////////////Get the pubkey from Bob, so we can create the share key - /////Create the shared key for sending the message if (crypto_kx_client_session_keys(client_rx, client_tx, pk, sk, pubkeyBob) != 0) { @@ -1304,18 +1324,13 @@ void Controller::refreshTransactions() { int encryptedMemoSize1 = ba.length(); //int headersize = ba1.length(); - //////unsigned char* as message from QString #define MESSAGE2 (const unsigned char *) encryptedMemo - ///////// length of the encrypted message #define CIPHERTEXT1_LEN encryptedMemoSize1 - ///////Message length is smaller then the encrypted message #define MESSAGE1_LEN encryptedMemoSize1 - crypto_secretstream_xchacha20poly1305_ABYTES - //////Set the length of the decrypted message - unsigned char decrypted[MESSAGE1_LEN+1]; unsigned char tag[crypto_secretstream_xchacha20poly1305_TAG_FINAL]; crypto_secretstream_xchacha20poly1305_state state; @@ -1343,7 +1358,6 @@ void Controller::refreshTransactions() { memodecrypt = QString::fromUtf8( decryptedMemo.data(), decryptedMemo.size()); ////Give us the output of the decrypted message as debug to see if it was successfully - ChatItem item = ChatItem( datetime, address, @@ -1367,8 +1381,6 @@ void Controller::refreshTransactions() { qDebug() << __func__ << ": ignoring txid="<< txid; } - //} else if (memo.startsWith("{")) { - //qDebug() << __func__ << ": ignoring a header memo"; } else { // Add a chatitem for the initial CR ChatItem item = ChatItem( diff --git a/src/datamodel.cpp b/src/datamodel.cpp index 45d42d3..c17629b 100644 --- a/src/datamodel.cpp +++ b/src/datamodel.cpp @@ -1,4 +1,4 @@ -// Copyright 2019-2023 The Hush developers +// Copyright 2019-2024 The Hush developers // Released under the GPLv3 #include "datamodel.h" diff --git a/src/datamodel.h b/src/datamodel.h index 0a1cf6d..31f38d6 100644 --- a/src/datamodel.h +++ b/src/datamodel.h @@ -1,11 +1,11 @@ -// Copyright 2019-2023 The Hush developers +// Copyright 2019-2024 The Hush developers // Released under the GPLv3 #ifndef DATAMODEL_H #define DATAMODEL_H #include "camount.h" #include "precompiled.h" - +#include struct UnspentOutput { QString address; @@ -48,6 +48,9 @@ public: CAmount getBalZ() { QReadLocker locker(lock); return balZ; } void setBalZ(CAmount a) { QReadLocker locker(lock); this->balZ = a; } + CAmount getBalU() { QReadLocker locker(lock); return balU; } + void setBalU(CAmount a) { QReadLocker locker(lock); this->balU = a; } + CAmount getBalVerified() { QReadLocker locker(lock); return balVerified; } void setBalVerified(CAmount a) { QReadLocker locker(lock); this->balVerified = a; } @@ -76,6 +79,7 @@ private: CAmount balT; CAmount balZ; + CAmount balU; CAmount balVerified; CAmount balSpendable; diff --git a/src/fillediconlabel.h b/src/fillediconlabel.h index 2f35269..88fe5f9 100644 --- a/src/fillediconlabel.h +++ b/src/fillediconlabel.h @@ -1,4 +1,4 @@ -// Copyright 2019-2023 The Hush developers +// Copyright 2019-2024 The Hush developers // Released under the GPLv3 #ifndef FILLEDICONLABEL_H #define FILLEDICONLABEL_H diff --git a/src/firsttimewizard.cpp b/src/firsttimewizard.cpp index c69632f..daa272e 100644 --- a/src/firsttimewizard.cpp +++ b/src/firsttimewizard.cpp @@ -1,4 +1,4 @@ -// Copyright 2019-2023 The Hush developers +// Copyright 2019-2024 The Hush developers // Released under the GPLv3 #include "firsttimewizard.h" #include "ui_newseed.h" @@ -293,10 +293,28 @@ void NewSeedPage::initializePage() { // Call the library to create a new wallet. qDebug() << __func__; - char* resp = litelib_initialize_new(parent->dangerous,parent->server.toStdString().c_str()); - QString reply = litelib_process_response(resp); + QString reply = ""; + try { + char* resp = litelib_initialize_new(parent->dangerous,parent->server.toStdString().c_str()); + reply = litelib_process_response(resp); + } catch (const std::exception& e) { + qDebug() << __func__ << ": caught an exception, ignoring: " << e.what(); + } + qDebug() << __func__ << ": reply=" << reply; + if (reply.isEmpty()) { + qDebug() << "Lite server " << parent->server << " is down, getting a random one"; + parent->server = Settings::getRandomServer(); + qDebug() << __func__ << ": new server is " << parent->server; + + // retry with the new server + // we use litelib_initialize_existing because the call to litelib_initialize_new above + // has already created a wallet on disk + char* resp = litelib_initialize_existing(parent->dangerous,parent->server.toStdString().c_str()); + reply = litelib_process_response(resp); + } + auto parsed = json::parse(reply.toStdString().c_str(), nullptr, false); if (parsed.is_discarded() || parsed.is_null() || parsed.find("seed") == parsed.end()) { form.txtSeed->setPlainText(tr("Error creating a wallet") + "\n" + reply); @@ -607,21 +625,49 @@ bool NewSeedPage::validatePage() { dialog.exec(); - if ((verifyseed.verify->toPlainText() == seed) && (verifyseed.verifyBirthday->toPlainText() == birthday)) - { - char* resp = litelib_execute("save", ""); - QString reply = litelib_process_response(resp); + QString reply = ""; + if ((verifyseed.verify->toPlainText() == seed) && (verifyseed.verifyBirthday->toPlainText() == birthday)) { + try { + char* resp = litelib_execute("save", ""); + reply = litelib_process_response(resp); + } catch (const std::exception& e) { + qDebug() << __func__ << ": caught an exception, ignoring: " << e.what(); + } - auto parsed = json::parse(reply.toStdString().c_str(), nullptr, false); - if (parsed.is_discarded() || parsed.is_null() || parsed.find("result") == parsed.end()) { + qDebug() << __func__ << ": reply=" << reply; + + // 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(); + } + } - QMessageBox::warning(this, tr("Failed to save wallet"), - tr("Couldn't save the wallet") + "\n" + reply, - QMessageBox::Ok); - return false; - } else { - return true; - } + qDebug() << __func__ << ": reply=" << reply; + + auto parsed = json::parse(reply.toStdString().c_str(), nullptr, false); + if (parsed.is_discarded() || parsed.is_null() || parsed.find("result") == parsed.end()) { + + QMessageBox::warning(this, tr("Failed to save wallet"), + tr("Couldn't save the wallet") + "\n" + "server=" + parent->server + "\n" + reply, + QMessageBox::Ok); + return false; + } else { + return true; + } }else{ qDebug()<<"Wrong Seed"; QFile file(dirwalletencfirst); @@ -629,9 +675,7 @@ bool NewSeedPage::validatePage() { file.remove(); file1.remove(); - QMessageBox::warning(this, tr("Wrong Seed"), - tr("Please try again") + "\n" , - QMessageBox::Ok); + QMessageBox::warning(this, tr("Wrong Seed"), tr("Please try again") + "\n" , QMessageBox::Ok); form.birthday->setVisible(true); form.txtSeed->setVisible(true); return false; @@ -686,32 +730,79 @@ bool RestoreSeedPage::validatePage() { qint64 number = number_str.toUInt(); // 3. Attempt to restore wallet with the seed phrase { - char* resp = litelib_initialize_new_from_phrase(parent->dangerous, parent->server.toStdString().c_str(), - seed.toStdString().c_str(), birthday, number); - QString reply = litelib_process_response(resp); + QString reply = ""; + try { + char* resp = litelib_initialize_new_from_phrase(parent->dangerous, parent->server.toStdString().c_str(), + seed.toStdString().c_str(), birthday, number); + reply = litelib_process_response(resp); + } catch (const std::exception& e) { + qDebug() << __func__ << ": caught an exception, ignoring: " << e.what(); + } + + qDebug() << __func__ << ": reply=" << reply; if (reply.toUpper().trimmed() != "OK") { - QMessageBox::warning(this, tr("Failed to restore wallet"), - tr("Couldn't restore the wallet") + "\n" + reply, + qDebug() << "Lite server " << parent->server << " is down, getting a random one"; + parent->server = Settings::getRandomServer(); + qDebug() << __func__ << ": new server is " << parent->server; + + // retry with the new server + char* resp = litelib_initialize_new_from_phrase(parent->dangerous, parent->server.toStdString().c_str(), + seed.toStdString().c_str(), birthday, number); + reply = litelib_process_response(resp); + } + + + if (reply.toUpper().trimmed() != "OK") { + QMessageBox::warning(this, tr("Failed to restore wallet"), + tr("Couldn't restore the wallet") + "\n" + "server=" + parent->server + "\n" + reply, QMessageBox::Ok); return false; - } + } } // 4. Finally attempt to save the wallet { - char* resp = litelib_execute("save", ""); - QString reply = litelib_process_response(resp); + QString reply = ""; + try { + char* resp = litelib_execute("save", ""); + reply = litelib_process_response(resp); + } catch (const std::exception& e) { + qDebug() << __func__ << ": caught an exception, ignoring: " << e.what(); + } + + // TODO: this is duplicated code that should be refactored + // into a dedicated function + if (reply.isEmpty()) { + qDebug() << "Lite server " << parent->server << " is down, getting a random one"; + parent->server = Settings::getRandomServer(); + qDebug() << __func__ << ": new server is " << parent->server; + + // make a new connection to the new server + char* resp = litelib_initialize_new_from_phrase(parent->dangerous, parent->server.toStdString().c_str(), + seed.toStdString().c_str(), birthday, number); + reply = litelib_process_response(resp); + + // retry with the new server + try { + resp = litelib_execute("save", ""); + reply = litelib_process_response(resp); + } catch (const std::exception& e) { + qDebug() << __func__ << ": caught an exception with new server, something is fucky: " << e.what(); + } + } + + qDebug() << __func__ << ": reply=" << reply; auto parsed = json::parse(reply.toStdString().c_str(), nullptr, false); if (parsed.is_discarded() || parsed.is_null() || parsed.find("result") == parsed.end()) { qDebug() << __func__ << ": Failed to save wallet, reply=" << reply; - QMessageBox::warning(this, tr("Failed to save wallet"), - tr("Couldn't save the wallet") + "\n" + reply, + QMessageBox::warning(this, tr("Failed to save wallet"), + tr("Couldn't save the wallet") + "\n" + "server=" + parent->server + "\n" + reply, QMessageBox::Ok); return false; } else { return true; - } + } } } diff --git a/src/firsttimewizard.h b/src/firsttimewizard.h index 994b602..b02015f 100644 --- a/src/firsttimewizard.h +++ b/src/firsttimewizard.h @@ -1,4 +1,4 @@ -// Copyright 2019-2023 The Hush developers +// Copyright 2019-2024 The Hush developers // Released under the GPLv3 #ifndef FIRSTTIMEWIZARD_H #define FIRSTTIMEWIZARD_H diff --git a/src/liteinterface.cpp b/src/liteinterface.cpp index 4d7779d..03c206d 100644 --- a/src/liteinterface.cpp +++ b/src/liteinterface.cpp @@ -1,4 +1,4 @@ -// Copyright 2019-2023 The Hush developers +// Copyright 2019-2024 The Hush developers // Released under the GPLv3 #include "liteinterface.h" diff --git a/src/liteinterface.h b/src/liteinterface.h index 2fc500a..cb3ecc6 100644 --- a/src/liteinterface.h +++ b/src/liteinterface.h @@ -1,4 +1,4 @@ -// Copyright 2019-2023 The Hush developers +// Copyright 2019-2024 The Hush developers // Released under the GPLv3 #ifndef hushDRPC_H #define hushDRPC_H diff --git a/src/logger.cpp b/src/logger.cpp index 11ffd33..ecfc7b2 100644 --- a/src/logger.cpp +++ b/src/logger.cpp @@ -1,4 +1,4 @@ -// Copyright 2019-2023 The Hush developers +// Copyright 2019-2024 The Hush developers // Released under the GPLv3 #include "logger.h" diff --git a/src/logger.h b/src/logger.h index 6fed592..dee5819 100644 --- a/src/logger.h +++ b/src/logger.h @@ -1,4 +1,4 @@ -// Copyright 2019-2023 The Hush developers +// Copyright 2019-2024 The Hush developers // Released under the GPLv3 #ifndef LOGGER_H #define LOGGER_H diff --git a/src/main.cpp b/src/main.cpp index 347ee2a..5b4ad6d 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,4 +1,4 @@ -// Copyright 2019-2023 The Hush developers +// Copyright 2019-2024 The Hush developers // Released under the GPLv3 #include @@ -6,6 +6,7 @@ #include "mainwindow.h" #include "controller.h" #include "settings.h" +#include #include "version.h" diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index 6562979..234bbca 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -1,4 +1,4 @@ -// Copyright 2019-2023 The Hush developers +// Copyright 2019-2024 The Hush developers // Released under the GPLv3 #include "mainwindow.h" #include "addressbook.h" @@ -25,7 +25,6 @@ #include "ui_startupencryption.h" #include "ui_removeencryption.h" #include "ui_seedrestore.h" -#include "websockets.h" #include "sodium.h" #include "sodium/crypto_generichash_blake2b.h" #include @@ -38,6 +37,7 @@ #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, [=]() { - - Ui_Restore restoreSeed; - QDialog dialog(this); - restoreSeed.setupUi(&dialog); - Settings::saveRestore(&dialog); + DEBUG("rescan action triggered"); + Ui_Restore restoreSeed; + QDialog dialog(this); + restoreSeed.setupUi(&dialog); + Settings::saveRestore(&dialog); rpc->fetchSeed([=](json reply) { if (isJsonError(reply)) { @@ -209,35 +209,74 @@ MainWindow::MainWindow(QWidget *parent) : config->server = Settings::getInstance()->getSettings().server; // 3. Attempt to restore wallet with the seed phrase { - char* resp = litelib_initialize_new_from_phrase(config->dangerous, config->server.toStdString().c_str(), - seed.toStdString().c_str(), birthday, number); - QString reply = litelib_process_response(resp); + QString reply = ""; + try { + char* resp = litelib_initialize_new_from_phrase(config->dangerous, config->server.toStdString().c_str(), + seed.toStdString().c_str(), birthday, number); + reply = litelib_process_response(resp); + } catch (const std::exception& e) { + qDebug() << __func__ << ": caught an exception, ignoring: " << e.what(); + } + + if (reply.toUpper().trimmed() != "OK") { + qDebug() << "Lite server " << config->server << " is down, getting a random one"; + config->server = Settings::getRandomServer(); + qDebug() << __func__ << ": new server is " << config->server; + // retry with the new server + char* resp = litelib_initialize_new_from_phrase(config->dangerous,config->server.toStdString().c_str(), + seed.toStdString().c_str(), birthday, number); + reply = litelib_process_response(resp); + } if (reply.toUpper().trimmed() != "OK") { - QMessageBox::warning(this, tr("Failed to restore wallet"), - tr("Couldn't restore the wallet") + "\n" + reply, + QMessageBox::warning(this, tr("Failed to restore wallet"), + tr("Couldn't restore the wallet") + "\n" + "server=" + config->server + "\n" + reply, QMessageBox::Ok); - - } + return false; + } } // 4. Finally attempt to save the wallet { - char* resp = litelib_execute("save", ""); - QString reply = litelib_process_response(resp); + QString reply = ""; + try { + char* resp = litelib_execute("save", ""); + QString reply = litelib_process_response(resp); + } catch (const std::exception& e) { + qDebug() << __func__ << ": caught an exception, ignoring: " << e.what(); + } + + if (reply.isEmpty()) { + qDebug() << "Lite server " << config->server << " is down, getting a random one"; + config->server = Settings::getRandomServer(); + qDebug() << __func__ << ": new server is " << config->server; + // make a new connection to the new server + char* resp = litelib_initialize_new_from_phrase(config->dangerous,config->server.toStdString().c_str(), + seed.toStdString().c_str(), birthday, number); + reply = litelib_process_response(resp); + + // retry with the new server + try { + resp = litelib_execute("save", ""); + reply = litelib_process_response(resp); + } catch (const std::exception& e) { + qDebug() << __func__ << ": caught an exception with new server, something is fucky: " << e.what(); + } + } + QByteArray ba_reply = reply.toUtf8(); QJsonDocument jd_reply = QJsonDocument::fromJson(ba_reply); QJsonObject parsed = jd_reply.object(); if (parsed.isEmpty() || parsed["result"].isNull()) { - QMessageBox::warning(this, tr("Failed to save wallet"), - tr("Couldn't save the wallet") + "\n" + reply, + QMessageBox::warning(this, tr("Failed to save wallet"), + tr("Couldn't save the wallet") + "\n" + "server=" + config->server + "\n" + reply, QMessageBox::Ok); } else { qDebug() << __func__ << ": saved wallet correctly"; - } + } dialog.close(); // To rescan, we clear the wallet state, and then reload the connection @@ -250,15 +289,14 @@ MainWindow::MainWindow(QWidget *parent) : // Then reload the connection. The ConnectionLoader deletes itself. auto cl = new ConnectionLoader(this, rpc); cl->loadConnection(); - }); + }); }); - + } }); - dialog.exec(); -}); + }); // actionReason // Import Privkey QObject::connect(ui->actionImport_Privatkey, &QAction::triggered, this, &MainWindow::importPrivKey); @@ -294,16 +332,6 @@ MainWindow::MainWindow(QWidget *parent) : restoreSavedStates(); - if (AppDataServer::getInstance()->isAppConnected()) { - qDebug() << __func__ << ": app is connected to wormhole"; - auto ads = AppDataServer::getInstance(); - - QString wormholecode = ""; - if (ads->getAllowInternetConnection()) - wormholecode = ads->getWormholeCode(ads->getSecretHex()); - - createWebsocket(wormholecode); - } } bool MainWindow::fileExists(QString path) @@ -312,36 +340,6 @@ bool MainWindow::fileExists(QString path) return (check_file.exists() && check_file.isFile()); } -void MainWindow::createWebsocket(QString wormholecode) { - qDebug() << "Listening for app connections on port 8777"; - // Create the websocket server, for listening to direct connections - wsserver = new WSServer(8777, false, this); - - if (!wormholecode.isEmpty()) { - // Connect to the wormhole service - wormhole = new WormholeClient(this, wormholecode); - } -} - -void MainWindow::stopWebsocket() { - delete wsserver; - wsserver = nullptr; - - delete wormhole; - wormhole = nullptr; - - qDebug() << "Websockets for app connections shut down"; -} - -bool MainWindow::isWebsocketListening() { - return wsserver != nullptr; -} - -void MainWindow::replaceWormholeClient(WormholeClient* newClient) { - delete wormhole; - wormhole = newClient; -} - void MainWindow::restoreSavedStates() { QSettings s; restoreGeometry(s.value("geometry").toByteArray()); @@ -933,7 +931,7 @@ void MainWindow::doImport(QList* keys) { keys->pop_front(); //bool rescan = keys->isEmpty(); - if (key.startsWith("SK") || key.startsWith("secret")) { + if (key.startsWith("secret")) { rpc->importZPrivKey(key, [=] (auto) { this->doImport(keys); }); } else if (key.startsWith("U") || key.startsWith("5") || key.startsWith("L") || key.startsWith("K")) { // 5 = uncompressed, len=51 @@ -1097,10 +1095,10 @@ void MainWindow::payhushURI(QString uri, QString myAddr) { // Save the wallet this->getRPC()->saveWallet([=] (auto) { // Then reload the connection. The ConnectionLoader deletes itself. - auto cl = new ConnectionLoader(this, rpc); + auto cl = new ConnectionLoader(this, rpc); cl->loadProgress(); - }); - }); + }); + }); }else if ((pui.rescan->isChecked() == true) && (pui.privKeyTxt->toPlainText().startsWith("secret"))){ @@ -2724,8 +2722,6 @@ MainWindow::~MainWindow() delete loadingMovie; delete logger; - delete wsserver; - delete wormhole; } void MainWindow::on_givemeZaddr_clicked() { diff --git a/src/mainwindow.h b/src/mainwindow.h index 6a2486e..31ab6e1 100644 --- a/src/mainwindow.h +++ b/src/mainwindow.h @@ -1,4 +1,4 @@ -// Copyright 2019-2023 The Hush developers +// Copyright 2019-2024 The Hush developers // Released under the GPLv3 #ifndef MAINWINDOW_H #define MAINWINDOW_H @@ -14,8 +14,6 @@ using json = nlohmann::json; // Forward declare to break circular dependency. class Controller; class Settings; -class WSServer; -class WormholeClient; class ChatModel; @@ -70,10 +68,6 @@ public: - void replaceWormholeClient(WormholeClient* newClient); - bool isWebsocketListening(); - void createWebsocket(QString wormholecode); - void stopWebsocket(); void saveContact(); void saveandsendContact(); void showRequesthush(); @@ -200,10 +194,6 @@ private: bool uiPaymentsReady = false; QString pendingURIPayment; - WSServer* wsserver = nullptr; - WormholeClient* wormhole = nullptr; - - Controller* rpc = nullptr; QCompleter* labelCompleter = nullptr; diff --git a/src/mainwindow.ui b/src/mainwindow.ui index 0a4b91d..db12534 100644 --- a/src/mainwindow.ui +++ b/src/mainwindow.ui @@ -641,6 +641,33 @@ + + + 0 + 0 + + + + Unconfirmed + + + + + + + + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + + 0 @@ -664,7 +691,7 @@ - + @@ -691,14 +718,14 @@ - + Qt::Horizontal - + @@ -735,7 +762,7 @@ - + color:red; @@ -748,7 +775,7 @@ - + @@ -767,14 +794,14 @@ - + Deposit Hush - + Qt::Vertical diff --git a/src/memoedit.cpp b/src/memoedit.cpp index adf2292..8790d8f 100644 --- a/src/memoedit.cpp +++ b/src/memoedit.cpp @@ -1,4 +1,4 @@ -// Copyright 2019-2023 The Hush developers +// Copyright 2019-2024 The Hush developers // Released under the GPLv3 #include "memoedit.h" diff --git a/src/memoedit.h b/src/memoedit.h index 9d4e310..b099b1d 100644 --- a/src/memoedit.h +++ b/src/memoedit.h @@ -1,4 +1,4 @@ -// Copyright 2019-2023 The Hush developers +// Copyright 2019-2024 The Hush developers // Released under the GPLv3 #ifndef MEMOEDIT_H #define MEMOEDIT_H diff --git a/src/mobileappconnector.cpp b/src/mobileappconnector.cpp deleted file mode 100644 index 98501db..0000000 --- a/src/mobileappconnector.cpp +++ /dev/null @@ -1,16 +0,0 @@ -// Copyright 2019-2023 The Hush developers -// Released under the GPLv3 -#include "mobileappconnector.h" -#include "ui_mobileappconnector.h" - -MobileAppConnector::MobileAppConnector(QWidget *parent) : - QDialog(parent), - ui(new Ui::MobileAppConnector) -{ - ui->setupUi(this); -} - -MobileAppConnector::~MobileAppConnector() -{ - delete ui; -} diff --git a/src/mobileappconnector.h b/src/mobileappconnector.h deleted file mode 100644 index 868a80f..0000000 --- a/src/mobileappconnector.h +++ /dev/null @@ -1,24 +0,0 @@ -// 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 deleted file mode 100644 index 823a497..0000000 --- a/src/mobileappconnector.ui +++ /dev/null @@ -1,214 +0,0 @@ - - - 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 25fa01f..1eba304 100644 --- a/src/precompiled.h +++ b/src/precompiled.h @@ -1,4 +1,4 @@ -// Copyright 2019-2023 The Hush developers +// Copyright 2019-2024 The Hush developers // Released under the GPLv3 #if defined __cplusplus /* Add C++ includes here */ @@ -64,7 +64,6 @@ #include #include #include -#include #include #include #include diff --git a/src/qrcodelabel.cpp b/src/qrcodelabel.cpp index 6b2778c..5813809 100644 --- a/src/qrcodelabel.cpp +++ b/src/qrcodelabel.cpp @@ -1,4 +1,4 @@ -// Copyright 2019-2023 The Hush developers +// Copyright 2019-2024 The Hush developers // Released under the GPLv3 #include "qrcodelabel.h" diff --git a/src/qrcodelabel.h b/src/qrcodelabel.h index 313ec65..51a40dd 100644 --- a/src/qrcodelabel.h +++ b/src/qrcodelabel.h @@ -1,4 +1,4 @@ -// Copyright 2019-2023 The Hush developers +// Copyright 2019-2024 The Hush developers // Released under the GPLv3 #ifndef QRCODELABEL_H #define QRCODELABEL_H diff --git a/src/recurring.cpp b/src/recurring.cpp index 2e94744..88dcfe7 100644 --- a/src/recurring.cpp +++ b/src/recurring.cpp @@ -1,4 +1,4 @@ -// Copyright 2019-2023 The Hush developers +// Copyright 2019-2024 The Hush developers // Released under the GPLv3 #include "recurring.h" diff --git a/src/recurring.h b/src/recurring.h index 2f27f45..94e2019 100644 --- a/src/recurring.h +++ b/src/recurring.h @@ -1,4 +1,4 @@ -// Copyright 2019-2023 The Hush developers +// Copyright 2019-2024 The Hush developers // Released under the GPLv3 #ifndef RECURRING_H #define RECURRING_H diff --git a/src/requestdialog.cpp b/src/requestdialog.cpp index bb4c214..749eb85 100644 --- a/src/requestdialog.cpp +++ b/src/requestdialog.cpp @@ -1,4 +1,4 @@ -// Copyright 2019-2023 The Hush developers +// Copyright 2019-2024 The Hush developers // Released under the GPLv3 #include "requestdialog.h" #include "ui_requestdialog.h" diff --git a/src/requestdialog.h b/src/requestdialog.h index 8dbeaca..657026a 100644 --- a/src/requestdialog.h +++ b/src/requestdialog.h @@ -1,4 +1,4 @@ -// Copyright 2019-2023 The Hush developers +// Copyright 2019-2024 The Hush developers // Released under the GPLv3 #ifndef REQUESTDIALOG_H #define REQUESTDIALOG_H diff --git a/src/scripts/docker/Dockerfile b/src/scripts/docker/Dockerfile index 361d2fe..6391c24 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 qtwebsockets + make -j$(nproc) MXE_TARGETS=x86_64-w64-mingw32.static qtbase # Add rust RUN apt install -y gcc-aarch64-linux-gnu diff --git a/src/sdl.h b/src/sdl.h new file mode 100644 index 0000000..68b24b3 --- /dev/null +++ b/src/sdl.h @@ -0,0 +1 @@ +#define DEBUG(x) (qDebug() << QString(__func__) << ": " << x) diff --git a/src/sendtab.cpp b/src/sendtab.cpp index 61e8ad9..38bd5e1 100644 --- a/src/sendtab.cpp +++ b/src/sendtab.cpp @@ -1,4 +1,4 @@ -// Copyright 2019-2023 The Hush developers +// Copyright 2019-2024 The Hush developers // Released under the GPLv3 #include "mainwindow.h" #include "ui_mainwindow.h" diff --git a/src/settings.cpp b/src/settings.cpp index d6243b6..3389412 100644 --- a/src/settings.cpp +++ b/src/settings.cpp @@ -1,9 +1,10 @@ -// Copyright 2019-2023 The Hush developers +// Copyright 2019-2024 The Hush developers // Released under the GPLv3 #include "mainwindow.h" #include "settings.h" #include "camount.h" #include "../lib/silentdragonlitelib.h" +#include Settings* Settings::instance = nullptr; @@ -36,9 +37,14 @@ Config Settings::getSettings() { if (server.trimmed().isEmpty()) { server = Settings::getRandomServer(); + QString response = ""; // make sure existing server in conf is alive, otherwise choose random one - char* resp = litelib_initialize_existing(false, server.toStdString().c_str()); - QString response = litelib_process_response(resp); + try { + char* resp = litelib_initialize_existing(false, server.toStdString().c_str()); + response = litelib_process_response(resp); + } catch (const std::exception& e) { + qDebug() << __func__ << ": caught an exception, ignoring: " << e.what(); + } if (response.toUpper().trimmed() != "OK") { qDebug() << "Lite server in conf " << server << " is down, getting a random one"; @@ -310,14 +316,14 @@ QString Settings::getRandomServer() { // We try every server,in order, starting from a random place in the list while (tries < servers.size() ) { qDebug() << "Checking if lite server " << server << " is a alive, try=" << tries; - char* resp = litelib_initialize_existing(false, server.toStdString().c_str()); QString response = ""; try { + char* resp = litelib_initialize_existing(false, server.toStdString().c_str()); response = litelib_process_response(resp); } catch (const std::exception& e) { - qDebug() << __func__ << ": litelib_process_response threw an exception, ignoring: " << e.what(); + qDebug() << __func__ << ": caught an exception, ignoring: " << e.what(); } // if we see a valid connection, return this server diff --git a/src/settings.h b/src/settings.h index f65e4cd..376131b 100644 --- a/src/settings.h +++ b/src/settings.h @@ -1,4 +1,4 @@ -// Copyright 2019-2023 The Hush developers +// Copyright 2019-2024 The Hush developers // Released under the GPLv3 #ifndef SETTINGS_H #define SETTINGS_H diff --git a/src/txtablemodel.cpp b/src/txtablemodel.cpp index 633145c..04ea0dd 100644 --- a/src/txtablemodel.cpp +++ b/src/txtablemodel.cpp @@ -1,4 +1,4 @@ -// Copyright 2019-2023 The Hush developers +// Copyright 2019-2024 The Hush developers // Released under the GPLv3 #include "txtablemodel.h" #include "settings.h" diff --git a/src/txtablemodel.h b/src/txtablemodel.h index 0479518..a0a147b 100644 --- a/src/txtablemodel.h +++ b/src/txtablemodel.h @@ -1,4 +1,4 @@ -// Copyright 2019-2023 The Hush developers +// Copyright 2019-2024 The Hush developers // Released under the GPLv3 #ifndef STRINGSTABLEMODEL_H #define STRINGSTABLEMODEL_H diff --git a/src/version.h b/src/version.h index 514ba63..0f14577 100644 --- a/src/version.h +++ b/src/version.h @@ -1,3 +1,3 @@ -// Copyright 2019-2023 The Hush developers +// Copyright 2019-2024 The Hush developers // Released under the GPLv3 -#define APP_VERSION "1.5.3" +#define APP_VERSION "1.5.4" diff --git a/src/viewalladdresses.cpp b/src/viewalladdresses.cpp index d3fbe22..6eb6d3c 100644 --- a/src/viewalladdresses.cpp +++ b/src/viewalladdresses.cpp @@ -1,4 +1,4 @@ -// Copyright 2019-2023 The Hush developers +// Copyright 2019-2024 The Hush developers // Released under the GPLv3 #include "viewalladdresses.h" #include "camount.h" diff --git a/src/viewalladdresses.h b/src/viewalladdresses.h index cafc47e..0963e3f 100644 --- a/src/viewalladdresses.h +++ b/src/viewalladdresses.h @@ -1,4 +1,4 @@ -// Copyright 2019-2023 The Hush developers +// Copyright 2019-2024 The Hush developers // Released under the GPLv3 #ifndef VIEWALLADDRESSES_H #define VIEWALLADDRESSES_H diff --git a/src/websockets.cpp b/src/websockets.cpp deleted file mode 100644 index e09d1b0..0000000 --- a/src/websockets.cpp +++ /dev/null @@ -1,940 +0,0 @@ -// Copyright 2019-2023 The Hush developers -// Released under the GPLv3 -#include "websockets.h" -#include "controller.h" -#include "settings.h" -#include "ui_mobileappconnector.h" -#include "version.h" - -// Weap the sendTextMessage to check if the connection is valid and that the parent WebServer didn't close this connection -// for some reason. -void ClientWebSocket::sendTextMessage(QString m) { - if (client) { - if (server && !server->isValidConnection(client)) { - return; - } - - if (client->isValid()) - client->sendTextMessage(m); - } -} - -WSServer::WSServer(quint16 port, bool debug, QObject *parent) : - QObject(parent), - m_pWebSocketServer(new QWebSocketServer(QStringLiteral("Direct Connection Server"), - QWebSocketServer::NonSecureMode, this)), - m_debug(debug) -{ - m_mainWindow = (MainWindow *) parent; - if (m_pWebSocketServer->listen(QHostAddress::AnyIPv4, port)) { - if (m_debug) - qDebug() << "Echoserver listening on port" << port; - connect(m_pWebSocketServer, &QWebSocketServer::newConnection, - this, &WSServer::onNewConnection); - connect(m_pWebSocketServer, &QWebSocketServer::closed, this, &WSServer::closed); - } -} - -WSServer::~WSServer() -{ - qDebug() << "Closing websocket server"; - m_pWebSocketServer->close(); - qDeleteAll(m_clients.begin(), m_clients.end()); - qDebug() << "Deleted all websocket clients"; -} - -void WSServer::onNewConnection() -{ - qDebug() << "Websocket server: new connection"; - QWebSocket *pSocket = m_pWebSocketServer->nextPendingConnection(); - - connect(pSocket, &QWebSocket::textMessageReceived, this, &WSServer::processTextMessage); - connect(pSocket, &QWebSocket::binaryMessageReceived, this, &WSServer::processBinaryMessage); - connect(pSocket, &QWebSocket::disconnected, this, &WSServer::socketDisconnected); - - m_clients << pSocket; -} - -void WSServer::processTextMessage(QString message) -{ - QWebSocket *pClient = qobject_cast(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 deleted file mode 100644 index 65e9311..0000000 --- a/src/websockets.h +++ /dev/null @@ -1,179 +0,0 @@ -// Copyright 2019-2023 The Hush developers -// Released under the GPLv3 -#ifndef WEBSOCKETS_H -#define WEBSOCKETS_H - -#include "precompiled.h" -#include "camount.h" -#include "mainwindow.h" -#include "ui_mobileappconnector.h" - -QT_FORWARD_DECLARE_CLASS(QWebSocketServer) -QT_FORWARD_DECLARE_CLASS(QWebSocket) - -class WSServer; - -// We're going to wrap the websocket in this class, because the underlying QWebSocket might get closed -// or deleted while a callback is waiting to get the data back. Therefore, we write a custom "sendTextMessage" -// class that checks all this before sending. -class ClientWebSocket { -public: - ClientWebSocket(QWebSocket* c, WSServer* s = nullptr) { client = c; server = s; } - - void sendTextMessage(QString m); - void close(QWebSocketProtocol::CloseCode code, const QString& msg) { client->close(code, msg); } -private: - QWebSocket* client; - WSServer* server; -}; - -class WSServer : public QObject -{ - Q_OBJECT -public: - explicit WSServer(quint16 port, bool debug = false, QObject *parent = nullptr); - bool isValidConnection(QWebSocket* c) { return m_clients.contains(c); } - ~WSServer(); - -Q_SIGNALS: - void closed(); - -private Q_SLOTS: - void onNewConnection(); - void processTextMessage(QString message); - void processBinaryMessage(QByteArray message); - void socketDisconnected(); - -private: - QWebSocketServer *m_pWebSocketServer; - MainWindow *m_mainWindow; - QList 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 d659ab5..24b5b3d 100644 --- a/util/SilentDragonLite.desktop +++ b/util/SilentDragonLite.desktop @@ -1,7 +1,7 @@ [Desktop Entry] Version=1.0 Name=SilentDragonLite -Comment=Full-node wallet for HUSH cryptocurrency +Comment=Lite 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 a24680e..7fed756 100755 --- a/util/add-linux-icons.sh +++ b/util/add-linux-icons.sh @@ -1,5 +1,5 @@ #!/bin/bash -# Copyright 2019-2023 The Hush Developers +# Copyright 2019-2024 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 da3e59c..8107b10 100755 --- a/util/install.sh +++ b/util/install.sh @@ -1,12 +1,10 @@ #!/bin/bash -# Copyright 2019-2023 The Hush Developers +# Copyright 2019-2024 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 51ab56d..ef99cb8 100755 --- a/util/replace.pl +++ b/util/replace.pl @@ -1,5 +1,5 @@ #!/usr/bin/perl -# Copyright (c) 2016-2023 The Hush developers +# Copyright (c) 2016-2024 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 293602f..2ff3e64 100755 --- a/util/update-copyrights.sh +++ b/util/update-copyrights.sh @@ -1,10 +1,22 @@ #!/usr/bin/env bash -# Copyright (c) 2016-2023 The Hush developers + +# Copyright (c) 2016-2024 The Hush developers # Released under the GPLv3 -# Usage: update-copyrights.sh 2021 2022 +# Usage: update-copyrights.sh 2024 2025 # TODO: verify $1 and $2 exist -# TODO: verify ack and xargs exist on this system + +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 # 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 3c10329..db587a3 100755 --- a/win-static-build.sh +++ b/win-static-build.sh @@ -1,5 +1,5 @@ #!/bin/bash -# Copyright 2019-2023 The Hush Developers +# Copyright 2019-2024 The Hush Developers VERSION=$(cat src/version.h |cut -d\" -f2) echo "Compiling SilentDragonLite $VERSION .exe with $JOBS threads..."