Compare commits

...

398 Commits

Author SHA1 Message Date
onryo 00fe0ea59d Merge pull request 'Merge dev into main' (#149) from dev into master 4 days ago
onryo 32ba8b8f9b Add release notes for v2.0.2 4 days ago
onryo ddad184bb9 cargo vendor 4 days ago
onryo e1ef74c83c Point to the commit with the latest sdl-cli 4 days ago
onryo 70237c2d84 rm backend server 5 days ago
onryo d2ceecaffa rm backend server 5 days ago
onryo c2d7161ea2 Merge branch 'dev' 2 months ago
onryo b917e39071 Update version file 2 months ago
onryo 35482c2ab1 cargo vendor 2 months ago
onryo 0c142c7b23 Point to the commit with the latest sdl-cli 2 months ago
onryo a5d7beb19b Update notes for v2.0.1 2 months ago
duke c73ac543f4 Merge pull request 'Move connection errror to status Bar' (#148) from lucretius/SilentDragonLite:dev into dev 2 months ago
lucretius e94df062a8 add Qt::CaseInsensitive for compression error 2 months ago
lucretius 068a3935e2 move connection error to status bar only if there is a compression flag error 2 months ago
lucretius 26182290f5 move connection error to status bar, lib update 2 months ago
Duke bd272dacb7 Merge branch 'dev' of https://git.hush.is/hush/SilentDragonLite into dev 2 months ago
Duke a32146470b Do not log seed to STDOUT 2 months ago
lucretius da09dc0ae2 Merge pull request 'hush/dev pull' (#11) from hush/SilentDragonLite:dev into dev 2 months ago
onryo b8dc50f903 Beta version 2 months ago
onryo 2ababaef70 cargo vendor 2 months ago
onryo 5a338c7b55 Point to the commit with the latest sdl-cli 2 months ago
onryo 002fba353e beta release 2 months ago
onryo 16e194d644 Preparation for 2.0.1 2 months ago
Duke 0c10cf1243 Also prevent logging of passphrase length in first time wizard 2 months ago
Duke 775135cc44 Do not log passphrase length to STDOUT 2 months ago
duke e299fe33e9 Merge pull request 'Add custom Fee, fix a problem with isOnline in getsettings, note Automation only for chat related tx' (#146) from lucretius/SilentDragonLite:dev into dev 2 months ago
lucretius 49d587cd42 Add custom fee to gui 2 months ago
lucretius 4f0229a823 fix for isOnline in getSettings() 2 months ago
lucretius 683718008c use note automation only for chat related txs 2 months ago
lucretius 58f59661af Merge pull request 'pull hush/dev' (#10) from hush/SilentDragonLite:dev into dev 2 months ago
Duke 4b95013d15 Fix typo 2 months ago
duke 4d2a32b6b2 Merge pull request 'Update lib with WalletTx version changes, Sticky Server and Note Automation as GUI setting, fix for getRandomServer' (#145) from lucretius/SilentDragonLite:dev into dev 2 months ago
lucretius 8da49166a8 delete not needed commentar 2 months ago
lucretius d0b8ab074e add new method for litelib to check if server is online 2 months ago
lucretius 366f6e24bc fix for getRandomServer() 2 months ago
lucretius 95090a90ad add missing semicolon 2 months ago
lucretius 24d262dcb9 deactivate debug for StickyServer 2 months ago
lucretius 6f7fd863f0 Sticky Server and Note Automation as GUI setting 2 months ago
lucretius 8348e61e2e Merge pull request 'hush/dev pull' (#9) from hush/SilentDragonLite:dev into dev 2 months ago
Duke 68d9388c1b Check for valid QT versions or bail early 2 months ago
Duke 3b79e5fcd0 Fix the URL for checking releases 2 months ago
duke e7a974ec47 Merge pull request 'Restore backward compatibility with qt 5.12.0 issue: #141 , check libsodium sha256 checksum issue: #140' (#142) from lucretius/SilentDragonLite:dev into dev 2 months ago
lucretius 156b1a6def check libsodium sha256 checksum 2 months ago
lucretius 063303413c Restore backward compatibility with qt 5.12.0 2 months ago
lucretius d8b88dcb3b Merge pull request 'hush/dev pull' (#7) from hush/SilentDragonLite:dev into dev 2 months ago
Duke 5199f9487c Merge remote-tracking branch 'lucretius/dev' into dev 2 months ago
duke 370058fa95 Merge pull request 'updated build.sh for better OS compatibility' (#138) from jahway603 into dev 2 months ago
jahway603 1fb344a8c2 updated build.sh for better OS compatibility 2 months ago
lucretius 1a5ab786bc update lib with proto changes 2 months ago
Duke 2fcb4f8358 Use 8 jobs by default for compiling libsodium on mac 2 months ago
Duke 6bbd2ac358 Fix bug in using more cores to compile in build.sh 2 months ago
Duke 45e5091208 Bump version 2 months ago
Duke f15a28f3ec Fix bug in reporting version being compiled in build.sh 2 months ago
Duke fd5eec230e Allow custom number of cores to compile via build.sh #137 2 months ago
Deniod 618625bc00 seperate dust and normal transaction 3 months ago
Deniod 130e0560d5 delete junk 3 months ago
Deniod 0d6b84ec8a fix conversion from CAmount to double 3 months ago
Duke df67f779f7 Do not log blake3 hash to stdout, fixes #136 3 months ago
Duke 0f8f028d7d Fix indentation, no functional changes 3 months ago
Deniod 261b3ad643 fix typo 3 months ago
Deniod c6e8268450 check for funds before spread notes 3 months ago
Deniod c802a55bac replace sietch transactions with the new note automatic if spendable notes < 30 3 months ago
Deniod fb1626d11d less DEBUG flood, add an automation that triggers when there are less than 7 free spendable notes and increases their number by executing a transaction with the amount = fee by replacing a sietch transaction. 3 months ago
Deniod 84196cda87 create Datastore for countedNotes over 10000 puposhis, debug for notes in send 3 months ago
Deniod 2b46484f90 fix merge conflicts 3 months ago
Deniod 9276519c7b change lib commit 3 months ago
Deniod 98c21693e9 change lib commit 3 months ago
onryo 4e074b20fd change version to 2.0.0 3 months ago
onryo 391af1c75a change version to 2.0.0 3 months ago
onryo 16b6d43786 Revert the merge revert 3 months ago
onryo 3c2414028b Revert "Merge branch 'dev'" 3 months ago
onryo 4a7dd7f959 Merge branch 'dev' 3 months ago
onryo 07c16a6009 cargo vendor 3 months ago
onryo c01e7ac728 Preparing for the release 3 months ago
onryo 6dca2fafa5 Add notes for the next release 3 months ago
Duke cb0de2c3f6 We do not support sprout privkeys that have prefix SK 3 months ago
Deniod 1f31adc30c add more debug, use singleshot instead of loop 4 months ago
Deniod 7863d6ffb2 more debug, free mem, lib update 4 months ago
jahway603 5df4d75a43 Revert "Ubuntu 18.04 is now EOL, so removing from README" 4 months ago
lucretius 7dd665131e Merge pull request 'Merge upstream branch dev' (#1) from hush/SilentDragonLite:dev into dev 4 months ago
jahway603 6183c244e5 Merge pull request 'Ubuntu 18.04 is now EOL, so removing from README' (#131) from jahway603/SilentDragonLite:jah-doc into dev 4 months ago
jahway603 5114b76be2 Ubuntu 18.04 is now EOL, so removing from README 4 months ago
Duke 973ec2e823 Remove res/libsodium.a from git 4 months ago
duke eb7a083d41 Merge pull request 'mempool integration' (#126) from lucretius/SilentDragonLite:mempool-new into dev 4 months ago
Deniod 3962b42e30 mempool integration 4 months ago
duke aadb7e7c9e Merge pull request 'Add build instruction for Ubuntu 22.04' (#125) from onryo-build1 into dev 5 months ago
onryo 9a7e87fa1d Add build instruction for Ubuntu 22.04 5 months ago
onryo 2519acdd7a Merge pull request 'Add files to create deb package' (#123) from onryo/SilentDragonLite:dev into dev 10 months ago
onryo aa58e3a4ce Initial docs 10 months ago
onryo 50964ce8b7 Update 'contrib/debian/control' 10 months ago
onryo 2e23886d86 add compat 10 months ago
onryo d8ff0de15d add copyright 10 months ago
onryo b8c18aa38b add rules 10 months ago
onryo 1f31c40172 add changelog 10 months ago
onryo eca9c53ff7 add control file 10 months ago
Duke 828a912d85 Do not change servers when retrying sync RPC 1 year ago
Duke bfdda1f1af Try really hard to make sync RPC finish 1 year ago
Duke 5b33cb3638 Much DEBUG such wow 1 year ago
Duke a3987fca13 Add note for improvement 1 year ago
Duke d05d8271ec Add SDL dev docs 1 year ago
Duke 69cf815ed2 litelib_initialize_new returns a seed when it succeeds, not OK 1 year ago
Duke f46e1b4a57 Potentially fix #120 1 year ago
Duke 77ac1f99ae Try to fix #119 1 year ago
Duke 7364e21f99 Check for a non-empty response from litelib_execute 1 year ago
Duke 51fe4d6cde Look for non-empty responses instead of the string "OK" 1 year ago
Duke a080d0ca80 Update current server on info tab since it can change at run-time 1 year ago
Duke b84828604f Catch exceptions when parsing invalid json 1 year ago
Duke 7e54360b72 Try another server if we get an error when executing an RPC, possibly fixes #119 1 year ago
Duke 4116de6a69 Merge branch 'dev' of https://git.hush.is/hush/SilentDragonLite into dev 1 year ago
Duke 9befa3450f Try another server if current is down when saving wallet via a rescan 1 year ago
fekt 5508050fcc Update 'res/css/Dark.css' 1 year ago
Duke c7e0f0fae6 Initialize a new server connection from seedphrase when restoring from seed 1 year ago
Duke ad5b294d95 Make sure to init from phrase when trying a new server during restore in first time wizard 1 year ago
Duke 89bf5b0f7c Make sure to init from phrase when trying a new server during restore 1 year ago
Duke 51483843ac Report down server in errors of first time wizard 1 year ago
Duke 17fcb84a89 Report server in error when saving wallet as part of rescan 1 year ago
Duke f22f97463b derp 1 year ago
Duke f7787fe9e9 Try another server if current is down when restoring during a rescan; report down server in error 1 year ago
Duke 0b72d01f4a Add DEBUG macro for less typing 1 year ago
Duke 557e10e5e8 Try another server if current is down when restoring a wallet from seed or saving a wallet 1 year ago
Duke 3f8ae1f9d7 Try another server if current is down when creating new seed 1 year ago
Duke 3b6da338c9 Delete mobile app connector 1 year ago
Duke 430a7ab474 Delete websuckets 1 year ago
Duke 5d5447aced Improve error handling when restoring from seedphrase 1 year ago
Duke 1e6e77055b Catch exceptions from litelib_initialize_existing 1 year ago
Duke 6165733e03 Ignore exceptions in litelib_initialize_existing() in a few places 1 year ago
duke 6590a49bb5 Update 'doc/release-process.md' 1 year ago
onryo a89a0cc1c6 Merge branch 'dev' 1 year ago
onryo 335eeedbee Release name for 1.5.3 1 year ago
onryo 2f328b005c rm test theme 1 year ago
onryo 613df81407 Add Q_OBJECT macros and fix Cannot invoke tr 1 year ago
onryo 5a389cf1cf Revert "Add Q_OBJECT macros" 1 year ago
onryo 4ec06fffc3 Revert "Update 'src/controller.h'" 1 year ago
onryo 69a2058bc4 Update 'src/controller.h' 1 year ago
onryo c50588713a Add Q_OBJECT macros 1 year ago
onryo 7dbe92e848 Update image 1 year ago
onryo a10d4a88f6 Upload files to 'res/images' 1 year ago
onryo 04ae4641f4 Update image 1 year ago
onryo fbab03a768 Upload files to 'res/images' 1 year ago
onryo 052a7286f7 build.sh linguist 1 year ago
onryo ea707b7b54 update pl+ru+be 1 year ago
fekt 89f503ffda Setting fixed size for QR on deposit popup 1 year ago
fekt 4969275156 UI/color tweaks from SD 1 year ago
fekt 7dfce16b5f Theme changes from SD 1 year ago
fekt ae130c4dd5 Icon assets from SD 1 year ago
onryo c0deb766eb Update Dutch language 1 year ago
fekt 6c2d6d876d Remove Apps menu option and ctrl+m shortcut 1 year ago
onryo 937f2d575d Update translations 1 year ago
onryo 41713e1954 Revert "Update Dutch language" 1 year ago
onryo 79bbcc975f Update Dutch language 1 year ago
onryo b74d2952f5 update copyrights 1 year ago
onryo 5bfbe3b3fa cp replace.pl and update-copyrights.sh from hush3 1 year ago
fekt d5daed4cd8 Update logobig.gif 1 year ago
fekt 5c6a38fbec Update image for QR logo 1 year ago
fekt 85ee7b9378 Fix QR logo path 1 year ago
fekt 370cb7623b QR code changes 1 year ago
fekt 6a8c9a0adf Merge branch 'dev' of https://git.hush.is/hush/SilentDragonLite into dev 1 year ago
fekt 2e11d6164b wind0ze cross-compile tweaks 1 year ago
fekt 679b90734a Added Mac wallet location 1 year ago
fekt 5f483c2659 Build script for wind0ze 1 year ago
jahway603 a113b3a3df Update 'README.md' 1 year ago
onryo 1f2c7defb7 Fit in 1 year ago
onryo 29efa85177 Update 'doc/relnotes.md' 1 year ago
onryo 73694a0a27 More avatars and some notes 1 year ago
onryo 6c9f947455 add a new avatar 1 year ago
onryo 255901e4eb add a new avatar and remove very old ones 1 year ago
onryo db3957040c Update 'doc/relnotes.md' 1 year ago
onryo 19e12ba5a6 Update Belarusian language 1 year ago
onryo fc3c445f21 Update Russian language 1 year ago
onryo 78806743b6 Update Polish language 1 year ago
onryo 3613ddea06 Update 'doc/release-process.md' 1 year ago
onryo 670bc59826 Update silentdragonlite-cli for new checkpoints 1 year ago
onryo b0d6aa3285 Less Microsoft 1 year ago
onryo 5ab5cf8e43 rm no longer in use lite server 1 year ago
onryo db66200363 rm no longer in use lite server 1 year ago
onryo 3b2a3b0716 Update 'doc/relnotes.md' 1 year ago
onryo 1f54ceba2d Update 'doc/relnotes.md' 1 year ago
onryo 26980ade87 Update 'doc/relnotes.md' 1 year ago
onryo 2f16e966b9 Update 'doc/relnotes.md' 1 year ago
onryo 99782f3002 Update 'doc/relnotes.md' 1 year ago
onryo c0fe5d281c add two more lite servers 1 year ago
onryo b5051bfd3d the prodigal son has returned 1 year ago
jahway603 4674e367b6 Update 'doc/relnotes.md' 1 year ago
onryo 5c144fa9c7 add two more lite servers 1 year ago
onryo 68ef85b4ed Update 'doc/relnotes.md' 1 year ago
onryo 08d9a92820 add two more lite servers 1 year ago
onryo dd128294dd New screenshot 1 year ago
onryo 69ea9ace50 New screenshot 1 year ago
Duke a8fc12e0e2 Change lite server after sending a tx for improved privacy 1 year ago
Duke 6cab5f68f9 remove sprout code 1 year ago
Duke 9d4cbd64b8 unfuck the server list 1 year ago
Duke 1a7af9682c update lightwalletd server list 1 year ago
duke 44d6de806a Update 'issue_template.md' 1 year ago
jahway603 5427d400e4 added wtfistheinternet SDL server and removed crabdance (RIP) 1 year ago
Duke 25fab30e1d Document where headerbytes and publickey come from 1 year ago
Duke 31cdbc5f9e More details about header memo fields 1 year ago
Duke fc3f4ce99b Add datatypes to createHeaderMemo comments 1 year ago
Duke 15ec7e3bf5 Improve createHeaderMemo comments 1 year ago
Duke Leto fcdbfe2c34 update silentdragonlite-cli for new checkpoints 1 year ago
Duke Leto fe15384c10 Merge pull request 'Replace a duplicate string & Update old animation' (#94) from onryo into dev 1 year ago
onryo 778158ec88 Replace a duplicate string 1 year ago
onryo 5b008a8d65 Update old animation 1 year ago
fekt 7649418a7b Update firsttimewizard.cpp 1 year ago
fekt ff8692fa39 Wizard UX fixes 1 year ago
fekt 7454854bf6 Merge branch 'dev' of https://git.hush.is/hush/SilentDragonLite into dev 1 year ago
fekt 1f7b8186f0 Properly close app on welcome back cancel 1 year ago
Duke Leto ce998601db Update 'doc/release-process.md' 1 year ago
fekt bf4b9e53ca Revert "Close app on welcome back cancel" 1 year ago
fekt 7398c70e2b Close app on welcome back cancel 1 year ago
Duke Leto 72eba34791 Update 'doc/release-process.md' 1 year ago
Duke Leto 44d407d4b0 Update 'doc/release-process.md' 1 year ago
Duke Leto a4e1b51c79 Update 'doc/release-process.md' 1 year ago
Jonathan "Duke" Leto 14c354a864 tweak issue template 1 year ago
Jonathan "Duke" Leto 6709ff2297 See if gitea recognizes this issue template 1 year ago
Jonathan "Duke" Leto 9079499265 See if gitea recognizes this issue template 1 year ago
Jonathan "Duke" Leto c460cfad41 Mention checkpoints in our release doc 1 year ago
Jonathan "Duke" Leto 757d303802 Add release doc 1 year ago
fekt 4efcbc630e Removing donation stuff 1 year ago
fekt 364c775d6d Removing taddr on receive tab 1 year ago
fekt e179e723f5 Fix no connection status on sync 1 year ago
Duke Leto a9ad534241 update translations and add PL 2 years ago
Duke Leto 463a4ea6ce Merge pull request 'Polish translation & typos' (#85) from onryo/SilentDragonLite:dev into dev 2 years ago
onryo f0145c7b1b typo 2 years ago
onryo a603c38742 some typos 2 years ago
onryo f0200e26bc Update 'res/silentdragonlite_pl.ts' 2 years ago
onryo a1bb19da8d Polish language 2 years ago
onryo b22a79cff9 Update 'silentdragon-lite.pro' 2 years ago
onryo 980b650827 Update 'application.qrc' 2 years ago
Duke Leto 4803686bdc Merge pull request 'added poop to release notes' (#84) from jahway603/SilentDragonLite:dev into dev 2 years ago
jahway603 6b36f013b1 added poop 2 years ago
Duke Leto 4bab1aa9b7 Add relnotes to repo 2 years ago
Duke Leto e420c93aa6 Correctly update silentdragonlite-cli dependency 2 years ago
Duke Leto af333d8e07 Update silentdragonlite-cli to latest commit on master 2 years ago
Duke Leto aabb8c5f29 Add some spanish translations 2 years ago
Duke Leto 825e50b2ea Show qt version in About screen 2 years ago
Duke Leto 9e8e95200c Strip leading/trailing whitespace from wallet birthdays 2 years ago
Duke Leto 4aeab433a4 This text about mining only serves to confuse users 2 years ago
Duke Leto 42b5d182ee Create new rpc connection during shutdown if we don't have one and debug logging 2 years ago
Duke Leto fd2fb3757a Try to avoid coredumping if zrpc object doesn't exist, which can happen if backend server is misbehaving 2 years ago
Duke Leto d5cef76eb4 update translations 2 years ago
Duke Leto 82751b7b57 update text for new and restoring seeds 2 years ago
Duke Leto 3695e68190 update copyright 2 years ago
Duke Leto 9579702f0f bump version to 1.5.3 2 years ago
Duke Leto fbb9ea7670 Update Cargo.lock 2 years ago
Duke Leto bfab526aba Merge branch 'dev' of https://git.hush.is/hush/SilentDragonLite into dev 2 years ago
Duke Leto ccbf1515f8 update to latest silentdragonlite-cli master commit which has new checkpoints 2 years ago
Duke Leto 890b95665b Merge pull request 'fixed port of poop SDL server' (#75) from jahway603/SilentDragonLite:dev into dev 2 years ago
jahway603 8a5c8e4898 fixed port of poop SDL server 2 years ago
jahway603 2d3ef67a82 Merge remote-tracking branch 'remotes/upstream/dev' into dev 2 years ago
Duke Leto 5a1dd4114f Add docs for adding a new SDL server to the code 2 years ago
Duke Leto 6c5ffca056 Add lite.hushpool.is to random server algorithm 2 years ago
Duke Leto 60815a95b0 Merge branch 'master' into dev 2 years ago
Duke Leto 06702a65bb Merge pull request 'Update mainwindow.cpp' (#73) from fekt/SilentDragonLite:master into master 2 years ago
fekt 6b04faefdd Update mainwindow.cpp 2 years ago
Duke Leto 5825b30e71 Merge pull request '"Create a new wallet" button is already marked as complete, but the next button is not' (#72) from onryo/SilentDragonLite:dev into dev 2 years ago
onryo 532b308a2f Update 'src/firsttimewizard.cpp' 2 years ago
onryo 5d7856b4cf adding install.sh 2 years ago
onryo 9c1c46f317 Upload files to 'util' 2 years ago
onryo 448a080053 Delete 'util/install.sh' 2 years ago
onryo 50b205cc61 Upload files to 'util' 2 years ago
onryo c283cc7513 Upload files to 'util' 2 years ago
onryo 91f64b235e copying files from dev to master 2 years ago
onryo d8eb008b7c Update 'util/install.sh' 2 years ago
Duke Leto 8acb4a5db1 update copyright year 2 years ago
Duke Leto a7b9c89d97 Fix some issues related to #65 2 years ago
onryo 045696520b Update 'util/install.sh' 2 years ago
onryo c862bc3ceb Update 'util/install.sh' 2 years ago
onryo ed11d0b56e Delete 'peda-session-SilentDragonLite.txt' 2 years ago
onryo 5eb4b2af24 already in util dev 2 years ago
onryo dbd352d18a already in util 2 years ago
onryo 2259c365eb already in util 2 years ago
Duke Leto 52dad167d7 more debug 2 years ago
Duke Leto 60e4443501 Merge branch 'dev' of https://git.hush.is/hush/SilentDragonLite into dev 2 years ago
Duke Leto cbc77e9d58 more error checking, logging and fix some compiler warnings 2 years ago
Duke Leto 3f9fc49207 removed unused migration ui, since we never had sprout zaddrs 2 years ago
Duke Leto 5f8babd5a1 Fix cancelEvent warning and better logging+error checking 2 years ago
onryo 5696afaa69 comment 2 years ago
onryo 1afffea528 rm install.sh 2 years ago
Duke Leto eda57b5a1b Try to gracefully handle exceptions in litelib_process_response 2 years ago
Duke Leto 3db92080fd Add missing build-essential dep to default compile instructions 2 years ago
jahway603 68eefa1b0e removed unneeded files 2 years ago
jahway603 25a6d289ab cleanup of README.md between the diffs in dev and master branch 2 years ago
jahway603 1b73513a0b Merge remote-tracking branch 'remotes/upstream/dev' into dev 2 years ago
onryo 743f35dd79 Upload files to 'res' 2 years ago
Duke Leto c14c7f2b4b add translation analysis script 2 years ago
Duke Leto 9722b5ec15 update translations 2 years ago
onryo 18a9c5b58e +nl 2 years ago
onryo 743943ae2b +nl 2 years ago
Duke Leto 7c43664652 Update 'README.md' 2 years ago
oDinZu 47ab9470d6 improve rust instructions 2 years ago
Duke Leto 672cf54b0a Merge branch 'show_server' into dev 2 years ago
Duke Leto f63313b83c Merge remote-tracking branch 'origin/master' into dev 2 years ago
Duke Leto 3e0acd9be2 Merge pull request 'New animated startup GIF' (#53) from onryo/SilentDragonLite:master into master 2 years ago
onryo 814918d353 Upload files to 'res' 2 years ago
Duke Leto 532d8824ab Render current server in hushd tab 2 years ago
Duke Leto e7a23a4bfb Start implementing the showing of server details in Hushd Tab 2 years ago
Duke Leto 7975f02a36 Check for qmake and make in build.sh 2 years ago
jahway603 5a6fb909a6 working on getting windows bins 2 years ago
jahway603 cd890f3ae0 created doc dir 2 years ago
jahway603 a6bf9a645f Merge pull request 'fixed wormholeconnect image' (#47) from jahway603/SilentDragonLite:dev into dev 2 years ago
jahway603 633cd782f3 moved install.sh to util dir 2 years ago
jahway603 e1df174991 created util directory 2 years ago
jahway603 4a61624ae6 fixed wormholeconnect image 2 years ago
onryo b4c5f2d26a updated lang 2 years ago
oDinZu 2f63d978aa Update 'README.md' 2 years ago
oDinZu 11d689c5ba Update 'README.md' 2 years ago
jahway603 dae0dd016d Merge pull request 'adding poop to random server list in SDL' (#38) from jahway603/SilentDragonLite:dev into dev 2 years ago
jahway603 2fa022f37b added poo to random server list 2 years ago
jahway603 c6d9164068 added some poo 2 years ago
onryo 2ae5bb40e3 yep 2 years ago
onryo 3465738d7e yep 2 years ago
onryo 2e5977a38d Upload files to '' 2 years ago
onryo b77db78e36 Upload files to '' 2 years ago
onryo b2174fcdca Upload files to '' 2 years ago
Duke Leto 2b23bd7603 Merge pull request 'hush builder and launcher creator' (#36) from onryo/SilentDragonLite:master into master 2 years ago
onryo ca0f770fb5 Upload files to '' 2 years ago
Duke Leto 5fb3e364ca Merge pull request 'adding nyami to random server list in SDL' (#33) from oDinZu/SilentDragonLite:sdl-odinzu into dev 3 years ago
oDinZu e574663895 Merge branch 'dev' of https://git.hush.is/hush/SilentDragonLite into sdl-odinzu 3 years ago
oDinZu a9063e865e add nyami to random servers 3 years ago
oDinZu ce1dfcb735 Update 'src/mainwindow.cpp' 3 years ago
Duke Leto aebaa01e19 Set error code correctly when cargo or rustc not found 3 years ago
Duke Leto 3ab6c3254b Give a useful error if curl is not installed 3 years ago
Duke Leto fc474d797d Add error checking to libsodium build 3 years ago
Duke Leto e7eed1052a Git not github 3 years ago
Duke Leto e303f0b12b update ignored files 3 years ago
Duke Leto 4a82643ba1 copyright and tweaks 3 years ago
Duke Leto b8f5b90fbc Merge branch 'dev' of https://git.hush.is/hush/SilentDragonLite into dev 3 years ago
Duke Leto 760729f1b1 more useful debug log 3 years ago
Duke Leto d61048dcdd Merge pull request 'added rustc and cargo checks to build.sh' (#29) from jahway603/SilentDragonLite:dev into dev 3 years ago
jahway603 e6d3c8db51 added rustc and cargo checks to build.sh 3 years ago
Duke Leto f558309969 Merge branch 'master' into dev 3 years ago
Duke Leto f872c0af6b add debugging 3 years ago
Duke Leto f13b37ad44 . 3 years ago
Duke Leto 2a22418779 Merge branch 'dev' 3 years ago
Duke Leto 86ce11ff2c update about tab 3 years ago
Duke Leto b15cd39c5f Welcome To The Land Of Hush 3 years ago
Duke Leto 62b5fdacf2 Merge pull request 'lite.hush.land' (#26) from onryo/SilentDragonLite:dev into dev 3 years ago
onryo 75cdd68711 Update 'src/mainwindow.cpp' 3 years ago
jahway603 89b46edbcf Merge pull request 'clarified rust pre-installation from user feedback' (#24) from jahway603/SilentDragonLite:dev into dev 3 years ago
jahway603 d7c1f81a7a clarified rust pre-installation from user feedback 3 years ago
Duke Leto 3a4b1de6c3 1.5.2 3 years ago
Duke Leto b0b39054a7 Prevent chats from being showed twice, fixes qa#1 3 years ago
Duke Leto a135753cef logging and error handling 3 years ago
Duke Leto 14ab550b76 . 3 years ago
Duke Leto 9dce18e151 continue instead of returning after secretstream badness 3 years ago
Duke Leto 3ce1a8c1e8 More details on secretstream errors and cleanups 3 years ago
Duke Leto f3c3684f88 Fix compile errors and warnings 3 years ago
Duke Leto 35593443b5 Abort when we see funky stuff from secretstream api 3 years ago
Duke Leto 92b86b3dc7 Abort on secretstream funky stuff 3 years ago
Duke Leto f1fb4209b0 clean 3 years ago
Duke Leto 413cb8a92f . 3 years ago
Duke Leto 35e7072784 Send people to TG support for filing a bug, since Gitea requires an account 3 years ago
Duke Leto 6fd0f808cc 1.5.1 3 years ago
Duke Leto bd3a839269 HUSHPrice 3 years ago
Duke Leto d826ca8c92 Abort when we see corrupted ciphertext 3 years ago
Duke Leto 461b41307e Merge branch 'master' into dev 3 years ago
Duke Leto fe6f38d0bd Prevent Rust from falling victim to trailing slashitis 3 years ago
Duke Leto 10a23e795d Update 'README.md' 3 years ago
Duke Leto 83d6d38491 . 3 years ago
Duke Leto 1d38959e7e Merge branch 'dev' 3 years ago
Duke Leto 0d13df88e3 Bump version 3 years ago
Duke Leto 3de22a07a7 Merge branch 'dev' of https://git.hush.is/hush/SilentDragonLite into dev 3 years ago
Duke Leto e4e321fa6a Merge branch 'duke' into dev 3 years ago
Duke Leto f601767811 Randomly choose an SDL server and recognize malicious domain without prefix 3 years ago
Duke Leto e2770675b5 Better GUI error message for down server 3 years ago
Duke Leto aad29abc15 . 3 years ago
Duke Leto 8688baa5b8 Better nomenclature 3 years ago
Duke Leto 204fb77d0d Spelling and nomenclature 3 years ago
Duke Leto e6828434ce Private Key 3 years ago
Duke Leto fa1054acb5 Allow importing old privkey format 3 years ago
Duke Leto aa36a44cae Merge pull request 'bies.xyz -> lite.hush.community' (#22) from onryo/SilentDragonLite:dev into dev 3 years ago
onryo 325a647326 bies.xyz -> lite.hush.community 3 years ago
Duke Leto 68104f2247 Fix stuff and get sticky 3 years ago
Duke Leto cb843addd8 Fix halving calc 3 years ago
Duke Leto 3149f04fc1 . 3 years ago
Duke Leto 0bede7d202 translations 3 years ago
Duke Leto eeba8ec9da convert to git.hush.is 3 years ago
Duke Leto eb831a1e69 Use only 4 cores for now to prevent running out of RAM 3 years ago
Duke Leto 00534af1e8 Merge branch 'master' into dev 3 years ago
Duke Leto 2d5c336a2d Merge branch 'master' of https://git.hush.is/hush/SilentDragonLite 3 years ago
Duke Leto d75c4a2fda Update 'README.md' 3 years ago
Duke Leto 3eeb47e222 Update 'README.md' 3 years ago
Duke Leto 9877ed3c42 Merge pull request 'updated BE and RU langs for SDL' (#15) from onryo/SilentDragonLite:dev into dev 3 years ago
Duke Leto fc69a710cc Merge pull request 'changed an old link to git.hush.is' (#16) from jahway603/SilentDragonLite:dev into dev 3 years ago
jahway603 6544459e38 changed an old link to git.hush.is 3 years ago
onryo b5cd176ee3 Merge branch 'dev' into dev 3 years ago
onryo 27474dd275 updated RU lang 3 years ago
onryo 1c71400a21 updated BE lang 3 years ago
Duke Leto b3912a24a2 changes from jahway603 3 years ago
Duke Leto 42fcf98866 Merge pull request 'added bies.xyz to the list of default servers' (#12) from onryo/SilentDragonLite:onryo-patch-3 into dev 3 years ago
onryo 9f59959526 added https://bies.xyz to the list of default servers 3 years ago
Duke Leto 8a19bf4b62 Merge pull request 'updated README.md' (#8) from jahway603/SilentDragonLite:dev into dev 3 years ago
jahway603 d1e0263dcf updated README.md 3 years ago
Duke Leto 5126106956 Add BE+RU translations 3 years ago
Duke Leto 0598ee20e8 updates 3 years ago
Duke Leto 0ac223e9f5 Update Telegram link in all translations 3 years ago
Duke Leto 0b57ffbfc0 Merge pull request 'changed Discord text to Telegram for Help section' (#6) from jahway603/SilentDragonLite:dev into dev 3 years ago
jahway603 fbb602c9fc changed Discord text to Telegram for Help section 3 years ago
  1. 2
      .gitignore
  2. 2
      .travis.yml
  3. 2
      LICENSE
  4. 105
      README.md
  5. 70
      application.qrc
  6. 61
      build.sh
  7. 11
      contrib/debian/README.md
  8. 5
      contrib/debian/changelog
  9. 1
      contrib/debian/compat
  10. 13
      contrib/debian/control
  11. 5
      contrib/debian/copyright
  12. 20
      contrib/debian/rules
  13. 62
      doc/developer.md
  14. 67
      doc/release-process.md
  15. 75
      doc/relnotes.md
  16. 13
      doc/win/DEVELOPING-Ubuntu-18-04.md
  17. 7
      issue_template.md
  18. 1967
      lib/Cargo.lock
  19. 4
      lib/Cargo.toml
  20. 1
      lib/silentdragonlitelib.h
  21. 104
      lib/src/lib.rs
  22. 2
      peda-session-SilentDragonLite.txt
  23. BIN
      res/Anonymous.png
  24. BIN
      res/Berg.png
  25. BIN
      res/Elsa.png
  26. BIN
      res/Garfield.png
  27. BIN
      res/Mickey.png
  28. BIN
      res/Pinguin.png
  29. BIN
      res/Popey.png
  30. BIN
      res/Snoopy.png
  31. BIN
      res/Stag.png
  32. BIN
      res/Yoda.png
  33. 2
      res/css/Dark.css
  34. 2
      res/css/Light.css
  35. 21
      res/css/Midnight.css
  36. 114
      res/css/dragonx.css
  37. BIN
      res/darkwing.png
  38. BIN
      res/fekt.png
  39. BIN
      res/hushdlogo.png
  40. BIN
      res/images/silentdragonlite.png
  41. BIN
      res/jahway603.png
  42. BIN
      res/liblibsodium.a
  43. BIN
      res/libsodium.lib
  44. 50
      res/libsodium/buildlibsodium.sh
  45. BIN
      res/libsodiumd.lib
  46. BIN
      res/lock_closed.png
  47. BIN
      res/lock_open.png
  48. BIN
      res/logobig.gif
  49. BIN
      res/onryo.png
  50. BIN
      res/remove.png
  51. BIN
      res/send.png
  52. BIN
      res/silentdragonlite-animated-startup-dark.gif
  53. BIN
      res/silentdragonlite_ar.qm
  54. 1008
      res/silentdragonlite_ar.ts
  55. BIN
      res/silentdragonlite_be.qm
  56. 2849
      res/silentdragonlite_be.ts
  57. BIN
      res/silentdragonlite_de.qm
  58. 969
      res/silentdragonlite_de.ts
  59. BIN
      res/silentdragonlite_es.qm
  60. 1021
      res/silentdragonlite_es.ts
  61. BIN
      res/silentdragonlite_fa.qm
  62. 971
      res/silentdragonlite_fa.ts
  63. BIN
      res/silentdragonlite_fr.qm
  64. 989
      res/silentdragonlite_fr.ts
  65. BIN
      res/silentdragonlite_hr.qm
  66. 973
      res/silentdragonlite_hr.ts
  67. BIN
      res/silentdragonlite_id.qm
  68. 52
      res/silentdragonlite_id.ts
  69. BIN
      res/silentdragonlite_it.qm
  70. 1006
      res/silentdragonlite_it.ts
  71. BIN
      res/silentdragonlite_nl.qm
  72. 2843
      res/silentdragonlite_nl.ts
  73. BIN
      res/silentdragonlite_pl.qm
  74. 2850
      res/silentdragonlite_pl.ts
  75. BIN
      res/silentdragonlite_pt.qm
  76. 989
      res/silentdragonlite_pt.ts
  77. BIN
      res/silentdragonlite_ro.qm
  78. 52
      res/silentdragonlite_ro.ts
  79. BIN
      res/silentdragonlite_ru.qm
  80. 2849
      res/silentdragonlite_ru.ts
  81. BIN
      res/silentdragonlite_sr.qm
  82. 973
      res/silentdragonlite_sr.ts
  83. 2
      res/silentdragonlite_template.ts
  84. BIN
      res/silentdragonlite_tr.qm
  85. 987
      res/silentdragonlite_tr.ts
  86. BIN
      res/silentdragonlite_ud.qm
  87. 50
      res/silentdragonlite_ud.ts
  88. BIN
      res/silentdragonlite_zh.qm
  89. 987
      res/silentdragonlite_zh.ts
  90. BIN
      res/synced.png
  91. BIN
      res/transaction0.png
  92. BIN
      res/transaction2.png
  93. BIN
      res/transaction_abandoned.png
  94. BIN
      res/transaction_conflicted.png
  95. BIN
      res/tx_inout.png
  96. BIN
      res/tx_input.png
  97. BIN
      res/tx_mined.png
  98. BIN
      res/tx_output.png
  99. BIN
      res/verify.png
  100. BIN
      res/warning.png
  101. BIN
      res/wormholeconnect.png
  102. 4
      run-after-build.sh
  103. 36
      silentdragon-lite.pro
  104. 2
      src/3rdparty/sodium.h
  105. 87
      src/Chat/Chat.cpp
  106. 2
      src/Chat/Chat.h
  107. 3
      src/Chat/Helper/ChatDelegator.h
  108. 2
      src/Crypto/FileEncryption.cpp
  109. 2
      src/Crypto/FileEncryption.h
  110. 2
      src/Crypto/passwd.cpp
  111. 2
      src/Crypto/passwd.h
  112. 11
      src/DataStore/ChatDataStore.cpp
  113. 2
      src/DataStore/ChatDataStore.h
  114. 2
      src/DataStore/ContactDataStore.cpp
  115. 2
      src/DataStore/ContactDataStore.h
  116. 2
      src/DataStore/DataStore-deprecated.h
  117. 7
      src/DataStore/DataStore.cpp
  118. 4
      src/DataStore/DataStore.h
  119. 51
      src/DataStore/NoteCountDataStore.cpp
  120. 36
      src/DataStore/NoteCountDataStore.h
  121. 2
      src/DataStore/SietchDataStore.cpp
  122. 2
      src/DataStore/SietchDataStore.h
  123. 2
      src/FileSystem/FileSystem.cpp
  124. 2
      src/FileSystem/FileSystem.h
  125. 2
      src/Logger/LogContext.h
  126. 2
      src/Logger/LogCrtitical.h
  127. 2
      src/Logger/LogDebug.h
  128. 2
      src/Logger/LogError.h
  129. 2
      src/Logger/LogFatal.h
  130. 2
      src/Logger/LogInfo.h
  131. 2
      src/Logger/LogStrategy.h
  132. 2
      src/Logger/LogSuccess.h
  133. 2
      src/Logger/LogType.h
  134. 2
      src/Logger/LogWarning.h
  135. 2
      src/Logger/LogWriter.cpp
  136. 2
      src/Logger/LogWriter.h
  137. 2
      src/Logger/Logger.h
  138. 2
      src/Logger/SimpleLogger.h
  139. 2
      src/Logger/test.cpp
  140. 41
      src/Model/ChatItem.cpp
  141. 2
      src/Model/ChatItem.h
  142. 2
      src/Model/ContactItem.cpp
  143. 2
      src/Model/ContactItem.h
  144. 2
      src/Model/ContactRequest.cpp
  145. 2
      src/Model/ContactRequest.h
  146. 2
      src/Model/ContactRequestChatItem.cpp
  147. 2
      src/Model/ContactRequestChatItem.h
  148. 13
      src/about.ui
  149. 3
      src/addressbook.cpp
  150. 4
      src/addressbook.h
  151. 86
      src/addressbook.ui
  152. 2
      src/addresscombo.cpp
  153. 2
      src/addresscombo.h
  154. 16
      src/balancestablemodel.cpp
  155. 8
      src/balancestablemodel.h
  156. 4
      src/camount.cpp
  157. 2
      src/camount.h
  158. 2
      src/chatbubbleme.cpp
  159. 2
      src/chatbubbleme.h
  160. 2
      src/chatbubblepartner.cpp
  161. 2
      src/chatbubblepartner.h
  162. 79
      src/chatmodel.cpp
  163. 2
      src/chatmodel.h
  164. 309
      src/connection.cpp
  165. 3
      src/connection.h
  166. 18
      src/contactmodel.cpp
  167. 2
      src/contactmodel.h
  168. 86
      src/contactrequest.ui
  169. 648
      src/controller.cpp
  170. 8
      src/controller.h
  171. 2
      src/datamodel.cpp
  172. 8
      src/datamodel.h
  173. 104
      src/deposithush.ui
  174. 23
      src/fillediconlabel.cpp
  175. 2
      src/fillediconlabel.h
  176. 326
      src/firsttimewizard.cpp
  177. 28
      src/firsttimewizard.h
  178. 20
      src/guiconstants.h
  179. 9
      src/liteinterface.cpp
  180. 2
      src/liteinterface.h
  181. 2
      src/logger.cpp
  182. 2
      src/logger.h
  183. 3
      src/main.cpp
  184. 709
      src/mainwindow.cpp
  185. 13
      src/mainwindow.h
  186. 927
      src/mainwindow.ui
  187. 2
      src/memoedit.cpp
  188. 8
      src/memoedit.h
  189. 139
      src/migration.ui
  190. 16
      src/mobileappconnector.cpp
  191. 24
      src/mobileappconnector.h
  192. 214
      src/mobileappconnector.ui
  193. 2
      src/newseed.ui
  194. 5
      src/newwallet.ui
  195. 3
      src/precompiled.h
  196. 18
      src/qrcodelabel.cpp
  197. 2
      src/qrcodelabel.h
  198. 10
      src/recurring.cpp
  199. 6
      src/recurring.h
  200. 2
      src/recurringdialog.ui
  201. 2
      src/recurringpayments.ui
  202. 90
      src/requestContactDialog.ui
  203. 2
      src/requestdialog.cpp
  204. 2
      src/requestdialog.h
  205. 72
      src/restoreSeed.ui
  206. 2
      src/restoreseed.ui
  207. 2
      src/scripts/docker/Dockerfile
  208. 19
      src/scripts/translation_analysis.sh
  209. 1
      src/sdl.h
  210. 68
      src/sendtab.cpp
  211. 143
      src/settings.cpp
  212. 20
      src/settings.h
  213. 68
      src/settings.ui
  214. 65
      src/txtablemodel.cpp
  215. 3
      src/txtablemodel.h
  216. 4
      src/version.h
  217. 2
      src/viewalladdresses.cpp
  218. 4
      src/viewalladdresses.h
  219. 943
      src/websockets.cpp
  220. 179
      src/websockets.h
  221. 9
      util/SilentDragonLite.desktop
  222. 6
      util/add-linux-icons.sh
  223. 10
      util/install.sh
  224. 42
      util/replace.pl
  225. 26
      util/update-copyrights.sh
  226. 38
      win-static-build.sh

2
.gitignore

@ -42,3 +42,5 @@ silentdragonlite_plugin_import.cpp
silentdragonlite_resource.rc
SilentDragonLite
.gdb_history
.*sw?
core

2
.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

2
LICENSE

@ -1,4 +1,4 @@
Copyright 2019-2021 The Hush developers
Copyright 2019-2024 The Hush developers
Copyright 2018 adityapk

105
README.md

@ -2,8 +2,7 @@
SilentDragonLite is a lightwallet for HUSH ($HUSH) runs on Linux and Windows which does not require you to download the full blockchain. This is experimental software under active development!
<img src="hushchat-screenshot.png">
<img src="res/images/silentdragonlite.png" width="750">
## PRIVACY NOTICE
@ -12,28 +11,84 @@ The first two are option features, to get real-time price data feeds and if you
to look at explorer details. Price feed can be turned off in Settings and you can set
a custom block explorer URL as well.
* coingecko.com for price data API (optional)
* explorer.hush.is for explorer links (optional)
* various community-run lite wallet servers to provide basic functionality (required)
* coingecko.com for price data API (optional)
* explorer.hush.is for explorer links (optional)
* various community-run lite wallet servers to provide basic functionality (required)
This means your IP address is known to these servers. Enable Tor setting in SilentDragon to prevent this, or better yet, use TAILS: https://tails.boum.org/
This means your IP address is known to these servers. Enable Tor setting in your wallet to prevent this, or better yet, use TAILS: https://tails.boum.org/
or https://qubes-os.org
## Installation
Go to the releases page and grab the latest installers or binary. https://git.hush.is/hush/SilentDragonLite/releases
Choose to install a binary release or compile it yourself.
For Arch Linux users, we have a silentdragonlite package on [AUR](https://aur.archlinux.org/).
### Option 1: Binary Release
Go to the [releases page](https://git.hush.is/hush/SilentDragonLite/releases) and grab the latest binary.
### Option 2: Compile Release Yourself
* SilentDragonLite is written in C++ 14, and can be compiled with g++/clang++/visual c++.
* It also depends on Qt5, which you can get from [here](https://www.qt.io/download) or we recommend installing using your Linux version's package manager (if available).
* **You'll need Rust v1.49**, so install it via [Rustup in Linux](https://rustup.rs/). **If you use a version greater then 1.63, then it will not currently build** as seen in [Issue #89](https://git.hush.is/hush/SilentDragonLite/issues/89).
#### Building on Linux
**Nothing below will work without rust. Check that your system has rustc 1.49. If not then you need to use [Rustup in Linux](https://rustup.rs/).**
An example of how to install Rust 1.49 with rustup is below:
```
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
Choose: 1) Proceed with installation (default)
source $HOME/.cargo/env
rustup install 1.49
rustup default 1.49
rustup -V
```
**Nothing below will work without the Linux "build-essential" package. Check that your system has it installed. If not, and you're using a Ubuntu/Debian distro, then you can install with `apt install build-essential`.**
##### Ubuntu 22.04:
```shell script
sudo apt-get -y install build-essential qtbase5-dev qt5-qmake qtcreator qttools5-dev-tools
```
## Install Torsocks (or any other Socks service for TOR) on Ubuntu 18.04
##### Ubuntu 18.04 and 20.04:
```shell script
sudo apt-get -y install build-essential qt5-default qt5-qmake qtcreator qttools5-dev-tools
```
Compiling can take some time, so be patient and wait for it to finish. It will take potentially a long time for slower systems. Be Patient and please report compiler problems!
```shell script
git clone https://git.hush.is/hush/SilentDragonLite
cd SilentDragonLite
./build.sh linguist
# This defaults to using 2 cores to compile
./build.sh
# To use a custom number of cores to compile, such as 8 :
# ./build.sh -j8
./SilentDragonLite
```
### Other notes
#### Install Torsocks (or any other Socks service for TOR) on Ubuntu 18.04
```shell script
sudo apt update
sudo apt install torsocks
```
## Connection to our TOR onion service Server
#### Connection to our TOR onion service Server
NOTE: Tor server is currently under maintenance.
```
* Open SDL Edit->Settings->LightwalletServer->6onaaujm4ozaokzu.onion:80
* Open SDL Edit->Settings->LightwalletServer->nope.onion:80
* Open the folder of SDL in a Terminal -> Enter: TORSOCKS_LOG_LEVEL=1 torsocks -i ./SilentDragonLite
```
## Note Management
### Note Management
SilentDragonLite does automatic note and utxo management, which means it doesn't allow you to manually select which address to send outgoing transactions from. It follows these principles:
* Defaults to sending shielded transactions, which are now enforced via consensus rules
@ -42,18 +97,20 @@ SilentDragonLite does automatic note and utxo management, which means it doesn't
* Will automatically shield your transparent funds at the first opportunity
* When sending an outgoing transaction to a shielded address, SilentDragonLite can decide to use the transaction to additionally shield your transparent funds (i.e., send your transparent funds to your own shielded address in the same transaction)
## Compiling from source
* SilentDragonLite is written in C++ 14, and can be compiled with g++/clang++/visual c++.
* It also depends on Qt5, which you can get from [here](https://www.qt.io/download).
* You'll need Rust v1.41 +
## Where is my wallet stored?
## Building on Linux
Linux: `~/.silentdragonlite`
```
git clone https://git.hush.is/hush/SilenDragonLite
cd SilentDragonLite
# the next step will take potentially a long time for slower systems
# Be Patient and please report compiler problems!
./build.sh
./SilentDragonLite
```
Windows 10: `C:\Users\%user\AppData\Roaming\silentdragonlite`
Mac: `~/Library/Application Support/silentdragonlite`
## Support
For support join us on [Telegram Support](https://hush.is/telegram_support), or our [Main Telegram](https://hush.is/telegram), or toot at our [Mastodon](https://fosstodon.org/@myhushteam), or [file an issue](https://git.hush.is/hush/SilentDragonLite/issues).
You can also subscribe to our channels on [PeerTube](https://videos.hush.is), on [YouTube](https://hush.is/yt), or on [Odyssee/LBRY](https://odysee.com/@MyHushTeam:3).
## License
GPLv3 or later

70
application.qrc

@ -8,21 +8,15 @@
<file>res/paymentreq.gif</file>
<file>res/icon.ico</file>
<file>res/mail.png</file>
<file>res/darkwing.png</file>
<file>res/SDLogo.png</file>
<file>res/sdlogo2.png</file>
<file>res/Berg.png</file>
<file>res/Denio.png</file>
<file>res/Duke.png</file>
<file>res/onryo.png</file>
<file>res/fekt.png</file>
<file>res/jahway603.png</file>
<file>res/Sharpee.png</file>
<file>res/Yoda.png</file>
<file>res/Mickey.png</file>
<file>res/Snoopy.png</file>
<file>res/Popey.png</file>
<file>res/Garfield.png</file>
<file>res/Pinguin.png</file>
<file>res/Stag.png</file>
<file>res/Elsa.png</file>
<file>res/Anonymous.png</file>
<file>res/send.png</file>
<file>res/send.svg</file>
<file>res/addcontact.svg</file>
@ -51,9 +45,12 @@
<file>res/money-mouth.png</file>
<file>res/money-outgoing.png</file>
<file>res/hush-money-white.png</file>
<file>res/tx_input.png</file>
<file>res/tx_output.png</file>
<file>res/tx_mined.png</file>
</qresource>
<qresource prefix="/img">
<file>res/hushdlogo.png</file>
<file>res/hushdlogo.gif</file>
<file>res/silentdragonlite-animated.gif</file>
<file>res/silentdragonlite-animated-dark.gif</file>
@ -61,39 +58,46 @@
<file>res/silentdragonlite-animated-startup-dark.gif</file>
<file>res/loaderblack.gif</file>
<file>res/loaderwhite.gif</file>
<file>res/logobig.gif</file>
</qresource>
<qresource prefix="/emoji">
<file>res/emoji/emoji1.png</file>
<file>res/emoji/laughing.png</file>
<file>res/emoji/money-mouth.png</file>
<file>res/emoji/joy.png</file>
<file>res/emoji/innocent.png</file>
<file>res/emoji/partying_face.png</file>
<file>res/emoji/face_with_3hearts.png</file>
<file>res/emoji/face-with-rolling-eyes.png</file>
<file>res/emoji/face-with-tongue.png</file>
<file>res/emoji/heart_shaped_eyes.png</file>
<file>res/emoji/nauseated-face.png</file>
<file>res/emoji/pile-of-poo.png</file>
<file>res/emoji/serious-face-with-symbols-covering-mouth.png</file>
<file>res/emoji/smiling-face-with-sunglasses.png</file>
<file>res/emoji/stuck-out.png</file>
<file>res/emoji/sweet_smile.png</file>
<file>res/emoji/hush-money-white.png</file>
<file>res/emoji/SD.png</file>
<file>res/emoji/emoji1.png</file>
<file>res/emoji/laughing.png</file>
<file>res/emoji/money-mouth.png</file>
<file>res/emoji/joy.png</file>
<file>res/emoji/innocent.png</file>
<file>res/emoji/partying_face.png</file>
<file>res/emoji/face_with_3hearts.png</file>
<file>res/emoji/face-with-rolling-eyes.png</file>
<file>res/emoji/face-with-tongue.png</file>
<file>res/emoji/heart_shaped_eyes.png</file>
<file>res/emoji/nauseated-face.png</file>
<file>res/emoji/pile-of-poo.png</file>
<file>res/emoji/serious-face-with-symbols-covering-mouth.png</file>
<file>res/emoji/smiling-face-with-sunglasses.png</file>
<file>res/emoji/stuck-out.png</file>
<file>res/emoji/sweet_smile.png</file>
<file>res/emoji/hush-money-white.png</file>
<file>res/emoji/SD.png</file>
</qresource>
<qresource prefix="/translations">
<file>res/silentdragonlite_ar.qm</file>
<file>res/silentdragonlite_be.qm</file>
<file>res/silentdragonlite_pl.qm</file>
<file>res/silentdragonlite_de.qm</file>
<file>res/silentdragonlite_es.qm</file>
<file>res/silentdragonlite_fa.qm</file>
<file>res/silentdragonlite_fr.qm</file>
<file>res/silentdragonlite_pt.qm</file>
<file>res/silentdragonlite_it.qm</file>
<file>res/silentdragonlite_hr.qm</file>
<file>res/silentdragonlite_fa.qm</file>
<file>res/silentdragonlite_id.qm</file>
<file>res/silentdragonlite_ar.qm</file>
<file>res/silentdragonlite_it.qm</file>
<file>res/silentdragonlite_pt.qm</file>
<file>res/silentdragonlite_ro.qm</file>
<file>res/silentdragonlite_ru.qm</file>
<file>res/silentdragonlite_ud.qm</file>
<file>res/silentdragonlite_sr.qm</file>
<file>res/silentdragonlite_tr.qm</file>
<file>res/silentdragonlite_zh.qm</file>
</qresource>
<qresource prefix="/css">
<file>res/css/Blue.css</file>

61
build.sh

@ -1,20 +1,50 @@
#!/bin/bash
# Copyright 2019-2021 The Hush Developers
#!/usr/bin/env bash
# Copyright 2019-2024 The Hush Developers
# Released under the GPLv3
UNAME=$(uname)
if [ "$UNAME" == "Linux" ] ; then
JOBS=$(nproc)
elif [ "$UNAME" == "FreeBSD" ] ; then
JOBS=$(nproc)
elif [ "$UNAME" == "Darwin" ] ; then
JOBS=$(sysctl -n hw.ncpu)
else
JOBS=1
# check if rustc and cargo are installed, otherwise exit with error
if ! command -v rustc &> /dev/null
then
echo "rustc could not be found. Please install it and try again."
exit 1
fi
if ! command -v cargo &> /dev/null
then
echo "cargo could not be found. Please install it and try again."
exit 1
fi
if ! command -v qmake &> /dev/null
then
echo "qmake could not be found. Please install QT and try again."
exit 1
fi
if ! command -v make &> /dev/null
then
echo "make could not be found. Please install it and try again."
exit 1
fi
VERSION=$(grep APP_VERSION src/version.h |cut -d\" -f2)
QTVERSION=$(qmake --version | tail -n 1 | cut -d' ' -f4)
QT_MAJOR_VERSION=$(echo $QTVERSION | cut -d. -f1)
QT_SUB_VERSION=$(echo $QTVERSION | cut -d. -f2)
if [ "$QT_MAJOR_VERSION" != "5" ]; then
echo "Your QT version $QTVERSION is not compatible, only QT 5.x is supported"
exit 1
fi
if [ "$QT_SUB_VERSION" -lt "12" ]; then
echo "Your QT version $QTVERSION is not compatible, at least QT 5.12.0 is required"
exit 1
fi
VERSION=$(cat src/version.h |cut -d\" -f2)
echo "Compiling SilentDragonLite $VERSION with $JOBS threads..."
echo "Compiling SilentDragonLite $VERSION on $UNAME with QT $QTVERSION and args=$@"
CONF=silentdragon-lite.pro
set -e
@ -22,7 +52,8 @@ qbuild () {
qmake $CONF CONFIG+=debug
#lupdate $CONF
#lrelease $CONF
make -j$JOBS
# default to 2 jobs or use the -j value given as argument to this script
make -j2 "$@"
}
if [ "$1" == "clean" ]; then
@ -32,7 +63,7 @@ elif [ "$1" == "linguist" ]; then
lrelease $CONF
elif [ "$1" == "cleanbuild" ]; then
make clean
qbuild
qbuild "$@"
else
qbuild
qbuild "$@"
fi

11
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
```

5
contrib/debian/changelog

@ -0,0 +1,5 @@
silentdragonlite (2.0.1) stable; urgency=medium
* 2.0.1.1 release.
-- onryo <onryo@hush.land> Sat, 06 Jan 2024 10:20:30 +0200

1
contrib/debian/compat

@ -0,0 +1 @@
9

13
contrib/debian/control

@ -0,0 +1,13 @@
Source: silentdragonlite
Section: utils
Priority: optional
Maintainer: onryo <onryo@hush.land>
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.

5
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

20
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)

62
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
...
}
```

67
doc/release-process.md

@ -0,0 +1,67 @@
# SilentDragonLite Release Process
## High-Level Philosophy
Beware of making high-risk changes too close to a new release, because they will not get as much testing as they should. Don't merge large branches which haven't undergone lots of testing just before a release.
It is best to keep doc/relnotes/README.md up to date as changes and bug fixes are made. It's more work to summarize all changes and bugfixes just before the release.
## Check for changes on master that should be on dev
See https://git.hush.is/hush/hush3/src/branch/master/doc/release-process.md#check-for-changes-on-master-that-should-be-on-dev , there is no sense repeating the exact same thing here.
SD+SDL very often has merge conflicts in generated translation files, because QT embeds line numbers in XML.
Read how to deal with them efficiently here: https://git.hush.is/hush/SilentDragon/src/branch/dev/doc/release-process.md#dealing-with-merge-conflicts
## Git Issues
Look for Git issues that should be fixed in the next release: https://git.hush.is/hush/SilentDragonLite/issues Especially low-risk and simple things and like documentation changes and improvements to error messages. Take note that changing strings in the source code, such as adding a new string or changing an existing one, will affect translations.
## Translations
...
```
# update generated translation data
./build.sh linguist
git commit -am "update translations"
git push
```
## Adding Checkpoints
Adding checkpoints make SDL sync much faster, especially for brand new wallets. If there are no recent checkpoints,
when a user makes a new wallet, it will sync from a block far in the past, which wastes time, bandwidth and CPU resources. To add a checkpoint , they are added to the file `lib/src/lightclient/checkpoints.rs` in the silentdragonlite-cli repo, and then the dependency on silentdragonlite-cli is updated in this SDL repo. Here is an example commit that updates checkpoints:
https://git.hush.is/hush/silentdragonlite-cli/commit/ef477f152e1a8bb8a5f7883a99e2a74a6f9eeb0b
To actually generate the checkpoint data, use the `sdl_checkpoints.pl` script in the hush3 repo: https://git.hush.is/hush/hush3/src/branch/master/contrib/sdl_checkpoints.pl . It uses the `getblockmerkletree` RPC to get the merkle tree data for a block height. It prints the data out in the format that checkpoints.rs wants it in, you simply need to copy and paste the output into the checkpoints.rs file. Once the data is updated in silentdragonlite-cli checkpoints.rs file, the file `lib/Cargo.toml` must be updated in this repo, and point to the commit id of the updated data. Once you update the manually-edited `Cargo.toml` you must run `cargo update` to update the generated `Cargo.lock` file. See https://doc.rust-lang.org/cargo/commands/cargo-update.html for more info. Once both files are updates, commit and push.
---
To fix `error: failed to select a version for the requirement 'aes = "^0.3"'` add the following to `.cargo/config.toml`:
```
[source.crates-io]
replace-with = "vendored-sources"
[source.vendored-sources]
directory = "vendor"
```
To update the file run `cargo vendor` as was mentioned in https://git.hush.is/hush/SilentDragonLite/issues/91.
---
## 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

75
doc/relnotes.md

@ -0,0 +1,75 @@
# SilentDragonLite v2.0.2
This is an optional maintenance release.
* Updated checkpoints to 1.710.000 for security and faster syncing of new wallets.
* Removed a no longer supported lite server.
# SilentDragonLite v2.0.1 "Ethereal Electric Eel"
* Notes automation: https://git.hush.is/hush/SilentDragonLite/commit/84196cda87bc86802691fb89d1f89e3d52c9c412, https://git.hush.is/hush/SilentDragonLite/commit/fb1626d11d730e8c6d6f632c4be10acf6079cf45, https://git.hush.is/hush/SilentDragonLite/commit/c802a55bac46e18ee07f56e08e3e22c96d0f363b, https://git.hush.is/hush/SilentDragonLite/commit/c6e8268450fdeb4dfad2e29ecd9af1e0b276fab1, https://git.hush.is/hush/SilentDragonLite/commit/618625bc00fa8727befd146076b2d90dfd6b9f3b.
* Set notes automation only for HushChat related TXs: https://git.hush.is/hush/SilentDragonLite/commit/683718008c930a1226bce393bdf0350726dde2c5.
* Allow custom number of cores to compile via build.sh: https://git.hush.is/hush/SilentDragonLite/commit/fd5eec230ef36d3bf889dfcac5129dedc2f7924a.
* Updated build.sh for better OS compatibility: https://git.hush.is/hush/SilentDragonLite/commit/1fb344a8c251ff2e780fe4484f88b829a37278a1.
* Fix bug in reporting version being compiled in build.sh: https://git.hush.is/hush/SilentDragonLite/commit/f15a28f3ec7169ec27c044f54cb0f828cc4d7167.
* Check for valid QT versions or bail early: https://git.hush.is/hush/SilentDragonLite/commit/68d9388c1b87139d00fcc10ce94dd7a2109fdced.
* Check libsodium sha256 checksum: https://git.hush.is/hush/SilentDragonLite/commit/156b1a6defa974c804709678db14fbe3a0d9e477.
* Add Sticky Server and Note Automation as GUI checkbox in the settings: https://git.hush.is/hush/SilentDragonLite/commit/6f7fd863f01ed84596cc9661a989cac6c8d15816.
* Add custom Fee: https://git.hush.is/hush/SilentDragonLite/pulls/146.
* Fix for the getRandomServer() function: https://git.hush.is/hush/SilentDragonLite/issues/144.
* Disable passphrase length and seed to STDOUT: https://git.hush.is/hush/SilentDragonLite/commit/0c10cf1243e1b9a1c716a8a59d462a2f345e91f6, https://git.hush.is/hush/SilentDragonLite/commit/775135cc4478dfcf276de78811d18cc6dddec7d2, https://git.hush.is/hush/SilentDragonLite/commit/a32146470b47fed5ee3752e7e2a82163df0e3062.
* Move connection errror to status Bar: https://git.hush.is/hush/SilentDragonLite/pulls/148.
# SilentDragonLite v2.0.0 "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.
* Update silentdragonlite-cli dependency, this makes syncing new wallets drastically faster: https://git.hush.is/hush/SilentDragonLite/commit/670bc598265f70b7140af4b8287ddcf28a6a6a04.
* Add backend servers `lite.hushpool.is` and `lite2.hushpool.is`: https://git.hush.is/hush/SilentDragonLite/commit/6c5ffca05615b21ea3651897f108eb576ecc07a8, https://git.hush.is/hush/SilentDragonLite/commit/1a7af9682c2bb42959d0a8e0c826477f1ee79c95.
* Add backend servers `poop.granitefone.me` and `wtfistheinternet.hush.is`: https://git.hush.is/hush/SilentDragonLite/commit/8a5c8e4898aac993736a150f77c880a3b6c153f8, https://git.hush.is/hush/SilentDragonLite/commit/5427d400e406915562aa285bbc3bb325092672c7.
* Add backend servers `lite.myhush.org` and `lite.hush.community`: https://git.hush.is/hush/SilentDragonLite/commit/c0fe5d281cdd21da6f55d0fc300842ab4f729c22
* Remove sprout code and unused migration ui: https://git.hush.is/hush/SilentDragonLite/commit/6cab5f68f9b2c59b23ae590515ed802abe7d08e7, https://git.hush.is/hush/SilentDragonLite/commit/3f9fc49207c2455dad857f76984fef5ba35560a9.
* Fix cancelEvent warning and better logging and error checking, fix some compiler warnings: https://git.hush.is/hush/SilentDragonLite/commit/5f8babd5a192f0f7a30b2b22321c9919fba67187, https://git.hush.is/hush/SilentDragonLite/commit/cbc77e9d58c4808297f63c6da1950ba9a5945b2c.
* Fix various bugs in the New Wallet Wizard: https://git.hush.is/hush/SilentDragonLite/commit/7649418a7b52c6452726ba047c8039eb90a79714, https://git.hush.is/hush/SilentDragonLite/commit/ff8692fa391ccb6ea889002a6fff14419a5e68c6, https://git.hush.is/hush/SilentDragonLite/commit/5825b30e71847663fa2666f629c598c781b1480d.
* Ignore leading/trailing spaces in wallet birthday when importing a seed: https://git.hush.is/hush/SilentDragonLite/commit/9e8e95200c80cdc9280d406d935dbe9074412a9c.
* Welcome screen fix: https://git.hush.is/hush/SilentDragonLite/commit/1f7b8186f06fe6807e107b0ebe5e24c3551a54fd, https://git.hush.is/hush/SilentDragonLite/commit/7398c70e2b9f592310e8727f5c9542ccbcb933a9, https://git.hush.is/hush/SilentDragonLite/commit/7398c70e2b9f592310e8727f5c9542ccbcb933a9.
* Show QT Version in About screen: https://git.hush.is/hush/SilentDragonLite/commit/825e50b2ea0a1ce9be9bd78bff784c4790cb11e5.
* Removed confusing text about mining: https://git.hush.is/hush/SilentDragonLite/commit/4aeab433a46437ee42b8852c3f455bcae63065e6.
* Update translations for Spanish, Russian and Belarusian languages: https://git.hush.is/hush/SilentDragonLite/commit/aabb8c5f292d11fbb73f007dda6651928de63d63, https://git.hush.is/hush/SilentDragonLite/commit/fc3c445f219532440b262721d6bc52f251e20b5e, https://git.hush.is/hush/SilentDragonLite/commit/19e12ba5a6e17264873e4ed084391bb13c30f475.
* Add Polish language: https://git.hush.is/hush/SilentDragonLite/commit/a1bb19da8d3242cd1acd80acaaecee8a1979a6dd, https://git.hush.is/hush/SilentDragonLite/commit/78806743b665069d0f65d54d6c69edbec2c89de4.
* Memo stuff: https://git.hush.is/hush/SilentDragonLite/commit/25fab30e1dadefdb93f634692d5ff11f10162f0b, https://git.hush.is/hush/SilentDragonLite/commit/fc3f4ce99b813b57e1a81cf053242ccd17ab13d8, https://git.hush.is/hush/SilentDragonLite/commit/fc3f4ce99b813b57e1a81cf053242ccd17ab13d8, https://git.hush.is/hush/SilentDragonLite/commit/fc3f4ce99b813b57e1a81cf053242ccd17ab13d8.
* Fix no connection status on sync: https://git.hush.is/hush/SilentDragonLite/commit/e179e723f5d6243e74a432273da7ea73893fe174.
* Try to avoid coredumping if zrpc object doesn't exist, which can happen if backend server is misbehaving: https://git.hush.is/hush/SilentDragonLite/commit/fd2fb3757add1d407bf9b8a46652712b9ca88fa7, https://git.hush.is/hush/SilentDragonLite/commit/42b5d182ee639933a8dd639f12f5c99e66f55a63.
* Add debugging: https://git.hush.is/hush/SilentDragonLite/commit/f872c0af6b3a8c6116c580cf9883ac21e14b4d6b, https://git.hush.is/hush/SilentDragonLite/commit/760729f1b1833e4a4fdb398abfed09e405c633ff.
* Add rustc, cargo and libsodium checks: https://git.hush.is/hush/SilentDragonLite/commit/e6d3c8db51752179e630ab271eba4eea53dd2ac2, https://git.hush.is/hush/SilentDragonLite/commit/fc474d797dc170126a9451d4336bad3d36101cf4.
* Update graphics: https://git.hush.is/hush/SilentDragonLite/commit/69ea9ace50de72593c86be7f54871130631c3ba1, https://git.hush.is/hush/SilentDragonLite/commit/fe15384c10783e061a41165ea3fd82b55bb932de.
* Less Microsoft: https://git.hush.is/hush/SilentDragonLite/commit/b0d6aa3285706b50b233a8b8c523b9f2899a272f.
* Windows binary was provided. (in progress)
* Linux binary and debian package were provided. (in progress)
# SilentDragonLite v1.5.2 "Zany Zulu"
* Fixes connection problems for older versions
* Updated one of the community servers to new domain: lite.hush.land
* Fix bug where trailing slash on server name crashes SDL
* Improved error-handling of invalid data at libsodium layer
* Avoid showing corrupted ciphertext in GUI

13
DEVELOPING.md → doc/win/DEVELOPING-Ubuntu-18-04.md

@ -1,5 +1,5 @@
## Crosscompile for Windows (only tested for Ubuntu 18.04)
## Crosscompile for Windows (only tested for Ubuntu 18.04) by DenioD
```
# build dependencies
@ -52,11 +52,11 @@ make -j$(nproc) install
```
# Build MXE (Cross-compiled Qt5 for Windows in Linux)
```
mkdir ~/github && cd ~/github
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
@ -71,3 +71,10 @@ echo 'source $HOME/.cargo/env' >> $HOME/.bashrc
./win-static-build.sh
```
# Adding a new SDL lite server backend to the code
* Add the new server name to the array in getRandomServer() in settings.cpp
* Add the new server to dropdown in mainwindow.cpp
TODO: Make both of these places use a single list of servers.

7
.github/ISSUE_TEMPLATE/issue_template.md → issue_template.md

@ -7,7 +7,8 @@ assignees: ''
---
Please make sure you have the latest SilentDragonLite.
Please make sure you have the latest SilentDragonLite and let us
know if you have any non-default settings.
**Describe the bug**
A clear and concise description of what the bug is.
@ -23,9 +24,7 @@ Steps to reproduce the behavior:
A clear and concise description of what you expected to happen.
**Desktop (please complete the following information):**
- OS: [e.g. iOS]
- Browser [e.g. chrome, safari]
- Version [e.g. 22]
- OS: [e.g. Linux/Mac/Windows with version]
**Additional context**
Add any other context about the problem here.

1967
lib/Cargo.lock

File diff suppressed because it is too large

4
lib/Cargo.toml

@ -1,7 +1,7 @@
[package]
name = "qtlib"
version = "0.1.0"
authors = ["zecwallet"]
authors = ["zecwallet", "The Hush Developers"]
edition = "2018"
[lib]
@ -12,4 +12,4 @@ crate-type = ["staticlib"]
libc = "0.2.58"
lazy_static = "1.4.0"
blake3 = "0.3.4"
silentdragonlitelib = { git = "https://github.com/MyHush/silentdragonlite-cli", rev = "8535a11e3774d79de2ebeaa5540567ccb4988f81" }
silentdragonlitelib = { git = "https://git.hush.is/hush/silentdragonlite-cli", rev = "6476e438d002ca70c941f73bc0188a012d891def" }

1
lib/silentdragonlitelib.h

@ -14,6 +14,7 @@ extern char * litelib_initialize_existing (bool dangerous,const char* server);
extern char * litelib_execute (const char* s, const char* args);
extern void litelib_rust_free_string (char* s);
extern char * blake3_PW (char* pw);
extern bool litelib_check_server_online (const char* server);
#ifdef __cplusplus
}

104
lib/src/lib.rs

@ -6,6 +6,7 @@ use libc::{c_char};
use std::ffi::{CStr, CString};
use std::sync::{Mutex, Arc};
use std::cell::RefCell;
use std::ptr;
use silentdragonlitelib::{commands, lightclient::{LightClient, LightClientConfig}};
@ -43,16 +44,15 @@ pub extern fn blake3_PW(pw: *const c_char) -> *mut c_char{
};
let data = passwd.as_bytes();
// Hash an input all at once.
let hash1 = blake3::hash(data).to_hex();
println!("\nBlake3 Hash: {}", hash1);
//let sttring = CString::new(hash1).unwrap();
let e_str = CString::new(format!("{}", hash1)).unwrap();
return e_str.into_raw();
// Hash an input all at once.
let hash1 = blake3::hash(data).to_hex();
// This is sensitive metadata, do not log it to stdout
//println!("\nBlake3 Hash: {}", hash1);
println!("\nBlake3 Hash calculated");
//let sttring = CString::new(hash1).unwrap();
let e_str = CString::new(format!("{}", hash1)).unwrap();
return e_str.into_raw();
}
/// Create a new wallet and return the seed for the newly created wallet.
@ -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();
@ -101,33 +109,43 @@ pub extern fn litelib_initialize_new(dangerous: bool,server: *const c_char) -> *
/// Restore a wallet from the seed phrase
#[no_mangle]
pub extern fn litelib_initialize_new_from_phrase(dangerous: bool,server: *const c_char,
pub extern "C" fn litelib_initialize_new_from_phrase(dangerous: bool, server: *const c_char,
seed: *const c_char, birthday: u64, number: u64, overwrite: bool) -> *mut c_char {
let server_str = unsafe {
assert!(!server.is_null());
if server.is_null() || seed.is_null() {
println!("Server or seed is null");
return ptr::null_mut();
}
let server_str = unsafe {
CStr::from_ptr(server).to_string_lossy().into_owned()
};
let seed_str = unsafe {
assert!(!seed.is_null());
CStr::from_ptr(seed).to_string_lossy().into_owned()
};
//println!("Initializing with server: {}, seed: {}", server_str, seed_str);
let server = LightClientConfig::get_server_or_default(Some(server_str));
let (config, _latest_block_height) = match LightClientConfig::create(server,dangerous) {
Ok((c, h)) => (c, h),
let (config, _latest_block_height) = match LightClientConfig::create(server, dangerous) {
Ok((c, h)) => {
println!("Config created successfully");
(c, h)
},
Err(e) => {
let e_str = CString::new(format!("Error: {}", e)).unwrap();
println!("Error creating config: {}", e);
let e_str = CString::new(format!("Error: {}", e)).unwrap_or_else(|_| CString::new("Error creating CString").unwrap());
return e_str.into_raw();
}
};
let lightclient = match LightClient::new_from_phrase(seed_str, &config, birthday, number, overwrite) {
Ok(l) => l,
Ok(l) => {
println!("LightClient created successfully");
l
},
Err(e) => {
let e_str = CString::new(format!("Error: {}", e)).unwrap();
println!("Error creating LightClient: {}", e);
let e_str = CString::new(format!("Error: {}", e)).unwrap_or_else(|_| CString::new("Error creating CString").unwrap());
return e_str.into_raw();
}
};
@ -135,9 +153,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 c_str = CString::new("OK").unwrap();
let lc = Arc::new(lightclient);
match LightClient::start_mempool_monitor(lc.clone()) {
Ok(_) => println!("Starting Mempool"),
Err(e) => println!("Could not start mempool: {}", e)
}
LIGHTCLIENT.lock().unwrap().replace(Some(lc));
let c_str = CString::new("OK").unwrap_or_else(|_| CString::new("CString creation failed").unwrap());
return c_str.into_raw();
}
@ -169,8 +193,16 @@ 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();
@ -213,6 +245,24 @@ pub extern fn litelib_execute(cmd: *const c_char, args: *const c_char) -> *mut c
return c_str.into_raw();
}
// Check is Server Connection is fine
#[no_mangle]
pub extern "C" fn litelib_check_server_online(server: *const c_char) -> bool {
let server_str = unsafe {
assert!(!server.is_null());
CStr::from_ptr(server).to_string_lossy().into_owned()
};
let server = LightClientConfig::get_server_or_default(Some(server_str));
let result = LightClientConfig::create(server, false);
match result {
Ok(_) => true,
Err(_) => false,
}
}
/**
* Callers that receive string return values from other functions should call this to return the string
* back to rust, so it can be freed. Failure to call this function will result in a memory leak
@ -223,4 +273,4 @@ pub extern fn litelib_rust_free_string(s: *mut c_char) {
if s.is_null() { return }
CString::from_raw(s)
};
}
}

2
peda-session-SilentDragonLite.txt

@ -1,2 +0,0 @@
break FileSystem::readContactsOldFormat

BIN
res/Anonymous.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

BIN
res/Berg.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 68 KiB

BIN
res/Elsa.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 92 KiB

BIN
res/Garfield.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 106 KiB

BIN
res/Mickey.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 57 KiB

BIN
res/Pinguin.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 52 KiB

BIN
res/Popey.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 38 KiB

BIN
res/Snoopy.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 45 KiB

BIN
res/Stag.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 140 KiB

BIN
res/Yoda.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 82 KiB

2
res/css/Dark.css

@ -1,5 +1,5 @@
QWidget, QMainWindow, QMenuBar, QMenu, QDialog, QTabWidget, QTableView, QTableView::item, QScrollArea, QGroupBox, QPlainTextEdit, QLineEdit, QLabel, MainWindow, ChatModel, requestDialog
QWidget, QMainWindow, QMenuBar, QMenu, QDialog, QTabWidget, QTableView, QScrollArea, QGroupBox, QPlainTextEdit, QLineEdit, QLabel, MainWindow
{
background-color: #303335;
color: #ffffff;

2
res/css/Light.css

@ -1,4 +1,4 @@
QWidget, QMainWindow, QMenuBar, QMenu, QDialog, QTabWidget, QTableView, QTableView::item, QScrollArea, QGroupBox, QWidget, QPlainTextEdit, QLineEdit, QLabel, MainWindow
QWidget, QMainWindow, QMenuBar, QMenu, QDialog, QTabWidget, QTableView, QScrollArea, QGroupBox, QWidget, QPlainTextEdit, QLineEdit, QLabel, MainWindow
{
background-color: #dadada;
color: #000000;

21
res/css/Midnight.css

@ -9,7 +9,7 @@ Website: https://www.csharpe.me
License: https://opensource.org/licenses/MIT
*/
QWidget, QMainWindow, QMenuBar, QMenu, QDialog, QTabWidget, QTableView, QTableView::item, QScrollArea, QGroupBox, QPlainTextEdit, QLineEdit, QLabel, MainWindow
QWidget, QMainWindow, QMenuBar, QMenu, QDialog, QTabWidget, QTableView, QScrollArea, QGroupBox, QPlainTextEdit, QLineEdit, QLabel, MainWindow, QPixmap, QHBoxLayout, QVBoxLayout, QGridLayout, QAbstractItemView, QFrame
{
background-color: #111;
color: #fff;
@ -23,6 +23,7 @@ QPushButton:hover {
background: #222;
}
/*
QLineEdit, QRadioButton::indicator::unchecked, QCheckBox::indicator::unchecked {
background: #222;
border: 1px solid #333;
@ -35,19 +36,24 @@ font-size: 12px;
QLineEdit:focus {
border: 1px solid #9d8400;
}
}*/
/*
QWidget QLabel {
font-size: 11pt;
}
*/
QWidget QCheckBox {
font-weight: bold;
}
QTabWidget QTabBar::tab {
min-height: 15px;
padding: 15px 25px;
/*min-height: 15px;*/
padding-left:20px;
padding-right:20px;
padding-top:5px;
padding-bottom:5px;
border: 1px ridge #222;
left: 1px; /* Fix 1px alignment */
background-color:qlineargradient(x1: 0, y1: 0, x2: 0, y2: 0.25, stop: 0 #333, stop: 1 #111);
@ -62,6 +68,7 @@ border-bottom: 0px; /* Overwrites border-bottom */
QTabWidget QTabBar::tab:hover {
background-color:qlineargradient(x1: 0, y1: 0, x2: 0, y2: 0.25, stop: 0 #555, stop: 1 #111);
min-height: 20px
}
QHeaderView { /* Table Header */
@ -74,7 +81,7 @@ background-color:qlineargradient(x1: 0, y1: 0, x2: 0, y2: 0.25, stop: 0 #333, st
color:#fff;
min-height:25px;
font-weight:bold;
font-size:12px;
font-size:11px;
outline:0;
border:1px ridge #222;
padding: 2px 5px;
@ -112,8 +119,8 @@ color: #fff;
QMenuBar::item {
background-color:qlineargradient(x1: 0, y1: 0, x2: 0, y2: 0.25, stop: 0 #222, stop: 1 #111);
color: #fff;
padding: 5px 7px;
margin: 0px;
/*padding: 5px 7px;
margin: 0px;*/
}
QMenuBar::item:selected {

114
res/css/dragonx.css

@ -0,0 +1,114 @@
QWidget, QMainWindow, QMenuBar, QMenu, QDialog, QTabWidget, QTableView, QScrollArea, QGroupBox, QPlainTextEdit, QLineEdit, QLabel, MainWindow {
background-color: #232834;
color: #91a4b8;
}
QTabWidget QTabBar::tab {
padding-left:20px;
padding-right:20px;
padding-top:5px;
padding-bottom:5px;
border: 1px solid #343F4B;
background-color:qlineargradient(x1: 0, y1: 0, x2: 0, y2: 0.25, stop: 0 #343F4B, stop: 1 #232834);
}
QTabWidget QTabBar::tab:selected {
min-height: 10px;
background-color:qlineargradient(x1: 0, y1: 0, x2: 0, y2: 0.25, stop: 0 #343F4B, stop: 1 #232834);
color:#91a4b8;
border: 1px ridge #91a4b8;
}
QTabWidget QTabBar::tab:hover {
background-color:qlineargradient(x1: 0, y1: 0, x2: 0, y2: 0.25, stop: 0 #343F4B, stop: 1 #232834);
color:#91a4b8;
border: 1px ridge #91a4b8;
min-height: 20px
}
QHeaderView {
/* Table Header */
background-color:#232834;
}
QHeaderView::section {
/* Table Header Sections */
qproperty-alignment:center;
background-color:qlineargradient(x1: 0, y1: 0, x2: 0, y2: 0.25, stop: 0 #343F4B, stop: 1 #232834);
color:#91a4b8;
min-height:25px;
font-weight:bold;
font-size:11px;
outline:0;
border:1px solid #343F4B;
border-right:1px solid #91a4b8;
border-left:1px solid #91a4b8;
padding-left:5px;
padding-right:5px;
padding-top:2px;
padding-bottom:2px;
}
QHeaderView::section:last {
border-right: 0px solid #d7d7d7;
}
QScrollArea {
background:transparent;
border:0px;
}
QTableView {
/* Table - has to be selected as a class otherwise it throws off QCalendarWidget */
background:#232834;
}
QTableView::item {
/* Table Item */
background-color:#232834;
border:1px solid #91a4b8;
font-size:12px;
}
QTableView::item:selected {
/* Table Item Selected */
background-color:#91a4b8;
color:#232834;
}
QMenuBar {
background-color:qlineargradient(x1: 0, y1: 0, x2: 0, y2: 0.25, stop: 0 #343F4B, stop: 1 #232834);
color: #91a4b8;
}
QMenuBar::item {
background-color:qlineargradient(x1: 0, y1: 0, x2: 0, y2: 0.25, stop: 0 #343F4B, stop: 1 #232834);
color: #91a4b8;
}
QMenuBar::item:selected {
background-color:qlineargradient(x1: 0, y1: 0, x2: 0, y2: 0.25, stop: 0 #343F4B, stop: 1 #232834);
}
QPushButton#startmining {
background-color: #343F4B;
border-color: #91A4B8;
padding: 10px;
}
QPushButton#startmining:hover {
background-color: #232834;
}
QPushButton#startmining:pressed {
background-color: #232834;
}
QPushButton#startmining:disabled {
background-color: #232834;
}
QPushButton#stopmining {
background-color: #343F4B;
border-color: #91A4B8;
padding: 10px;
margin-top: 7px;
}
QPushButton#stopmining:hover {
background-color: #232834;
}
QPushButton#stopmining:pressed {
background-color: #232834;
}
QPushButton#stopmining:disabled {
background-color: #232834;
}
QComboBox#genproclimit{
font-size: 24px;
height: 40px;
}
QMenu::item:selected{
background-color: #343F4B
}

BIN
res/darkwing.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 174 KiB

BIN
res/fekt.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 87 KiB

BIN
res/hushdlogo.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

BIN
res/images/silentdragonlite.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 123 KiB

BIN
res/jahway603.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 43 KiB

BIN
res/liblibsodium.a

Binary file not shown.

BIN
res/libsodium.lib

Binary file not shown.

50
res/libsodium/buildlibsodium.sh

@ -1,32 +1,74 @@
#!/bin/bash
# Copyright 2019-2024 The Hush developers
# Released under the GPLv3
VERSION=1.0.18
# First thing to do is see if libsodium.a exists in the res folder. If it does, then there's nothing to do
if [ -f res/libsodium.a ]; then
echo "libsodium $VERSION is already built! Nothing to do"
exit 0
fi
echo "Building libsodium"
echo "Building libsodium $VERSION"
if ! command -v curl &> /dev/null
then
echo "curl could not be found. Please install it and try again."
exit 1
fi
# Go into the lib sodium directory
cd res/libsodium
if [ ! -f libsodium-1.0.18.tar.gz ]; then
curl -LO https://github.com/MyHush/libsodium/releases/download/1.0.18/libsodium-1.0.18.tar.gz
echo "Downloading libsodium $VERSION"
curl -L https://git.hush.is/attachments/0d9f589e-a9f9-4ddb-acaa-0f1b423b32eb -o libsodium-1.0.18.tar.gz
fi
if [ ! -f libsodium-1.0.18.tar.gz ]; then
echo "Unable to download libsodium $VERSION !!! Aborting"
exit 1
fi
# Sha256 checksum for ibsodium-1.0.18.tar.gz
EXPECTED_CHECKSUM="6f504490b342a4f8a4c4a02fc9b866cbef8622d5df4e5452b46be121e46636c1"
# Check if the checksum matchs
echo "Checking SHA256 Checksum for libsodium $VERSION"
ACTUAL_CHECKSUM=$(sha256sum libsodium-1.0.18.tar.gz | awk '{ print $1 }')
if [ "$EXPECTED_CHECKSUM" != "$ACTUAL_CHECKSUM" ]; then
echo "Error: The checksum of libsodium does not match the expected checksum. "
exit 1
fi
if [ ! -d libsodium-1.0.18 ]; then
echo "Unpacking libsodium $VERSION"
tar xf libsodium-1.0.18.tar.gz
fi
if [ ! -d libsodium-1.0.18 ]; then
echo "Unable to unpack libsodium $VERSION !!! Aborting"
exit 1
fi
# Now build it
cd libsodium-1.0.18
echo "Configuring libsodium $VERSION"
LIBS="" ./configure
make clean
echo "Compiling libsodium $VERSION"
if [[ "$OSTYPE" == "darwin"* ]]; then
make CFLAGS="-mmacosx-version-min=10.11" CPPFLAGS="-mmacosx-version-min=10.11" -j4
make CFLAGS="-mmacosx-version-min=10.11" CPPFLAGS="-mmacosx-version-min=10.11" -j8 # "$@"
else
make -j8
make -j8 # "$@"
fi
cd ..
if [ ! -e libsodium-1.0.18/src/libsodium/.libs/libsodium.a ]; then
echo "Unable to compile libsodium $VERSION !!! Aborting"
exit 1
fi
# copy the library to the parents's res/ folder
cp libsodium-1.0.18/src/libsodium/.libs/libsodium.a ../

BIN
res/libsodiumd.lib

Binary file not shown.

BIN
res/lock_closed.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

BIN
res/lock_open.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

BIN
res/logobig.gif

Binary file not shown.

Before

Width:  |  Height:  |  Size: 18 KiB

After

Width:  |  Height:  |  Size: 8.3 KiB

BIN
res/onryo.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 119 KiB

BIN
res/remove.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

BIN
res/send.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.1 KiB

After

Width:  |  Height:  |  Size: 1.7 KiB

BIN
res/silentdragonlite-animated-startup-dark.gif

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.0 MiB

After

Width:  |  Height:  |  Size: 902 KiB

BIN
res/silentdragonlite_ar.qm

Binary file not shown.

1008
res/silentdragonlite_ar.ts

File diff suppressed because it is too large

BIN
res/silentdragonlite_be.qm

Binary file not shown.

2849
res/silentdragonlite_be.ts

File diff suppressed because it is too large

BIN
res/silentdragonlite_de.qm

Binary file not shown.

969
res/silentdragonlite_de.ts

File diff suppressed because it is too large

BIN
res/silentdragonlite_es.qm

Binary file not shown.

1021
res/silentdragonlite_es.ts

File diff suppressed because it is too large

BIN
res/silentdragonlite_fa.qm

Binary file not shown.

971
res/silentdragonlite_fa.ts

File diff suppressed because it is too large

BIN
res/silentdragonlite_fr.qm

Binary file not shown.

989
res/silentdragonlite_fr.ts

File diff suppressed because it is too large

BIN
res/silentdragonlite_hr.qm

Binary file not shown.

973
res/silentdragonlite_hr.ts

File diff suppressed because it is too large

BIN
res/silentdragonlite_id.qm

Binary file not shown.

52
res/silentdragonlite_id.ts

@ -98,29 +98,29 @@
<context>
<name>Controller</name>
<message>
<location filename="../src/controller.cpp" line="1500"/>
<location filename="../src/controller.cpp" line="1479"/>
<source>Wallet Password</source>
<translation>Password Alamat</translation>
</message>
<message>
<location filename="../src/controller.cpp" line="1501"/>
<location filename="../src/controller.cpp" line="1480"/>
<source>Your wallet is encrypted.
Please enter your wallet password</source>
<translation>Wallet Anda terkunci. Mohon masukkan Password Alamat Anda</translation>
</message>
<message>
<location filename="../src/controller.cpp" line="1509"/>
<location filename="../src/controller.cpp" line="1529"/>
<location filename="../src/controller.cpp" line="1488"/>
<location filename="../src/controller.cpp" line="1508"/>
<source>Wallet Decryption Failed</source>
<translation>Gagal Mengdeskripsi Dompet</translation>
</message>
<message>
<location filename="../src/controller.cpp" line="1510"/>
<location filename="../src/controller.cpp" line="1489"/>
<source>Please enter a valid password</source>
<translation>Mohon Masukkan Password yang benar</translation>
</message>
<message>
<location filename="../src/controller.cpp" line="1599"/>
<location filename="../src/controller.cpp" line="1578"/>
<source>Failed to unlock wallet</source>
<translation>Gagal Membuka Dompet</translation>
</message>
@ -739,8 +739,8 @@ p, li { white-space: pre-wrap; }
</message>
<message>
<location filename="../src/mainwindow.ui" line="1957"/>
<source>&amp;Hush Discord</source>
<translation>&amp;Hush Discord</translation>
<source>&amp;Hush Telegram</source>
<translation>&amp;Hush Telegram</translation>
</message>
<message>
<location filename="../src/mainwindow.ui" line="1962"/>
@ -825,7 +825,7 @@ p, li { white-space: pre-wrap; }
</message>
<message>
<location filename="../src/mainwindow.ui" line="2038"/>
<source>Import Privatkey</source>
<source>Import Private Key</source>
<translation type="unfinished"></translation>
</message>
<message>
@ -1659,7 +1659,7 @@ Note: Dana membutuhkan 5 konfirmasi sebelum mereka bisa digunakan</translation>
</message>
<message>
<location filename="../src/connection.cpp" line="303"/>
<location filename="../src/controller.cpp" line="615"/>
<location filename="../src/controller.cpp" line="594"/>
<source>Connection Error</source>
<translation>Koneksi error</translation>
</message>
@ -1667,7 +1667,7 @@ Note: Dana membutuhkan 5 konfirmasi sebelum mereka bisa digunakan</translation>
<location filename="../src/chatmodel.cpp" line="666"/>
<location filename="../src/chatmodel.cpp" line="1004"/>
<location filename="../src/connection.cpp" line="416"/>
<location filename="../src/controller.cpp" line="1564"/>
<location filename="../src/controller.cpp" line="1543"/>
<location filename="../src/mainwindow.cpp" line="2069"/>
<location filename="../src/mainwindow.cpp" line="2352"/>
<location filename="../src/sendtab.cpp" line="913"/>
@ -1680,8 +1680,8 @@ Note: Dana membutuhkan 5 konfirmasi sebelum mereka bisa digunakan</translation>
<translation>Ada error dalam mengirim transaksi. Error nya:</translation>
</message>
<message>
<location filename="../src/controller.cpp" line="263"/>
<location filename="../src/controller.cpp" line="265"/>
<location filename="../src/controller.cpp" line="242"/>
<location filename="../src/controller.cpp" line="244"/>
<source>No Connection</source>
<translation>Tidak ada Koneksi</translation>
</message>
@ -1692,7 +1692,7 @@ Note: Dana membutuhkan 5 konfirmasi sebelum mereka bisa digunakan</translation>
<message>
<location filename="../src/chatmodel.cpp" line="660"/>
<location filename="../src/chatmodel.cpp" line="994"/>
<location filename="../src/controller.cpp" line="1556"/>
<location filename="../src/controller.cpp" line="1535"/>
<location filename="../src/mainwindow.cpp" line="2063"/>
<location filename="../src/mainwindow.cpp" line="2347"/>
<location filename="../src/recurring.cpp" line="609"/>
@ -1703,7 +1703,7 @@ Note: Dana membutuhkan 5 konfirmasi sebelum mereka bisa digunakan</translation>
<message>
<location filename="../src/chatmodel.cpp" line="660"/>
<location filename="../src/chatmodel.cpp" line="994"/>
<location filename="../src/controller.cpp" line="1556"/>
<location filename="../src/controller.cpp" line="1535"/>
<location filename="../src/mainwindow.cpp" line="2063"/>
<location filename="../src/mainwindow.cpp" line="2347"/>
<location filename="../src/recurring.cpp" line="609"/>
@ -1714,7 +1714,7 @@ Note: Dana membutuhkan 5 konfirmasi sebelum mereka bisa digunakan</translation>
<message>
<location filename="../src/chatmodel.cpp" line="664"/>
<location filename="../src/chatmodel.cpp" line="1002"/>
<location filename="../src/controller.cpp" line="1560"/>
<location filename="../src/controller.cpp" line="1539"/>
<location filename="../src/mainwindow.cpp" line="2067"/>
<location filename="../src/mainwindow.cpp" line="2350"/>
<location filename="../src/sendtab.cpp" line="904"/>
@ -1724,7 +1724,7 @@ Note: Dana membutuhkan 5 konfirmasi sebelum mereka bisa digunakan</translation>
<message>
<location filename="../src/chatmodel.cpp" line="664"/>
<location filename="../src/chatmodel.cpp" line="1002"/>
<location filename="../src/controller.cpp" line="1560"/>
<location filename="../src/controller.cpp" line="1539"/>
<location filename="../src/mainwindow.cpp" line="2067"/>
<location filename="../src/mainwindow.cpp" line="2350"/>
<location filename="../src/sendtab.cpp" line="904"/>
@ -1732,17 +1732,17 @@ Note: Dana membutuhkan 5 konfirmasi sebelum mereka bisa digunakan</translation>
<translation>Gagal. Error nya:</translation>
</message>
<message>
<location filename="../src/controller.cpp" line="616"/>
<location filename="../src/controller.cpp" line="595"/>
<source>There was an error connecting to the server. Please check your internet connection. The error was</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/controller.cpp" line="1658"/>
<location filename="../src/controller.cpp" line="1637"/>
<source>Update Available</source>
<translation>Pembaruan tersedia</translation>
</message>
<message>
<location filename="../src/controller.cpp" line="1659"/>
<location filename="../src/controller.cpp" line="1638"/>
<source>A new release v%1 is available! You have v%2.
Would you like to visit the releases page?</source>
@ -1751,24 +1751,24 @@ Would you like to visit the releases page?</source>
Maukah anda mengunjungi laman pembaruan ini</translation>
</message>
<message>
<location filename="../src/controller.cpp" line="1678"/>
<location filename="../src/controller.cpp" line="1657"/>
<source>No updates available</source>
<translation>Tidak ada Pembaruan tersedia</translation>
</message>
<message>
<location filename="../src/controller.cpp" line="1679"/>
<location filename="../src/controller.cpp" line="1658"/>
<source>You already have the latest release v%1</source>
<translation>Anda sudah memiliki Versi terbaru dari v%1</translation>
</message>
<message>
<location filename="../src/controller.cpp" line="2063"/>
<location filename="../src/controller.cpp" line="2071"/>
<location filename="../src/controller.cpp" line="2042"/>
<location filename="../src/controller.cpp" line="2050"/>
<source>Please wait for SilentDragonLite to exit</source>
<translation>Mohon tunggu untuk SilentDragonLite untuk keluar</translation>
</message>
<message>
<location filename="../src/controller.cpp" line="2064"/>
<location filename="../src/controller.cpp" line="2072"/>
<location filename="../src/controller.cpp" line="2043"/>
<location filename="../src/controller.cpp" line="2051"/>
<source>Waiting for hushd to exit</source>
<translation>Menunggu untuk hushd untuk keluar</translation>
</message>

BIN
res/silentdragonlite_it.qm

Binary file not shown.

1006
res/silentdragonlite_it.ts

File diff suppressed because it is too large

BIN
res/silentdragonlite_nl.qm

Binary file not shown.

2843
res/silentdragonlite_nl.ts

File diff suppressed because it is too large

BIN
res/silentdragonlite_pl.qm

Binary file not shown.

2850
res/silentdragonlite_pl.ts

File diff suppressed because it is too large

BIN
res/silentdragonlite_pt.qm

Binary file not shown.

989
res/silentdragonlite_pt.ts

File diff suppressed because it is too large

BIN
res/silentdragonlite_ro.qm

Binary file not shown.

52
res/silentdragonlite_ro.ts

@ -98,29 +98,29 @@
<context>
<name>Controller</name>
<message>
<location filename="../src/controller.cpp" line="1500"/>
<location filename="../src/controller.cpp" line="1479"/>
<source>Wallet Password</source>
<translation>Parola Portofelului</translation>
</message>
<message>
<location filename="../src/controller.cpp" line="1501"/>
<location filename="../src/controller.cpp" line="1480"/>
<source>Your wallet is encrypted.
Please enter your wallet password</source>
<translation>Portofelul Dvs. este criptat</translation>
</message>
<message>
<location filename="../src/controller.cpp" line="1509"/>
<location filename="../src/controller.cpp" line="1529"/>
<location filename="../src/controller.cpp" line="1488"/>
<location filename="../src/controller.cpp" line="1508"/>
<source>Wallet Decryption Failed</source>
<translation>Decriptarea Portofelului a Esuat</translation>
</message>
<message>
<location filename="../src/controller.cpp" line="1510"/>
<location filename="../src/controller.cpp" line="1489"/>
<source>Please enter a valid password</source>
<translation>Rugam sa introduceti parola valida</translation>
</message>
<message>
<location filename="../src/controller.cpp" line="1599"/>
<location filename="../src/controller.cpp" line="1578"/>
<source>Failed to unlock wallet</source>
<translation>Deblocarea portofelului a esuat</translation>
</message>
@ -739,8 +739,8 @@ p, li { white-space: pre-wrap; }
</message>
<message>
<location filename="../src/mainwindow.ui" line="1957"/>
<source>&amp;Hush Discord</source>
<translation>Hush Discord</translation>
<source>&amp;Hush Telegram</source>
<translation>Hush Telegram</translation>
</message>
<message>
<location filename="../src/mainwindow.ui" line="1962"/>
@ -825,7 +825,7 @@ p, li { white-space: pre-wrap; }
</message>
<message>
<location filename="../src/mainwindow.ui" line="2038"/>
<source>Import Privatkey</source>
<source>Import Private Key</source>
<translation type="unfinished"></translation>
</message>
<message>
@ -1652,7 +1652,7 @@ Nota: Fondurile au nevoie de 5 confirmatii inainte ca sa fiu transmise</translat
</message>
<message>
<location filename="../src/connection.cpp" line="303"/>
<location filename="../src/controller.cpp" line="615"/>
<location filename="../src/controller.cpp" line="594"/>
<source>Connection Error</source>
<translation>Eroare la Conexiune</translation>
</message>
@ -1660,7 +1660,7 @@ Nota: Fondurile au nevoie de 5 confirmatii inainte ca sa fiu transmise</translat
<location filename="../src/chatmodel.cpp" line="666"/>
<location filename="../src/chatmodel.cpp" line="1004"/>
<location filename="../src/connection.cpp" line="416"/>
<location filename="../src/controller.cpp" line="1564"/>
<location filename="../src/controller.cpp" line="1543"/>
<location filename="../src/mainwindow.cpp" line="2069"/>
<location filename="../src/mainwindow.cpp" line="2352"/>
<location filename="../src/sendtab.cpp" line="913"/>
@ -1673,8 +1673,8 @@ Nota: Fondurile au nevoie de 5 confirmatii inainte ca sa fiu transmise</translat
<translation>A avut loc eroarea la transmiterea tranzactiei. Eroarea a fost de tip:</translation>
</message>
<message>
<location filename="../src/controller.cpp" line="263"/>
<location filename="../src/controller.cpp" line="265"/>
<location filename="../src/controller.cpp" line="242"/>
<location filename="../src/controller.cpp" line="244"/>
<source>No Connection</source>
<translation>Conexiunea nu exista</translation>
</message>
@ -1685,7 +1685,7 @@ Nota: Fondurile au nevoie de 5 confirmatii inainte ca sa fiu transmise</translat
<message>
<location filename="../src/chatmodel.cpp" line="660"/>
<location filename="../src/chatmodel.cpp" line="994"/>
<location filename="../src/controller.cpp" line="1556"/>
<location filename="../src/controller.cpp" line="1535"/>
<location filename="../src/mainwindow.cpp" line="2063"/>
<location filename="../src/mainwindow.cpp" line="2347"/>
<location filename="../src/recurring.cpp" line="609"/>
@ -1696,7 +1696,7 @@ Nota: Fondurile au nevoie de 5 confirmatii inainte ca sa fiu transmise</translat
<message>
<location filename="../src/chatmodel.cpp" line="660"/>
<location filename="../src/chatmodel.cpp" line="994"/>
<location filename="../src/controller.cpp" line="1556"/>
<location filename="../src/controller.cpp" line="1535"/>
<location filename="../src/mainwindow.cpp" line="2063"/>
<location filename="../src/mainwindow.cpp" line="2347"/>
<location filename="../src/recurring.cpp" line="609"/>
@ -1707,7 +1707,7 @@ Nota: Fondurile au nevoie de 5 confirmatii inainte ca sa fiu transmise</translat
<message>
<location filename="../src/chatmodel.cpp" line="664"/>
<location filename="../src/chatmodel.cpp" line="1002"/>
<location filename="../src/controller.cpp" line="1560"/>
<location filename="../src/controller.cpp" line="1539"/>
<location filename="../src/mainwindow.cpp" line="2067"/>
<location filename="../src/mainwindow.cpp" line="2350"/>
<location filename="../src/sendtab.cpp" line="904"/>
@ -1717,7 +1717,7 @@ Nota: Fondurile au nevoie de 5 confirmatii inainte ca sa fiu transmise</translat
<message>
<location filename="../src/chatmodel.cpp" line="664"/>
<location filename="../src/chatmodel.cpp" line="1002"/>
<location filename="../src/controller.cpp" line="1560"/>
<location filename="../src/controller.cpp" line="1539"/>
<location filename="../src/mainwindow.cpp" line="2067"/>
<location filename="../src/mainwindow.cpp" line="2350"/>
<location filename="../src/sendtab.cpp" line="904"/>
@ -1725,17 +1725,17 @@ Nota: Fondurile au nevoie de 5 confirmatii inainte ca sa fiu transmise</translat
<translation>a esuat. Eroarea a fost</translation>
</message>
<message>
<location filename="../src/controller.cpp" line="616"/>
<location filename="../src/controller.cpp" line="595"/>
<source>There was an error connecting to the server. Please check your internet connection. The error was</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/controller.cpp" line="1658"/>
<location filename="../src/controller.cpp" line="1637"/>
<source>Update Available</source>
<translation>Update Valabil </translation>
</message>
<message>
<location filename="../src/controller.cpp" line="1659"/>
<location filename="../src/controller.cpp" line="1638"/>
<source>A new release v%1 is available! You have v%2.
Would you like to visit the releases page?</source>
@ -1743,24 +1743,24 @@ Would you like to visit the releases page?</source>
Doriti sa vizitati pagina veriunii?</translation>
</message>
<message>
<location filename="../src/controller.cpp" line="1678"/>
<location filename="../src/controller.cpp" line="1657"/>
<source>No updates available</source>
<translation>Update nu este valabil</translation>
</message>
<message>
<location filename="../src/controller.cpp" line="1679"/>
<location filename="../src/controller.cpp" line="1658"/>
<source>You already have the latest release v%1</source>
<translation>Deja aveti cea mai recenta versiune v%1</translation>
</message>
<message>
<location filename="../src/controller.cpp" line="2063"/>
<location filename="../src/controller.cpp" line="2071"/>
<location filename="../src/controller.cpp" line="2042"/>
<location filename="../src/controller.cpp" line="2050"/>
<source>Please wait for SilentDragonLite to exit</source>
<translation>Rugam sa asteptati pina ce SilentDragonLite sa o sa iasa</translation>
</message>
<message>
<location filename="../src/controller.cpp" line="2064"/>
<location filename="../src/controller.cpp" line="2072"/>
<location filename="../src/controller.cpp" line="2043"/>
<location filename="../src/controller.cpp" line="2051"/>
<source>Waiting for hushd to exit</source>
<translation>Asteptam ca hushd sa iasa</translation>
</message>

BIN
res/silentdragonlite_ru.qm

Binary file not shown.

2849
res/silentdragonlite_ru.ts

File diff suppressed because it is too large

BIN
res/silentdragonlite_sr.qm

Binary file not shown.

973
res/silentdragonlite_sr.ts

File diff suppressed because it is too large

2
res/silentdragonlite_template.ts

@ -468,7 +468,7 @@ Please enter your wallet password</source>
</message>
<message>
<location filename="../src/mainwindow.ui" line="1415"/>
<source>&amp;Hush Discord</source>
<source>&amp;Hush Telegram</source>
<translation type="unfinished"></translation>
</message>
<message>

BIN
res/silentdragonlite_tr.qm

Binary file not shown.

987
res/silentdragonlite_tr.ts

File diff suppressed because it is too large

BIN
res/silentdragonlite_ud.qm

Binary file not shown.

50
res/silentdragonlite_ud.ts

@ -102,29 +102,29 @@
<context>
<name>Controller</name>
<message>
<location filename="../src/controller.cpp" line="1500"/>
<location filename="../src/controller.cpp" line="1479"/>
<source>Wallet Password</source>
<translation>ولیٹ پاسورڈ</translation>
</message>
<message>
<location filename="../src/controller.cpp" line="1501"/>
<location filename="../src/controller.cpp" line="1480"/>
<source>Your wallet is encrypted.
Please enter your wallet password</source>
<translation>آپ کا ولیٹ انکرائپٹیڈ ھے۔ برائے مہربانی اپنا پاسورڈ ڈالیں</translation>
</message>
<message>
<location filename="../src/controller.cpp" line="1509"/>
<location filename="../src/controller.cpp" line="1529"/>
<location filename="../src/controller.cpp" line="1488"/>
<location filename="../src/controller.cpp" line="1508"/>
<source>Wallet Decryption Failed</source>
<translation>ویلٹ ڈیکرئپشن فیل ھو گئی ہے</translation>
</message>
<message>
<location filename="../src/controller.cpp" line="1510"/>
<location filename="../src/controller.cpp" line="1489"/>
<source>Please enter a valid password</source>
<translation>اپنا ویلڈ پاسورڈ ڈالیں</translation>
</message>
<message>
<location filename="../src/controller.cpp" line="1599"/>
<location filename="../src/controller.cpp" line="1578"/>
<source>Failed to unlock wallet</source>
<translation>ویلٹ نہں کھلا فیلڈ</translation>
</message>
@ -743,7 +743,7 @@ p, li { white-space: pre-wrap; }
</message>
<message>
<location filename="../src/mainwindow.ui" line="1957"/>
<source>&amp;Hush Discord</source>
<source>&amp;Hush Telegram</source>
<translation>ھش ڈسکارڈ</translation>
</message>
<message>
@ -829,7 +829,7 @@ p, li { white-space: pre-wrap; }
</message>
<message>
<location filename="../src/mainwindow.ui" line="2038"/>
<source>Import Privatkey</source>
<source>Import Private Key</source>
<translation type="unfinished"></translation>
</message>
<message>
@ -1661,7 +1661,7 @@ Note: Funds need 5 confirmations before they can be spent</source>
</message>
<message>
<location filename="../src/connection.cpp" line="303"/>
<location filename="../src/controller.cpp" line="615"/>
<location filename="../src/controller.cpp" line="594"/>
<source>Connection Error</source>
<translation>کنیکشن عرر</translation>
</message>
@ -1675,8 +1675,8 @@ Note: Funds need 5 confirmations before they can be spent</source>
<translation>ٹرانزیکشن بھیجنے میں غلطی تھی۔ غلطی یہ تھی</translation>
</message>
<message>
<location filename="../src/controller.cpp" line="263"/>
<location filename="../src/controller.cpp" line="265"/>
<location filename="../src/controller.cpp" line="242"/>
<location filename="../src/controller.cpp" line="244"/>
<source>No Connection</source>
<translation>کنیکشن نہیں ھے</translation>
</message>
@ -1687,7 +1687,7 @@ Note: Funds need 5 confirmations before they can be spent</source>
<message>
<location filename="../src/chatmodel.cpp" line="660"/>
<location filename="../src/chatmodel.cpp" line="994"/>
<location filename="../src/controller.cpp" line="1556"/>
<location filename="../src/controller.cpp" line="1535"/>
<location filename="../src/mainwindow.cpp" line="2063"/>
<location filename="../src/mainwindow.cpp" line="2347"/>
<location filename="../src/recurring.cpp" line="609"/>
@ -1698,7 +1698,7 @@ Note: Funds need 5 confirmations before they can be spent</source>
<message>
<location filename="../src/chatmodel.cpp" line="660"/>
<location filename="../src/chatmodel.cpp" line="994"/>
<location filename="../src/controller.cpp" line="1556"/>
<location filename="../src/controller.cpp" line="1535"/>
<location filename="../src/mainwindow.cpp" line="2063"/>
<location filename="../src/mainwindow.cpp" line="2347"/>
<location filename="../src/recurring.cpp" line="609"/>
@ -1709,7 +1709,7 @@ Note: Funds need 5 confirmations before they can be spent</source>
<message>
<location filename="../src/chatmodel.cpp" line="664"/>
<location filename="../src/chatmodel.cpp" line="1002"/>
<location filename="../src/controller.cpp" line="1560"/>
<location filename="../src/controller.cpp" line="1539"/>
<location filename="../src/mainwindow.cpp" line="2067"/>
<location filename="../src/mainwindow.cpp" line="2350"/>
<location filename="../src/sendtab.cpp" line="904"/>
@ -1719,7 +1719,7 @@ Note: Funds need 5 confirmations before they can be spent</source>
<message>
<location filename="../src/chatmodel.cpp" line="664"/>
<location filename="../src/chatmodel.cpp" line="1002"/>
<location filename="../src/controller.cpp" line="1560"/>
<location filename="../src/controller.cpp" line="1539"/>
<location filename="../src/mainwindow.cpp" line="2067"/>
<location filename="../src/mainwindow.cpp" line="2350"/>
<location filename="../src/sendtab.cpp" line="904"/>
@ -1730,7 +1730,7 @@ Note: Funds need 5 confirmations before they can be spent</source>
<location filename="../src/chatmodel.cpp" line="666"/>
<location filename="../src/chatmodel.cpp" line="1004"/>
<location filename="../src/connection.cpp" line="416"/>
<location filename="../src/controller.cpp" line="1564"/>
<location filename="../src/controller.cpp" line="1543"/>
<location filename="../src/mainwindow.cpp" line="2069"/>
<location filename="../src/mainwindow.cpp" line="2352"/>
<location filename="../src/sendtab.cpp" line="913"/>
@ -1738,17 +1738,17 @@ Note: Funds need 5 confirmations before they can be spent</source>
<translation type="unfinished">ٹرانزیکشنس عرر</translation>
</message>
<message>
<location filename="../src/controller.cpp" line="616"/>
<location filename="../src/controller.cpp" line="595"/>
<source>There was an error connecting to the server. Please check your internet connection. The error was</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/controller.cpp" line="1658"/>
<location filename="../src/controller.cpp" line="1637"/>
<source>Update Available</source>
<translation>اپڈیٹ موجود ہے </translation>
</message>
<message>
<location filename="../src/controller.cpp" line="1659"/>
<location filename="../src/controller.cpp" line="1638"/>
<source>A new release v%1 is available! You have v%2.
Would you like to visit the releases page?</source>
@ -1756,12 +1756,12 @@ Would you like to visit the releases page?</source>
کیا آپ ریلیز والے صفحے پر جانا چاہیں گے؟</translation>
</message>
<message>
<location filename="../src/controller.cpp" line="1678"/>
<location filename="../src/controller.cpp" line="1657"/>
<source>No updates available</source>
<translation>کوئی تازہ اپڈیٹ دستیاب نہیں ہے</translation>
</message>
<message>
<location filename="../src/controller.cpp" line="1679"/>
<location filename="../src/controller.cpp" line="1658"/>
<source>You already have the latest release v%1</source>
<translation type="unfinished"></translation>
</message>
@ -1770,14 +1770,14 @@ Would you like to visit the releases page?</source>
<translation type="vanished">Deja aveti cea mai recenta versiune v%1</translation>
</message>
<message>
<location filename="../src/controller.cpp" line="2063"/>
<location filename="../src/controller.cpp" line="2071"/>
<location filename="../src/controller.cpp" line="2042"/>
<location filename="../src/controller.cpp" line="2050"/>
<source>Please wait for SilentDragonLite to exit</source>
<translation> باہر جانے کا انتظار کریں Silent DragonLite براہ کرم</translation>
</message>
<message>
<location filename="../src/controller.cpp" line="2064"/>
<location filename="../src/controller.cpp" line="2072"/>
<location filename="../src/controller.cpp" line="2043"/>
<location filename="../src/controller.cpp" line="2051"/>
<source>Waiting for hushd to exit</source>
<translation>ہش ڈی کے باہر نکلنے کا انتظار کریں</translation>
</message>

BIN
res/silentdragonlite_zh.qm

Binary file not shown.

987
res/silentdragonlite_zh.ts

File diff suppressed because it is too large

BIN
res/synced.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

BIN
res/transaction0.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

BIN
res/transaction2.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

BIN
res/transaction_abandoned.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

BIN
res/transaction_conflicted.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

BIN
res/tx_inout.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

BIN
res/tx_input.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

BIN
res/tx_mined.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

BIN
res/tx_output.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

BIN
res/verify.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

BIN
res/warning.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

BIN
res/wormholeconnect.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 67 KiB

After

Width:  |  Height:  |  Size: 79 KiB

4
run-after-build.sh

@ -0,0 +1,4 @@
#!/bin/bash
# Copyright 2019-2024 The Hush Developers
./build.sh && ./SilentDragonLite

36
silentdragon-lite.pro

@ -3,7 +3,8 @@
# Project created by QtCreator 2018-10-05T09:54:45
#
#-------------------------------------------------
# Copyright 2019-2021 The Hush Developers
# Copyright 2019-2024 The Hush Developers
# Released under the GPLv3
QT += core gui network
@ -12,7 +13,6 @@ CONFIG += precompile_header
PRECOMPILED_HEADER = src/precompiled.h
QT += widgets
QT += websockets
TARGET = SilentDragonLite
TEMPLATE = app
@ -58,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 \
@ -75,6 +73,7 @@ SOURCES += \
src/DataStore/DataStore.cpp \
src/DataStore/ChatDataStore.cpp \
src/DataStore/SietchDataStore.cpp \
src/DataStore/NoteCountDataStore.cpp \
src/DataStore/ContactDataStore.cpp \
src/Model/ChatItem.cpp \
src/Model/ContactRequestChatItem.cpp \
@ -87,6 +86,7 @@ SOURCES += \
src/Crypto/passwd.cpp
HEADERS += \
src/guiconstants.h \
src/firsttimewizard.h \
src/mainwindow.h \
src/precompiled.h \
@ -102,8 +102,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 \
@ -125,7 +123,6 @@ FORMS += \
src/encryption.ui \
src/hushrequest.ui \
src/mainwindow.ui \
src/migration.ui \
src/newseed.ui \
src/newwallet.ui \
src/recurringpayments.ui \
@ -142,7 +139,6 @@ FORMS += \
src/connection.ui \
src/addressbook.ui \
src/memodialog.ui \
src/mobileappconnector.ui \
src/createhushconfdialog.ui \
src/recurringdialog.ui \
src/requestContactDialog.ui \
@ -154,20 +150,24 @@ FORMS += \
src/chatbubblepartner.ui
TRANSLATIONS = res/silentdragonlite_es.ts \
res/silentdragonlite_fr.ts \
TRANSLATIONS = res/silentdragonlite_ar.ts \
res/silentdragonlite_be.ts \
res/silentdragonlite_de.ts \
res/silentdragonlite_pt.ts \
res/silentdragonlite_it.ts \
res/silentdragonlite_zh.ts \
res/silentdragonlite_hr.ts \
res/silentdragonlite_sr.ts \
res/silentdragonlite_es.ts \
res/silentdragonlite_fa.ts \
res/silentdragonlite_fr.ts \
res/silentdragonlite_hr.ts \
res/silentdragonlite_id.ts \
res/silentdragonlite_ar.ts \
res/silentdragonlite_it.ts \
res/silentdragonlite_nl.ts \
res/silentdragonlite_pt.ts \
res/silentdragonlite_pl.ts \
res/silentdragonlite_ro.ts \
res/silentdragonlite_ru.ts \
res/silentdragonlite_sr.ts \
res/silentdragonlite_tr.ts \
res/silentdragonlite_ud.ts \
res/silentdragonlite_tr.ts
res/silentdragonlite_zh.ts
include(singleapplication/singleapplication.pri)
DEFINES += QAPPLICATION_CLASS=QApplication _FORTIFY_SOURCE=2
@ -184,7 +184,7 @@ else: unix:!android: target.path = /opt/$${TARGET}/bin
libsodium.target = $$PWD/res/libsodium.a
libsodium.commands = res/libsodium/buildlibsodium.sh
libsodium.commands = res/libsodium/buildlibsodium.sh "$@"
unix: librust.target = $$PWD/lib/target/release/libsilentdragonlite.a
else:win32: librust.target = $$PWD/lib/target/x86_64-pc-windows-gnu/release/silentdragonlite.lib

2
src/3rdparty/sodium.h

@ -1,4 +1,4 @@
// Copyright 2019-2021 The Hush developers
// Copyright 2019-2024 The Hush developers
// Released under the GPLv3
#ifndef sodium_H

87
src/Chat/Chat.cpp

@ -1,5 +1,5 @@
// Copyright 2019-2021 The Hush developers
// GPLv3
// Copyright 2019-2024 The Hush developers
// Released under the GPLv3
#include "Chat.h"
#include "../addressbook.h"
@ -22,8 +22,7 @@ void ChatMemoEdit::updateDisplayChat() {
if (lenDisplayLabelchat)
lenDisplayLabelchat->setStyleSheet("");
}
else {
} else {
// Overweight
if (sendChatButton)
sendChatButton->setEnabled(false);
@ -50,6 +49,8 @@ ChatMemoEditRequest::ChatMemoEditRequest(QWidget* parent) : QTextEdit(parent) {
QObject::connect(this, &QTextEdit::textChanged, this, &ChatMemoEditRequest::updateDisplayChatRequest);
}
// TODO: unify this with updateDisplayChat()
void ChatMemoEditRequest::updateDisplayChatRequest() {
QString txt = this->toPlainText();
if (lenDisplayLabelchatRequest)
@ -62,8 +63,7 @@ void ChatMemoEditRequest::updateDisplayChatRequest() {
if (lenDisplayLabelchatRequest)
lenDisplayLabelchatRequest->setStyleSheet("");
}
else {
} else {
// Overweight
if (sendRequestButton)
sendRequestButton->setEnabled(false);
@ -85,59 +85,68 @@ void ChatMemoEditRequest::SetSendRequestButton(QPushButton* button) {
void ChatMemoEditRequest::setLenDisplayLabelChatRequest(QLabel* label) {
this->lenDisplayLabelchatRequest = label;
}
void Chat::renderChatBox(Ui::MainWindow *ui, QListView *view, QLabel *label)
{
QStandardItemModel *chat = new QStandardItemModel();
DataStore::getChatDataStore()->dump(); // test to see if the chat items in datastore are correctly dumped to json
for (auto &p : AddressBook::getInstance()->getAllAddressLabels())
{
for (auto &c : DataStore::getChatDataStore()->getAllMemos())
{
std::map<QString,int> seenTxids;
if (
(p.getName() == ui->contactNameMemo->text().trimmed()) &&
(p.getPartnerAddress() == c.second.getAddress()) &&
(c.second.isOutgoing() == true))
{
//qDebug() << __func__ << ": looking at memos...";
for (auto &contact : AddressBook::getInstance()->getAllAddressLabels())
{
for (auto &memo : DataStore::getChatDataStore()->getAllMemos()) {
if ( (contact.getName() == ui->contactNameMemo->text().trimmed()) &&
(contact.getPartnerAddress() == memo.second.getAddress()) &&
(memo.second.isOutgoing() == true)) {
QStandardItem *Items = new QStandardItem(c.second.toChatLine());
QStandardItem *Items = new QStandardItem(memo.second.toChatLine());
Items->setData(OUTGOING, Qt::UserRole + 1);
// qDebug() << __func__ << ": appending row to OUTGOING chatitems to contact " << contact.getName() << " with item " << Items;
chat->appendRow(Items);
ui->listChat->setModel(chat);
}
else
{
} else {
ui->listChat->setModel(chat);
}
if (
(p.getName() == ui->contactNameMemo->text().trimmed()) &&
(p.getMyAddress() == c.second.getAddress()) &&
(c.second.isOutgoing() == false) &&
(c.second.getCid() == p.getCid())
)
{
QStandardItem *Items1 = new QStandardItem(c.second.toChatLine());
// qDebug() << __func__ << ": memo.first=" << memo.first;
if ( (contact.getName() == ui->contactNameMemo->text().trimmed()) &&
(contact.getMyAddress() == memo.second.getAddress()) &&
(memo.second.isOutgoing() == false) &&
(memo.second.getCid() == contact.getCid())
) {
QStandardItem *Items1 = new QStandardItem(memo.second.toChatLine());
Items1->setData(INCOMING, Qt::UserRole + 1);
chat->appendRow(Items1);
ui->listChat->setModel(chat);
ui->memoTxtChat->setEnabled(true);
ui->emojiButton->setEnabled(true);
ui->sendChatButton->setEnabled(true);
// qDebug() << __func__ << ": appending row to INCOMING chatitems to contact " << contact.getName() << "with txid=" << memo.second.getTxid() << " cid=" << contact.getCid() << " item " << Items1 << " memo=" << memo.second.getMemo();
if(seenTxids.count( memo.second.getTxid() ) > 0) {
// Do not render the same chat multiple times
// TODO: this should also look at outputindex to allow for multi-part memos, when that is supported
// qDebug() << __func__ << ": INCOMING ignoring txid=" << memo.second.getTxid();
continue;
}
// TODO: better header memo detection
if (memo.second.getMemo().startsWith("{")) {
// qDebug() << __func__ << ": ignoring header memo=" << memo.second.getMemo();
} else {
chat->appendRow(Items1);
ui->listChat->setModel(chat);
ui->memoTxtChat->setEnabled(true);
ui->emojiButton->setEnabled(true);
ui->sendChatButton->setEnabled(true);
seenTxids[ memo.second.getTxid() ] = 1;
}
}
else
{
} else {
ui->listChat->setModel(chat);
}
}
}
}

2
src/Chat/Chat.h

@ -1,4 +1,4 @@
// Copyright 2019-2021 The Hush developers
// Copyright 2019-2024 The Hush developers
// Released under the GPLv3
#ifndef CHAT_H
#define CHAT_H

3
src/Chat/Helper/ChatDelegator.h

@ -1,4 +1,4 @@
// Copyright 2019-2020 The Hush developers
// Copyright 2019-2024 The Hush developers
// GPLv3
#ifndef CHATDELEGATOR_H
@ -42,6 +42,7 @@ inline ListViewDelegate::ListViewDelegate(QObject *parent): QAbstractItemDelegat
}
//TODO: this data must be kept in sync with sizeHint(), refactor
inline void ListViewDelegate::paint(QPainter *painter, QStyleOptionViewItem const &option, QModelIndex const &index) const
{
QTextDocument bodydoc;

2
src/Crypto/FileEncryption.cpp

@ -1,4 +1,4 @@
// Copyright 2019-2021 The Hush developers
// Copyright 2019-2024 The Hush developers
// Released under the GPLv3
#include "FileEncryption.h"

2
src/Crypto/FileEncryption.h

@ -1,4 +1,4 @@
// Copyright 2019-2021 The Hush developers
// Copyright 2019-2024 The Hush developers
// Released under the GPLv3
#ifndef FILEENCRYPTION_H
#define FILEENCRYPTION_H

2
src/Crypto/passwd.cpp

@ -1,4 +1,4 @@
// Copyright 2019-2021 The Hush developers
// Copyright 2019-2024 The Hush developers
// Released under the GPLv3
#include "passwd.h"

2
src/Crypto/passwd.h

@ -1,4 +1,4 @@
// Copyright 2019-2021 The Hush developers
// Copyright 2019-2024 The Hush developers
// Released under the GPLv3
#ifndef PASSWD_H
#define PASSWD_H

11
src/DataStore/ChatDataStore.cpp

@ -1,4 +1,4 @@
// Copyright 2019-2021 The Hush developers
// Copyright 2019-2024 The Hush developers
// Released under the GPLv3
#include "ChatDataStore.h"
@ -160,14 +160,7 @@ std::map<QString, ChatItem> ChatDataStore::getAllMemos()
std::map<QString, ChatItem> filteredItems;
for(auto &c: this->data)
{
if (
(c.second.getMemo().startsWith("{") == false) &&
(c.second.getMemo().isEmpty() == false)
)
{
if ((c.second.getMemo().startsWith("{") == false) && (c.second.getMemo().isEmpty() == false) ) {
filteredItems[c.first] = c.second;
}
}

2
src/DataStore/ChatDataStore.h

@ -1,4 +1,4 @@
// Copyright 2019-2021 The Hush developers
// Copyright 2019-2024 The Hush developers
// Released under the GPLv3
#ifndef CHATDATASTORE_H
#define CHATDATASTORE_H

2
src/DataStore/ContactDataStore.cpp

@ -1,4 +1,4 @@
// Copyright 2019-2021 The Hush developers
// Copyright 2019-2024 The Hush developers
// GPLv3
#include "ContactDataStore.h"

2
src/DataStore/ContactDataStore.h

@ -1,4 +1,4 @@
// Copyright 2019-2021 The Hush developers
// Copyright 2019-2024 The Hush developers
// Released under the GPLv3
#ifndef CONTACTDATASTORE_H
#define CONTACTDATASTORE_H

2
src/DataStore/DataStore-deprecated.h

@ -1,4 +1,4 @@
// Copyright 2019-2021 The Hush developers
// Copyright 2019-2024 The Hush developers
// Released under the GPLv3
#ifndef DATASTORE_H
#define DATASTORE_H

7
src/DataStore/DataStore.cpp

@ -1,4 +1,4 @@
// Copyright 2019-2021 The Hush developers
// Copyright 2019-2024 The Hush developers
// Released under the GPLv3
#include "DataStore.h"
@ -7,6 +7,11 @@ SietchDataStore* DataStore::getSietchDataStore()
return SietchDataStore::getInstance();
}
NoteCountDataStore* DataStore::getNoteCountDataStore()
{
return NoteCountDataStore::getInstance();
}
ChatDataStore* DataStore::getChatDataStore()
{
return ChatDataStore::getInstance();

4
src/DataStore/DataStore.h

@ -1,9 +1,10 @@
// Copyright 2019-2021 The Hush developers
// Copyright 2019-2024 The Hush developers
// Released under the GPLv3
#ifndef DATASTORE_H
#define DATASTORE_H
#include "SietchDataStore.h"
#include "NoteCountDataStore.h"
#include "ChatDataStore.h"
#include "ContactDataStore.h"
@ -11,6 +12,7 @@ class DataStore
{
public:
static SietchDataStore* getSietchDataStore();
static NoteCountDataStore* getNoteCountDataStore();
static ChatDataStore* getChatDataStore();
static ContactDataStore* getContactDataStore();
};

51
src/DataStore/NoteCountDataStore.cpp

@ -0,0 +1,51 @@
#include "NoteCountDataStore.h"
NoteCountDataStore* NoteCountDataStore::instance = nullptr;
bool NoteCountDataStore::instanced = false;
NoteCountDataStore* NoteCountDataStore::getInstance() {
if (!instanced) {
instanced = true;
instance = new NoteCountDataStore();
}
return instance;
}
void NoteCountDataStore::clear() {
data.clear();
}
void NoteCountDataStore::setData(const QString& key, const QString& value) {
data[key] = value;
}
QString NoteCountDataStore::getData(const QString& key) {
return data.value(key);
}
QString NoteCountDataStore::dump() {
QString result;
for (const auto& key : data.keys()) {
result += key + ": " + data[key] + "\n";
}
return result;
}
void NoteCountDataStore::setSpendableNotesCount(int count) {
spendableNotesCount = count;
}
int NoteCountDataStore::getSpendableNotesCount() const {
return spendableNotesCount;
}
void NoteCountDataStore::setAddressWithMaxValue(const QString& address, int value) {
if (value > maxValue) {
maxValue = value;
addressWithMaxValue = address;
}
}
QString NoteCountDataStore::getAddressWithMaxValue() const {
return addressWithMaxValue;
}

36
src/DataStore/NoteCountDataStore.h

@ -0,0 +1,36 @@
#ifndef NOTECOUNTDATASTORE_H
#define NOTECOUNTDATASTORE_H
#include <QString>
#include <QMap>
class NoteCountDataStore {
private:
static NoteCountDataStore* instance;
static bool instanced;
QMap<QString, QString> data;
int spendableNotesCount;
QString addressWithMaxValue;
int maxValue; // Hinzugefügt, um den maximalen Wert zu speichern
NoteCountDataStore() : spendableNotesCount(0), maxValue(0) {} // Initialisiere maxValue
public:
static NoteCountDataStore* getInstance();
void clear();
void setData(const QString& key, const QString& value);
QString getData(const QString& key);
QString dump();
void setSpendableNotesCount(int count);
int getSpendableNotesCount() const;
void setAddressWithMaxValue(const QString& address, int value);
QString getAddressWithMaxValue() const;
~NoteCountDataStore() {
instanced = false;
instance = nullptr;
}
};
#endif // NOTECOUNTDATASTORE_H

2
src/DataStore/SietchDataStore.cpp

@ -1,4 +1,4 @@
// Copyright 2019-2021 The Hush developers
// Copyright 2019-2024 The Hush developers
// Released under the GPLv3
#include "SietchDataStore.h"

2
src/DataStore/SietchDataStore.h

@ -1,4 +1,4 @@
// Copyright 2019-2021 The Hush developers
// Copyright 2019-2024 The Hush developers
// Released under the GPLv3
#ifndef SIETCHDATASTORE_H
#define SIETCHDATASTORE_H

2
src/FileSystem/FileSystem.cpp

@ -1,4 +1,4 @@
// Copyright 2019-2021 The Hush developers
// Copyright 2019-2024 The Hush developers
// Released under the GPLv3
#include "FileSystem.h"

2
src/FileSystem/FileSystem.h

@ -1,4 +1,4 @@
// Copyright 2019-2021 The Hush developers
// Copyright 2019-2024 The Hush developers
// GPLv3
#ifndef FILESYSTEM_H
#define FILESYSTEM_H

2
src/Logger/LogContext.h

@ -1,4 +1,4 @@
// Copyright 2019-2021 The Hush developers
// Copyright 2019-2024 The Hush developers
// Released under the GPLv3
#ifndef LOGCONTEXT_H
#define LOGCONTEXT_H

2
src/Logger/LogCrtitical.h

@ -1,4 +1,4 @@
// Copyright 2019-2021 The Hush developers
// Copyright 2019-2024 The Hush developers
// Released under the GPLv3
#ifndef LOGCRITICAL_H
#define LOGCRITICAL_H

2
src/Logger/LogDebug.h

@ -1,4 +1,4 @@
// Copyright 2019-2021 The Hush developers
// Copyright 2019-2024 The Hush developers
// Released under the GPLv3
#ifndef LOGDEBUG_H
#define LOGDEBUG_H

2
src/Logger/LogError.h

@ -1,4 +1,4 @@
// Copyright 2019-2021 The Hush developers
// Copyright 2019-2024 The Hush developers
// Released under the GPLv3
#ifndef LOGERROR_H
#define LOGERROR_H

2
src/Logger/LogFatal.h

@ -1,4 +1,4 @@
// Copyright 2019-2021 The Hush developers
// Copyright 2019-2024 The Hush developers
// Released under the GPLv3
#ifndef LOGFATAL_H
#define LOGFATAL_H

2
src/Logger/LogInfo.h

@ -1,4 +1,4 @@
// Copyright 2019-2021 The Hush developers
// Copyright 2019-2024 The Hush developers
// Released under the GPLv3
#ifndef LOGINFO_H
#define LOGINFO_H

2
src/Logger/LogStrategy.h

@ -1,4 +1,4 @@
// Copyright 2019-2021 The Hush developers
// Copyright 2019-2024 The Hush developers
// Released under the GPLv3
#ifndef LOGSTRATEGY_H
#define LOGSTRATEGY_H

2
src/Logger/LogSuccess.h

@ -1,4 +1,4 @@
// Copyright 2019-2021 The Hush developers
// Copyright 2019-2024 The Hush developers
// Released under the GPLv3
#ifndef LOGSUCCESS_H
#define LOGSUCCESS_H

2
src/Logger/LogType.h

@ -1,4 +1,4 @@
// Copyright 2019-2021 The Hush developers
// Copyright 2019-2024 The Hush developers
// Released under the GPLv3
#ifndef LOGTYPE_H
#define LOGTYPE_H

2
src/Logger/LogWarning.h

@ -1,4 +1,4 @@
// Copyright 2019-2021 The Hush developers
// Copyright 2019-2024 The Hush developers
// Released under the GPLv3
#ifndef LOGWARNING_H
#define LOGWARNING_H

2
src/Logger/LogWriter.cpp

@ -1,4 +1,4 @@
// Copyright 2019-2021 The Hush developers
// Copyright 2019-2024 The Hush developers
// Released under the GPLv3
#include "LogWriter.h"

2
src/Logger/LogWriter.h

@ -1,4 +1,4 @@
// Copyright 2019-2021 The Hush developers
// Copyright 2019-2024 The Hush developers
// Released under the GPLv3
#ifndef LOGWRITER_H
#define LOGWRITER_H

2
src/Logger/Logger.h

@ -1,4 +1,4 @@
// Copyright 2019-2021 The Hush developers
// Copyright 2019-2024 The Hush developers
// Released under the GPLv3
#ifndef LOGGER_H
#define LOGGER_H

2
src/Logger/SimpleLogger.h

@ -1,4 +1,4 @@
// Copyright 2019-2021 The Hush developers
// Copyright 2019-2024 The Hush developers
// Released under the GPLv3
#ifndef SIMPLELOGGER_H
#define SIMPLELOGGER_H

2
src/Logger/test.cpp

@ -1,4 +1,4 @@
// Copyright 2019-2021 The Hush developers
// Copyright 2019-2024 The Hush developers
// Released under the GPLv3
#include "SimpleLogger.h"

41
src/Model/ChatItem.cpp

@ -1,4 +1,4 @@
// Copyright 2019-2021 The Hush developers
// Copyright 2019-2024 The Hush developers
// Released under the GPLv3
#include "ChatItem.h"
@ -163,22 +163,15 @@ QString ChatItem::toChatLine()
QString moneyTextRequest;
myDateTime.setTime_t(_timestamp);
if (_notarize == true)
{
if (_notarize == true) {
lock = "<b> <img src=':/icons/res/lock_orange.png'><b>";
} else {
lock = "<b> <img src=':/icons/res/unlocked.png'><b>";
}
}else{
lock = "<b> <img src=':/icons/res/unlocked.png'><b>";
}
if ((_confirmations > 0) && (_notarize == false))
{
if ((_confirmations > 0) && (_notarize == false)) {
lock = "<b> <img src=':/icons/res/lock_green.png'><b>";
}else{}
}
if (_memo.startsWith("Money transaction of :"))
{
@ -210,8 +203,6 @@ QString ChatItem::toChatLine()
}else{moneyTextRequest = "";
moneyTextRequest = ""; }
QString line = QString("<small>") + myDateTime.toString("yyyy-MM-dd hh:mm");
line += QString(lock) + QString(moneyText) + QString(moneyTextRequest) + QString("</small>");
@ -223,16 +214,16 @@ QString ChatItem::toChatLine()
json ChatItem::toJson()
{
json j;
j["_timestamp"] = _timestamp;
j["_address"] = _address.toStdString();
j["_contact"] = _contact.toStdString();
j["_memo"] = _memo.toStdString();
j["_requestZaddr"] = _requestZaddr.toStdString();
j["_type"] = _type.toStdString();
j["_cid"] = _cid.toStdString();
j["_txid"] = _txid.toStdString();
j["_timestamp"] = _timestamp;
j["_address"] = _address.toStdString();
j["_contact"] = _contact.toStdString();
j["_memo"] = _memo.toStdString();
j["_requestZaddr"] = _requestZaddr.toStdString();
j["_type"] = _type.toStdString();
j["_cid"] = _cid.toStdString();
j["_txid"] = _txid.toStdString();
j["_confirmations"] = _confirmations;
j["_outgoing"] = _outgoing;
j["_outgoing"] = _outgoing;
return j;
}

2
src/Model/ChatItem.h

@ -1,4 +1,4 @@
// Copyright 2019-2021 The Hush developers
// Copyright 2019-2024 The Hush developers
// Released under the GPLv3
#ifndef CHATITEM_H

2
src/Model/ContactItem.cpp

@ -1,4 +1,4 @@
// Copyright 2019-2021 The Hush developers
// Copyright 2019-2024 The Hush developers
// GPLv3
#include "ContactItem.h"
#include "chatmodel.h"

2
src/Model/ContactItem.h

@ -1,4 +1,4 @@
// Copyright 2019-2021 The Hush developers
// Copyright 2019-2024 The Hush developers
// Released under the GPLv3
#ifndef CONTACTITEM_H
#define CONTACTITEM_H

2
src/Model/ContactRequest.cpp

@ -1,4 +1,4 @@
// Copyright 2019-2021 The Hush developers
// Copyright 2019-2024 The Hush developers
// GPLv3
#include "ContactRequest.h"

2
src/Model/ContactRequest.h

@ -1,4 +1,4 @@
// Copyright 2019-2021 The Hush developers
// Copyright 2019-2024 The Hush developers
// Released under the GPLv3
#ifndef CONTACTREQUEST_H
#define CONTACTREQUEST_H

2
src/Model/ContactRequestChatItem.cpp

@ -1,3 +1,3 @@
// Copyright 2019-2021 The Hush developers
// Copyright 2019-2024 The Hush developers
// Released under the GPLv3
#include "ContactRequestChatItem.h"

2
src/Model/ContactRequestChatItem.h

@ -1,4 +1,4 @@
// Copyright 2019-2021 The Hush developers
// Copyright 2019-2024 The Hush developers
// Released under the GPLv3
#ifdef CONTACTREQUESTCHATITEM_H
#define CONTACTREQUESTCHATITEM_H

13
src/about.ui

@ -14,6 +14,7 @@
<string>About</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QGroupBox" name="groupBox">
<property name="title">
@ -27,9 +28,19 @@
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="qtversion">
<property name="text">
<string notr="true">QT Version</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QScrollArea" name="scrollArea">
<property name="widgetResizable">
@ -52,7 +63,7 @@
&lt;html&gt;&lt;head&gt;&lt;meta name=&quot;qrichtext&quot; content=&quot;1&quot; /&gt;&lt;style type=&quot;text/css&quot;&gt;
p, li { white-space: pre-wrap; }
&lt;/style&gt;&lt;/head&gt;&lt;body style=&quot; font-family:'Ubuntu'; font-size:11pt; font-weight:400; font-style:normal;&quot;&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;Copyright (c) 2019-2021 The Hush developers GNU Public License V3&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;Copyright (c) 2019-2024 The Hush developers GNU Public License V3&lt;/p&gt;
&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;Copyright (c) 2018-2019 Aditya Kulkarni, Duke Leto, Jane Mercer &lt;/p&gt;
&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;br /&gt;&lt;/p&gt;

3
src/addressbook.cpp

@ -1,4 +1,4 @@
// Copyright 2019-2021 The Hush developers
// Copyright 2019-2024 The Hush developers
// Released under the GPLv3
#include "addressbook.h"
@ -304,6 +304,7 @@ void AddressBook::open(MainWindow* parent, QLineEdit* target)
});
auto fnSetTargetLabelAddr = [=] (QLineEdit* target, QString label, QString addr, QString myAddr, QString cid, QString avatar) {
// qDebug() << __func__ << ": label=" << label << " cid=" << cid << " avatar=" << avatar;
target->setText(label % "/" % addr % myAddr);
};

4
src/addressbook.h

@ -1,4 +1,4 @@
// Copyright 2019-2021 The Hush developers
// Copyright 2019-2024 The Hush developers
// Released under the GPLv3
#ifndef ADDRESSBOOK_H
#define ADDRESSBOOK_H
@ -11,6 +11,8 @@ class MainWindow;
class AddressBookModel : public QAbstractTableModel {
Q_OBJECT
public:
AddressBookModel(QTableView* parent);
~AddressBookModel();

86
src/addressbook.ui

@ -145,11 +145,11 @@
<widget class="QComboBox" name="comboBoxAvatar">
<item>
<property name="text">
<string>SDLogo</string>
<string>Anonymous</string>
</property>
<property name="icon">
<iconset>
<activeon>:/icons/res/SDLogo.png</activeon>
<activeon>:/icons/res/Anonymous.png</activeon>
</iconset>
</property>
</item>
@ -165,116 +165,56 @@
</item>
<item>
<property name="text">
<string>Denio</string>
<string>onryo</string>
</property>
<property name="icon">
<iconset>
<activeon>:/icons/res/Denio.png</activeon>
<activeon>:/icons/res/onryo.png</activeon>
</iconset>
</property>
</item>
<item>
<property name="text">
<string>Berg</string>
<string>fekt</string>
</property>
<property name="icon">
<iconset>
<activeon>:/icons/res/Berg.png</activeon>
<activeon>:/icons/res/fekt.png</activeon>
</iconset>
</property>
</item>
<item>
<property name="text">
<string>Sharpee</string>
<string>jahway603</string>
</property>
<property name="icon">
<iconset>
<activeon>:/icons/res/Sharpee.png</activeon>
<activeon>:/icons/res/jahway603.png</activeon>
</iconset>
</property>
</item>
<item>
<property name="text">
<string>Elsa</string>
</property>
<property name="icon">
<iconset>
<normalon>:/icons/res/Elsa.png</normalon>
</iconset>
</property>
</item>
<item>
<property name="text">
<string>Yoda</string>
</property>
<property name="icon">
<iconset>
<activeon>:/icons/res/Yoda.png</activeon>
</iconset>
</property>
</item>
<item>
<property name="text">
<string>Garflied</string>
</property>
<property name="icon">
<iconset>
<activeon>:/icons/res/Garfield.png</activeon>
</iconset>
</property>
</item>
<item>
<property name="text">
<string>Snoopy</string>
</property>
<property name="icon">
<iconset>
<activeon>:/icons/res/Snoopy.png</activeon>
</iconset>
</property>
</item>
<item>
<property name="text">
<string>Popey</string>
</property>
<property name="icon">
<iconset>
<activeon>:/icons/res/Popey.png</activeon>
</iconset>
</property>
</item>
<item>
<property name="text">
<string>Pinguin</string>
</property>
<property name="icon">
<iconset>
<activeon>:/icons/res/Pinguin.png</activeon>
</iconset>
</property>
</item>
<item>
<property name="text">
<string>Mickey</string>
<string>Denio</string>
</property>
<property name="icon">
<iconset>
<activeon>:/icons/res/Mickey.png</activeon>
<activeon>:/icons/res/Denio.png</activeon>
</iconset>
</property>
</item>
<item>
<property name="text">
<string>Stag</string>
<string>Sharpee</string>
</property>
<property name="icon">
<iconset>
<activeon>:/icons/res/Stag.png</activeon>
<activeon>:/icons/res/Sharpee.png</activeon>
</iconset>
</property>
</item>
</widget>
</item>
</item>
<item row="4" column="1">
<widget class="QLabel" name="label_5">
<property name="text">

2
src/addresscombo.cpp

@ -1,4 +1,4 @@
// Copyright 2019-2021 The Hush developers
// Copyright 2019-2024 The Hush developers
// Released under the GPLv3
#include "addresscombo.h"
#include "addressbook.h"

2
src/addresscombo.h

@ -1,4 +1,4 @@
// Copyright 2019-2021 The Hush developers
// Copyright 2019-2024 The Hush developers
// Released under the GPLv3
#ifndef ADDRESSCOMBO_H
#define ADDRESSCOMBO_H

16
src/balancestablemodel.cpp

@ -1,9 +1,10 @@
// Copyright 2019-2021 The Hush developers
// Copyright 2019-2024 The Hush developers
// Released under the GPLv3
#include "balancestablemodel.h"
#include "addressbook.h"
#include "settings.h"
#include "camount.h"
#include "guiconstants.h"
BalancesTableModel::BalancesTableModel(QObject *parent): QAbstractTableModel(parent)
{}
@ -100,9 +101,16 @@ QVariant BalancesTableModel::data(const QModelIndex &index, int role) const
}
// Else, just return the default brush
QBrush b;
b.setColor(Qt::black);
// Get current theme name
QString theme_name = Settings::getInstance()->get_theme_name();
QBrush b;
QColor color;
if (theme_name == "Dark" || theme_name == "Midnight") {
color = COLOR_WHITE;
}else{
color = COLOR_BLACK;
}
b.setColor(color);
return b;
}

8
src/balancestablemodel.h

@ -1,4 +1,4 @@
// Copyright 2019-2021 The Hush developers
// Copyright 2019-2024 The Hush developers
// Released under the GPLv3
#ifndef BALANCESTABLEMODEL_H
#define BALANCESTABLEMODEL_H
@ -8,8 +8,10 @@
#include "camount.h"
class BalancesTableModel : public QAbstractTableModel
{
class BalancesTableModel : public QAbstractTableModel {
Q_OBJECT
public:
BalancesTableModel(QObject* parent);
~BalancesTableModel();

4
src/camount.cpp

@ -1,4 +1,4 @@
// Copyright 2019-2021 The Hush developers
// Copyright 2019-2024 The Hush developers
// Released under the GPLv3
#include "camount.h"
#include "settings.h"
@ -43,7 +43,7 @@ double CAmount::getDblAmount() const
QString CAmount::toDecimalUSDString() const
{
double price = Settings::getInstance()->getZECPrice();
double price = Settings::getInstance()->getHUSHPrice();
return "$ " + QLocale(QLocale::English).toString(this->getDblAmount() * price, 'f', 2);
}

2
src/camount.h

@ -1,4 +1,4 @@
// Copyright 2019-2021 The Hush developers
// Copyright 2019-2024 The Hush developers
// Released under the GPLv3
#ifndef CAMOUNT_H
#define CAMOUNT_H

2
src/chatbubbleme.cpp

@ -1,4 +1,4 @@
// Copyright 2019-2021 The Hush developers
// Copyright 2019-2024 The Hush developers
// Released under the GPLv3
#include "chatbubbleme.h"
#include "ui_chatbubbleme.h"

2
src/chatbubbleme.h

@ -1,4 +1,4 @@
// Copyright 2019-2021 The Hush developers
// Copyright 2019-2024 The Hush developers
// Released under the GPLv3
#ifndef CHATBUBBLEME_H
#define CHATBUBBLEME_H

2
src/chatbubblepartner.cpp

@ -1,4 +1,4 @@
// Copyright 2019-2021 The Hush developers
// Copyright 2019-2024 The Hush developers
// Released under the GPLv3
#include "chatbubblepartner.h"
#include "ui_chatbubblepartner.h"

2
src/chatbubblepartner.h

@ -1,4 +1,4 @@
// Copyright 2019-2021 The Hush developers
// Copyright 2019-2024 The Hush developers
// Released under the GPLv3
#ifndef CHATBUBBLEPARTNER_H
#define CHATBUBBLEPARTNER_H

79
src/chatmodel.cpp

@ -1,4 +1,4 @@
// Copyright 2019-2021 The Hush developers
// Copyright 2019-2024 The Hush developers
// Released under the GPLv3
#include "chatmodel.h"
#include "settings.h"
@ -65,11 +65,12 @@ void ChatModel::addMessage(QString timestamp, ChatItem item)
void ChatModel::showMessages()
{
/*
for(auto &c : this->chatItems)
{
}
*/
}
void ChatModel::addAddressbylabel(QString address, QString label)
@ -79,11 +80,6 @@ void ChatModel::addAddressbylabel(QString address, QString label)
QString ChatModel::Addressbylabel(QString address)
{
for(auto& pair : this->AddressbyLabelMap)
{
}
if(this->AddressbyLabelMap.count(address) > 0)
{
return this->AddressbyLabelMap[address];
@ -306,11 +302,6 @@ void ChatModel::addconfirmations(QString tx, int confirmation)
QString ChatModel::getCidByTx(QString tx)
{
for(auto& pair : this->cidMap)
{
}
if(this->cidMap.count(tx) > 0)
{
return this->cidMap[tx];
@ -321,11 +312,6 @@ QString ChatModel::getCidByTx(QString tx)
QString ChatModel::getMemoByTx(QString tx)
{
for(auto& pair : this->OldMemoByTx)
{
}
if(this->OldMemoByTx.count(tx) > 0)
{
return this->OldMemoByTx[tx];
@ -339,11 +325,6 @@ QString ChatModel::getMemoByTx(QString tx)
QString ChatModel::getHeaderByTx(QString tx)
{
for(auto& pair : this->headerMap)
{
}
if(this->headerMap.count(tx) > 0)
{
return this->headerMap[tx];
@ -354,11 +335,6 @@ QString ChatModel::getHeaderByTx(QString tx)
QString ChatModel::getConfirmationByTx(QString tx)
{
for(auto& pair : this->confirmationsMap)
{
}
if(this->confirmationsMap.count(tx) > 0)
{
return this->confirmationsMap[tx];
@ -369,11 +345,6 @@ QString ChatModel::getConfirmationByTx(QString tx)
QString ChatModel::getrequestZaddrByTx(QString tx)
{
for(auto& pair : this->requestZaddrMap)
{
}
if(this->requestZaddrMap.count(tx) > 0)
{
return this->requestZaddrMap[tx];
@ -409,19 +380,18 @@ QString MainWindow::createHeaderMemo(QString type, QString cid, QString zaddr, Q
QJsonObject h;
// We use short keynames to use less space for metadata and so allow
// the user to send more actual data in memos
h["h"] = headerNumber; // header number
h["v"] = version; // HushChat version
h["z"] = zaddr; // zaddr to respond to
h["cid"] = cid; // conversation id
h["t"] = type; // Memo or incoming contact request
h["e"] = headerbytes; // Memo or incoming contact request
h["p"] = publickey; // Memo or incoming contact request
h["h"] = headerNumber; // integer, header number starting from 1
h["v"] = version; // integer, HushChat version. currently 0
h["z"] = zaddr; // string, zaddr to respond to
h["cid"] = cid; // string, conversation id (UUID)
h["t"] = type; // string, Memo or incoming contact request
h["e"] = headerbytes; // string, hex-encoded libsodium headerbytes from crypto_secretstream_xchacha20poly1305_init_push()
h["p"] = publickey; // string, hex-encoded libsodium public key from crypto_kx_seed_keypair()
j.setObject(h);
header = j.toJson();
return header;
}
@ -477,20 +447,23 @@ Tx MainWindow::createTxFromChatPage() {
unsigned char pk[crypto_kx_PUBLICKEYBYTES];
unsigned char server_rx[crypto_kx_SESSIONKEYBYTES], server_tx[crypto_kx_SESSIONKEYBYTES];
if (crypto_kx_seed_keypair(pk,sk,
MESSAGEAS1) !=0) {
if (crypto_kx_seed_keypair(pk,sk, MESSAGEAS1) !=0) {
this->logger->write("Suspicious keypair, bail out ");
// qDebug() << __func__<< ": Suspicious client public outgoing key from crypto_kx_seed_keypair, aborting!";
return tx;
}
this->logger->write("Suspicious keypair, bail out ");
}
////////////////Get the pubkey from Bob, so we can create the share key
const QByteArray pubkeyBobArray = QByteArray::fromHex(pubkey.toLatin1());
const unsigned char *pubkeyBob = reinterpret_cast<const unsigned char *>(pubkeyBobArray.constData());
/////Create the shared key for sending the message
if (crypto_kx_server_session_keys(server_rx, server_tx,
pk, sk, pubkeyBob) != 0) {
this->logger->write("Suspicious client public send key, bail out ");
/////Create the shared key for sending the message
if (crypto_kx_server_session_keys(server_rx, server_tx, pk, sk, pubkeyBob) != 0) {
this->logger->write("Suspicious client public send key, bail out ");
// << __func__ << ": Suspicious client public send key from crypto_kx_server_session_keys, aborting!";
return tx;
}
@ -623,7 +596,7 @@ void MainWindow::sendChat() {
ui->memoTxtChat->clear();
// And send the Tx
rpc->executeTransaction(tx,
rpc->executeTransaction(tx, true,
[=] (QString txid) {
ui->statusBar->showMessage(Settings::txidStatusMessage + " " + txid);
@ -821,6 +794,8 @@ Tx MainWindow::createTxForSafeContactRequest()
if (crypto_kx_seed_keypair(pk, sk, MESSAGEAS1) !=0) {
this->logger->write("Suspicious client public contact request key, bail out ");
// qDebug() << __func__ << ": Suspicious client public send key from crypto_kx_seed_keypair, aborting!";
return tx;
}
QString publicKey = QByteArray(reinterpret_cast<const char*>(pk), crypto_kx_PUBLICKEYBYTES).toHex();
@ -892,8 +867,8 @@ void MainWindow::ContactRequest() {
auto d = new QDialog(this);
auto connD = new Ui_ConnectionDialog();
connD->setupUi(d);
QMovie *movie1 = new QMovie(":/img/res/silentdragonlite-animated.gif");
QMovie *movie2 = new QMovie(":/img/res/silentdragonlite-animated-dark.gif");
QMovie *movie1 = new QMovie(":/img/res/silentdragonlite-animated-startup-dark.gif");
QMovie *movie2 = new QMovie(":/img/res/silentdragonlite-animated-startup-dark.gif");
auto theme = Settings::getInstance()->get_theme_name();
if (theme == "Dark" || theme == "Midnight") {
movie2->setScaledSize(QSize(512,512));
@ -912,7 +887,7 @@ void MainWindow::ContactRequest() {
ui->memoTxtChat->clear();
// And send the Tx
rpc->executeTransaction(tx,
rpc->executeTransaction(tx, true,
[=] (QString txid) {
ui->statusBar->showMessage(Settings::txidStatusMessage + " " + txid);

2
src/chatmodel.h

@ -1,4 +1,4 @@
// Copyright 2019-2021 The Hush developers
// Copyright 2019-2024 The Hush developers
// Released under the GPLv3
#ifndef CHATMODEL_H

309
src/connection.cpp

@ -1,4 +1,4 @@
// Copyright 2019-2021 The Hush developers
// Copyright 2019-2024 The Hush developers
// Released under the GPLv3
#include "connection.h"
#include "mainwindow.h"
@ -9,6 +9,8 @@
#include "controller.h"
#include "../lib/silentdragonlitelib.h"
#include "precompiled.h"
#include <QThreadPool>
#include "sdl.h"
using json = nlohmann::json;
@ -32,7 +34,7 @@ ConnectionLoader::ConnectionLoader(MainWindow* main, Controller* rpc)
connD->setupUi(d);
auto theme = Settings::getInstance()->get_theme_name();
qDebug() << theme << "theme has loaded";
//DEBUG("theme " << theme << " has loaded");
auto size = QSize(512,512);
if (theme == "Dark" || theme == "Midnight") {
@ -42,7 +44,7 @@ ConnectionLoader::ConnectionLoader(MainWindow* main, Controller* rpc)
connD->topIcon->setMovie(movie2);
movie2->start();
} else {
QMovie *movie1 = new QMovie(":/img/res/silentdragonlite-animated-startup.gif");;
QMovie *movie1 = new QMovie(":/img/res/silentdragonlite-animated-startup-dark.gif");;
movie1->setScaledSize(size);
qDebug() << "Animation light loaded";
connD->topIcon->setMovie(movie1);
@ -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,70 +73,89 @@ 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();
}
void ConnectionLoader::ShowProgress()
{
qDebug() << __func__;
auto config = std::shared_ptr<ConnectionConfig>(new ConnectionConfig());
config->dangerous = false;
config->server = Settings::getInstance()->getSettings().server;
DEBUG("Creating connection with server=" << config->server);
auto connection = makeConnection(config);
auto me = this;
qDebug() << __func__ << ": server=" << config->server
<< " connection=" << connection << " me=" << me;
if (!connection) {
DEBUG("Failed to create connection");
return;
}
auto me = this;
isSyncing = new QAtomicInteger<bool>(true);
DEBUG("isSyncing set to true");
isSyncing = new QAtomicInteger<bool>();
isSyncing->store(true);
main->logger->write("isSyncing");
// Do a sync after import
syncTimer = new QTimer(main);
main->logger->write("Beginning sync after import wif");
connection->doRPCWithDefaultErrorHandling("sync", "", [=](auto) {
DEBUG("Created syncTimer");
connection->doRPC("sync", "", [=](auto) {
qDebug()<< "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
if (isSyncing != nullptr && isSyncing->load()) {
// Get the sync status
try {
if (!isSyncing || !isSyncing->load()) {
DEBUG("Syncing complete or isSyncing is null, stopping timer");
syncTimer->stop();
return;
}
DEBUG("Checking sync status");
try {
connection->doRPC("syncstatus", "", [=](json reply) {
if (isSyncing != nullptr && reply.find("synced_blocks") != reply.end())
{
if (isSyncing && reply.find("synced_blocks") != reply.end()) {
qint64 synced = reply["synced_blocks"].get<json::number_unsigned_t>();
qint64 total = reply["total_blocks"].get<json::number_unsigned_t>();
DEBUG("Sync status: " << synced << " / " << total);
me->showInformation(
"Synced " + QString::number(synced) + " / " + QString::number(total)
"Syncing... " + QString::number(synced) + " / " + QString::number(total)
);
}
},
[=](QString err) {
qDebug() << "Sync error" << err;
}, [=](QString err) {
DEBUG("Sync status error: " << err);
config->server = Settings::getRandomServer();
DEBUG("Changed server to " << config->server);
});
}catch (...)
{
main->logger->write("catch sync progress reply");
}
} catch (const std::exception& e) {
DEBUG("Exception caught in syncstatus: " << e.what());
throw;
}
});
syncTimer->setInterval(1* 1000);
syncTimer->start();
main->logger->write("Start sync timer");
});
int interval = 1 * 1000;
syncTimer->setInterval(interval);
syncTimer->start();
DEBUG("Sync timer started with interval=" << interval);
}
void ConnectionLoader::doAutoConnect()
@ -140,28 +163,53 @@ void ConnectionLoader::doAutoConnect()
auto config = std::shared_ptr<ConnectionConfig>(new ConnectionConfig());
config->dangerous = false;
config->server = Settings::getInstance()->getSettings().server;
qDebug() << __func__ << " server=" << config->server;
DEBUG("Creating connection with 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()))
{
if (litelib_wallet_exists(Settings::getDefaultChainName().toStdString().c_str())) {
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")
{
showError(response);
return;
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 {
DEBUG("Successfully connected to random server: " << config->server << " !!!");
}
} else {
DEBUG("Successfully connected to " << config->server << " !!!");
}
} else {
DEBUG("no existing wallet");
main->logger->write(QObject::tr("Create/restore wallet."));
createOrRestore(config->dangerous, config->server);
d->show();
@ -169,64 +217,73 @@ void ConnectionLoader::doAutoConnect()
auto connection = makeConnection(config);
auto me = this;
qDebug() << __func__ << ": server=" << config->server
qDebug() << __func__ << ": server=" << config->server
<< " connection=" << connection << " me=" << me << endl;
// After the lib is initialized, try to do get info
connection->doRPC("info", "", [=](auto reply) {
// If success, set the connection
main->logger->write("Connection is online.");
DEBUG("Connection is online.");
connection->setInfo(reply);
main->logger->write("getting Connection reply");
DEBUG("getting Connection reply");
isSyncing = new QAtomicInteger<bool>();
isSyncing->store(true);
main->logger->write("isSyncing");
DEBUG("isSyncing set to true");
// Do a sync at startup
syncTimer = new QTimer(main);
main->logger->write("Beginning sync");
connection->doRPCWithDefaultErrorHandling("sync", "", [=](auto) {
DEBUG("Beginning sync at startup");
connection->doRPC("sync", "", [=](auto) {
qDebug()<<"finished syncing startup";
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);
// Attempt to retry sync RPC with a delay
QTimer::singleShot(5000, [=]() { // 5-second delay
connection->doRPC("sync", "", [=](auto) mutable {
qDebug()<<"sync success with server=" << config->server;
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 << " . retrying after delay");
});
});
});
// While it is syncing, we'll show the status updates while it is alive.
QObject::connect(syncTimer, &QTimer::timeout, [=]() {
// Check the sync status
DEBUG("Check the sync status");
if (isSyncing != nullptr && isSyncing->load()) {
// Get the sync status
DEBUG("Getting the sync status");
try {
connection->doRPC("syncstatus", "", [=](json reply) {
if (isSyncing != nullptr && reply.find("synced_blocks") != reply.end())
{
if (isSyncing != nullptr && reply.find("synced_blocks") != reply.end()) {
qint64 synced = reply["synced_blocks"].get<json::number_unsigned_t>();
qint64 total = reply["total_blocks"].get<json::number_unsigned_t>();
me->showInformation(
"Synced " + QString::number(synced) + " / " + QString::number(total)
"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);
@ -235,47 +292,52 @@ void ConnectionLoader::doAutoConnect()
void ConnectionLoader::createOrRestore(bool dangerous, QString server)
{
qDebug() << __func__ << ": server=" << server;
// Close the startup dialog, since we'll be showing the wizard
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();
QTimer::singleShot(1, [=]() { delete this; });
QFile plaintextWallet(dirwalletconnection);
try {
QFile plaintextWallet(dirwalletconnection);
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() );
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) {});
QTimer::singleShot(1, [=]() { delete this; });
QFile plaintextWallet(dirwalletconnection);
try {
QFile plaintextWallet(dirwalletconnection);
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");
DEBUG("No plaintext wallet found! file=" << plaintextWallet);
}
}
@ -309,7 +371,7 @@ void ConnectionLoader::showError(QString explanation)
QString litelib_process_response(char* resp)
{
qDebug() << __func__ << ": " << resp;
//qDebug() << __func__ << ": " << resp;
char* resp_copy = new char[strlen(resp) + 1];
//a safer version of strcpy
@ -326,19 +388,50 @@ QString litelib_process_response(char* resp)
************************************************************************************/
void Executor::run()
{
char* resp = litelib_execute(this->cmd.toStdString().c_str(), this->args.toStdString().c_str());
QString reply = litelib_process_response(resp);
auto parsed = json::parse(
reply.toStdString().c_str(),
nullptr,
false
);
if (parsed.is_discarded() || parsed.is_null())
emit handleError(reply);
auto config = std::shared_ptr<ConnectionConfig>(new ConnectionConfig());
//DEBUG("cmd=" << cmd << " args=" << args << " server=" << config->server);
QString response = "";
try {
char* resp = litelib_execute(this->cmd.toStdString().c_str(), this->args.toStdString().c_str());
response = litelib_process_response(resp);
} catch (const std::exception& e) {
DEBUG("ignoring exception: " << e.what() );
}
//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
);
else
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)
@ -359,18 +452,19 @@ Connection::Connection(MainWindow* m, std::shared_ptr<ConnectionConfig> conf)
{
this->config = conf;
this->main = m;
qDebug() << __func__;
// qDebug() << __func__;
// Register the JSON type as a type that can be passed between signals and slots.
qRegisterMetaType<json>("json");
}
void Connection::doRPC(const QString cmd, const QString args, const std::function<void(json)>& cb, const std::function<void(QString)>& errCb)
{
if (shutdownInProgress)
// Ignoring RPC because shutdown in progress
if (shutdownInProgress) {
DEBUG("Ignoring RPC because shutdown in progress");
return;
}
qDebug() << __func__ << ": " << cmd;
//DEBUG("cmd=" << cmd << " args=" << args);
// Create a runner.
auto runner = new Executor(cmd, args);
@ -385,7 +479,7 @@ void Connection::doRPC(const QString cmd, const QString args, const std::functio
void Connection::doRPCWithDefaultErrorHandling(const QString cmd, const QString args, const std::function<void(json)>& cb)
{
qDebug() << __func__ << ": " << cmd;
//DEBUG("cmd=" << cmd << " args=" << args);
doRPC(cmd, args, cb, [=] (QString err) {
this->showTxError(err);
});
@ -393,7 +487,7 @@ void Connection::doRPCWithDefaultErrorHandling(const QString cmd, const QString
void Connection::doRPCIgnoreError(const QString cmd, const QString args, const std::function<void(json)>& cb)
{
qDebug() << __func__ << ": " << cmd;
// DEBUG("cmd=" << cmd << " args=" << args);
doRPC(cmd, args, cb, [=] (auto) {
// Ignored error handling
});
@ -401,7 +495,7 @@ void Connection::doRPCIgnoreError(const QString cmd, const QString args, const s
void Connection::showTxError(const QString& error)
{
qDebug() << __func__ << ": " << error;
// qDebug() << __func__ << ": " << error;
if (error.isNull())
return;
@ -425,5 +519,6 @@ void Connection::showTxError(const QString& error)
*/
void Connection::shutdown()
{
DEBUG("shutting down");
shutdownInProgress = true;
}

3
src/connection.h

@ -1,4 +1,4 @@
// Copyright 2019-2021 The Hush developers
// Copyright 2019-2024 The Hush developers
// Released under the GPLv3
#ifndef CONNECTION_H
#define CONNECTION_H
@ -6,6 +6,7 @@
#include "mainwindow.h"
#include "ui_connection.h"
#include "precompiled.h"
#include <QRunnable>
using json = nlohmann::json;

18
src/contactmodel.cpp

@ -1,4 +1,4 @@
// Copyright 2019-2020 The Hush developers
// Copyright 2019-2024 The Hush developers
// GPLv3
#include "contactmodel.h"
@ -18,11 +18,6 @@ void ContactModel::addLabel(QString addr, QString label)
QString ContactModel::getContactbyAddress(QString addr)
{
for(auto& pair : this->AddressMap)
{
}
if(this->AddressMap.count(addr) > 0)
{
return this->AddressMap[addr];
@ -65,9 +60,7 @@ void MainWindow::showRequesthush() {
for(auto &p : AddressBook::getInstance()->getAllAddressLabels())
{
if (p.getName() == label)
{
if (p.getName() == label) {
QString addr = p.getPartnerAddress();
QString myzaddr = p.getMyAddress();
@ -135,7 +128,8 @@ void MainWindow::showRequesthush() {
}
}
if (d.exec() == QDialog::Accepted) {
if (d.exec() == QDialog::Accepted) {
// Construct a hush Payment URI with the data and pay it immediately.
CAmount amount = CAmount::fromDecimalString(req.txtAmount->text());
QString memoURI = "hush:" + req.lblAddressInfo->text()
@ -150,10 +144,6 @@ void MainWindow::showRequesthush() {
// sapling address
this->payhushURI(sendURI, req.lblAddressInfo->text());
}
}

2
src/contactmodel.h

@ -1,4 +1,4 @@
// Copyright 2019-2021 The Hush developers
// Copyright 2019-2024 The Hush developers
// Released under the GPLv3
#ifndef CONTACTMODEL_H
#define CONTACTMODEL_H

86
src/contactrequest.ui

@ -229,11 +229,11 @@
</property>
<item>
<property name="text">
<string>SDLogo</string>
<string>Anonymous</string>
</property>
<property name="icon">
<iconset>
<activeon>:/icons/res/SDLogo.png</activeon>
<activeon>:/icons/res/Anonymous.png</activeon>
</iconset>
</property>
</item>
@ -249,116 +249,56 @@
</item>
<item>
<property name="text">
<string>Denio</string>
<string>onryo</string>
</property>
<property name="icon">
<iconset>
<activeon>:/icons/res/Denio.png</activeon>
<activeon>:/icons/res/onryo.png</activeon>
</iconset>
</property>
</item>
<item>
<property name="text">
<string>Berg</string>
<string>fekt</string>
</property>
<property name="icon">
<iconset>
<activeon>:/icons/res/Berg.png</activeon>
<activeon>:/icons/res/fekt.png</activeon>
</iconset>
</property>
</item>
<item>
<property name="text">
<string>Stag</string>
<string>jahway603</string>
</property>
<property name="icon">
<iconset>
<activeon>:/icons/res/Stag.png</activeon>
<activeon>:/icons/res/jahway603.png</activeon>
</iconset>
</property>
</item>
<item>
<property name="text">
<string>Sharpee</string>
</property>
<property name="icon">
<iconset>
<activeon>:/icons/res/Sharpee.png</activeon>
</iconset>
</property>
</item>
<item>
<property name="text">
<string>Elsa</string>
</property>
<property name="icon">
<iconset>
<normalon>:/icons/res/Elsa.png</normalon>
</iconset>
</property>
</item>
<item>
<property name="text">
<string>Yoda</string>
</property>
<property name="icon">
<iconset>
<activeon>:/icons/res/Yoda.png</activeon>
</iconset>
</property>
</item>
<item>
<property name="text">
<string>Garfield</string>
</property>
<property name="icon">
<iconset>
<activeon>:/icons/res/Garfield.png</activeon>
</iconset>
</property>
</item>
<item>
<property name="text">
<string>Snoopy</string>
</property>
<property name="icon">
<iconset>
<activeon>:/icons/res/Snoopy.png</activeon>
</iconset>
</property>
</item>
<item>
<property name="text">
<string>Popey</string>
</property>
<property name="icon">
<iconset>
<activeon>:/icons/res/Popey.png</activeon>
</iconset>
</property>
</item>
<item>
<property name="text">
<string>Pinguin</string>
<string>Denio</string>
</property>
<property name="icon">
<iconset>
<activeon>:/icons/res/Pinguin.png</activeon>
<activeon>:/icons/res/Denio.png</activeon>
</iconset>
</property>
</item>
<item>
<property name="text">
<string>Mickey</string>
<string>Sharpee</string>
</property>
<property name="icon">
<iconset>
<activeon>:/icons/res/Mickey.png</activeon>
<activeon>:/icons/res/Sharpee.png</activeon>
</iconset>
</property>
</item>
</widget>
</item>
</item>
<item>
<spacer name="horizontalSpacer_2">
<property name="orientation">

648
src/controller.cpp

File diff suppressed because it is too large

8
src/controller.h

@ -46,7 +46,7 @@ public:
int _lag;
void checkForUpdate(bool silent = true);
void refreshZECPrice();
void refreshHUSHPrice();
void refreshEURPrice();
void refreshBTCPrice();
void refreshCNYPrice();
@ -86,11 +86,11 @@ public:
void executeStandardUITransaction(Tx tx);
void executeTransaction(Tx tx,
void executeTransaction(Tx tx, bool isChatMessage,
const std::function<void(QString txid)> submitted,
const std::function<void(QString txid, QString errStr)> error);
void fillTxJsonParams(json& params, Tx tx);
void fillTxJsonParams(json& params, Tx tx, bool isChatMessage);
const TxTableModel* getTransactionsModel() { return transactionsTableModel; }
@ -98,6 +98,8 @@ public:
void noConnection();
bool isEmbedded() { return ehushd != nullptr; }
void fetchAndProcessUnspentNotes();
void encryptWallet(QString password, const std::function<void(json)>& cb) {
zrpc->encryptWallet(password, cb);
}

2
src/datamodel.cpp

@ -1,4 +1,4 @@
// Copyright 2019-2021 The Hush developers
// Copyright 2019-2024 The Hush developers
// Released under the GPLv3
#include "datamodel.h"

8
src/datamodel.h

@ -1,11 +1,11 @@
// Copyright 2019-2021 The Hush developers
// Copyright 2019-2024 The Hush developers
// Released under the GPLv3
#ifndef DATAMODEL_H
#define DATAMODEL_H
#include "camount.h"
#include "precompiled.h"
#include <QReadLocker>
struct UnspentOutput {
QString address;
@ -48,6 +48,9 @@ public:
CAmount getBalZ() { QReadLocker locker(lock); return balZ; }
void setBalZ(CAmount a) { QReadLocker locker(lock); this->balZ = a; }
CAmount getBalU() { QReadLocker locker(lock); return balU; }
void setBalU(CAmount a) { QReadLocker locker(lock); this->balU = a; }
CAmount getBalVerified() { QReadLocker locker(lock); return balVerified; }
void setBalVerified(CAmount a) { QReadLocker locker(lock); this->balVerified = a; }
@ -76,6 +79,7 @@ private:
CAmount balT;
CAmount balZ;
CAmount balU;
CAmount balVerified;
CAmount balSpendable;

104
src/deposithush.ui

@ -14,7 +14,64 @@
<string>Deposit Hush</string>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="0" colspan="2">
<item row="2" column="3">
<spacer name="horizontalSpacer_2">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>214</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item row="2" column="2">
<widget class="QRCodeLabel" name="qrcodeDisplayDeposit">
<property name="sizePolicy">
<sizepolicy hsizetype="Maximum" vsizetype="Maximum">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>300</width>
<height>300</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>300</width>
<height>300</height>
</size>
</property>
<property name="styleSheet">
<string notr="true">background-color: #fff</string>
</property>
<property name="text">
<string/>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
<item row="2" column="0">
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>214</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item row="0" column="0" colspan="4">
<widget class="QTextBrowser" name="textBrowser">
<property name="maximumSize">
<size>
@ -24,42 +81,44 @@
</property>
<property name="html">
<string>&lt;!DOCTYPE HTML PUBLIC &quot;-//W3C//DTD HTML 4.0//EN&quot; &quot;http://www.w3.org/TR/REC-html40/strict.dtd&quot;&gt;
&lt;html&gt;&lt;head&gt;&lt;meta name=&quot;qrichtext&quot; content=&quot;1&quot; /&gt;&lt;style type=&quot;text/css&quot;&gt;
&lt;html&gt;&lt;head&gt;&lt;meta name=&quot;qrichtext&quot; content=&quot;1&quot; /&gt;&lt;meta charset=&quot;utf-8&quot; /&gt;&lt;style type=&quot;text/css&quot;&gt;
p, li { white-space: pre-wrap; }
&lt;/style&gt;&lt;/head&gt;&lt;body style=&quot; font-family:'Ubuntu'; font-size:11pt; font-weight:400; font-style:normal;&quot;&gt;
hr { height: 1px; border-width: 0; }
li.unchecked::marker { content: &quot;\2610&quot;; }
li.checked::marker { content: &quot;\2612&quot;; }
&lt;/style&gt;&lt;/head&gt;&lt;body style=&quot; font-family:'.AppleSystemUIFont'; font-size:13pt; font-weight:400; font-style:normal;&quot;&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'Ubuntu'; font-size:16pt;&quot;&gt;Please use the following hush address to transfer funds to SilentDragonLite. You can either copy the address or use the QR Code. &lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
</widget>
</item>
<item row="1" column="0" colspan="2">
<widget class="QLabel" name="label">
<item row="5" column="0">
<widget class="QPushButton" name="CopyAddress">
<property name="text">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p align=&quot;center&quot;&gt;QR Code of your Hush Address&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
<string>Copy Address</string>
</property>
</widget>
</item>
<item row="3" column="0" colspan="2">
<item row="3" column="0" colspan="4">
<widget class="QLabel" name="label_2">
<property name="text">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p align=&quot;center&quot;&gt;&lt;span style=&quot; text-decoration: underline;&quot;&gt;Your Hush Address &lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
<item row="4" column="0" colspan="2">
<item row="4" column="0" colspan="4">
<widget class="QLabel" name="zaddr">
<property name="text">
<string>Hush zaddr</string>
</property>
</widget>
</item>
<item row="5" column="0">
<widget class="QPushButton" name="CopyAddress">
<property name="text">
<string>Copy Address</string>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
<item row="6" column="1">
<item row="6" column="0" colspan="4">
<widget class="QDialogButtonBox" name="buttonBox">
<property name="orientation">
<enum>Qt::Horizontal</enum>
@ -69,19 +128,10 @@ p, li { white-space: pre-wrap; }
</property>
</widget>
</item>
<item row="2" column="0" colspan="2">
<widget class="QRCodeLabel" name="qrcodeDisplayDeposit">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="styleSheet">
<string notr="true">background-color: #fff</string>
</property>
<item row="1" column="0" colspan="4">
<widget class="QLabel" name="label">
<property name="text">
<string/>
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p align=&quot;center&quot;&gt;QR Code of your Hush Address&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
</widget>
</item>

23
src/fillediconlabel.cpp

@ -1,6 +1,8 @@
// Copyright 2019-2021 The Hush developers
// Copyright 2019-2022 The Hush developers
// Released under the GPLv3
#include "fillediconlabel.h"
#include "settings.h"
#include "guiconstants.h"
FilledIconLabel::FilledIconLabel(QWidget* parent) :
QLabel(parent) {
@ -20,8 +22,25 @@ void FilledIconLabel::resizeEvent(QResizeEvent*) {
QPixmap scaled = basePm.scaled(sz, Qt::KeepAspectRatio, Qt::SmoothTransformation);
QString theme_name = Settings::getInstance()->get_theme_name();
QColor color;
if (theme_name == "Blue"){
color = COLOR_BLUE_BG;
}else if(theme_name == "Light"){
color = COLOR_LIGHT_BG;
}else if(theme_name == "Dark"){
color = COLOR_DARK_BG;
}else if(theme_name =="Midnight"){
color = COLOR_MIDNIGHT_BG;
}else if(theme_name =="dragonx"){
color = COLOR_DRAGONX_BG;
}else{
color = COLOR_DEFAULT_BG;
}
QPixmap p(sz);
p.fill(Qt::white);
p.fill(color);
QPainter painter(&p);
painter.drawPixmap((sz.width() - scaled.width()) / 2, (sz.height() - scaled.height()) / 2, scaled);

2
src/fillediconlabel.h

@ -1,4 +1,4 @@
// Copyright 2019-2021 The Hush developers
// Copyright 2019-2024 The Hush developers
// Released under the GPLv3
#ifndef FILLEDICONLABEL_H
#define FILLEDICONLABEL_H

326
src/firsttimewizard.cpp

@ -1,4 +1,4 @@
// Copyright 2019-2021 The Hush developers
// Copyright 2019-2024 The Hush developers
// Released under the GPLv3
#include "firsttimewizard.h"
#include "ui_newseed.h"
@ -7,7 +7,6 @@
#include "ui_newwallet.h"
#include "mainwindow.h"
#include "DataStore/DataStore.h"
#include "../lib/silentdragonlitelib.h"
#ifdef Q_OS_WIN
@ -50,8 +49,13 @@ void FirstTimeWizard::slot_change_theme(const QString& theme_name) {
}
FirstTimeWizard::FirstTimeWizard(bool dangerous, QString server)
{
FirstTimeWizard::FirstTimeWizard(bool dangerous, QString server){
qDebug() << __func__ << ": dangerous=" << dangerous << " server=" << server;
// Set window flags and disable close button - force user to use Wizard's cancel button to prevent funk
this->setWindowFlags(this->windowFlags() | Qt::CustomizeWindowHint);
this->setWindowFlags(this->windowFlags() & ~Qt::WindowCloseButtonHint);
// Include css
QString theme_name;
try
@ -64,21 +68,19 @@ FirstTimeWizard::FirstTimeWizard(bool dangerous, QString server)
}
this->slot_change_theme(theme_name);
setWindowTitle("New wallet wizard");
setWindowTitle(tr("New wallet wizard"));
this->dangerous = dangerous;
this->server = server;
////backup addresslabels.dat if there is one, to restore it later
//backup addresslabels.dat if there is one, to restore it later
auto dir = QDir(QStandardPaths::writableLocation(QStandardPaths::AppDataLocation));
QString addressbook = dir.filePath("addresslabels.dat.enc");
QFile file(addressbook);
if (file.exists())
{
file.rename(dir.filePath("addresslabels.dat.enc-backup"));
if (file.exists()) {
file.rename(dir.filePath("addresslabels.dat.enc-backup"));
qDebug() << __func__ << ": backed up old addresslabels";
}
// Create the pages
@ -104,88 +106,90 @@ int FirstTimeWizard::nextId() const {
QString FirstTimeWizard::getSeed()
{
return _seed;
}
void FirstTimeWizard::setSeed(QString seed)
{
_seed = seed;
}
QString FirstTimeWizard::getBirthday()
{
return _birthday;
}
void FirstTimeWizard::setBirthday(QString birthday)
{
_birthday = birthday;
}
void FirstTimeWizard::initializePage() {
qDebug() << "FirstTimeWizard:" <<__func__;
}
void NewOrRestorePage::initializePage() {
qDebug() << "NewOrRestorePage:" <<__func__;
}
NewOrRestorePage::NewOrRestorePage(FirstTimeWizard *parent) : QWizardPage(parent) {
setTitle("Create or Restore wallet.");
qDebug() << __func__;
setTitle(tr("Create or Restore wallet."));
QWidget* pageWidget = new QWidget();
Ui_CreateWalletForm form;
form.setupUi(pageWidget);
QGraphicsScene* scene = new QGraphicsScene();
QGraphicsView* view = new QGraphicsView(scene);
form.Logo->setScene(scene);
QPixmap pixmap(":/icons/res/dark-01.png");
scene->addPixmap(pixmap);
form.Logo->show();
setButtonText(QWizard::CommitButton, tr("Next"));
// Remove back button
parent->setOption(QWizard::NoBackButtonOnStartPage);
parent->setOption(QWizard::NoBackButtonOnLastPage);
parent->button(QWizard::CommitButton)->setEnabled(false);
setButtonText(QWizard::CommitButton, "Next");
form.txtPassword->setEnabled(false);
form.txtConfirmPassword->setEnabled(false);
QObject::connect(form.TOS, &QRadioButton::clicked, [=](bool checked) {
QObject::connect(form.TOS, &QRadioButton::clicked, [=](bool checked) {
qDebug() << __func__ << ": TOS radio button clicked";
if (checked) {
form.txtPassword->setEnabled(true);
form.txtConfirmPassword->setEnabled(true);
}else{
qDebug() << __func__ << ": disabling next/commit buttons";
parent->button(QWizard::CommitButton)->setEnabled(false);
parent->button(QWizard::NextButton)->setEnabled(false);
}
});
});
auto fnPasswordEdited = [=](const QString&) {
auto fnPasswordEdited = [=](const QString&) {
// Enable the Finish button if the passwords match.
QString passphraseBlank = form.txtPassword->text();
QString passphrase = QString("HUSH3") + passphraseBlank + QString("SDL");
if (!form.txtPassword->text().isEmpty() &&
form.txtPassword->text() == form.txtConfirmPassword->text() && passphraseBlank.size() >= 16 ){
form.lblPasswordMatch->setText("");
form.radioRestoreWallet->setEnabled(true);
form.radioNewWallet->setEnabled(true);
form.radioNewWallet->setChecked(true);
parent->button(QWizard::NextButton)->setEnabled(false);
int length = passphrase.length();
form.lblPasswordMatch->setText("");
form.radioRestoreWallet->setEnabled(true);
form.radioNewWallet->setEnabled(true);
parent->button(QWizard::NextButton)->setEnabled(false);
int length = passphrase.length();
//qDebug() << __func__ << ": passphrase length=" << length;
char *sequence = NULL;
sequence = new char[length+1];
strncpy(sequence, passphrase.toUtf8(), length +1);
QString passphraseHash = blake3_PW(sequence);
char *sequence1 = NULL;
sequence1 = new char[length+1];
@ -200,18 +204,20 @@ NewOrRestorePage::NewOrRestorePage(FirstTimeWizard *parent) : QWizardPage(parent
unsigned char key[KEY_LEN];
if (crypto_pwhash
(key, sizeof key, PASSWORD, strlen(PASSWORD), hash,
if (crypto_pwhash(key, sizeof key, PASSWORD, strlen(PASSWORD), hash,
crypto_pwhash_OPSLIMIT_SENSITIVE, crypto_pwhash_MEMLIMIT_SENSITIVE,
crypto_pwhash_ALG_DEFAULT) != 0) {
/* out of memory */
}
qDebug() << __func__ << ": crypto_pwhash failed! Possibly out of memory";
exit(1);
}
QString passphraseHash1 = QByteArray(reinterpret_cast<const char*>(key), KEY_LEN).toHex();
DataStore::getChatDataStore()->setPassword(passphraseHash1);
// Exclusive buttons
QObject::connect(form.radioNewWallet, &QRadioButton::clicked, [=](bool checked) {
if (checked) {
qDebug() << __func__ << ": new wallet radio button clicked";
form.radioRestoreWallet->setChecked(false);
parent->button(QWizard::CommitButton)->setEnabled(true);
@ -220,18 +226,16 @@ NewOrRestorePage::NewOrRestorePage(FirstTimeWizard *parent) : QWizardPage(parent
QObject::connect(form.radioRestoreWallet, &QRadioButton::clicked, [=](bool checked) {
if (checked) {
qDebug() << __func__ << ": restore wallet radio button clicked";
form.radioNewWallet->setChecked(false);
parent->button(QWizard::CommitButton)->setEnabled(true);
}
});
} else {
form.lblPasswordMatch->setText(tr("Passphrase don't match or You have entered too few letters (16 minimum)"));
qDebug() << __func__ << ": passphrases do not match";
form.lblPasswordMatch->setText(tr("Passphrase don't match or You have entered too few letters (16 minimum)"));
parent->button(QWizard::CommitButton)->setEnabled(false);
form.radioRestoreWallet->setEnabled(false);
@ -243,24 +247,38 @@ NewOrRestorePage::NewOrRestorePage(FirstTimeWizard *parent) : QWizardPage(parent
QVBoxLayout *layout = new QVBoxLayout;
layout->addWidget(pageWidget);
setLayout(layout);
QObject::connect(form.txtConfirmPassword, &QLineEdit::textChanged, fnPasswordEdited);
QObject::connect(form.txtPassword, &QLineEdit::textChanged, fnPasswordEdited);
registerField("intro.new", form.radioNewWallet);
registerField("intro.restore", form.radioRestoreWallet);
// A trailing * means these are REQUIRED fields and "Next" button will be disabled
// until they are filled
registerField("TOS*", form.TOS);
registerField("txtPassword*", form.txtPassword);
registerField("txtConfirmPassword*", form.txtPassword);
form.radioRestoreWallet->setEnabled(false);
form.radioNewWallet->setEnabled(false);
qDebug() << __func__ << ": disabling next/commit buttons";
setCommitPage(true);
parent->button(QWizard::CommitButton)->setEnabled(false);
parent->button(QWizard::NextButton)->setEnabled(false);
// Connect cancelEvent
disconnect(parent->button(QWizard::CancelButton ), SIGNAL( clicked() ), parent, SLOT( reject() ) );
connect(parent->button(QWizard::CancelButton ), SIGNAL( clicked() ), parent, SLOT( cancelEvent() ) );
}
NewSeedPage::NewSeedPage(FirstTimeWizard *parent) : QWizardPage(parent) {
qDebug() << __func__;
this->parent = parent;
setTitle("Your new wallet");
setTitle(tr("Your new wallet"));
QWidget* pageWidget = new QWidget();
form.setupUi(pageWidget);
@ -273,9 +291,29 @@ NewSeedPage::NewSeedPage(FirstTimeWizard *parent) : QWizardPage(parent) {
void NewSeedPage::initializePage() {
// Call the library to create a new wallet.
qDebug() << __func__;
QString reply = "";
try {
char* resp = litelib_initialize_new(parent->dangerous,parent->server.toStdString().c_str());
reply = litelib_process_response(resp);
} catch (const std::exception& e) {
qDebug() << __func__ << ": caught an exception, ignoring: " << e.what();
}
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;
char* resp = litelib_initialize_new(parent->dangerous,parent->server.toStdString().c_str());
QString reply = litelib_process_response(resp);
// 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()) {
@ -287,26 +325,27 @@ void NewSeedPage::initializePage() {
parent->setSeed(seed);
parent->setBirthday(birthday);
form.birthday->setPlainText(birthday);
parent->button(QWizard::CancelButton)->setEnabled(false);
disconnect(parent->button(QWizard::CancelButton ), SIGNAL( clicked() ), parent, SLOT( reject() ) );
connect(parent->button(QWizard::CancelButton ), SIGNAL( clicked() ), parent, SLOT( cancelEvent() ) );
qDebug() << __func__ << ": page initialized with birthday=" << birthday;
}
}
void FirstTimeWizard::cancelEvent()
{
if( QMessageBox::question( this, ( "Quit Setup" ), ( "Setup is not complete yet. Are you sure you want to quit setup?" ), QMessageBox::Yes, QMessageBox::No ) == QMessageBox::Yes ) {
// allow cancel
reject();
}
void FirstTimeWizard::cancelEvent() {
qDebug() << __func__;
if( QMessageBox::question( this, tr(( "Quit Setup" )), tr(( "Setup is not complete yet. Are you sure you want to quit setup and close the app?" )), QMessageBox::Yes, QMessageBox::No ) == QMessageBox::Yes ) {
qDebug() << __func__ << ": wizard canceled";
// Allow cancel
reject();
// Close the app
qApp->exit();
}
}
// Will be called just before closing. Make sure we can save the seed in the wallet
// before we allow the page to be closed
bool NewSeedPage::validatePage() {
qDebug() << __func__;
Ui_verifyseed verifyseed;
QDialog dialog(this);
@ -315,7 +354,6 @@ bool NewSeedPage::validatePage() {
form.birthday->setVisible(false);
form.txtSeed->setVisible(false);
QString seed = parent->getSeed();
QString birthday = parent->getBirthday();
@ -587,44 +625,71 @@ 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;
}
}else{
qDebug() << __func__ << ": reply=" << reply;
qDebug()<<"Falscher Seed";
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);
QFile file1(dirwalletfirst);
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;
this->validatePage();
}
return false;
}
RestoreSeedPage::RestoreSeedPage(FirstTimeWizard *parent) : QWizardPage(parent) {
this->parent = parent;
setTitle("Restore wallet from seed");
setTitle(tr("Restore wallet from seed"));
QWidget* pageWidget = new QWidget();
form.setupUi(pageWidget);
@ -637,8 +702,10 @@ RestoreSeedPage::RestoreSeedPage(FirstTimeWizard *parent) : QWizardPage(parent)
bool RestoreSeedPage::validatePage() {
// 1. Validate that we do have 24 words
QString seed = form.txtSeed->toPlainText().replace(QRegExp("[ \n\r\t]+"), " ");
if (seed.trimmed().split(" ").length() != 24) {
QString seed = form.txtSeed->toPlainText().replace(QRegExp("[ \n\r\t]+"), " "); //TODO: use .simplified()
auto seedLength = seed.trimmed().split(" ").length();
qDebug() << __func__ << ": seed length=" << seedLength;
if (seedLength != 24) {
QMessageBox::warning(this, tr("Failed to restore wallet"),
tr("SilentDragonLite needs 24 words to restore wallet"),
QMessageBox::Ok);
@ -648,45 +715,92 @@ bool RestoreSeedPage::validatePage() {
// 2. Validate birthday
QString birthday_str = form.txtBirthday->text();
bool ok;
qint64 birthday = birthday_str.toUInt(&ok);
// simplified() Returns a string that has whitespace removed from the start and the end, and that has each sequence of internal whitespace replaced with a single space.
qint64 birthday = birthday_str.simplified().toUInt(&ok);
if (!ok) {
qDebug() << __func__ << ": Failed to parse wallet birthday=" << birthday_str;
QMessageBox::warning(this, tr("Failed to parse wallet birthday"),
tr("Couldn't understand wallet birthday. This should be a block height from where to rescan the wallet. You can leave it as '0' if you don't know what it should be."),
tr("Couldn't understand wallet birthday. This should be a block height from where to rescan the wallet. You can leave the default if you don't know what it should be."),
QMessageBox::Ok);
return false;
}
///Number
// 3. Initialize wallet with number
QString number_str = form.number->text();
qint64 number = number_str.toUInt();
qDebug() << __func__ << ": Initializing wallet with number: " << number;
QString number_str = form.number->text();
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);
if (reply.toUpper().trimmed() != "OK") {
QMessageBox::warning(this, tr("Failed to restore wallet"),
tr("Couldn't restore the wallet") + "\n" + reply,
QMessageBox::Ok);
return false;
}
if (resp != nullptr) {
reply = litelib_process_response(resp);
} else {
qDebug() << __func__ << ": Null response from litelib_initialize_new_from_phrase";
}
} catch (const std::exception &e) {
qDebug() << __func__ << ": caught an exception, ignoring: " << e.what();
}
qDebug() << __func__ << ": reply=" << reply;
if (reply.toUpper().trimmed() != "OK") {
qDebug() << "Lite server " << parent->server << " is down, getting a random one";
parent->server = Settings::getRandomServer();
qDebug() << __func__ << ": new server is " << parent->server;
char *resp = litelib_initialize_new_from_phrase(parent->dangerous, parent->server.toStdString().c_str(),
seed.toStdString().c_str(), birthday, number);
if (resp != nullptr) {
reply = litelib_process_response(resp);
} else {
qDebug() << __func__ << ": Null response on retry from litelib_initialize_new_from_phrase";
}
}
// 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()) {
QMessageBox::warning(this, tr("Failed to save wallet"),
tr("Couldn't save the wallet") + "\n" + reply,
qDebug() << __func__ << ": Failed to save wallet, reply=" << reply;
QMessageBox::warning(this, tr("Failed to save wallet"),
tr("Couldn't save the wallet") + "\n" + "server=" + parent->server + "\n" + reply,
QMessageBox::Ok);
return false;
} else {
return true;
}
}
}
}

28
src/firsttimewizard.h

@ -1,4 +1,4 @@
// Copyright 2019-2020 The Hush developers
// Copyright 2019-2024 The Hush developers
// Released under the GPLv3
#ifndef FIRSTTIMEWIZARD_H
#define FIRSTTIMEWIZARD_H
@ -12,7 +12,7 @@
class FirstTimeWizard: public QWizard
{
Q_OBJECT
public:
FirstTimeWizard(bool dangerous, QString server);
@ -23,16 +23,17 @@ public:
QString _seed;
void setSeed(QString Seed);
void setBirthday(QString Birthday);
void cancelEvent();
public slots:
void slot_change_theme(const QString& themeName);
void cancelEvent();
protected:
int nextId() const;
virtual void initializePage();
private:
FirstTimeWizard* parent;
enum {
Page_NewOrRestore,
Page_New,
@ -46,19 +47,29 @@ private:
friend class NewSeedPage;
friend class RestoreSeedPage;
};
class NewOrRestorePage: public QWizardPage {
Q_OBJECT
public:
NewOrRestorePage(FirstTimeWizard* parent);
protected:
virtual void initializePage();
private:
FirstTimeWizard* parent;
};
class NewSeedPage: public QWizardPage {
Q_OBJECT
public:
NewSeedPage(FirstTimeWizard* parent);
@ -74,6 +85,9 @@ private:
class RestoreSeedPage: public QWizardPage {
Q_OBJECT
public:
RestoreSeedPage(FirstTimeWizard* parent);
@ -85,6 +99,4 @@ private:
Ui_RestoreSeedForm form;
};
#endif // FIRSTTIMEWIZARD_H

20
src/guiconstants.h

@ -0,0 +1,20 @@
// Copyright 2019-2022 The Hush developers
// Released under the GPLv3
#ifndef GUICONSTANTS_H
#define GUICONSTANTS_H
// Generic colors
#define COLOR_BLACK QColor(0, 0, 0)
#define COLOR_WHITE QColor(255, 255, 255)
#define COLOR_UNCONFIRMED_TX QColor(255, 0, 0)
#define COLOR_DRAGONX_TEXT QColor(145, 164, 184)
// Theme background colors
#define COLOR_DEFAULT_BG QColor(229, 229, 229)
#define COLOR_BLUE_BG QColor(229, 229, 229)
#define COLOR_LIGHT_BG QColor(218, 218, 218)
#define COLOR_DARK_BG QColor(48, 51, 53)
#define COLOR_MIDNIGHT_BG QColor(17, 17, 17)
#define COLOR_DRAGONX_BG QColor(35, 40, 52)
#endif // GUICONSTANTS_H

9
src/liteinterface.cpp

@ -1,4 +1,4 @@
// Copyright 2019-2021 The Hush developers
// Copyright 2019-2024 The Hush developers
// Released under the GPLv3
#include "liteinterface.h"
@ -40,17 +40,20 @@ void LiteInterface::importTPrivKey(QString addr,const std::function<void(json)>&
if (conn == nullptr)
return;
conn->doRPCWithDefaultErrorHandling("timport", addr, cb);
conn->doRPCWithDefaultErrorHandling("timport", addr, cb);
}
void LiteInterface::fetchUnspent(const std::function<void(json)>& cb) {
if (conn == nullptr)
if (conn == nullptr) {
qDebug() << "fetchUnspent: conn ist nullptr, breche ab";
return;
}
conn->doRPCWithDefaultErrorHandling("notes", "", cb);
}
void LiteInterface::createNewZaddr(bool, const std::function<void(json)>& cb) {
if (conn == nullptr)
return;

2
src/liteinterface.h

@ -1,4 +1,4 @@
// Copyright 2019-2021 The Hush developers
// Copyright 2019-2024 The Hush developers
// Released under the GPLv3
#ifndef hushDRPC_H
#define hushDRPC_H

2
src/logger.cpp

@ -1,4 +1,4 @@
// Copyright 2019-2021 The Hush developers
// Copyright 2019-2024 The Hush developers
// Released under the GPLv3
#include "logger.h"

2
src/logger.h

@ -1,4 +1,4 @@
// Copyright 2019-2021 The Hush developers
// Copyright 2019-2024 The Hush developers
// Released under the GPLv3
#ifndef LOGGER_H
#define LOGGER_H

3
src/main.cpp

@ -1,4 +1,4 @@
// Copyright 2019-2021 The Hush developers
// Copyright 2019-2024 The Hush developers
// Released under the GPLv3
#include <singleapplication.h>
@ -6,6 +6,7 @@
#include "mainwindow.h"
#include "controller.h"
#include "settings.h"
#include <QCommandLineParser>
#include "version.h"

709
src/mainwindow.cpp

File diff suppressed because it is too large

13
src/mainwindow.h

@ -1,4 +1,4 @@
// Copyright 2019-2021 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();
@ -167,6 +161,7 @@ private:
void addAddressSection();
void maxAmountChecked(int checked);
void toggleMinerFeeEditable(int state);
void editSchedule();
@ -200,10 +195,6 @@ private:
bool uiPaymentsReady = false;
QString pendingURIPayment;
WSServer* wsserver = nullptr;
WormholeClient* wormhole = nullptr;
Controller* rpc = nullptr;
QCompleter* labelCompleter = nullptr;

927
src/mainwindow.ui

File diff suppressed because it is too large

2
src/memoedit.cpp

@ -1,4 +1,4 @@
// Copyright 2019-2021 The Hush developers
// Copyright 2019-2024 The Hush developers
// Released under the GPLv3
#include "memoedit.h"

8
src/memoedit.h

@ -1,12 +1,14 @@
// Copyright 2019-2021 The Hush developers
// Copyright 2019-2024 The Hush developers
// Released under the GPLv3
#ifndef MEMOEDIT_H
#define MEMOEDIT_H
#include "precompiled.h"
class MemoEdit : public QPlainTextEdit
{
class MemoEdit : public QPlainTextEdit {
Q_OBJECT
public:
MemoEdit(QWidget* parent);

139
src/migration.ui

@ -1,139 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>MigrationDialog</class>
<widget class="QDialog" name="MigrationDialog">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>511</width>
<height>498</height>
</rect>
</property>
<property name="windowTitle">
<string>Migration Turnstile</string>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="9" column="0" colspan="2">
<widget class="QDialogButtonBox" name="buttonBox">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="standardButtons">
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
</property>
</widget>
</item>
<item row="7" column="0" colspan="2">
<widget class="QGroupBox" name="groupBox">
<property name="title">
<string>Migration History</string>
</property>
<layout class="QGridLayout" name="gridLayout_2">
<item row="2" column="1">
<widget class="QLabel" name="label_4">
<property name="text">
<string>Migrated Amount</string>
</property>
</widget>
</item>
<item row="4" column="1" colspan="2">
<widget class="QTableView" name="tblTxids">
<attribute name="horizontalHeaderStretchLastSection">
<bool>true</bool>
</attribute>
</widget>
</item>
<item row="0" column="1">
<widget class="QLabel" name="label_2">
<property name="text">
<string>Unmigrated Amount</string>
</property>
</widget>
</item>
<item row="0" column="2">
<widget class="QLabel" name="lblUnMigrated">
<property name="text">
<string notr="true">TextLabel</string>
</property>
</widget>
</item>
<item row="2" column="2">
<widget class="QLabel" name="lblMigrated">
<property name="text">
<string notr="true">TextLabel</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item row="0" column="0" colspan="2">
<widget class="QCheckBox" name="chkEnabled">
<property name="text">
<string>Sprout -&gt; Sapling migration enabled</string>
</property>
</widget>
</item>
<item row="1" column="0" colspan="2">
<widget class="QLabel" name="label">
<property name="text">
<string>If enabled, hushd will slowly migrate your Sprout shielded funds to your Sapling address. </string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
<item row="4" column="0" colspan="2">
<widget class="Line" name="line">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
<item row="2" column="0" colspan="2">
<widget class="QLabel" name="lblSaplingAddress">
<property name="text">
<string notr="true"/>
</property>
</widget>
</item>
</layout>
</widget>
<resources/>
<connections>
<connection>
<sender>buttonBox</sender>
<signal>accepted()</signal>
<receiver>MigrationDialog</receiver>
<slot>accept()</slot>
<hints>
<hint type="sourcelabel">
<x>248</x>
<y>254</y>
</hint>
<hint type="destinationlabel">
<x>157</x>
<y>274</y>
</hint>
</hints>
</connection>
<connection>
<sender>buttonBox</sender>
<signal>rejected()</signal>
<receiver>MigrationDialog</receiver>
<slot>reject()</slot>
<hints>
<hint type="sourcelabel">
<x>316</x>
<y>260</y>
</hint>
<hint type="destinationlabel">
<x>286</x>
<y>274</y>
</hint>
</hints>
</connection>
</connections>
</ui>

16
src/mobileappconnector.cpp

@ -1,16 +0,0 @@
// Copyright 2019-2021 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;
}

24
src/mobileappconnector.h

@ -1,24 +0,0 @@
// Copyright 2019-2021 The Hush developers
// Released under the GPLv3
#ifndef MOBILEAPPCONNECTOR_H
#define MOBILEAPPCONNECTOR_H
#include <QDialog>
namespace Ui {
class MobileAppConnector;
}
class MobileAppConnector : public QDialog
{
Q_OBJECT
public:
explicit MobileAppConnector(QWidget *parent = nullptr);
~MobileAppConnector();
private:
Ui::MobileAppConnector *ui;
};
#endif // MOBILEAPPCONNECTOR_H

214
src/mobileappconnector.ui

@ -1,214 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>MobileAppConnector</class>
<widget class="QDialog" name="MobileAppConnector">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>800</width>
<height>530</height>
</rect>
</property>
<property name="windowTitle">
<string>Mobile Connector App</string>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="4" column="1" colspan="2">
<widget class="QDialogButtonBox" name="buttonBox">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="standardButtons">
<set>QDialogButtonBox::Close</set>
</property>
</widget>
</item>
<item row="0" column="0" colspan="3">
<widget class="QLabel" name="label">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Minimum">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Scan this QRCode from your silentdragon companion app to connect your phone</string>
</property>
</widget>
</item>
<item row="1" column="0" colspan="2">
<widget class="QGroupBox" name="groupBox_2">
<property name="title">
<string>QR Code</string>
</property>
<layout class="QGridLayout" name="gridLayout_3">
<item row="1" column="0">
<widget class="QLabel" name="label_2">
<property name="text">
<string>Connection String</string>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLineEdit" name="txtConnStr">
<property name="font">
<font>
<pointsize>9</pointsize>
</font>
</property>
<property name="readOnly">
<bool>true</bool>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QRCodeLabel" name="qrcode">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="MinimumExpanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="styleSheet">
<string notr="true">background-color: #fff</string>
</property>
<property name="text">
<string/>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QCheckBox" name="chkInternetConn">
<property name="text">
<string>Allow connections over the internet via silentdragon wormhole</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item row="1" column="2" rowspan="2">
<widget class="QGroupBox" name="groupBox">
<property name="title">
<string>silentdragon Companion App</string>
</property>
<layout class="QGridLayout" name="gridLayout_2">
<item row="5" column="0">
<widget class="QPushButton" name="btnDisconnect">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Disconnect</string>
</property>
</widget>
</item>
<item row="6" column="0">
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
<item row="2" column="0">
<widget class="QLabel" name="lblLastSeen">
<property name="text">
<string>TextLabel</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_3">
<property name="text">
<string>Last seen:</string>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QLabel" name="lblRemoteName">
<property name="text">
<string notr="true">TextLabel</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QLabel" name="label_4">
<property name="text">
<string>Connection type:</string>
</property>
</widget>
</item>
<item row="4" column="0">
<widget class="QLabel" name="lblConnectionType">
<property name="text">
<string>TextLabel</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
</layout>
</widget>
</item>
</layout>
</widget>
<customwidgets>
<customwidget>
<class>QRCodeLabel</class>
<extends>QLabel</extends>
<header>qrcodelabel.h</header>
</customwidget>
</customwidgets>
<resources/>
<connections>
<connection>
<sender>buttonBox</sender>
<signal>accepted()</signal>
<receiver>MobileAppConnector</receiver>
<slot>accept()</slot>
<hints>
<hint type="sourcelabel">
<x>248</x>
<y>254</y>
</hint>
<hint type="destinationlabel">
<x>157</x>
<y>274</y>
</hint>
</hints>
</connection>
<connection>
<sender>buttonBox</sender>
<signal>rejected()</signal>
<receiver>MobileAppConnector</receiver>
<slot>reject()</slot>
<hints>
<hint type="sourcelabel">
<x>316</x>
<y>260</y>
</hint>
<hint type="destinationlabel">
<x>286</x>
<y>274</y>
</hint>
</hints>
</connection>
</connections>
</ui>

2
src/newseed.ui

@ -17,7 +17,7 @@
<item row="0" column="0">
<widget class="QLabel" name="label">
<property name="text">
<string>This is your new wallet's seed phrase. PLEASE BACK IT UP SECURELY.</string>
<string>This is your new wallet's seed phrase. PLEASE BACK IT UP SECURELY. Write it on paper. Do not store it anywhere others can access it.</string>
</property>
<property name="wordWrap">
<bool>true</bool>

5
src/newwallet.ui

@ -110,6 +110,9 @@ p, li { white-space: pre-wrap; }
<height>16777215</height>
</size>
</property>
<property name="styleSheet">
<string notr="true">color: red;</string>
</property>
<property name="text">
<string>I accept the Terms of Service</string>
</property>
@ -146,7 +149,7 @@ p, li { white-space: pre-wrap; }
<string notr="true">color: red;</string>
</property>
<property name="text">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;span style=&quot; font-style:italic;&quot;&gt;Passphrase don't match&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
<string></string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>

3
src/precompiled.h

@ -1,4 +1,4 @@
// Copyright 2019-2021 The Hush developers
// Copyright 2019-2024 The Hush developers
// Released under the GPLv3
#if defined __cplusplus
/* Add C++ includes here */
@ -64,7 +64,6 @@
#include <QtNetwork/QNetworkRequest>
#include <QtNetwork/QNetworkAccessManager>
#include <QtNetwork/QNetworkReply>
#include <QtWebSockets/QtWebSockets>
#include <QJsonDocument>
#include <QJsonArray>
#include <QJsonObject>

18
src/qrcodelabel.cpp

@ -1,4 +1,4 @@
// Copyright 2019-2021 The Hush developers
// Copyright 2019-2024 The Hush developers
// Released under the GPLv3
#include "qrcodelabel.h"
@ -12,7 +12,7 @@ QRCodeLabel::QRCodeLabel(QWidget *parent) :
QSize QRCodeLabel::sizeHint() const
{
int w = this->width();
return QSize(w, w); // 1:1
return QSize(w, w); // 1:1
}
void QRCodeLabel::resizeEvent(QResizeEvent*)
@ -25,8 +25,8 @@ QPixmap QRCodeLabel::scaledPixmap() const {
QPixmap pm(size());
pm.fill(Qt::white);
QPainter painter(&pm);
qrcodegen::QrCode qr = qrcodegen::QrCode::encodeText(str.toUtf8().constData(), qrcodegen::QrCode::Ecc::LOW);
qrcodegen::QrCode qr = qrcodegen::QrCode::encodeText(str.toUtf8().constData(), qrcodegen::QrCode::Ecc::HIGH);
const int s = qr.getSize()>0?qr.getSize():1;
const double w = pm.width();
const double h = pm.height();
@ -35,8 +35,8 @@ QPixmap QRCodeLabel::scaledPixmap() const {
const double scale = size/(s+2);
const double woff = (w - size) > 0 ? (w - size) / 2 : 0;
const double hoff = (h - size) > 0 ? (h - size) / 2 : 0;
// NOTE: For performance reasons my implementation only draws the foreground parts
// NOTE: For performance reasons my implementation only draws the foreground parts
painter.setPen(Qt::NoPen);
painter.setBrush(QColor(Qt::black));
for(int y=0; y<s; y++) {
@ -49,7 +49,11 @@ QPixmap QRCodeLabel::scaledPixmap() const {
}
}
}
// TODO: Maybe add logo if it doesn't break QR code - requires setting Ecc to HIGH
painter.drawPixmap((w/2)-50, (h/2)-50, 100, 100, QPixmap(":/img/res/logobig.gif"));
painter.end();
return pm;
}

2
src/qrcodelabel.h

@ -1,4 +1,4 @@
// Copyright 2019-2021 The Hush developers
// Copyright 2019-2024 The Hush developers
// Released under the GPLv3
#ifndef QRCODELABEL_H
#define QRCODELABEL_H

10
src/recurring.cpp

@ -1,4 +1,4 @@
// Copyright 2019-2021 The Hush developers
// Copyright 2019-2024 The Hush developers
// Released under the GPLv3
#include "recurring.h"
@ -279,7 +279,7 @@ void Recurring::updateInfoWithTx(RecurringPaymentInfo* r, Tx tx) {
r->fromAddr = tx.fromAddr;
if (r->currency.isEmpty() || r->currency == "USD") {
r->currency = "USD";
r->amt = tx.toAddrs[0].amount.toqint64() * Settings::getInstance()->getZECPrice();
r->amt = tx.toAddrs[0].amount.toqint64() * Settings::getInstance()->getHUSHPrice();
}
else {
r->currency = Settings::getTokenName();
@ -547,7 +547,7 @@ void Recurring::executeRecurringPayment(MainWindow* main, RecurringPaymentInfo r
double amount = rpi.amt;
if (rpi.currency == "USD") {
// If there is no price, then fail the payment
if (Settings::getInstance()->getZECPrice() == 0) {
if (Settings::getInstance()->getHUSHPrice() == 0) {
for (auto paymentNumber: paymentNumbers) {
updatePaymentItem(rpi.getHash(), paymentNumber,
"", QObject::tr("No hush price was available to convert from USD"),
@ -559,7 +559,7 @@ void Recurring::executeRecurringPayment(MainWindow* main, RecurringPaymentInfo r
}
// Translate it into hush
amount = rpi.amt / Settings::getInstance()->getZECPrice();
amount = rpi.amt / Settings::getInstance()->getHUSHPrice();
}
// Build a Tx
@ -600,7 +600,7 @@ void Recurring::executeRecurringPayment(MainWindow* main, RecurringPaymentInfo r
* Execute a send Tx
*/
void Recurring::doSendTx(MainWindow* mainwindow, Tx tx, std::function<void(QString, QString)> cb) {
mainwindow->getRPC()->executeTransaction(tx,
mainwindow->getRPC()->executeTransaction(tx, false,
[=] (QString txid) {
mainwindow->ui->statusBar->showMessage(Settings::txidStatusMessage + " " + txid);
cb(txid, "");

6
src/recurring.h

@ -1,4 +1,4 @@
// Copyright 2019-2021 The Hush developers
// Copyright 2019-2024 The Hush developers
// Released under the GPLv3
#ifndef RECURRING_H
#define RECURRING_H
@ -121,6 +121,8 @@ private:
// Model for list of configured recurring payments
class RecurringListViewModel : public QAbstractTableModel {
Q_OBJECT
public:
RecurringListViewModel(QTableView* parent);
~RecurringListViewModel() = default;
@ -138,6 +140,8 @@ private:
// Model for history of payments
class RecurringPaymentsListViewModel : public QAbstractTableModel {
Q_OBJECT
public:
RecurringPaymentsListViewModel(QTableView* parent, RecurringPaymentInfo rpi);
~RecurringPaymentsListViewModel() = default;

2
src/recurringdialog.ui

@ -11,7 +11,7 @@
</rect>
</property>
<property name="windowTitle">
<string>Reccuring Dialog</string>
<string>Recurring Dialog</string>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="0">

2
src/recurringpayments.ui

@ -11,7 +11,7 @@
</rect>
</property>
<property name="windowTitle">
<string>Reocurring Payments</string>
<string>Recurring Payments</string>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="1">

90
src/requestContactDialog.ui

@ -326,29 +326,29 @@
<rect>
<x>417</x>
<y>430</y>
<width>106</width>
<width>130</width>
<height>25</height>
</rect>
</property>
<property name="minimumSize">
<size>
<width>106</width>
<width>130</width>
<height>25</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>106</width>
<width>130</width>
<height>25</height>
</size>
</property>
<item>
<property name="text">
<string>SDLogo</string>
<string>Anonymous</string>
</property>
<property name="icon">
<iconset>
<activeon>:/icons/res/SDLogo.png</activeon>
<activeon>:/icons/res/Anonymous.png</activeon>
</iconset>
</property>
</item>
@ -364,111 +364,51 @@
</item>
<item>
<property name="text">
<string>Denio</string>
</property>
<property name="icon">
<iconset>
<activeon>:/icons/res/Denio.png</activeon>
</iconset>
</property>
</item>
<item>
<property name="text">
<string>Berg</string>
</property>
<property name="icon">
<iconset>
<activeon>:/icons/res/Berg.png</activeon>
</iconset>
</property>
</item>
<item>
<property name="text">
<string>Sharpee</string>
</property>
<property name="icon">
<iconset>
<activeon>:/icons/res/Sharpee.png</activeon>
</iconset>
</property>
</item>
<item>
<property name="text">
<string>Elsa</string>
<string>onryo</string>
</property>
<property name="icon">
<iconset>
<normalon>:/icons/res/Elsa.png</normalon>
<activeon>:/icons/res/onryo.png</activeon>
</iconset>
</property>
</item>
<item>
<property name="text">
<string>Yoda</string>
<string>fekt</string>
</property>
<property name="icon">
<iconset>
<activeon>:/icons/res/Yoda.png</activeon>
<activeon>:/icons/res/fekt.png</activeon>
</iconset>
</property>
</item>
<item>
<property name="text">
<string>Garfield</string>
<string>jahway603</string>
</property>
<property name="icon">
<iconset>
<activeon>:/icons/res/Garfield.png</activeon>
<activeon>:/icons/res/jahway603.png</activeon>
</iconset>
</property>
</item>
<item>
<property name="text">
<string>Snoopy</string>
</property>
<property name="icon">
<iconset>
<activeon>:/icons/res/Snoopy.png</activeon>
</iconset>
</property>
</item>
<item>
<property name="text">
<string>Popey</string>
</property>
<property name="icon">
<iconset>
<activeon>:/icons/res/Popey.png</activeon>
</iconset>
</property>
</item>
<item>
<property name="text">
<string>Pinguin</string>
</property>
<property name="icon">
<iconset>
<activeon>:/icons/res/Pinguin.png</activeon>
</iconset>
</property>
</item>
<item>
<property name="text">
<string>Mickey</string>
<string>Denio</string>
</property>
<property name="icon">
<iconset>
<activeon>:/icons/res/Mickey.png</activeon>
<activeon>:/icons/res/Denio.png</activeon>
</iconset>
</property>
</item>
<item>
<property name="text">
<string>Stag</string>
<string>Sharpee</string>
</property>
<property name="icon">
<iconset>
<activeon>:/icons/res/Stag.png</activeon>
<activeon>:/icons/res/Sharpee.png</activeon>
</iconset>
</property>
</item>

2
src/requestdialog.cpp

@ -1,4 +1,4 @@
// Copyright 2019-2021 The Hush developers
// Copyright 2019-2024 The Hush developers
// Released under the GPLv3
#include "requestdialog.h"
#include "ui_requestdialog.h"

2
src/requestdialog.h

@ -1,4 +1,4 @@
// Copyright 2019-2021 The Hush developers
// Copyright 2019-2024 The Hush developers
// Released under the GPLv3
#ifndef REQUESTDIALOG_H
#define REQUESTDIALOG_H

72
src/restoreSeed.ui

@ -1,72 +0,0 @@
<ui version="4.0" >
<author></author>
<comment></comment>
<exportmacro></exportmacro>
<class>Dialog</class>
<widget class="QDialog" name="Dialog" >
<property name="geometry" >
<rect>
<x>0</x>
<y>0</y>
<width>400</width>
<height>300</height>
</rect>
</property>
<property name="windowTitle" >
<string>Dialog</string>
</property>
<widget class="QDialogButtonBox" name="buttonBox" >
<property name="geometry" >
<rect>
<x>30</x>
<y>240</y>
<width>341</width>
<height>32</height>
</rect>
</property>
<property name="orientation" >
<enum>Qt::Horizontal</enum>
</property>
<property name="standardButtons" >
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
</property>
</widget>
</widget>
<pixmapfunction></pixmapfunction>
<resources/>
<connections>
<connection>
<sender>buttonBox</sender>
<signal>accepted()</signal>
<receiver>Dialog</receiver>
<slot>accept()</slot>
<hints>
<hint type="sourcelabel" >
<x>248</x>
<y>254</y>
</hint>
<hint type="destinationlabel" >
<x>157</x>
<y>274</y>
</hint>
</hints>
</connection>
<connection>
<sender>buttonBox</sender>
<signal>rejected()</signal>
<receiver>Dialog</receiver>
<slot>reject()</slot>
<hints>
<hint type="sourcelabel" >
<x>316</x>
<y>260</y>
</hint>
<hint type="destinationlabel" >
<x>286</x>
<y>274</y>
</hint>
</hints>
</connection>
</connections>
</ui>

2
src/restoreseed.ui

@ -62,7 +62,7 @@
</font>
</property>
<property name="text">
<string>Wallet birthday is the block height at which the wallet had the first transaction. If you don't know this, you can leave it as &quot;0&quot; (It'll take longer to rescan)</string>
<string>Wallet birthday is the block height at which the wallet had the first transaction. If you don't know this, you can leave the default. (It'll take longer to rescan)</string>
</property>
<property name="wordWrap">
<bool>true</bool>

2
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

19
src/scripts/translation_analysis.sh

@ -0,0 +1,19 @@
#!/bin/bash
echo -n AR: ;grep unfinished silentdragonlite_ar.ts | wc -l
echo -n BE: ;grep unfinished silentdragonlite_be.ts | wc -l
echo -n DE: ;grep unfinished silentdragonlite_de.ts | wc -l
echo -n ES: ;grep unfinished silentdragonlite_es.ts | wc -l
echo -n FA: ;grep unfinished silentdragonlite_fa.ts | wc -l
echo -n FR: ;grep unfinished silentdragonlite_fr.ts | wc -l
echo -n HR: ;grep unfinished silentdragonlite_hr.ts | wc -l
echo -n ID: ;grep unfinished silentdragonlite_id.ts | wc -l
echo -n IT: ;grep unfinished silentdragonlite_it.ts | wc -l
echo -n NL: ;grep unfinished silentdragonlite_nl.ts | wc -l
echo -n PT: ;grep unfinished silentdragonlite_pt.ts | wc -l
echo -n RO: ;grep unfinished silentdragonlite_ro.ts | wc -l
echo -n RU: ;grep unfinished silentdragonlite_ru.ts | wc -l
echo -n SR: ;grep unfinished silentdragonlite_sr.ts | wc -l
echo -n TR: ;grep unfinished silentdragonlite_tr.ts | wc -l
echo -n UD: ;grep unfinished silentdragonlite_ud.ts | wc -l
echo -n ZH: ;grep unfinished silentdragonlite_zh.ts | wc -l

1
src/sdl.h

@ -0,0 +1 @@
#define DEBUG(x) (qDebug() << QString(__func__) << ": " << x)

68
src/sendtab.cpp

@ -1,4 +1,4 @@
// Copyright 2019-2021 The Hush developers
// Copyright 2019-2024 The Hush developers
// Released under the GPLv3
#include "mainwindow.h"
#include "ui_mainwindow.h"
@ -31,6 +31,9 @@ void MainWindow::setupSendTab() {
// Max available Checkbox
QObject::connect(ui->Max1, &QCheckBox::stateChanged, this, &MainWindow::maxAmountChecked);
//Custom Fee Checkbox
QObject::connect(ui->customFee, &QCheckBox::stateChanged, this, &MainWindow::toggleMinerFeeEditable);
// The first Address button
QObject::connect(ui->Address1, &QLineEdit::textChanged, [=] (auto text) {
this->addressChanged(1, text);
@ -57,8 +60,8 @@ void MainWindow::setupSendTab() {
this->amountChanged(1, text);
});
// Fee amount changed
ui->minerFeeAmt->setReadOnly(true);
// Fee amount changed
QObject::connect(ui->minerFeeAmt, &QLineEdit::textChanged, [=](auto txt) {
CAmount fee = CAmount::fromDecimalString(txt);
@ -520,7 +523,6 @@ Tx MainWindow::createTxFromSendPage() {
CAmount amt;
// Make sure it parses
amtStr.toDouble(&ok);
if (!ok) {
@ -534,16 +536,21 @@ Tx MainWindow::createTxFromSendPage() {
QString memo = ui->sendToWidgets->findChild<QLabel*>(QString("MemoTxt") % QString::number(i+1))->text().trimmed();
tx.toAddrs.push_back( ToFields{addr, amt, memo} );
}
// Allow Custom Fee in SendTab
bool customFee = ui->customFee->isChecked();
tx.fee = Settings::getMinerFee();
CAmount fee ;
if (customFee) {
QString feeStr = ui->minerFeeAmt->text();
tx.fee = CAmount::fromDecimalString(feeStr);
}else{
tx.fee = Settings::getMinerFee();
}
return tx;
}
@ -797,11 +804,20 @@ bool MainWindow::confirmTx(Tx tx, RecurringPaymentInfo* rpi) {
confirm.lblRecurringDesc->setText(rpi->getScheduleDescription());
}
CAmount defaultFee = Settings::getMinerFee();
if (tx.fee.toDecimalString() != defaultFee.toDecimalString() ) {
auto customFeeWarning = new QLabel(confirm.sendToAddrs);
customFeeWarning->setObjectName(QStringLiteral("Custom Fee"));
customFeeWarning->setText(tr("You are using a custom Fee"));
customFeeWarning->setStyleSheet("color: red;");
confirm.gridLayout->addWidget(customFeeWarning);
confirm.gridLayout->rowStretch(1);
row++;
}
// Syncing warning
confirm.syncingWarning->setVisible(Settings::getInstance()->isSyncing());
// Show the dialog and submit it if the user confirms
return d.exec() == QDialog::Accepted;
}
@ -845,8 +861,8 @@ void MainWindow::sendButton() {
auto d = new QDialog(this);
auto connD = new Ui_ConnectionDialog();
connD->setupUi(d);
QMovie *movie1 = new QMovie(":/img/res/silentdragonlite-animated.gif");;
QMovie *movie2 = new QMovie(":/img/res/silentdragonlite-animated-dark.gif");;
QMovie *movie1 = new QMovie(":/img/res/silentdragonlite-animated-startup-dark.gif");;
QMovie *movie2 = new QMovie(":/img/res/silentdragonlite-animated-startup-dark.gif");;
auto theme = Settings::getInstance()->get_theme_name();
if (theme == "Dark" || theme == "Midnight") {
movie2->setScaledSize(QSize(512,512));
@ -864,7 +880,7 @@ void MainWindow::sendButton() {
d->show();
// And send the Tx
rpc->executeTransaction(tx,
rpc->executeTransaction(tx, false,
[=] (QString txid) {
ui->statusBar->showMessage(Settings::txidStatusMessage + " " + txid);
@ -881,6 +897,19 @@ void MainWindow::sendButton() {
ui->tabWidget->setCurrentIndex(0);
});
bool isStickyServerEnabled = Settings::getInstance()->getUseStickyServer();
if(isStickyServerEnabled) {
qDebug() << "Not changing servers because stickyServer=1";
} else {
// After each transaction, change servers to spread out
// (ip,txid) metadata across different lite servers
// TODO: should we try to ensure that our new random server is actually different?
auto server = Settings::getRandomServer();
qDebug() << "Changed server to " << server << " for extreme privacy";
ui->statusBar->showMessage("Changed server to " % server);
ui->current_server->setText(server);
}
// Force a UI update so we get the unconfirmed Tx
rpc->refresh(true);
@ -943,9 +972,24 @@ QString MainWindow::doSendTxValidations(Tx tx) {
.arg(available.toDecimalhushString(), total.toDecimalhushString());
}
if (total == 0) {
return tr("Value or fee must be > 0\n\nValue and fee cannot both be 0.");
}
return "";
}
void MainWindow::cancelButton() {
clearSendForm();
}
//Check for custom fee checkbox
void MainWindow::toggleMinerFeeEditable(int state) {
if (state == Qt::Checked) {
ui->minerFeeAmt->setReadOnly(false);
} else {
ui->minerFeeAmt->setReadOnly(true);
ui->minerFeeAmt->setText(Settings::getMinerFee().toDecimalString());
}
}

143
src/settings.cpp

@ -1,8 +1,10 @@
// Copyright 2019-2021 The Hush developers
// Copyright 2019-2024 The Hush developers
// Released under the GPLv3
#include "mainwindow.h"
#include "settings.h"
#include "camount.h"
#include "../lib/silentdragonlitelib.h"
#include <QUrlQuery>
Settings* Settings::instance = nullptr;
@ -18,26 +20,48 @@ Settings* Settings::getInstance() {
}
Config Settings::getSettings() {
qDebug() << __func__;
// Load from the QT Settings.
QSettings s;
// this domain is stolen and malicious!
auto malicious = "https://lite.myhush.org";
auto server = s.value("connection/server").toString();
if(server == malicious) {
server = "https://lite.hush.is";
qDebug() << "Replacing malicious SDL server with " << server;
s.setValue("connection/server", server);
s.sync();
// re-init to load correct settings
init();
bool sticky = s.value("connection/stickyServer").toBool();
bool torOnly = s.value("connection/torOnly").toBool();
while (server.endsWith("/")) {
// trailing slashes make Rust sad
server.chop(1);
}
// default behavior : no server listed in conf, randomly choose from server list, unless sticky
if (server.trimmed().isEmpty()) {
server = Settings::getDefaultServer();
server = Settings::getRandomServer();
bool isOnline = false;
// make sure existing server in conf is alive, otherwise choose random one
try {
isOnline = litelib_check_server_online(server.toStdString().c_str());
} catch (const std::exception& e) {
qDebug() << __func__ << ": caught an exception, ignoring: " << e.what();
}
if (!isOnline) {
qDebug() << "Lite server in conf " << server << " is down, getting a random one";
server = Settings::getRandomServer();
s.setValue("connection/server", server);
}
} else {
if (sticky) {
qDebug() << server << " is sticky";
}
// if it's down, oh well
}
return Config{server};
s.sync();
// re-init to load correct settings
init();
return Config{server, torOnly, sticky};
}
void Settings::saveSettings(const QString& server) {
@ -66,13 +90,6 @@ bool Settings::isSaplingAddress(QString addr) {
(!isTestnet() && addr.startsWith("zs1"));
}
bool Settings::isSproutAddress(QString addr) {
if (!isValidAddress(addr))
return false;
return isZAddress(addr) && !isSaplingAddress(addr);
}
bool Settings::isZAddress(QString addr) {
if (!isValidAddress(addr))
return false;
@ -115,8 +132,8 @@ bool Settings::isSaplingActive() {
return (isTestnet() && getBlockNumber() > 0) || (!isTestnet() && getBlockNumber() > 0);
}
double Settings::getZECPrice() {
return ZECPrice;
double Settings::getHUSHPrice() {
return HUSHPrice;
}
double Settings::getEURPrice() {
return EURPrice;
@ -232,6 +249,22 @@ void Settings::setAllowFetchPrices(bool allow) {
QSettings().setValue("options/allowfetchprices", allow);
}
bool Settings::getUseStickyServer() {
return QSettings().value("connection/stickyServer", false).toBool();
}
void Settings::setUseStickyServer(bool allow) {
QSettings().setValue("connection/stickyServer", allow);
}
bool Settings::getUseNoteAutomation() {
return QSettings().value("options/useNoteAutomation", true).toBool();
}
void Settings::setUseNoteAutomation(bool allow) {
QSettings().setValue("options/useNoteAutomation", allow);
}
QString Settings::get_currency_name() {
// Load from the QT Settings.
return QSettings().value("options/currency_name", false).toString();
@ -250,9 +283,7 @@ void Settings::set_theme_name(QString theme_name) {
QSettings().setValue("options/theme_name", theme_name);
}
//=================================
// Static Stuff
//=================================
void Settings::saveRestore(QDialog* d) {
d->restoreGeometry(QSettings().value(d->objectName() % "geometry").toByteArray());
@ -271,20 +302,54 @@ void Settings::saveRestoreTableHeader(QTableView* table, QDialog* d, QString tab
}
QString Settings::getRandomServer() {
qDebug() << __func__;
// The more servers from different TLDs, the better
QList<QString> servers = {
"https://lite.hush.is",
"https://lite.myhush.org",
"https://wtfistheinternet.hush.is",
"https://poop.granitefone.me",
// These can be un-commented to test out how code deals with down servers
//"https://thisisdown1.example.com",
//"https://thisisdown2.example.com",
//"https://thisisdown3.example.com",
//"https://thisisdown4.example.com",
//"https://thisisdown5.example.com",
"https://lite.hush.land",
"https://lite.hushpool.is",
"https://lite2.hushpool.is"
};
// we don't need cryptographic random-ness, but we want
// clients to never get "stuck" with the same server, which
// prevents various attacks
QList<QString> servers;
//TODO: This should be a much larger list which we randomly choose from
servers[0] = "https://lite.hush.is";
servers[1] = "https://miodrag.zone:9876";
servers[2] = "https://hush.leto.net:5420";
int x = rand() % 3;
return servers[1];
}
QString Settings::getDefaultServer() {
return "https://miodrag.zone:9876";
int x = rand() % servers.size();
auto server = servers[x];
int tries = 0;
// 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 alive, try=" << tries;
bool isOnline = "";
try {
isOnline = litelib_check_server_online(server.toStdString().c_str());
} catch (const std::exception& e) {
qDebug() << __func__ << ": caught an exception, ignoring: " << e.what();
}
// if we see a valid connection, return this server.
if (isOnline) {
qDebug() << "Choosing lite server " << server;
return server;
}
x++;
x = x % servers.size();
server = servers[x];
tries++;
}
return server;
}
void Settings::openAddressInExplorer(QString address) {
@ -302,20 +367,12 @@ const QString Settings::txidStatusMessage = QString(QObject::tr("Tx submitted (r
QString Settings::getTokenName() {
if (Settings::getInstance()->isTestnet()) {
return "HUSHT";
return "TUSH";
} else {
return "HUSH";
}
}
QString Settings::getDonationAddr() {
if (Settings::getInstance()->isTestnet())
return "ztestsaplingXXX";
else
return "zs1fq9f7vg797qaeac9lyx0njyjmjg4w7m60hwq6lhyhvdcqltl5hdkm8vwx9cxy60ehuuz2x49jxt";
}
CAmount Settings::getMinerFee() {
return CAmount::fromqint64(10000);
}

20
src/settings.h

@ -1,4 +1,4 @@
// Copyright 2019-2021 The Hush developers
// Copyright 2019-2024 The Hush developers
// Released under the GPLv3
#ifndef SETTINGS_H
#define SETTINGS_H
@ -9,7 +9,12 @@
using json = nlohmann::json;
struct Config {
// The randomly chosen server we are talking to OR user-specific server
QString server;
// Shouuld we only speak Tor to this server?
bool torOnly {false};
// Should we randomly try other servers if specified server is down?
bool stickyServer {false};
};
struct ToFields;
@ -37,7 +42,6 @@ public:
void setTestnet(bool isTestnet);
bool isSaplingAddress(QString addr);
bool isSproutAddress(QString addr);
bool isValidSaplingPrivateKey(QString pk);
@ -62,6 +66,12 @@ public:
bool getCheckForUpdates();
void setCheckForUpdates(bool allow);
bool getUseStickyServer();
void setUseStickyServer(bool allow);
bool getUseNoteAutomation();
void setUseNoteAutomation(bool allow);
QString get_theme_name();
void set_theme_name(QString theme_name);
@ -71,7 +81,7 @@ public:
bool isSaplingActive();
void setZECPrice(double p) { ZECPrice = p; }
void setHUSHPrice(double p) { HUSHPrice = p; }
void setEURPrice(double p) { EURPrice = p; }
void setBTCPrice(double p) { BTCPrice = p; }
void setCNYPrice(double p) { CNYPrice = p; }
@ -104,7 +114,7 @@ public:
void setINRCAP(double p) { INRCAP = p; }
void setGBPCAP(double p) { GBPCAP = p; }
void setAUDCAP(double p) { AUDCAP = p; }
double getZECPrice();
double getHUSHPrice();
double getEURPrice();
double getBTCPrice();
double getCNYPrice();
@ -190,7 +200,7 @@ private:
bool _useEmbedded = false;
bool _headless = false;
double ZECPrice = 0.0;
double HUSHPrice = 0.0;
double BTCPrice = 0.0;
double EURPrice = 0.0;
double CNYPrice = 0.0;

68
src/settings.ui

@ -38,7 +38,7 @@
<item>
<widget class="QTabWidget" name="tabWidget">
<property name="currentIndex">
<number>1</number>
<number>0</number>
</property>
<widget class="QWidget" name="tab">
<attribute name="title">
@ -79,6 +79,20 @@
</item>
</layout>
</item>
<item>
<widget class="QCheckBox" name="chkUseStickyServer">
<property name="text">
<string>Use Sticky Server</string>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="label_13">
<property name="text">
<string>Uses a fixed server instead of random </string>
</property>
</widget>
</item>
<item>
<spacer name="verticalSpacer">
<property name="orientation">
@ -87,7 +101,7 @@
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
<height>20</height>
</size>
</property>
</spacer>
@ -102,7 +116,7 @@
<property name="geometry">
<rect>
<x>80</x>
<y>110</y>
<y>190</y>
<width>111</width>
<height>25</height>
</rect>
@ -138,11 +152,6 @@
<string>Default</string>
</property>
</item>
<item>
<property name="text">
<string>test</string>
</property>
</item>
</widget>
<widget class="QCheckBox" name="chkFetchPrices">
<property name="geometry">
@ -183,11 +192,27 @@
<string>Connect to git on startup to check for updates</string>
</property>
</widget>
<widget class="QCheckBox" name="chkUseNoteAutomation">
<property name="geometry">
<rect>
<x>10</x>
<y>110</y>
<width>200</width>
<height>23</height>
</rect>
</property>
<property name="text">
<string>Use Note Automation</string>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
<widget class="QLabel" name="label_20">
<property name="geometry">
<rect>
<x>9</x>
<y>113</y>
<x>10</x>
<y>190</y>
<width>47</width>
<height>17</height>
</rect>
@ -208,8 +233,8 @@
<widget class="Line" name="line_2">
<property name="geometry">
<rect>
<x>10</x>
<y>180</y>
<x>0</x>
<y>300</y>
<width>691</width>
<height>16</height>
</rect>
@ -227,7 +252,7 @@
<widget class="QLabel" name="label_10">
<property name="geometry">
<rect>
<x>9</x>
<x>10</x>
<y>90</y>
<width>601</width>
<height>17</height>
@ -241,7 +266,7 @@
<property name="geometry">
<rect>
<x>10</x>
<y>150</y>
<y>230</y>
<width>61</width>
<height>20</height>
</rect>
@ -263,7 +288,7 @@
<property name="geometry">
<rect>
<x>80</x>
<y>150</y>
<y>230</y>
<width>111</width>
<height>25</height>
</rect>
@ -325,6 +350,19 @@
</property>
</item>
</widget>
<widget class="QLabel" name="label_11">
<property name="geometry">
<rect>
<x>10</x>
<y>140</y>
<width>601</width>
<height>17</height>
</rect>
</property>
<property name="text">
<string>Increases the number of zutxo for instant hushchat</string>
</property>
</widget>
</widget>
</widget>
</item>

65
src/txtablemodel.cpp

@ -1,8 +1,9 @@
// Copyright 2019-2021 The Hush developers
// Copyright 2019-2024 The Hush developers
// Released under the GPLv3
#include "txtablemodel.h"
#include "settings.h"
#include "controller.h"
#include "guiconstants.h"
TxTableModel::TxTableModel(QObject *parent)
: QAbstractTableModel(parent) {
@ -87,6 +88,17 @@ QString TxTableModel::concatMultipleMemos(const TransactionItem& dat) const {
};
QVariant TxTableModel::data(const QModelIndex &index, int role) const {
// Get current theme name
QString theme_name = Settings::getInstance()->get_theme_name();
QBrush b;
QColor color;
if (theme_name == "Dark" || theme_name == "Midnight") {
color = COLOR_WHITE;
}else{
color = COLOR_BLACK;
}
// Align numeric columns (confirmations, amount) right
if (role == Qt::TextAlignmentRole &&
(index.column() == Column::Confirmations || index.column() == Column::Amount))
@ -95,15 +107,11 @@ QVariant TxTableModel::data(const QModelIndex &index, int role) const {
auto dat = modeldata->at(index.row());
if (role == Qt::ForegroundRole) {
if (dat.confirmations <= 0) {
QBrush b;
b.setColor(Qt::red);
return b;
}
// Else, just return the default brush
QBrush b;
b.setColor(Qt::black);
return b;
b.setColor(color);
return b;
}
if (role == Qt::DisplayRole) {
@ -195,29 +203,30 @@ QVariant TxTableModel::data(const QModelIndex &index, int role) const {
hasMemo = true;
}
}
// If the memo is a Payment URI, then show a payment request icon
if (dat.items.length() == 1 && dat.items[0].memo.startsWith("hush:")) {
QIcon icon(":/icons/res/paymentreq.gif");
QImage image = colorizeIcon(QIcon(":/icons/res/paymentreq.gif"), color);
QIcon icon;
icon.addPixmap(QPixmap::fromImage(image));
return QVariant(icon.pixmap(16, 16));
} else if (hasMemo) {
// Return the info pixmap to indicate memo
QIcon icon(":/icons/res/mail.png");
return QVariant(icon.pixmap(16, 16));
} else {
if (dat.type == "Receive"){
// Empty pixmap to make it align
QPixmap p(16, 16);
QIcon icon = QApplication::style()->standardIcon(QStyle::SP_ArrowLeft);
return QVariant(icon.pixmap(16, 16));
}
if (dat.type == "Receive"){
QImage image = colorizeIcon(QIcon(":/icons/res/tx_input.png"), color);
QIcon icon;
icon.addPixmap(QPixmap::fromImage(image));
return QVariant(icon.pixmap(16, 16));
}
if (dat.type == "send"){
// Empty pixmap to make it align
QPixmap p(16, 16);
QIcon icon = QApplication::style()->standardIcon(QStyle::SP_ArrowForward);
return QVariant(icon.pixmap(16, 16));
}
QImage image = colorizeIcon(QIcon(":/icons/res/tx_output.png"), color);
QIcon icon;
icon.addPixmap(QPixmap::fromImage(image));
return QVariant(icon.pixmap(16, 16));
}
}
}
@ -278,3 +287,17 @@ QString TxTableModel::getAmt(int row) const {
}
return total.toDecimalString();
}
QImage TxTableModel::colorizeIcon(QIcon icon, QColor color) const{
QImage img(icon.pixmap(16, 16).toImage());
img = img.convertToFormat(QImage::Format_ARGB32);
for (int x = img.width(); x--; )
{
for (int y = img.height(); y--; )
{
const QRgb rgb = img.pixel(x, y);
img.setPixel(x, y, qRgba(color.red(), color.green(), color.blue(), qAlpha(rgb)));
}
}
return img;
}

3
src/txtablemodel.h

@ -1,4 +1,4 @@
// Copyright 2019-2021 The Hush developers
// Copyright 2019-2024 The Hush developers
// Released under the GPLv3
#ifndef STRINGSTABLEMODEL_H
#define STRINGSTABLEMODEL_H
@ -38,6 +38,7 @@ public:
int columnCount(const QModelIndex &parent) const;
QVariant data(const QModelIndex &index, int role) const;
QVariant headerData(int section, Qt::Orientation orientation, int role) const;
QImage colorizeIcon(const QIcon icon, const QColor color) const;
private:
QString concatMultipleMemos(const TransactionItem&) const;

4
src/version.h

@ -1,3 +1 @@
// Copyright 2019-2021 The Hush developers
// Released under the GPLv3
#define APP_VERSION "1.4.0"
#define APP_VERSION "2.0.2"

2
src/viewalladdresses.cpp

@ -1,4 +1,4 @@
// Copyright 2019-2021 The Hush developers
// Copyright 2019-2024 The Hush developers
// Released under the GPLv3
#include "viewalladdresses.h"
#include "camount.h"

4
src/viewalladdresses.h

@ -1,4 +1,4 @@
// Copyright 2019-2021 The Hush developers
// Copyright 2019-2024 The Hush developers
// Released under the GPLv3
#ifndef VIEWALLADDRESSES_H
#define VIEWALLADDRESSES_H
@ -8,6 +8,8 @@
class ViewAllAddressesModel : public QAbstractTableModel {
Q_OBJECT
public:
ViewAllAddressesModel(QTableView* parent, QList<QString> taddrs, Controller* rpc);
~ViewAllAddressesModel() = default;

943
src/websockets.cpp

@ -1,943 +0,0 @@
// Copyright 2019-2021 The Hush developers
// Released under the GPLv3
#include "websockets.h"
#include "controller.h"
#include "settings.h"
#include "ui_mobileappconnector.h"
#include "version.h"
// Weap the sendTextMessage to check if the connection is valid and that the parent WebServer didn't close this connection
// for some reason.
void ClientWebSocket::sendTextMessage(QString m) {
if (client) {
if (server && !server->isValidConnection(client)) {
return;
}
if (client->isValid())
client->sendTextMessage(m);
}
}
WSServer::WSServer(quint16 port, bool debug, QObject *parent) :
QObject(parent),
m_pWebSocketServer(new QWebSocketServer(QStringLiteral("Direct Connection Server"),
QWebSocketServer::NonSecureMode, this)),
m_debug(debug)
{
m_mainWindow = (MainWindow *) parent;
if (m_pWebSocketServer->listen(QHostAddress::AnyIPv4, port)) {
if (m_debug)
qDebug() << "Echoserver listening on port" << port;
connect(m_pWebSocketServer, &QWebSocketServer::newConnection,
this, &WSServer::onNewConnection);
connect(m_pWebSocketServer, &QWebSocketServer::closed, this, &WSServer::closed);
}
}
WSServer::~WSServer()
{
qDebug() << "Closing websocket server";
m_pWebSocketServer->close();
qDeleteAll(m_clients.begin(), m_clients.end());
qDebug() << "Deleted all websocket clients";
}
void WSServer::onNewConnection()
{
qDebug() << "Websocket server: new connection";
QWebSocket *pSocket = m_pWebSocketServer->nextPendingConnection();
connect(pSocket, &QWebSocket::textMessageReceived, this, &WSServer::processTextMessage);
connect(pSocket, &QWebSocket::binaryMessageReceived, this, &WSServer::processBinaryMessage);
connect(pSocket, &QWebSocket::disconnected, this, &WSServer::socketDisconnected);
m_clients << pSocket;
}
void WSServer::processTextMessage(QString message)
{
QWebSocket *pClient = qobject_cast<QWebSocket *>(sender());
if (m_debug)
qDebug() << "Message received:" << message;
if (pClient) {
std::shared_ptr<ClientWebSocket> client = std::make_shared<ClientWebSocket>(pClient, this);
AppDataServer::getInstance()->processMessage(message, m_mainWindow, client, AppConnectionType::DIRECT);
}
}
void WSServer::processBinaryMessage(QByteArray message)
{
//QWebSocket *pClient = qobject_cast<QWebSocket *>(sender());
if (m_debug)
qDebug() << "Binary Message received:" << message;
}
void WSServer::socketDisconnected()
{
QWebSocket *pClient = qobject_cast<QWebSocket *>(sender());
if (m_debug)
qDebug() << "socketDisconnected:" << pClient;
if (pClient) {
m_clients.removeAll(pClient);
pClient->deleteLater();
}
}
//===============================
// WormholeClient
//===============================
WormholeClient::WormholeClient(MainWindow* p, QString wormholeCode) {
this->parent = p;
this->code = wormholeCode;
connect();
qDebug() << "New wormhole client after connect()";
}
WormholeClient::~WormholeClient() {
qDebug() << "WormholeClient destructor";
shuttingDown = true;
if (m_webSocket && m_webSocket->isValid()) {
qDebug() << "Wormhole closing!";
m_webSocket->close();
}
if (timer) {
qDebug() << "Wormhole timer stopping";
timer->stop();
}
delete timer;
qDebug() << "Wormhole timer deleted";
}
void WormholeClient::connect() {
qDebug() << "Wormhole::connect";
delete m_webSocket;
m_webSocket = new QWebSocket();
if (m_webSocket) {
QObject::connect(m_webSocket, &QWebSocket::connected, this, &WormholeClient::onConnected);
QObject::connect(m_webSocket, &QWebSocket::disconnected, this, &WormholeClient::closed);
} else {
qDebug() << "Invalid websocket object!";
}
m_webSocket->open(QUrl("wss://wormhole.hush.is:443"));
//m_webSocket->open(QUrl("ws://127.0.0.1:7070"));
}
void WormholeClient::retryConnect() {
QTimer::singleShot(5 * 1000 * pow(2, retryCount), [=]() {
if (retryCount < 10) {
qDebug() << "Retrying websocket connection";
this->retryCount++;
connect();
} else {
qDebug() << "Retry count exceeded, will not attempt retry any more";
}
});
}
// Called when the websocket is closed. If this was closed without our explicitly closing it,
// then we need to try and reconnect
void WormholeClient::closed() {
if (!shuttingDown) {
retryConnect();
}
}
void WormholeClient::onConnected()
{
qDebug() << "WebSocket connected";
retryCount = 0;
qDebug() << "WebSocket connected, retryCount=" << retryCount;
QObject::connect(m_webSocket, &QWebSocket::textMessageReceived,
this, &WormholeClient::onTextMessageReceived);
auto payload = QJsonDocument( QJsonObject {
{"register", code}
}).toJson();
m_webSocket->sendTextMessage(payload);
// On connected, we'll also create a timer to ping it every 4 minutes, since the websocket
// will timeout after 5 minutes
if (m_webSocket && m_webSocket->isValid()) {
m_webSocket->sendTextMessage(payload);
qDebug() << "Sent registration message with code=" << code;
// On connected, we'll also create a timer to ping it every 4 minutes, since the websocket
// will timeout after 5 minutes
timer = new QTimer(parent);
qDebug() << "Created QTimer";
QObject::connect(timer, &QTimer::timeout, [=]() {
qDebug() << "Timer timeout!";
if (!shuttingDown && m_webSocket && m_webSocket->isValid()) {
auto payload = QJsonDocument(QJsonObject { {"ping", "ping"} }).toJson();
qint64 bytes = m_webSocket->sendTextMessage(payload);
qDebug() << "Sent ping, " << bytes << " bytes";
}
});
unsigned int interval = 4*60*1000;
timer->start(interval); // 4 minutes
qDebug() << "Started timer with interval=" << interval;
} else {
qDebug() << "Invalid websocket object onConnected!";
}
}
void WormholeClient::onTextMessageReceived(QString message)
{
AppDataServer::getInstance()->processMessage(message, parent, std::make_shared<ClientWebSocket>(m_webSocket), AppConnectionType::INTERNET);
qDebug() << "Destroyed tempWormholeClient and ui";
}
// ==============================
// AppDataServer
// ==============================
AppDataServer* AppDataServer::instance = nullptr;
QString AppDataServer::getWormholeCode(QString secretHex) {
unsigned char* secret = new unsigned char[crypto_secretbox_KEYBYTES];
sodium_hex2bin(secret, crypto_secretbox_KEYBYTES, secretHex.toStdString().c_str(), crypto_secretbox_KEYBYTES*2,
NULL, NULL, NULL);
unsigned char* out1 = new unsigned char[crypto_hash_sha256_BYTES];
crypto_hash_sha256(out1, secret, crypto_secretbox_KEYBYTES);
unsigned char* out2 = new unsigned char[crypto_hash_sha256_BYTES];
crypto_hash_sha256(out2, out1, crypto_hash_sha256_BYTES);
char* wmcode = new char[crypto_hash_sha256_BYTES*2 + 1];
sodium_bin2hex(wmcode, crypto_hash_sha256_BYTES*2 + 1, out2, crypto_hash_sha256_BYTES);
QString wmcodehex(wmcode);
delete[] wmcode;
delete[] out2;
delete[] out1;
delete[] secret;
return wmcodehex;
}
QString AppDataServer::getSecretHex() {
QSettings s;
return s.value("mobileapp/secret", "").toString();
}
void AppDataServer::saveNewSecret(QString secretHex) {
QSettings().setValue("mobileapp/secret", secretHex);
if (secretHex.isEmpty())
setAllowInternetConnection(false);
}
bool AppDataServer::getAllowInternetConnection() {
return QSettings().value("mobileapp/allowinternet", false).toBool();
}
void AppDataServer::setAllowInternetConnection(bool allow) {
QSettings().setValue("mobileapp/allowinternet", allow);
}
void AppDataServer::saveLastConnectedOver(AppConnectionType type) {
QSettings().setValue("mobileapp/lastconnectedover", type);
}
AppConnectionType AppDataServer::getLastConnectionType() {
return (AppConnectionType) QSettings().value("mobileapp/lastconnectedover", AppConnectionType::DIRECT).toInt();
}
void AppDataServer::saveLastSeenTime() {
QSettings().setValue("mobileapp/lastseentime", QDateTime::currentSecsSinceEpoch());
}
QDateTime AppDataServer::getLastSeenTime() {
return QDateTime::fromSecsSinceEpoch(QSettings().value("mobileapp/lastseentime", 0).toLongLong());
}
void AppDataServer::setConnectedName(QString name) {
QSettings().setValue("mobileapp/connectedname", name);
}
QString AppDataServer::getConnectedName() {
return QSettings().value("mobileapp/connectedname", "").toString();
}
bool AppDataServer::isAppConnected() {
return !getConnectedName().isEmpty() &&
getLastSeenTime().daysTo(QDateTime::currentDateTime()) < 14;
}
void AppDataServer::connectAppDialog(MainWindow* parent) {
QDialog d(parent);
ui = new Ui_MobileAppConnector();
ui->setupUi(&d);
Settings::saveRestore(&d);
updateUIWithNewQRCode(parent);
updateConnectedUI();
QObject::connect(ui->btnDisconnect, &QPushButton::clicked, [=] () {
QSettings().setValue("mobileapp/connectedname", "");
saveNewSecret("");
updateConnectedUI();
});
QObject::connect(ui->txtConnStr, &QLineEdit::cursorPositionChanged, [=](int, int) {
ui->txtConnStr->selectAll();
});
QObject::connect(ui->chkInternetConn, &QCheckBox::stateChanged, [=] (int state) {
if (state == Qt::Checked) {
}
updateUIWithNewQRCode(parent);
});
// If we're not listening for the app, then start the websockets
if (!parent->isWebsocketListening()) {
QString wormholecode = "";
if (getAllowInternetConnection())
wormholecode = AppDataServer::getInstance()->getWormholeCode(AppDataServer::getInstance()->getSecretHex());
parent->createWebsocket(wormholecode);
}
d.exec();
// If there is nothing connected when the dialog exits, then shutdown the websockets
if (!isAppConnected()) {
parent->stopWebsocket();
}
// Cleanup
tempSecret = "";
delete tempWormholeClient;
tempWormholeClient = nullptr;
delete ui;
ui = nullptr;
}
void AppDataServer::updateUIWithNewQRCode(MainWindow* mainwindow) {
// Get the address of the localhost
auto addrList = QNetworkInterface::allAddresses();
// Find a suitable address
QString ipv4Addr;
for (auto addr : addrList) {
if (addr.isLoopback() || addr.protocol() == QAbstractSocket::IPv6Protocol)
continue;
ipv4Addr = addr.toString();
break;
}
if (ipv4Addr.isEmpty())
return;
QString uri = "ws://" + ipv4Addr + ":8777";
qDebug() << "Websocket URI: " << uri;
// Get a new secret
unsigned char* secretBin = new unsigned char[crypto_secretbox_KEYBYTES];
randombytes_buf(secretBin, crypto_secretbox_KEYBYTES);
char* secretHex = new char[crypto_secretbox_KEYBYTES*2 + 1];
sodium_bin2hex(secretHex, crypto_secretbox_KEYBYTES*2+1, secretBin, crypto_secretbox_KEYBYTES);
QString secretStr(secretHex);
QString codeStr = uri + "," + secretStr;
if (ui->chkInternetConn->isChecked()) {
codeStr = codeStr + ",1";
}
registerNewTempSecret(secretStr, ui->chkInternetConn->isChecked(), mainwindow);
ui->qrcode->setQrcodeString(codeStr);
ui->txtConnStr->setText(codeStr);
qDebug() << "New QR="<<codeStr;
}
void AppDataServer::registerNewTempSecret(QString tmpSecretHex, bool allowInternet, MainWindow* main) {
qDebug() << "Registering new tempSecret, allowInternet=" << allowInternet;
tempSecret = tmpSecretHex;
delete tempWormholeClient;
tempWormholeClient = nullptr;
if (allowInternet)
tempWormholeClient = new WormholeClient(main, getWormholeCode(tempSecret));
qDebug() << "Created new wormhole client";
}
QString AppDataServer::connDesc(AppConnectionType t) {
if (t == AppConnectionType::DIRECT) {
return QObject::tr("Connected directly");
}
else {
return QObject::tr("Connected over the internet via silentdragon wormhole service");
}
}
void AppDataServer::updateConnectedUI() {
if (ui == nullptr)
return;
auto remoteName = getConnectedName();
ui->lblRemoteName->setText(remoteName.isEmpty() ? "(Not connected to any device)" : remoteName);
ui->lblLastSeen->setText(remoteName.isEmpty() ? "" : getLastSeenTime().toString(Qt::SystemLocaleLongDate));
ui->lblConnectionType->setText(remoteName.isEmpty() ? "" : connDesc(getLastConnectionType()));
ui->btnDisconnect->setEnabled(!remoteName.isEmpty());
}
QString AppDataServer::getNonceHex(NonceType nt) {
QSettings s;
QString hex;
if (nt == NonceType::LOCAL) {
// The default local nonce starts from 1, to always keep it odd
auto defaultLocalNonce = "01" + QString("00").repeated(crypto_secretbox_NONCEBYTES-1);
hex = s.value("mobileapp/localnoncehex", defaultLocalNonce).toString();
}
else {
hex = s.value("mobileapp/remotenoncehex", QString("00").repeated(crypto_secretbox_NONCEBYTES)).toString();
}
return hex;
}
void AppDataServer::saveNonceHex(NonceType nt, QString noncehex) {
QSettings s;
assert(noncehex.length() == crypto_secretbox_NONCEBYTES * 2);
if (nt == NonceType::LOCAL) {
s.setValue("mobileapp/localnoncehex", noncehex);
}
else {
s.setValue("mobileapp/remotenoncehex", noncehex);
}
s.sync();
}
// Encrypt an outgoing message with the stored secret key.
QString AppDataServer::encryptOutgoing(QString msg) {
int padding = 16*1024;
qDebug() << "Encrypt msg(pad="<<padding<<") prepad len=" << msg.length();
if (msg.length() % padding > 0) {
msg = msg + QString(" ").repeated(padding - (msg.length() % padding));
}
qDebug() << "Encrypt msg postpad len=" << msg.length();
QString localNonceHex = getNonceHex(NonceType::LOCAL);
unsigned char* noncebin = new unsigned char[crypto_secretbox_NONCEBYTES];
sodium_hex2bin(noncebin, crypto_secretbox_NONCEBYTES, localNonceHex.toStdString().c_str(), localNonceHex.length(),
NULL, NULL, NULL);
// Increment the nonce +2 and save
sodium_increment(noncebin, crypto_secretbox_NONCEBYTES);
sodium_increment(noncebin, crypto_secretbox_NONCEBYTES);
char* newLocalNonce = new char[crypto_secretbox_NONCEBYTES*2 + 1];
sodium_memzero(newLocalNonce, crypto_secretbox_NONCEBYTES*2 + 1);
sodium_bin2hex(newLocalNonce, crypto_secretbox_NONCEBYTES*2+1, noncebin, crypto_box_NONCEBYTES);
saveNonceHex(NonceType::LOCAL, QString(newLocalNonce));
unsigned char* secret = new unsigned char[crypto_secretbox_KEYBYTES];
sodium_hex2bin(secret, crypto_secretbox_KEYBYTES, getSecretHex().toStdString().c_str(), crypto_secretbox_KEYBYTES*2,
NULL, NULL, NULL);
int msgSize = strlen(msg.toStdString().c_str());
unsigned char* encrpyted = new unsigned char[ msgSize + crypto_secretbox_MACBYTES];
crypto_secretbox_easy(encrpyted, (const unsigned char *)msg.toStdString().c_str(), msgSize, noncebin, secret);
int encryptedHexSize = (msgSize + crypto_secretbox_MACBYTES) * 2 + 1;
char * encryptedHex = new char[encryptedHexSize];
sodium_memzero(encryptedHex, encryptedHexSize);
sodium_bin2hex(encryptedHex, encryptedHexSize, encrpyted, msgSize + crypto_secretbox_MACBYTES);
auto json = QJsonDocument(QJsonObject{
{"nonce", QString(newLocalNonce)},
{"payload", QString(encryptedHex)},
{"to", getWormholeCode(getSecretHex())}
});
delete[] noncebin;
delete[] newLocalNonce;
delete[] secret;
delete[] encrpyted;
delete[] encryptedHex;
return json.toJson();
}
/**
Attempt to decrypt a message. If the decryption fails, it returns the string "error", the decrypted message otherwise.
It will use the given secret to attempt decryption. In addition, it will enforce that the nonce is greater than the last seen nonce,
unless the skipNonceCheck = true, which is used when attempting decrtption with a temp secret key.
*/
QString AppDataServer::decryptMessage(QJsonDocument msg, QString secretHex, QString lastRemoteNonceHex) {
// Decrypt and then process
QString noncehex = msg.object().value("nonce").toString();
QString encryptedhex = msg.object().value("payload").toString();
// Enforce limits on the size of the message
if (noncehex.length() > ((int)crypto_secretbox_NONCEBYTES * 2) ||
encryptedhex.length() > 2 * 50 * 1024 /*50kb*/) {
return "error";
}
// Check to make sure that the nonce is greater than the last known remote nonce
unsigned char* lastRemoteBin = new unsigned char[crypto_secretbox_NONCEBYTES];
sodium_hex2bin(lastRemoteBin, crypto_secretbox_NONCEBYTES, lastRemoteNonceHex.toStdString().c_str(), lastRemoteNonceHex.length(),
NULL, NULL, NULL);
unsigned char* noncebin = new unsigned char[crypto_secretbox_NONCEBYTES];
sodium_hex2bin(noncebin, crypto_secretbox_NONCEBYTES, noncehex.toStdString().c_str(), noncehex.length(),
NULL, NULL, NULL);
assert(crypto_secretbox_KEYBYTES == crypto_hash_sha256_BYTES);
if (sodium_compare(lastRemoteBin, noncebin, crypto_secretbox_NONCEBYTES) != -1) {
// Refuse to accept a lower nonce, return an error
delete[] lastRemoteBin;
delete[] noncebin;
return "error";
}
unsigned char* secret = new unsigned char[crypto_secretbox_KEYBYTES];
sodium_hex2bin(secret, crypto_secretbox_KEYBYTES, secretHex.toStdString().c_str(), crypto_secretbox_KEYBYTES*2,
NULL, NULL, NULL);
unsigned char* encrypted = new unsigned char[encryptedhex.length() / 2];
sodium_hex2bin(encrypted, encryptedhex.length() / 2, encryptedhex.toStdString().c_str(), encryptedhex.length(),
NULL, NULL, NULL);
int decryptedLen = encryptedhex.length() / 2 - crypto_secretbox_MACBYTES;
unsigned char* decrypted = new unsigned char[decryptedLen];
int result = crypto_secretbox_open_easy(decrypted, encrypted, encryptedhex.length() / 2, noncebin, secret);
QString payload;
if (result == -1) {
payload = "error";
} else {
// Update the last seen remote hex
saveNonceHex(NonceType::REMOTE, noncehex);
saveLastSeenTime();
char* decryptedStr = new char[decryptedLen + 1];
sodium_memzero(decryptedStr, decryptedLen + 1);
memcpy(decryptedStr, decrypted, decryptedLen);
payload = QString(decryptedStr);
delete[] decryptedStr;
}
delete[] secret;
delete[] lastRemoteBin;
delete[] noncebin;
delete[] encrypted;
delete[] decrypted;
qDebug() << "Returning decrypted payload="<<payload;
return payload;
}
// Process an incoming text message. The message has to be encrypted with the secret key (or the temporary secret key)
void AppDataServer::processMessage(QString message, MainWindow* mainWindow, std::shared_ptr<ClientWebSocket> pClient, AppConnectionType connType) {
qDebug() << "processMessage message";
//qDebug() << "processMessage message=" << message; // this can log sensitive info
auto replyWithError = [=]() {
auto r = QJsonDocument(QJsonObject{
{"error", "Encryption error"},
{"to", getWormholeCode(getSecretHex())}
}).toJson();
pClient->sendTextMessage(r);
return;
};
// First, extract the command from the message
auto msg = QJsonDocument::fromJson(message.toUtf8());
// Check if we got an error from the websocket
if (msg.object().contains("error")) {
qDebug() << "Error:" << msg.toJson();
return;
}
// If the message is a ping, just ignore it
if (msg.object().contains("ping")) {
return;
}
// Then, check if the message is encrpted
if (!msg.object().contains("nonce")) {
replyWithError();
return;
}
auto decrypted = decryptMessage(msg, getSecretHex(), getNonceHex(NonceType::REMOTE));
// If the decryption failed, maybe this is a new connection, so see if the dialog is open and a
// temp secret is in place
if (decrypted == "error") {
// If the dialog is open, then there might be a temporary, new secret key. Attempt to decrypt
// with that.
if (!tempSecret.isEmpty()) {
// Since this is a temp secret, the last seen nonce will be "0", so basically we'll accept any nonce
QString zeroNonce = QString("00").repeated(crypto_secretbox_NONCEBYTES);
decrypted = decryptMessage(msg, tempSecret, zeroNonce);
if (decrypted == "error") {
// Oh, well. Just return an error
replyWithError();
return;
}
else {
// This is a new connection. So, update the the secret. Note the last seen remote nonce has already been updated by
// decryptMessage()
saveNewSecret(tempSecret);
setAllowInternetConnection(tempWormholeClient != nullptr);
// Swap out the wormhole connection
mainWindow->replaceWormholeClient(tempWormholeClient);
tempWormholeClient = nullptr;
saveLastConnectedOver(connType);
processDecryptedMessage(decrypted, mainWindow, pClient);
// If the Connection UI is showing, we have to update the UI as well
if (ui != nullptr) {
// Update the connected phone information
updateConnectedUI();
// Update with a new QR Code for safety, so this secret isn't used by anyone else
updateUIWithNewQRCode(mainWindow);
}
return;
}
}
else {
replyWithError();
return;
}
} else {
saveLastConnectedOver(connType);
processDecryptedMessage(decrypted, mainWindow, pClient);
return;
}
}
// Decrypted method will be executed here.
void AppDataServer::processDecryptedMessage(QString message, MainWindow* mainWindow, std::shared_ptr<ClientWebSocket> pClient) {
//qDebug() << "processDecryptedMessage message=" << message;
// First, extract the command from the message
auto msg = QJsonDocument::fromJson(message.toUtf8());
if (!msg.object().contains("command")) {
auto r = QJsonDocument(QJsonObject{
{"errorCode", -1},
{"errorMessage", "Unknown JSON format"}
}).toJson();
pClient->sendTextMessage(encryptOutgoing(r));
return;
}
if (msg.object()["command"] == "getInfo") {
processGetInfo(msg.object(), mainWindow, pClient);
}
else if (msg.object()["command"] == "getTransactions") {
processGetTransactions(mainWindow, pClient);
}
else if (msg.object()["command"] == "sendTx") {
processSendTx(msg.object()["tx"].toObject(), mainWindow, pClient);
}
else if (msg.object()["command"] == "sendmanyTx") {
processSendManyTx(msg.object()["tx"].toObject(), mainWindow, pClient);
}
else {
auto r = QJsonDocument(QJsonObject{
{"errorCode", -1},
{"errorMessage", "Command not found:" + msg.object()["command"].toString()}
}).toJson();
pClient->sendTextMessage(encryptOutgoing(r));
}
}
// "sendTx" command. This method will actually send money, so be careful with everything
void AppDataServer::processSendTx(QJsonObject sendTx, MainWindow* mainwindow, std::shared_ptr<ClientWebSocket> pClient) {
qDebug() << "processSendTx with to=" << sendTx["to"].toString();
auto error = [=](QString reason) {
auto r = QJsonDocument(QJsonObject{
{"errorCode", -1},
{"errorMessage", "Couldn't send Tx:" + reason}
}).toJson();
pClient->sendTextMessage(encryptOutgoing(r));
return;
};
// Refuse to send if the node is still syncing
if (Settings::getInstance()->isSyncing()) {
error(QObject::tr("Node is still syncing."));
return;
}
// Create a Tx Object
Tx tx;
tx.fee = Settings::getMinerFee();
// Find a from address that has at least the sending amout
CAmount amt = CAmount::fromDecimalString(sendTx["amount"].toString());
auto allBalances = mainwindow->getRPC()->getModel()->getAllBalances();
QList<QPair<QString, CAmount>> bals;
for (auto i : allBalances.keys()) {
// Filter out sprout addresses
if (Settings::getInstance()->isSproutAddress(i))
continue;
// Filter out balances that don't have the requisite amount
if (allBalances.value(i) < amt)
continue;
bals.append(QPair<QString, CAmount>(i, allBalances.value(i)));
}
if (bals.isEmpty()) {
error(QObject::tr("No sapling or transparent addresses with enough balance to spend."));
return;
}
std::sort(bals.begin(), bals.end(), [=](const QPair<QString, CAmount>a, const QPair<QString, CAmount> b) -> bool {
// Sort z addresses first
return a.first > b.first;
});
tx.fromAddr = bals[0].first;
tx.toAddrs = { ToFields{ sendTx["to"].toString(), amt, sendTx["memo"].toString()} };
// TODO: Respect the autoshield change setting
QString validation = mainwindow->doSendTxValidations(tx);
if (!validation.isEmpty()) {
error(validation);
return;
}
json params = json::array();
mainwindow->getRPC()->fillTxJsonParams(params, tx);
std::cout << std::setw(2) << params << std::endl;
// And send the Tx
mainwindow->getRPC()->executeTransaction(tx,
[=] (QString txid) {
auto r = QJsonDocument(QJsonObject{
{"version", 1.0},
{"command", "sendTxSubmitted"},
{"txid", txid}
}).toJson();
pClient->sendTextMessage(encryptOutgoing(r));
},
// Errored while submitting Tx
[=] (QString, QString errStr) {
auto r = QJsonDocument(QJsonObject{
{"version", 1.0},
{"command", "sendTxFailed"},
{"err", errStr}
}).toJson();
pClient->sendTextMessage(encryptOutgoing(r));
}
);
auto r = QJsonDocument(QJsonObject{
{"version", 1.0},
{"command", "sendTx"},
{"result", "success"}
}).toJson();
pClient->sendTextMessage(encryptOutgoing(r));
}
// "sendmanyTx" command. This method will actually send money, so be careful with everything
void AppDataServer::processSendManyTx(QJsonObject sendmanyTx, MainWindow* mainwindow, std::shared_ptr<ClientWebSocket> pClient) {
qDebug() << "processSendManyTx with to=" << sendmanyTx["to"].toString();
auto error = [=](QString reason) {
auto r = QJsonDocument(QJsonObject{
{"errorCode", -1},
{"errorMessage", "Couldn't send Tx:" + reason}
}).toJson();
pClient->sendTextMessage(encryptOutgoing(r));
return;
};
// Refuse to send if the node is still syncing
if (Settings::getInstance()->isSyncing()) {
error(QObject::tr("Node is still syncing."));
return;
}
// Create a Tx Object
Tx tx;
tx.fee = Settings::getMinerFee();
// Find a from address that has at least the sending amout
CAmount amt = CAmount::fromDecimalString(sendmanyTx["amount"].toString());
auto allBalances = mainwindow->getRPC()->getModel()->getAllBalances();
QList<QPair<QString, CAmount>> bals;
for (auto i : allBalances.keys()) {
// Filter out sprout addresses
if (Settings::getInstance()->isSproutAddress(i))
continue;
// Filter out balances that don't have the requisite amount
if (allBalances.value(i) < amt)
continue;
bals.append(QPair<QString, CAmount>(i, allBalances.value(i)));
}
if (bals.isEmpty()) {
error(QObject::tr("No sapling or transparent addresses with enough balance to spend."));
return;
}
std::sort(bals.begin(), bals.end(), [=](const QPair<QString, CAmount>a, const QPair<QString, CAmount> b) -> bool {
// Sort z addresses first
return a.first > b.first;
});
//send to more then one Receipent
int totalSendManyItems = sendmanyTx.size();
for (int i=0; i < totalSendManyItems; i++) {
amt = CAmount::fromDecimalString(sendmanyTx["amount"].toString() % QString::number(i+1));
QString addr = sendmanyTx["to"].toString() % QString::number(i+1);
QString memo = sendmanyTx["memo"].toString() % QString::number(i+1);
tx.fromAddr = bals[0].first;
tx.toAddrs = { ToFields{ addr, amt, memo} };
}
// TODO: Respect the autoshield change setting
QString validation = mainwindow->doSendTxValidations(tx);
if (!validation.isEmpty()) {
error(validation);
return;
}
json params = json::array();
mainwindow->getRPC()->fillTxJsonParams(params, tx);
std::cout << std::setw(2) << params << std::endl;
// And send the Tx
mainwindow->getRPC()->executeTransaction(tx,
[=] (QString txid) {
auto r = QJsonDocument(QJsonObject{
{"version", 1.0},
{"command", "sendTxSubmitted"},
{"txid", txid}
}).toJson();
pClient->sendTextMessage(encryptOutgoing(r));
},
// Errored while submitting Tx
[=] (QString, QString errStr) {
auto r = QJsonDocument(QJsonObject{
{"version", 1.0},
{"command", "sendTxFailed"},
{"err", errStr}
}).toJson();
pClient->sendTextMessage(encryptOutgoing(r));
}
);
auto r = QJsonDocument(QJsonObject{
{"version", 1.0},
{"command", "sendTx"},
{"result", "success"}
}).toJson();
pClient->sendTextMessage(encryptOutgoing(r));
}
// "getInfo" command
void AppDataServer::processGetInfo(QJsonObject jobj, MainWindow* mainWindow, std::shared_ptr<ClientWebSocket> pClient) {
auto connectedName = jobj["name"].toString();
if (mainWindow == nullptr || mainWindow->getRPC() == nullptr) {
pClient->close(QWebSocketProtocol::CloseCodeNormal, "Not yet ready");
return;
}
// Max spendable safely from a z address and from any address
CAmount maxZSpendable;
CAmount maxSpendable;
for (auto a : mainWindow->getRPC()->getModel()->getAllBalances().keys()) {
if (Settings::getInstance()->isSaplingAddress(a)) {
if (mainWindow->getRPC()->getModel()->getAllBalances().value(a) > maxZSpendable) {
maxZSpendable = mainWindow->getRPC()->getModel()->getAllBalances().value(a);
}
}
if (mainWindow->getRPC()->getModel()->getAllBalances().value(a) > maxSpendable) {
maxSpendable = mainWindow->getRPC()->getModel()->getAllBalances().value(a);
}
}
setConnectedName(connectedName);
auto r = QJsonDocument(QJsonObject {
{"version", 1.0},
{"command", "getInfo"},
{"saplingAddress", mainWindow->getRPC()->getDefaultSaplingAddress()},
{"tAddress", mainWindow->getRPC()->getDefaultTAddress()},
{"balance", AppDataModel::getInstance()->getTotalBalance().toDecimalDouble()},
{"maxspendable", maxSpendable.toDecimalDouble()},
{"maxzspendable", maxZSpendable.toDecimalDouble()},
{"tokenName", Settings::getTokenName()},
{"zecprice", Settings::getInstance()->getZECPrice()},
{"serverversion", QString(APP_VERSION)}
}).toJson();
pClient->sendTextMessage(encryptOutgoing(r));
}
void AppDataServer::processGetTransactions(MainWindow* mainWindow, std::shared_ptr<ClientWebSocket> pClient) {
QJsonArray txns;
auto model = mainWindow->getRPC()->getTransactionsModel();
qDebug() << "processGetTransactions";
// Add transactions
for (int i = 0; i < model->rowCount(QModelIndex()) && i < Settings::getMaxMobileAppTxns(); i++) {
txns.append(QJsonObject{
{"type", model->getType(i)},
{"datetime", model->getDate(i)},
{"amount", model->getAmt(i)},
{"txid", model->getTxId(i)},
{"address", model->getAddr(i)},
// {"memo", model->getMemo(i)},
{"confirmations", model->getConfirmations(i)}
});
}
auto r = QJsonDocument(QJsonObject{
{"version", 1.0},
{"command", "getTransactions"},
{"transactions", txns}
}).toJson();
pClient->sendTextMessage(encryptOutgoing(r));
}
// ==============================
// AppDataModel
// ==============================
AppDataModel* AppDataModel::instance = nullptr;

179
src/websockets.h

@ -1,179 +0,0 @@
// Copyright 2019-2021 The Hush developers
// Released under the GPLv3
#ifndef WEBSOCKETS_H
#define WEBSOCKETS_H
#include "precompiled.h"
#include "camount.h"
#include "mainwindow.h"
#include "ui_mobileappconnector.h"
QT_FORWARD_DECLARE_CLASS(QWebSocketServer)
QT_FORWARD_DECLARE_CLASS(QWebSocket)
class WSServer;
// We're going to wrap the websocket in this class, because the underlying QWebSocket might get closed
// or deleted while a callback is waiting to get the data back. Therefore, we write a custom "sendTextMessage"
// class that checks all this before sending.
class ClientWebSocket {
public:
ClientWebSocket(QWebSocket* c, WSServer* s = nullptr) { client = c; server = s; }
void sendTextMessage(QString m);
void close(QWebSocketProtocol::CloseCode code, const QString& msg) { client->close(code, msg); }
private:
QWebSocket* client;
WSServer* server;
};
class WSServer : public QObject
{
Q_OBJECT
public:
explicit WSServer(quint16 port, bool debug = false, QObject *parent = nullptr);
bool isValidConnection(QWebSocket* c) { return m_clients.contains(c); }
~WSServer();
Q_SIGNALS:
void closed();
private Q_SLOTS:
void onNewConnection();
void processTextMessage(QString message);
void processBinaryMessage(QByteArray message);
void socketDisconnected();
private:
QWebSocketServer *m_pWebSocketServer;
MainWindow *m_mainWindow;
QList<QWebSocket *> m_clients;
bool m_debug;
};
class WormholeClient : public QObject {
Q_OBJECT
private Q_SLOTS:
void onConnected();
void onTextMessageReceived(QString message);
void closed();
public:
WormholeClient(MainWindow* parent, QString wormholeCode);
~WormholeClient();
void connect();
void retryConnect();
private:
MainWindow* parent = nullptr;
QWebSocket* m_webSocket = nullptr;
QTimer* timer = nullptr;
QString code;
int retryCount = 0;
bool shuttingDown = false;
};
enum NonceType {
LOCAL = 1,
REMOTE
};
enum AppConnectionType {
DIRECT = 1,
INTERNET
};
class AppDataServer {
public:
static AppDataServer* getInstance() {
if (instance == nullptr) {
instance = new AppDataServer();
}
return instance;
}
void connectAppDialog(MainWindow* parent);
void updateConnectedUI();
void updateUIWithNewQRCode(MainWindow* mainwindow);
void processSendTx(QJsonObject sendTx, MainWindow* mainwindow, std::shared_ptr<ClientWebSocket> pClient);
void processSendManyTx(QJsonObject sendmanyTx, MainWindow* mainwindow, std::shared_ptr<ClientWebSocket> pClient);
void processMessage(QString message, MainWindow* mainWindow, std::shared_ptr<ClientWebSocket> pClient, AppConnectionType connType);
void processGetInfo(QJsonObject jobj, MainWindow* mainWindow, std::shared_ptr<ClientWebSocket> pClient);
void processDecryptedMessage(QString message, MainWindow* mainWindow, std::shared_ptr<ClientWebSocket> pClient);
void processGetTransactions(MainWindow* mainWindow, std::shared_ptr<ClientWebSocket> pClient);
QString decryptMessage(QJsonDocument msg, QString secretHex, QString lastRemoteNonceHex);
QString encryptOutgoing(QString msg);
QString getWormholeCode(QString secretHex);
QString getSecretHex();
void saveNewSecret(QString secretHex);
void registerNewTempSecret(QString tmpSecretHex, bool allowInternet, MainWindow* main);
QString getNonceHex(NonceType nt);
void saveNonceHex(NonceType nt, QString noncehex);
bool getAllowInternetConnection();
void setAllowInternetConnection(bool allow);
void saveLastSeenTime();
QDateTime getLastSeenTime();
void setConnectedName(QString name);
QString getConnectedName();
bool isAppConnected();
QString connDesc(AppConnectionType t);
void saveLastConnectedOver(AppConnectionType type);
AppConnectionType getLastConnectionType();
private:
AppDataServer() = default;
static AppDataServer* instance;
Ui_MobileAppConnector* ui;
QString tempSecret;
WormholeClient* tempWormholeClient = nullptr;
};
class AppDataModel {
public:
static AppDataModel* getInstance() {
if (instance == NULL)
instance = new AppDataModel();
return instance;
}
CAmount getTBalance() { return balTransparent; }
CAmount getZBalance() { return balShielded; }
CAmount getTotalBalance() { return balTotal; }
void setBalances(CAmount transparent, CAmount shielded) {
balTransparent = transparent;
balShielded = shielded;
balTotal = balTransparent + balShielded;
}
private:
AppDataModel() = default; // Private, for singleton
CAmount balTransparent;
CAmount balShielded;
CAmount balTotal;
QString saplingAddress;
static AppDataModel* instance;
};
#endif // WEBSOCKETS_H

9
util/SilentDragonLite.desktop

@ -0,0 +1,9 @@
[Desktop Entry]
Version=1.0
Name=SilentDragonLite
Comment=Lite wallet for HUSH cryptocurrency
Exec=/home/user/SilentDragonLite/SilentDragonLite
Icon=/home/user/SilentDragonLite/res/SDLogo.png
Terminal=false
Type=Application
Categories=Network;

6
util/add-linux-icons.sh

@ -0,0 +1,6 @@
#!/bin/bash
# Copyright 2019-2024 The Hush Developers
username=$(id -un)
sed -i "s|\/home\/.*\/SilentDragonLite\/|\/home\/$username\/SilentDragonLite\/|g" SilentDragonLite.desktop
cp SilentDragonLite.desktop ~/.local/share/applications

10
util/install.sh

@ -0,0 +1,10 @@
#!/bin/bash
# Copyright 2019-2024 The Hush Developers
cd ../ && ./build.sh linguist && ./build.sh
username=$(id -un)
cd util/ && sed -i "s|\/home\/.*\/SilentDragonLite\/|\/home\/$username\/SilentDragonLite\/|g" SilentDragonLite.desktop
cp SilentDragonLite.desktop ~/.local/share/applications

42
util/replace.pl

@ -0,0 +1,42 @@
#!/usr/bin/perl
# 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
use strict;
use warnings;
use autodie;
use Data::Dumper;
my ($find,$replace,@files) = @ARGV;
usage() unless $find && defined $replace;
unless( @files ) {
printf "No files to replace stuff!";
exit 0;
}
my $fh;
print "Going to replace $find with $replace in " . scalar(@files) . " files\n";
for my $file (@files) {
if (-d $file) {
printf "Skipping directory $file\n";
next;
}
unless ( -e $file ) {
printf "$file does not exist!\n";
next;
}
open $fh, '<', $file;
my $content = join('',<$fh>);
$content =~ s/\Q$find\E/$replace/g;
close $fh;
open $fh, '>', $file;
print $fh $content;
close $fh;
}
sub usage {
die "$0 stringtofind stringtoreplace file [more files...]\n";
}

26
util/update-copyrights.sh

@ -0,0 +1,26 @@
#!/usr/bin/env bash
# Copyright (c) 2016-2024 The Hush developers
# Released under the GPLv3
# Usage: update-copyrights.sh 2024 2025
# TODO: verify $1 and $2 exist
if ! command -v ack &> /dev/null
then
echo "ack could not be found. Please install it and try again."
exit 1
fi
if ! command -v xargs &> /dev/null
then
echo "xargs could not be found. Please install it and try again."
exit 1
fi
# This update comments in source code
ack -l -i "20..-20..*Hush dev" | xargs ./util/replace.pl -$1 -$2
# This updates the define which is used by C++ help output
./util/replace.pl "COPYRIGHT_YEAR $1" "COPYRIGHT_YEAR $2" src/clientversion.h
./util/replace.pl "COPYRIGHT_YEAR, $1" "COPYRIGHT_YEAR, $2" configure.ac

38
win-static-build.sh

@ -0,0 +1,38 @@
#!/bin/bash
# Copyright 2019-2024 The Hush Developers
VERSION=$(cat src/version.h |cut -d\" -f2)
echo "Compiling SilentDragonLite $VERSION .exe with $JOBS threads..."
CONF=silentdragon-lite.pro
set -e
echo 'source $HOME/.cargo/env' >> $HOME/.bashrc
CC_x86_64_pc_windows_gnu="x86_64-w64-mingw32.static-gcc"
PATH="/home/$USER/git/mxe/usr/bin:${PATH}"
if [ ! -d "release" ]
then
mkdir release
fi
cp src/precompiled.h release/
qbuild () {
/home/$USER/git/mxe/usr/bin/x86_64-w64-mingw32.static-qmake-qt5 $CONF CONFIG+=release
#lupdate $CONF
#lrelease $CONF
make -j2
}
if [ "$1" == "clean" ]; then
make clean
elif [ "$1" == "linguist" ]; then
lupdate $CONF
lrelease $CONF
elif [ "$1" == "cleanbuild" ]; then
make clean
qbuild
else
qbuild
fi
Loading…
Cancel
Save