diff --git a/.editorconfig b/.editorconfig deleted file mode 100644 index 07f5c90..0000000 --- a/.editorconfig +++ /dev/null @@ -1,15 +0,0 @@ -# EditorConfig helps maintain consistent coding styles -# https://editorconfig.org - -root = true - -[*] -indent_style = space -indent_size = 2 -end_of_line = lf -charset = utf-8 -trim_trailing_whitespace = true -insert_final_newline = true - -[Makefile] -indent_style = tab diff --git a/.github/workflows/amd64-image-build.yml b/.github/workflows/amd64-image-build.yml index 54b97a0..f8ff37a 100644 --- a/.github/workflows/amd64-image-build.yml +++ b/.github/workflows/amd64-image-build.yml @@ -1,9 +1,5 @@ name: amd64-image-build -concurrency: - group: amd64-image-build-${{ github.head_ref }} - cancel-in-progress: true - on: push: branches: [ "master" ] @@ -30,24 +26,17 @@ jobs: - uses: actions/checkout@v3 - name: Set values - id: set_values run: | echo "BUILD_DATE=$(date +"%Y-%m-%d")" >> $GITHUB_ENV echo "BUILD_VERSION=$(git describe --always --tags)" >> $GITHUB_ENV - if [[ "${{github.event_name}}" == "pull_request" ]]; then - echo "::set-output name=github_user::${{github.event.pull_request.head.repo.owner.login}}" - else - echo "::set-output name=github_user::$(echo ${{github.repository}} | cut -d'/' -f1)" - fi - - name: Display the build name + - name: Hello JoininBox run: echo "Building the joininbox-amd64-debian-image-${{ env.BUILD_DATE }}-${{ env.BUILD_VERSION }}" - name: Run the build script run: | - echo "Running with: ${{steps.set_values.outputs.github_user}} $GITHUB_HEAD_REF" cd ci/amd64 - bash packer.build.amd64-debian.sh ${{steps.set_values.outputs.github_user}} $GITHUB_HEAD_REF + bash packer.build.amd64-debian.sh $GITHUB_ACTOR $GITHUB_HEAD_REF - name: Compute checksum of the raw image run: | @@ -65,7 +54,7 @@ jobs: sha256sum joininbox-amd64-debian.qcow2.gz > joininbox-amd64-debian.qcow2.gz.sha256 - name: Upload the image and checksums - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@v3 with: name: joininbox-amd64-image-${{ env.BUILD_DATE }}-${{ env.BUILD_VERSION }} path: | diff --git a/.github/workflows/amd64-image-test.yml b/.github/workflows/amd64-image-test.yml deleted file mode 100644 index bc403df..0000000 --- a/.github/workflows/amd64-image-test.yml +++ /dev/null @@ -1,65 +0,0 @@ -name: amd64-image-test - -concurrency: - group: amd64-image-test-${{ github.event.workflow_run.id || inputs.run_id || github.run_id }} - cancel-in-progress: true - -on: - workflow_run: - workflows: ["amd64-image-build"] - types: [completed] - workflow_dispatch: - inputs: - run_id: - description: "amd64-image-build workflow run ID to test" - required: true - type: string - -permissions: - actions: read - contents: read - -jobs: - bats-image-test: - name: Run Bats against amd64 image artifact - runs-on: ubuntu-22.04 - timeout-minutes: 240 - if: ${{ github.event_name != 'workflow_run' || (github.event.workflow_run.conclusion == 'success' && github.event.workflow_run.head_repository.full_name == github.repository) }} - - steps: - - uses: actions/checkout@v4 - with: - repository: ${{ github.event.workflow_run.head_repository.full_name || github.repository }} - ref: ${{ github.event.workflow_run.head_sha || github.ref }} - - - name: Check out bats-core - uses: actions/checkout@v4 - with: - repository: bats-core/bats-core - # bats-core v1.12.0 - ref: 713504bc0224a19b3d7c7958c18dc07f64f54b44 - path: .bats-core - persist-credentials: false - - - name: Download amd64 image artifact - uses: actions/download-artifact@v4 - with: - github-token: ${{ github.token }} - run-id: ${{ github.event.workflow_run.id || inputs.run_id }} - pattern: joininbox-amd64-image-* - path: artifacts - merge-multiple: true - - - name: Verify and decompress image - shell: bash - run: | - set -euo pipefail - - cd artifacts - sha256sum -c joininbox-amd64-debian.qcow2.gz.sha256 - gzip -dk joininbox-amd64-debian.qcow2.gz - sha256sum -c joininbox-amd64-debian.qcow2.sha256 - - - name: Run image Bats tests - timeout-minutes: 30 - run: ci/amd64/test.amd64-image-bats.sh "${GITHUB_WORKSPACE}/artifacts/joininbox-amd64-debian.qcow2" diff --git a/.github/workflows/arm64-rpi-image-build.yml b/.github/workflows/arm64-rpi-image-build.yml index 137b2da..6d2c1f5 100644 --- a/.github/workflows/arm64-rpi-image-build.yml +++ b/.github/workflows/arm64-rpi-image-build.yml @@ -1,9 +1,5 @@ name: arm64-rpi-image-build -concurrency: - group: arm64-rpi-image-build-${{ github.head_ref }} - cancel-in-progress: true - on: push: branches: [ "master" ] @@ -32,17 +28,11 @@ jobs: - uses: actions/checkout@v3 - name: Set values - id: set_values run: | echo "BUILD_DATE=$(date +"%Y-%m-%d")" >> $GITHUB_ENV echo "BUILD_VERSION=$(git describe --always --tags)" >> $GITHUB_ENV - if [[ "${{github.event_name}}" == "pull_request" ]]; then - echo "::set-output name=github_user::${{github.event.pull_request.head.repo.owner.login}}" - else - echo "::set-output name=github_user::$(echo ${{github.repository}} | cut -d'/' -f1)" - fi - - name: Display the build name + - name: Hello JoininBox run: echo "Building the joininbox-arm64-rpi-image-${{ env.BUILD_DATE }}-${{ env.BUILD_VERSION }}" - name: Set up QEMU @@ -52,9 +42,8 @@ jobs: - name: Run the build script run: | - echo "Running with: ${{steps.set_values.outputs.github_user}} $GITHUB_HEAD_REF" cd ci/arm64-rpi - bash arm64-rpi.sh ${{steps.set_values.outputs.github_user}} $GITHUB_HEAD_REF + bash arm64-rpi.sh $GITHUB_ACTOR $GITHUB_HEAD_REF - name: Compute checksum of the raw image run: | @@ -72,7 +61,7 @@ jobs: sha256sum joininbox-arm64-rpi.img.gz > joininbox-arm64-rpi.img.gz.sha256 - name: Upload the image and checksums - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@v3 with: name: joininbox-arm64-rpi-image-${{ env.BUILD_DATE }}-${{ env.BUILD_VERSION }} path: | diff --git a/.github/workflows/packer-syntax-check.yml b/.github/workflows/packer-syntax-check.yml deleted file mode 100644 index d6dbd6f..0000000 --- a/.github/workflows/packer-syntax-check.yml +++ /dev/null @@ -1,60 +0,0 @@ -name: Packer Syntax Check - -concurrency: - group: packer-syntax-check-${{ github.head_ref || github.ref }} - cancel-in-progress: true - -on: - push: - branches: [ "master" ] - paths: - - '.github/workflows/packer-syntax-check.yml' - - 'ci/amd64/**/*.pkr.hcl' - - 'ci/amd64/**/*.pkrvars.hcl' - - 'ci/amd64/packer.build.amd64-debian.sh' - - 'ci/arm64-rpi/**/*.pkr.hcl' - - 'ci/arm64-rpi/**/*.pkrvars.hcl' - - 'ci/arm64-rpi/arm64-rpi.sh' - pull_request: - branches: [ "master" ] - paths: - - '.github/workflows/packer-syntax-check.yml' - - 'ci/amd64/**/*.pkr.hcl' - - 'ci/amd64/**/*.pkrvars.hcl' - - 'ci/amd64/packer.build.amd64-debian.sh' - - 'ci/arm64-rpi/**/*.pkr.hcl' - - 'ci/arm64-rpi/**/*.pkrvars.hcl' - - 'ci/arm64-rpi/arm64-rpi.sh' - workflow_dispatch: - -jobs: - validate-packer-syntax: - name: Validate Packer Syntax - runs-on: ubuntu-latest - - steps: - - name: Checkout repository - uses: actions/checkout@v4 - - - name: Setup Packer - uses: hashicorp/setup-packer@v3 - - - name: Show Packer version - run: packer version - - - name: Validate amd64 templates (syntax only) - shell: bash - run: | - set -euo pipefail - - mapfile -t templates < <(find ci/amd64 ci/arm64-rpi -type f \( -name '*.pkr.hcl' -o -name '*.pkrvars.hcl' \) | sort) - - if [ ${#templates[@]} -eq 0 ]; then - echo "No Packer templates found under ci/amd64 or ci/arm64-rpi" - exit 1 - fi - - for template in "${templates[@]}"; do - echo "Validating $template" - packer validate -syntax-only "$template" - done diff --git a/.github/workflows/test-shellcheck.yml b/.github/workflows/test-shellcheck.yml deleted file mode 100644 index f1c7b6f..0000000 --- a/.github/workflows/test-shellcheck.yml +++ /dev/null @@ -1,19 +0,0 @@ -name: "Test Shellcheck" - -on: - workflow_dispatch: - push: - branches: ["master"] - pull_request: - branches: ["master"] - -jobs: - shellcheck: - name: Run Shellcheck - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - name: Run ShellCheck - uses: ludeeus/action-shellcheck@master - with: - severity: error diff --git a/.gitignore b/.gitignore index 6d5fe6c..025a3fe 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,3 @@ scripts/wallets ci/arm64-rpi/.packer* ci/arm64-rpi/joininbox-arm64-rpi* -ci/amd64/builds -scripts/jam-remote/download diff --git a/FAQ.md b/FAQ.md index db608dd..97ea6c7 100644 --- a/FAQ.md +++ b/FAQ.md @@ -10,6 +10,7 @@ - [Log in through SSH using a hardware wallet](#log-in-through-ssh-using-a-hardware-wallet) - [SSH through Tor from Linux](#ssh-through-tor-from-linux) - [Allow Tor to connect to localhost](#allow-tor-to-connect-to-localhost) +- [Set up Armbian on the Hardkernel Odroid HC1 / XU4](#set-up-armbian-on-the-hardkernel-odroid-hc1--xu4) - [Download and verify Raspbian SDcard image for a Raspberry Pi](#download-and-verify-raspbian-sdcard-image-for-a-raspberry-pi) - [Error when connecting to a full node remotely through Tor](#error-when-connecting-to-a-full-node-remotely-through-tor) - [Erase the joinmarket user and the /home/joinmarket folder](#erase-the-joinmarket-user-and-the-homejoinmarket-folder) @@ -30,7 +31,6 @@ - [Wallet recovery](#wallet-recovery) - [on JoininBox](#on-joininbox) - [on the remote node](#on-the-remote-node) -- [Migrating from legacy wallet.dat to descriptor wallet](#migrating-from-legacy-walletdat-to-descriptor-wallet) - [USB SSD recommendation](#usb-ssd-recommendation) - [Pruned node notes](#pruned-node-notes) - [External drive](#external-drive) @@ -172,10 +172,55 @@ Use `ssh` with `torsocks` on the desktop (needs Tor installed): * Restart Tor: `sudo systemctl restart tor` +## Set up Armbian on the Hardkernel Odroid HC1 / XU4 +* Download the base image (`.img.gz`), the `.sha` and `.asc` file +https://www.armbian.com/odroid-xu4/ +* Verify: https://docs.armbian.com/User-Guide_Getting-Started/#how-to-check-download-authenticity + ```bash + gpg --keyserver ha.pool.sks-keyservers.net --recv-key DF00FAF1C577104B50BF1D0093D6889F9F0E78D5 + # gpg: key 93D6889F9F0E78D5: public key "Igor Pecovnik # " imported + # gpg: Total number processed: 1 + # gpg: imported: 1 + gpg --verify Armbian_21.02.3_Odroidxu4_buster_legacy_4.14.222.img.xz.asc + # gpg: assuming signed data in 'Armbian_21.02.3_Odroidxu4_buster_legacy_4.14.222.img.xz' + # gpg: Signature made Tue 09 Mar 2021 03:00:30 GMT + # gpg: using RSA key DF00FAF1C577104B50BF1D0093D6889F9F0E78D5 + # gpg: Good signature from "Igor Pecovnik " [unknown] + # gpg: aka "Igor Pecovnik (Ljubljana, Slovenia) " [unknown] + # gpg: WARNING: This key is not certified with a trusted signature! + # gpg: There is no indication that the signature belongs to the owner. + # Primary key fingerprint: DF00 FAF1 C577 104B 50BF 1D00 93D6 889F 9F0E 78D5 + shasum -c Armbian_21.02.3_Odroidxu4_buster_legacy_4.14.222.img.xz.sha + # Armbian_21.02.3_Odroidxu4_buster_legacy_4.14.222.img.xz: OK + ``` +* Preparation + Make sure you have a good & reliable SD card and a proper power supply. Archives can be uncompressed with 7-Zip on Windows, Keka on OS X and 7z on Linux (apt-get install p7zip-full). RAW images can be written with Etcher (all OS). +* Boot + Insert the SD card into the slot, connect a cable to your network if possible or a display and power your board. (First) boot (with DHCP) takes up to 35 seconds with a class 10 SD Card. +* Login + Log in as: `root` Password: `1234`. Then you are prompted to change this password (US-Keyboard setting). When done, you are asked to create a normal user-account for your everyday tasks. +* Change the password. +* Create a new user called `joinmarket` and set the password (the password will be changed to `joininbox`). + Keep pressing [ENTER] to use the default user information. +* Continue to [install JoininBox](README.md#install-joininbox) + ## Download and verify Raspbian SDcard image for a Raspberry Pi -* Download [Raspberry Pi Imager](https://www.raspberrypi.com/software/) -* enable the ssh login in the -* Flash the image to a min 32GB Endurance type SDcard +To be able to open the JoinMarket-QT GUI on the desktop from the RPI +need to use the Raspberry Pi OS (32-bit) with desktop image +* Download image: +https://downloads.raspberrypi.org/raspios_armhf/images/raspios_armhf-2020-05-28/2020-05-27-raspios-buster-armhf.zip +* Download signature: +https://downloads.raspberrypi.org/raspios_armhf/images/raspios_armhf-2020-05-28/2020-05-27-raspios-buster-armhf.zip.sig +* Import PGP pubkey: +`curl https://www.raspberrypi.org/raspberrypi_downloads.gpg.key | gpg --import` +* Verify the image: +`gpg --verify 2020-05-27-raspios-buster-armhf.zip.sig` +* Flash the image to an SDcard, can use the [Raspberry Pi Imager](https://www.raspberrypi.org/downloads/) +* put a file called simply: `ssh` to the root of the sdcard. +Read more on [how to gain ssh access here](https://www.raspberrypi.org/documentation/remote-access/ssh/). +* boot up the RPi and log in with ssh to: +`pi@LAN_IP_ADDRESS` +The default password is: `raspberry` * Continue to [install JoininBox](README.md#install-joininbox) ## Error when connecting to a full node remotely through Tor @@ -196,7 +241,7 @@ Use `ssh` with `torsocks` on the desktop (needs Tor installed): server=1 daemon=1 disablewallet=0 -main.wallet=watch-only-descriptor-wallet +main.wallet=wallet.dat # Connection settings rpcuser=REDACTED @@ -429,7 +474,7 @@ JoinMarket docs: * https://github.com/JoinMarket-Org/joinmarket-clientserver/blob/master/docs/USAGE.md#recover ### on JoininBox -* Connect the remote bitcoind with `CONFIG` -> `CONNECT` menu so it checks if the connection is successful. It will also set the remote watch-only-descriptor-wallet in bitcoind to "joininbox" so will need to rescan that after recovering an old wallet with previously used addresses. +* Connect the remote bitcoind with `CONFIG` -> `CONNECT` menu so it checks if the connection is successful. It will also set the remote watch-only wallet in bitcoind to "joininbox" so will need to rescan that after recovering an old wallet with previously used addresses. * When using the CLI and connecting to the remote node over Tor, you will need to use the script with the torsocks prefix like: `torsocks python3 wallet-tool.py --recoversync -g 20 ~/.joinmarket/wallets/wallet.jmdat` @@ -438,7 +483,7 @@ JoinMarket docs: * Use the menu option `WALLET` -> `RESCAN` or follow manually * the wallet defined as `rpc_wallet =` -in the joinmarket.cfg is the wallet which is used as a watch-only-descriptor-wallet in the remote bitcoind. +in the joinmarket.cfg is the wallet which is used as watch only in the remote bitcoind. You need to run rescanblockchain on that wallet in bitcoind after importing the joinmarket wallet. * The wallet is set in the joinmarket.cfg (by default called `joininbox` should show up when you run: `bitcoin-cli listwallets` @@ -448,67 +493,8 @@ You need to run rescanblockchain on that wallet in bitcoind after importing the Rescanning from the first SegWit block is sufficient for the default SegWit wallets. * Monitor progress (on a RaspiBlitz): -`sudo tail -fn 100 /mnt/hdd/app-storage/bitcoin/debug.log` +`sudo tail -fn 100 /mnt/hdd/bitcoin/debug.log` Once the rescan is finished you balances should appear in the `INFO` menu (`wallet-tool.py`) - -## Migrating from legacy wallet.dat to descriptor wallet - -Starting with the 0.9.0 version, JoininBox uses Bitcoin Core's descriptor wallets (`watch-only-descriptor-wallet`) instead of the legacy `wallet.dat`. This change provides better compatibility with modern Bitcoin Core versions (v26+) and aligns with Bitcoin Core's default wallet format. - -### Why this change? - -Bitcoin Core has deprecated BDB (Berkeley DB) wallets in favor of descriptor wallets. The new descriptor wallets: -- Are the default in Bitcoin Core v26+ -- Don't require the `deprecatedrpc=create_bdb` configuration -- Have better performance and features -- Are actively maintained and improved - -### How automatic migration works - -When `rpc_wallet_file` is still set to `wallet.dat`, JoininBox queries the connected Bitcoin Core node using RPC before changing the configuration: - -- Bitcoin Core v30.0 and newer: JoininBox atomically changes `rpc_wallet_file` to `watch-only-descriptor-wallet`, creates or loads that descriptor wallet, and displays the migration notice when the old `wallet.dat` is present. -- Bitcoin Core v29.x and earlier: JoininBox keeps using `wallet.dat` and does not start automatic migration. -- Version unavailable: JoininBox leaves `wallet.dat` configured rather than migrating without confirming compatibility. - -The migration does not rename, modify, or delete the old `wallet.dat`. It changes which Bitcoin Core wallet JoinMarket uses for watch-only address imports and transaction history. - -### Migration steps for existing users - -If you're upgrading from a previous version of JoininBox that used `wallet.dat`, follow these steps: - -1. **The migration notice will appear automatically on Bitcoin Core v30.0 and newer** - When you first use any wallet-related function after updating, JoininBox checks the connected Bitcoin Core version. On v30.0 and newer it switches the configured RPC wallet to `watch-only-descriptor-wallet`, detects the old `wallet.dat`, and displays a migration notice. Bitcoin Core v29.x and earlier continue using `wallet.dat` without starting the automatic migration. - -2. **Open each JoinMarket wallet** - Go to `WALLET` -> `DISPLAY` and open each of your JoinMarket wallets (`.jmdat` files) at least once. This imports the addresses into the new `watch-only-descriptor-wallet` in Bitcoin Core. - -3. **Run a blockchain rescan** - After opening all your wallets, go to `WALLET` -> `RESCAN` and enter a blockheight: - - Use `481824` (first SegWit block) for wallets created after August 2017 - - Can use a later blockheight if you know when your wallet had its first deposit - -4. **Wait for the rescan to complete** - The rescan can take several hours depending on the blockheight and your hardware. Monitor progress with: - ```bash - # On standalone JoininBox: - sudo tail -f /home/bitcoin/.bitcoin/debug.log - - # On RaspiBlitz: - sudo tail -f /mnt/hdd/bitcoin/debug.log - ``` - -5. **Verify your balances** - Once the rescan completes, check your wallet balances with `WALLET` -> `DISPLAY`. - -### Notes - -- The old `wallet.dat` is not deleted and remains in Bitcoin Core -- Automatic migration only runs when the connected Bitcoin Core version is v30.0 or newer -- You only need to perform this migration once -- The migration notice will not appear again after you acknowledge it -- If you have issues, you can reset the migration flag by removing `walletMigrationDone=true` from `/home/joinmarket/joinin.conf` - ## USB SSD recommendation **JoininBox operates on the minimum viable hardware under the assumption that the seed (and passphrase) of the wallets used is safely backed up and can be recovered fully** * The above warning is especially true for SDcard as they fail often, use a good quality one. @@ -579,16 +565,35 @@ Alternatively to a pruned node there could be a larger >400 GB storage connected # -rw------- 1 bitcoin bitcoin 1521305 Mar 21 10:38 peers.dat # -rw-r--r-- 1 bitcoin bitcoin 7 Mar 21 10:08 settings.json # drwx------ 34 bitcoin bitcoin 4096 Dec 7 23:39 specter - # drwx------ 2 bitcoin bitcoin 4096 Mar 21 10:38 watch-only-descriptor-wallet + # drwx------ 2 bitcoin bitcoin 4096 Mar 21 10:38 wallet.dat installMainnet - ... + # Failed to stop bitcoind.service: Unit bitcoind.service not loaded. + # + # [Unit] + # Description=Bitcoin daemon on mainnet + # [Service] + # User=bitcoin + # Group=bitcoin + # Type=forking + # PIDFile=/home/bitcoin/bitcoin/bitcoind.pid + # ExecStart=/home/bitcoin/bitcoin/bitcoind -daemon -pid=/home/bitcoin/bitcoin/bitcoind.pid + # Restart=always + # TimeoutSec=120 + # RestartSec=30 + # StandardOutput=null + # StandardError=journal + # + # [Install] + # WantedBy=multi-user.target + # + # Created symlink /etc/systemd/system/multi-user.target.wants/bitcoind.service → /etc/systemd/system/bitcoind.service. # # OK - the bitcoind.service is now enabled # # # Installed Bitcoin Core version v0.21.0 # # # Monitor the bitcoind with: sudo tail -f /home/bitcoin/.bitcoin/mainnet/debug.log # - # # Create watch-only-descriptor-wallet ... + # # Create wallet.dat ... # error code: -28 # error message: # Loading block index... @@ -599,6 +604,48 @@ Alternatively to a pruned node there could be a larger >400 GB storage connected ## IRC server settings * See the most up to date configuration in: https://github.com/JoinMarket-Org/joinmarket-clientserver/blob/master/jmclient/jmclient/configure.py +* The latest setting with Tor enabled: + ``` + [MESSAGING:server1] + #host = irc.darkscience.net + channel = joinmarket-pit + port = 6697 + usessl = true + #socks5 = false + socks5_host = localhost + socks5_port = 9050 + #for tor + host = darkirc6tqgpnwd3blln3yfv5ckl47eg7llfxkmtovrv7c7iwohhb6ad.onion + socks5 = true + + [MESSAGING:server2] + #host = irc.hackint.org + channel = joinmarket-pit + #port = 6697 + #usessl = true + #socks5 = false + socks5_host = localhost + socks5_port = 9050 + #for tor + host = ncwkrwxpq2ikcngxq3dy2xctuheniggtqeibvgofixpzvrwpa77tozqd.onion + port = 6667 + usessl = false + socks5 = true + + [MESSAGING:server3] + #host = agora.anarplex.net + channel = joinmarket-pit + #port = 14716 + #usessl = true + #socks5 = false + socks5_host = localhost + socks5_port = 9050 + #for tor + host = vxecvd6lc4giwtasjhgbrr3eop6pzq6i5rveracktioneunalgqlwfad.onion + port = 6667 + usessl = false + socks5 = true + ``` ## Install JoinMarket without the QT GUI and dependencies * Run the build script with the options `BRANCH` `GITHUBUSER` `without-qt`: diff --git a/Makefile b/Makefile index 35b4f7e..f26dc65 100644 --- a/Makefile +++ b/Makefile @@ -35,12 +35,3 @@ arm64-rpi-image: # Compute checksum of the compressed image cd ci/arm64-rpi && \ sha256sum joininbox-arm64-rpi.img.gz > joininbox-arm64-rpi.img.gz.sha256 - -release-tag: - @if [ -z "$(TAG)" ]; then \ - echo "Error: TAG parameter is required. Usage: make release-tag TAG=v0.7.4"; \ - exit 1; \ - fi - @echo "Creating signed tag $(TAG) and pushing to origin..." - git tag -s $(TAG) -m "$(TAG)" && git push origin $(TAG) - @echo "Successfully created and pushed signed tag $(TAG)" diff --git a/README.md b/README.md index f9e7ef4..3588164 100644 --- a/README.md +++ b/README.md @@ -23,7 +23,7 @@ A minimalistic, security focused linux environment for JoinMarket with a termina - [Features](#features) - [Required Hardware](#required-hardware) - [A computer running a Debian / Ubuntu Linux flavour.](#a-computer-running-a-debian--ubuntu-linux-flavour) - - [RaspberryPi 5 or 4](#raspberrypi-5-or-4) + - [RaspberryPi 4 or 3](#raspberrypi-4-or-3) - [VPS eg: host4coins.net](#vps-eg-host4coinsnet) - [Set up using an SDcard image](#set-up-using-an-sdcard-image) - [Set up JoininBox on Linux](#set-up-joininbox-on-linux) @@ -32,6 +32,7 @@ A minimalistic, security focused linux environment for JoinMarket with a termina - [More info](#more-info) - [About JoinMarket](#about-joinmarket) - [Forums](#forums) +- [Donations](#donations) ## Features @@ -43,19 +44,19 @@ A minimalistic, security focused linux environment for JoinMarket with a termina * RaspiBlitz over [LAN or Tor](prepare_remote_node.md#raspiblitz) * RoninDojo over [LAN or Tor](prepare_remote_node.md#ronindojo) * Start a pruned node from https://pruned.host4coins.net/blocks -* JoininBox is part of the RaspiBlitz SERVICES +* JoininBox is part the RaspiBlitz SERVICES -**The addresses, transactions and balances of JoinMarket can be seen in the watch-only-descriptor-wallet of the connected node.** +**The addresses, transactions and balances of JoinMarket can be seen in the watch-only wallet of the connected node.** * use your own or a trusted node * to protect privacy in case of physical access use disk encryption ## Required Hardware ### A computer running a Debian / Ubuntu Linux flavour. * See the [tested-environments](#tested-environments). -### RaspberryPi 5 or 4 +### RaspberryPi 4 or 3 * Power supply (5V 3A and above recommended) * Heatsink case -* 32 GB Endurance type SDcard +* 32 GB Endurence type SDcard * [(USB SSD to run a pruned bitcoin node locally)](FAQ.md#usb-ssd-recommendation) ### VPS eg: [host4coins.net](https://host4coins.net/) Recommended minimum: @@ -122,7 +123,7 @@ Recommended minimum: ### Install JoininBox * Start as the `root` user or change with: -`$ sudo su -` +`$ sudo - su` * Run the [build script](https://github.com/openoms/joininbox/blob/master/build_joininbox.sh): ```bash @@ -161,3 +162,8 @@ the default password is: `joininbox` - will be prompted to change it on the firs * IRC: #joinmarket on [libera.chat](https://libera.chat/) or [hackint.org](https://hackint.org/) * Reddit: * Keybase: + +## Donations +* For JoinMarket (general): https://bitcoinprivacy.me/joinmarket-donations +* To waxwing for JoinMarket: +* To openoms for JoininBox (LN + payjoin enabled - open in the [Tor Browser](https://www.torproject.org/)): diff --git a/build_joininbox.sh b/build_joininbox.sh index ade914a..9750546 100644 --- a/build_joininbox.sh +++ b/build_joininbox.sh @@ -52,7 +52,7 @@ echo " # https://github.com/${githubUser}/joininbox/tree/${wantedBranch} # Press ENTER to confirm or CTRL+C to exit" -read +read key echo echo "###################################" @@ -90,28 +90,7 @@ echo "# Preparing the base image" echo "############################" echo -echo "# Prevent sleep" # on all platforms https://wiki.debian.org/Suspend -systemctl mask sleep.target suspend.target hibernate.target hybrid-sleep.target -mkdir /etc/systemd/sleep.conf.d -echo "[Sleep] -AllowSuspend=no -AllowHibernation=no -AllowSuspendThenHibernate=no -AllowHybridSleep=no" | tee /etc/systemd/sleep.conf.d/nosuspend.conf -mkdir /etc/systemd/logind.conf.d -echo "[Login] -HandleLidSwitch=ignore -HandleLidSwitchDocked=ignore" | tee /etc/systemd/logind.conf.d/nosuspend.conf - -# check if /etc/hosts already has debian entry -# prevent "unable to resolve host debian" error -isDebianInHosts=$(grep -c "debian" /etc/hosts) -if [ ${isDebianInHosts} -eq 0 ]; then - echo "# Adding debian to /etc/hosts" - echo "127.0.1.1 debian" | tee -a /etc/hosts > /dev/null - systemctl restart networking -fi - +echo "# Prepare ${baseImage} " # special prepare on RPi if [ "${baseimage}" = "raspios" ] || [ "${baseimage}" = "debian_rpi64" ] || [ "${baseimage}" = "armbian" ]; then @@ -160,6 +139,17 @@ if [ "${baseimage}" = "raspios" ] || [ "${baseimage}" = "debian_rpi64" ]; then echo "$max_usb_current already in $configFile" fi + # run fsck on sd root partition on every startup to prevent "maintenance login" screen + # see: https://github.com/rootzoll/raspiblitz/issues/782#issuecomment-564981630 + # see https://github.com/rootzoll/raspiblitz/issues/1053#issuecomment-600878695 + # use command to check last fsck check: sudo tune2fs -l /dev/mmcblk0p2 + if [ "${tweak_boot_drive}" == "true" ]; then + echo "* running tune2fs" + tune2fs -c 1 /dev/mmcblk0p2 + else + echo "* skipping tweak_boot_drive" + fi + # edit kernel parameters kernelOptionsFile=/boot/cmdline.txt fsOption1="fsck.mode=force" @@ -276,46 +266,69 @@ echo "##########" echo # apt dependencies for python apt-get install -y python3 virtualenv python3-venv python3-dev python3-wheel python3-jinja2 python3-pip -if [ -f "/usr/bin/python3.13" ]; then - # use python 3.13 if available - update-alternatives --install /usr/bin/python python /usr/bin/python3.13 1 - echo "# python calls python3.13" -elif [ -f "/usr/bin/python3.12" ]; then - # use python 3.12 if available - update-alternatives --install /usr/bin/python python /usr/bin/python3.12 1 - echo "# python calls python3.12" -elif [ -f "/usr/bin/python3.11" ]; then - # use python 3.11 if available - update-alternatives --install /usr/bin/python python /usr/bin/python3.11 1 - echo "# python calls python3.11" -elif [ -f "/usr/bin/python3.10" ]; then - # use python 3.10 if available - update-alternatives --install /usr/bin/python python /usr/bin/python3.10 1 - echo "# python calls python3.10" -elif [ -f "/usr/bin/python3.9" ]; then - # use python 3.9 if available - update-alternatives --install /usr/bin/python python /usr/bin/python3.9 1 - echo "# python calls python3.9" -elif [ -f "/usr/bin/python3.8" ]; then - # use python 3.8 if available - update-alternatives --install /usr/bin/python python /usr/bin/python3.8 1 - echo "# python calls python3.8" +if [ "${cpu}" = "armv7l" ] || [ "${cpu}" = "armv6l" ]; then + if [ ! -f "/usr/bin/python3.7" ]; then + # install python37 + pythonVersion="3.7.9" + majorPythonVersion=$(echo "$pythonVersion" | awk -F. '{print $1"."$2}') + # dependencies + apt-get install software-properties-common build-essential libnss3-dev zlib1g-dev libgdbm-dev libncurses5-dev libssl-dev libffi-dev libreadline-dev libsqlite3-dev libbz2-dev -y + # download + wget --prefer-family=ipv4 --progress=bar:force https://www.python.org/ftp/python/${pythonVersion}/Python-${pythonVersion}.tgz + # optional signature for verification + wget --prefer-family=ipv4 --progress=bar:force https://www.python.org/ftp/python/${pythonVersion}/Python-${pythonVersion}.tgz.asc + # get PGP pubkey of Ned Deily (Python release signing key) + gpg --recv-key 0D96DF4D4110E5C43FBFB17F2D347EA6AA65421D + # check for: Good signature from "Pablo Galindo Salgado " + gpg --verify Python-${pythonVersion}.tgz.asc || exit 1 + # unzip + tar xvf Python-${pythonVersion}.tgz + cd Python-${pythonVersion} || exit 1 + # configure + ./configure --enable-optimizations + # install + make altinstall + # move the python binary to the expected directory + mv "$(which python${majorPythonVersion})" /usr/bin/ + # check + ls -la /usr/bin/python${majorPythonVersion} || exit 1 + # clean + cd .. + rm Python-${pythonVersion}.tgz + rm -rf Python-${pythonVersion} + fi + update-alternatives --install /usr/bin/python python /usr/bin/python3.7 1 + echo "# python calls python3.7" + else - echo "# FAIL- there is no tested version of python present" - exit 1 + if [ -f "/usr/bin/python3.7" ]; then + # make sure /usr/bin/python exists (and calls Python3.7) + update-alternatives --install /usr/bin/python python /usr/bin/python3.7 1 + echo "# python calls python3.7" + elif [ -f "/usr/bin/python3.8" ]; then + # use python 3.8 if available + update-alternatives --install /usr/bin/python python /usr/bin/python3.8 1 + echo "# python calls python3.8" + elif [ -f "/usr/bin/python3.9" ]; then + # use python 3.9 if available + update-alternatives --install /usr/bin/python python /usr/bin/python3.9 1 + echo "# python calls python3.9" + elif [ -f "/usr/bin/python3.10" ]; then + # use python 3.10 if available + update-alternatives --install /usr/bin/python python /usr/bin/python3.10 1 + echo "# python calls python3.10" + elif [ -f "/usr/bin/python3.11" ]; then + # use python 3.11 if available + update-alternatives --install /usr/bin/python python /usr/bin/python3.11 1 + echo "# python calls python3.11" + else + echo "# FAIL- there is no tested version of python present" + exit 1 + fi fi # make sure /usr/bin/pip exists (and calls pip3) update-alternatives --install /usr/bin/pip pip /usr/bin/pip3 1 - -# don't protect system packages from pip install -# tracking issue: https://github.com/raspiblitz/raspiblitz/issues/4170 -for PYTHONDIR in /usr/lib/python3.*; do - if [ -f "$PYTHONDIR/EXTERNALLY-MANAGED" ]; then - rm "$PYTHONDIR/EXTERNALLY-MANAGED" - fi -done - # setuptools needed for Nyx pip install setuptools @@ -346,8 +359,6 @@ apt-get install -y dialog apt-get install -y qrencode # unzip for the pruned node snapshot apt-get install -y unzip -# JoinMarket dependency https://github.com/JoinMarket-Org/joinmarket-clientserver/blob/5bfa08c6f558458c9a93e8095ce9dc1b62412838/install.sh#L76C10-L76C21 -apt-get install -y libltdl-dev apt-get clean apt-get -y autoremove @@ -357,9 +368,7 @@ echo "# JoininBox" echo "#############" echo echo "# add the 'joinmarket' user" -adduser --system --group --shell /bin/bash --home /home/joinmarket joinmarket -echo "Copy the skeleton files for login" -sudo -u joinmarket cp -r /etc/skel/. /home/joinmarket/ +adduser --disabled-password --gecos "" joinmarket echo "# clone the joininbox repo and copy the scripts" cd /home/joinmarket || exit 1 @@ -389,21 +398,21 @@ if echo "${lastCommit}" | grep 13C688DB5B9C745DE4D2E4545BFB77609B081B65; then PGPsigner="openoms" PGPpubkeyLink="https://github.com/openoms.gpg" PGPpubkeyFingerprint="13C688DB5B9C745DE4D2E4545BFB77609B081B65" -elif echo "${lastCommit}" | grep B5690EEEBB952194; then +elif echo "${lastCommit}" | grep 4AEE18F83AFDEB23; then echo "# The last commit was made on GitHub and is signed with the GitHub PGP key." PGPsigner="web-flow" PGPpubkeyLink="https://github.com/${PGPsigner}.gpg" - PGPpubkeyFingerprint="B5690EEEBB952194" + PGPpubkeyFingerprint="4AEE18F83AFDEB23" else echo "# No known PGP key found" exit 1 fi -command="bash /home/joinmarket/joininbox/scripts/verify.git.sh \ - ${PGPsigner} ${PGPpubkeyLink} ${PGPpubkeyFingerprint}" +command="sudo -u joinmarket bash /home/joinmarket/joininbox/scripts/verify.git.sh \ + ${PGPsigner} ${PGPpubkeyLink} ${PGPpubkeyFingerprint} ${tag}" echo "running: ${command}" chmod 777 /dev/shm -sudo -u joinmarket ${command} || exit 1 +${command} || exit 1 runuser joinmarket -c "cp /home/joinmarket/joininbox/scripts/* /home/joinmarket/" runuser joinmarket -c "cp /home/joinmarket/joininbox/scripts/.* /home/joinmarket/ 2>/dev/null" @@ -482,7 +491,7 @@ deb-src [arch=${arch}] https://deb.torproject.org/torproject.org ${distro} main" apt-get install -y build-essential fakeroot devscripts apt-get build-dep -y tor deb.torproject.org-keyring mkdir ~/debian-packages - cd ~/debian-packages || exit 1 + cd ~/debian-packages apt-get source tor cd tor-* || exit 1 debuild -rfakeroot -uc -us @@ -530,7 +539,6 @@ echo apt-get install -y fail2ban ufw # autostart fail2ban systemctl enable fail2ban -touch /var/log/auth.log # set up the firewall ufw default deny incoming @@ -583,6 +591,7 @@ echo "#############" echo " if [ -f \"/home/joinmarket/joinmarket-clientserver/jmvenv/bin/activate\" ]; then . /home/joinmarket/joinmarket-clientserver/jmvenv/bin/activate + /home/joinmarket/joinmarket-clientserver/jmvenv/bin/python -c \"import PySide2\" cd /home/joinmarket/joinmarket-clientserver/scripts/ fi # shortcut commands @@ -598,29 +607,23 @@ echo "#########################" echo "# Download Bitcoin Core" echo "#########################" echo -sudo -u joinmarket bash /home/joinmarket/install.bitcoincore.sh downloadCoreOnly || exit 1 +sudo -u joinmarket /home/joinmarket/install.bitcoincore.sh downloadCoreOnly || exit 1 echo echo "######################" echo "# Install JoinMarket" echo "######################" - -if [ "${cpu}" = x86_64 ]; then - qtgui=true -else - # no qtgui on arm - qtgui=false -fi +qtgui=true checkEntry=$(runuser joinmarket -c "cat /home/joinmarket/joinin.conf | grep -c qtgui") if [ ${checkEntry} -eq 0 ]; then - echo "qtgui=$qtgui" | tee -a /home/joinmarket/joinin.conf + echo "qtgui=true" | tee -a /home/joinmarket/joinin.conf fi if [ "$4" = "without-qt" ]; then qtgui="false" sed -i "s/^qtgui=.*/qtgui=false/g" /home/joinmarket/joinin.conf fi -sudo -u joinmarket bash /home/joinmarket/install.joinmarket.sh -i install -q $qtgui || exit 1 +sudo -u joinmarket /home/joinmarket/install.joinmarket.sh -i install -q $qtgui || exit 1 echo "###################" echo "# bootstrap.service" diff --git a/ci/amd64/debian/build.amd64-debian.pkr.hcl b/ci/amd64/debian/build.amd64-debian.pkr.hcl deleted file mode 100644 index f5a34d9..0000000 --- a/ci/amd64/debian/build.amd64-debian.pkr.hcl +++ /dev/null @@ -1,120 +0,0 @@ -# images, checksums and signatures are at: -# https://cdimage.debian.org/debian-cd/current/amd64/iso-cd/ -# NOTE: This template is intended to be invoked via the wrapper script: -# ci/amd64/packer.build.amd64-debian.sh -# The wrapper resolves and injects the latest point-release ISO name and matching checksum -# at runtime. Defaults below are placeholders and are not guaranteed to work if you run -# `packer build` directly. -variable "iso_name" { default = "debian-13-amd64-netinst.iso" } -variable "iso_checksum" { default = "file:https://cdimage.debian.org/debian-cd/current/amd64/iso-cd/SHA256SUMS" } - -variable "github_user" { default = "openoms" } -variable "branch" { default = "master" } - -variable "boot" { default = "uefi" } -variable "preseed_file" { default = "preseed.cfg" } -variable "hostname" { default = "joininbox-amd64" } - -variable "image_size" { default = "30000" } -variable "image_type" { default = "qcow2" } - -variable "memory" { default = "2048" } -variable "cpus" { default = "2" } - -locals { - name_template = "joininbox-amd64-debian" - image_extension = var.image_type == "raw" ? "img" : var.image_type - bios_file = var.boot == "uefi" ? "OVMF.fd" : "bios-256k.bin" - boot_command = var.boot == "uefi" ? [ - "c", - "linux /install.amd/vmlinuz ", - "auto=true ", - "url=http://{{ .HTTPIP }}:{{ .HTTPPort }}/${var.preseed_file} ", - "hostname=${var.hostname} ", - "domain=${var.hostname}.local ", - "interface=auto ", - "vga=788 noprompt quiet --", - "initrd /install.amd/initrd.gz", - "boot" - ] : [ - "install ", - " preseed/url=http://{{ .HTTPIP }}:{{ .HTTPPort }}/${var.preseed_file} ", - "debian-installer=en_US.UTF-8 ", - "auto ", - "locale=en_US.UTF-8 ", - "kbd-chooser/method=us ", - "keyboard-configuration/xkb-keymap=us ", - "netcfg/get_hostname=${var.hostname} ", - "netcfg/get_domain=${var.hostname}.local ", - "fb=false ", - "debconf/frontend=noninteractive ", - "console-setup/ask_detect=false ", - "console-keymaps-at/keymap=us ", - "grub-installer/bootdev=default ", - "" - ] -} - -source "qemu" "debian" { - boot_command = local.boot_command - boot_wait = "5s" - cpus = var.cpus - disk_size = var.image_size - http_directory = "./http" - iso_checksum = var.iso_checksum - iso_url = "https://cdimage.debian.org/debian-cd/current/amd64/iso-cd/${var.iso_name}" - memory = var.memory - output_directory = "../builds/${local.name_template}-qemu" - shutdown_command = "echo 'joininbox' | sudo /sbin/shutdown -hP now" - ssh_password = "joininbox" - ssh_port = 22 - ssh_timeout = "10000s" - ssh_username = "joinmarket" - format = var.image_type - vm_name = "${local.name_template}.${local.image_extension}" - headless = false - vnc_bind_address = "127.0.0.1" - vnc_port_max = 5900 - vnc_port_min = 5900 - qemuargs = [ - ["-m", var.memory], - ["-bios", local.bios_file], - ["-display", "none"] - ] -} - -build { - description = "JoininBox amd64 Debian image build" - sources = ["source.qemu.debian"] - - provisioner "shell" { - environment_vars = [ - "HOME_DIR=/home/joinmarket", - "github_user=${var.github_user}", - "branch=${var.branch}" - ] - - execute_command = "echo 'joininbox' | {{.Vars}} sudo -S -E sh -eux '{{.Path}}'" - expect_disconnect = true - scripts = [ - "./scripts/update.sh", - "./../_common/sshd.sh", - "./scripts/networking.sh", - "./scripts/sudoers.sh", - "./scripts/systemd.sh", - "./scripts/joininbox.sh", - "./scripts/cleanup.sh" - ] - } -} - -packer { - required_version = ">= 1.7.0, < 2.0.0" - - required_plugins { - qemu = { - source = "github.com/hashicorp/qemu" - version = ">= 1.0.0, < 2.0.0" - } - } -} diff --git a/ci/amd64/debian/http/debian-9/preseed.cfg b/ci/amd64/debian/http/debian-9/preseed.cfg new file mode 100644 index 0000000..a190f0b --- /dev/null +++ b/ci/amd64/debian/http/debian-9/preseed.cfg @@ -0,0 +1,47 @@ +choose-mirror-bin mirror/http/proxy string +d-i apt-setup/use_mirror boolean true +d-i base-installer/kernel/override-image string linux-server +d-i clock-setup/utc boolean true +d-i clock-setup/utc-auto boolean true +d-i finish-install/reboot_in_progress note +d-i grub-installer/only_debian boolean true +d-i grub-installer/with_other_os boolean true +d-i keymap select us +d-i mirror/country string manual +d-i mirror/http/directory string /debian +d-i mirror/http/hostname string httpredir.debian.org +d-i mirror/http/proxy string +d-i partman-auto-lvm/guided_size string max +d-i partman-auto/choose_recipe select atomic +d-i partman-auto/method string lvm +d-i partman-lvm/confirm boolean true +d-i partman-lvm/confirm_nooverwrite boolean true +d-i partman-lvm/device_remove_lvm boolean true +d-i partman/choose_partition select finish +d-i partman/confirm boolean true +d-i partman/confirm_nooverwrite boolean true +d-i partman/confirm_write_new_label boolean true +d-i passwd/root-login boolean false +d-i passwd/root-password-again password joininbox +d-i passwd/root-password password joininbox +d-i passwd/user-fullname string joinmarket +d-i passwd/user-uid string 1000 +d-i passwd/user-password password joininbox +d-i passwd/user-password-again password joininbox +d-i passwd/username string joinmarket +d-i pkgsel/include string sudo bzip2 acpid cryptsetup zlib1g-dev wget curl dkms fuse make nfs-common net-tools cifs-utils rsync +d-i pkgsel/install-language-support boolean false +d-i pkgsel/update-policy select none +d-i pkgsel/upgrade select full-upgrade +# Prevent packaged version of VirtualBox Guest Additions being installed: +d-i preseed/early_command string sed -i \ + '/in-target/idiscover(){/sbin/discover|grep -v VirtualBox;}' \ + /usr/lib/pre-pkgsel.d/20install-hwpackages +d-i time/zone string UTC +d-i user-setup/allow-password-weak boolean true +d-i user-setup/encrypt-home boolean false +d-i preseed/late_command string sed -i '/^deb cdrom:/s/^/#/' /target/etc/apt/sources.list +apt-cdrom-setup apt-setup/cdrom/set-first boolean false +apt-mirror-setup apt-setup/use_mirror boolean true +popularity-contest popularity-contest/participate boolean false +tasksel tasksel/first multiselect standard, ssh-server diff --git a/ci/amd64/debian/http/preseed.cfg b/ci/amd64/debian/http/preseed.cfg deleted file mode 100644 index 244ea2b..0000000 --- a/ci/amd64/debian/http/preseed.cfg +++ /dev/null @@ -1,72 +0,0 @@ -# https://github.com/chef/bento/blob/main/packer_templates/http/debian/preseed.cfg -# https://www.debian.org/releases/stable/example-preseed.txt -# https://github.com/tylert/packer-build/blob/master/source/debian/12_bookworm/base-uefi.preseed -# variables: https://github.com/tylert/packer-build/blob/master/source/debian/12_bookworm/base-uefi.pkr.hcl - -# Locale Setup -d-i debian-installer/language string en -d-i debian-installer/country string US -d-i debian-installer/locale string en_US.UTF-8 -# d-i localechooser/supported-locales multiselect en_CA.UTF-8 fr_CA.UTF-8 zh_CN.UTF-8 -# d-i pkgsel/install-language-support boolean true - -# Keyboard Setup -d-i keyboard-configuration/xkb-keymap select us - -# Clock Setup -# d-i time/zone string Canada/Eastern -d-i time/zone string UTC -d-i clock-setup/utc boolean true -# set above to false if making a bootable USB to run on same system as Windows - -# Network Setup -d-i netcfg/get_hostname string joininbox-amd64 -d-i netcfg/get_domain string -# https://bugs.launchpad.net/ubuntu/+source/netcfg/+bug/713385 -d-i netcfg/choose_interface select auto -# make sure you also add "interface=auto" to your boot command too -# https://bugs.launchpad.net/ubuntu/+source/netcfg/+bug/713385 - -# User Setup -d-i passwd/root-login boolean false -d-i passwd/root-password-again password joininbox -d-i passwd/root-password password joininbox -d-i passwd/user-fullname string joinmarket -d-i passwd/user-uid string 1000 -d-i passwd/user-password password joininbox -d-i passwd/user-password-again password joininbox -d-i passwd/username string joinmarket - -# Package Setup -d-i hw-detect/load_firmware boolean false -d-i hw-detect/load_media boolean false -apt-cdrom-setup apt-setup/cdrom/set-first boolean false -d-i mirror/country string manual -d-i mirror/http/hostname string httpredir.debian.org -d-i mirror/http/directory string /debian -d-i mirror/http/proxy string -d-i apt-setup/contrib boolean true -d-i apt-setup/non-free boolean true - -tasksel tasksel/first multiselect ssh-server, standard -d-i pkgsel/include string sudo bzip2 acpid cryptsetup zlib1g-dev wget curl dkms fuse make nfs-common net-tools cifs-utils rsync -d-i pkgsel/install-language-support boolean false -d-i pkgsel/update-policy select none -d-i pkgsel/upgrade select full-upgrade - -popularity-contest popularity-contest/participate boolean false - -# Drive setup -d-i partman-auto-lvm/guided_size string max -d-i partman-auto/choose_recipe select atomic -d-i partman-auto/method string lvm -d-i partman-lvm/confirm boolean true -d-i partman-lvm/confirm_nooverwrite boolean true -d-i partman-lvm/device_remove_lvm boolean true -d-i partman/choose_partition select finish -d-i partman/confirm boolean true -d-i partman/confirm_nooverwrite boolean true -d-i partman/confirm_write_new_label boolean true - -# Final Setup -d-i finish-install/reboot_in_progress note diff --git a/ci/amd64/debian/joininbox-amd64-debian.json b/ci/amd64/debian/joininbox-amd64-debian.json new file mode 100644 index 0000000..539f784 --- /dev/null +++ b/ci/amd64/debian/joininbox-amd64-debian.json @@ -0,0 +1,150 @@ +{ + "variables": { + "iso_name": "debian-12.1.0-amd64-netinst.iso", + "iso_checksum": "9f181ae12b25840a508786b1756c6352a0e58484998669288c4eec2ab16b8559", + "box_basename": "debian", + "build_directory": "../builds", + "build_timestamp": "{{isotime \"20060102150405\"}}", + "cpus": "2", + "disk_size": "30000", + "git_revision": "__unknown_git_revision__", + "guest_additions_url": "", + "headless": "false", + "http_directory": "{{template_dir}}/http", + "http_proxy": "{{env `http_proxy`}}", + "https_proxy": "{{env `https_proxy`}}", + "memory": "2048", + "mirror": "http://cdimage.debian.org/cdimage/release", + "mirror_directory": "current/amd64/iso-cd", + "name": "debian", + "no_proxy": "{{env `no_proxy`}}", + "preseed_path": "debian-9/preseed.cfg", + "qemu_display": "none", + "qemu_bios": "bios-256k.bin", + "template": "joininbox-amd64-debian", + "boot_command": "install preseed/url=http://{{ .HTTPIP }}:{{ .HTTPPort }}/{{user `preseed_path`}} debian-installer=en_US.UTF-8 auto locale=en_US.UTF-8 kbd-chooser/method=us keyboard-configuration/xkb-keymap=us netcfg/get_hostname={{ .Name }} netcfg/get_domain=vagrantup.com fb=false debconf/frontend=noninteractive console-setup/ask_detect=false console-keymaps-at/keymap=us grub-installer/bootdev=default ", + "version": "TIMESTAMP" +}, + "builders": [ + { + "boot_command": "{{user `boot_command`}}", + "boot_wait": "5s", + "cpus": "{{ user `cpus` }}", + "disk_size": "{{user `disk_size`}}", + "headless": "{{ user `headless` }}", + "http_directory": "{{user `http_directory`}}", + "iso_checksum": "{{user `iso_checksum`}}", + "iso_url": "{{user `mirror`}}/{{user `mirror_directory`}}/{{user `iso_name`}}", + "memory": "{{ user `memory` }}", + "output_directory": "{{ user `build_directory` }}/{{user `template`}}-qemu", + "shutdown_command": "echo 'joininbox' | sudo /sbin/shutdown -hP now", + "ssh_password": "joininbox", + "ssh_port": 22, + "ssh_timeout": "10000s", + "ssh_username": "joinmarket", + "type": "qemu", + "format": "qcow2", + "vm_name": "{{ user `template` }}.qcow2", + "qemuargs": [ + [ "-m", "{{ user `memory` }}" ], + [ "-bios", "{{ user `qemu_bios` }}" ], + [ "-display", "{{ user `qemu_display` }}" ] + ] + }, + { + "boot_command": "{{user `boot_command`}}", + "boot_wait": "5s", + "cpus": "{{ user `cpus` }}", + "disk_size": "{{user `disk_size`}}", + "guest_additions_path": "VBoxGuestAdditions_{{.Version}}.iso", + "guest_additions_url": "{{ user `guest_additions_url` }}", + "guest_os_type": "Debian_64", + "hard_drive_interface": "sata", + "headless": "{{ user `headless` }}", + "http_directory": "{{user `http_directory`}}", + "iso_checksum": "{{user `iso_checksum`}}", + "iso_url": "{{user `mirror`}}/{{user `mirror_directory`}}/{{user `iso_name`}}", + "memory": "{{ user `memory` }}", + "output_directory": "{{ user `build_directory` }}/packer-{{user `template`}}-virtualbox", + "shutdown_command": "echo 'joininbox' | sudo -S /sbin/shutdown -hP now", + "ssh_password": "joininbox", + "ssh_port": 22, + "ssh_timeout": "10000s", + "ssh_username": "joinmarket", + "type": "virtualbox-iso", + "virtualbox_version_file": ".vbox_version", + "vm_name": "{{ user `template` }}" + }, + { + "boot_command": "{{user `boot_command`}}", + "boot_wait": "5s", + "cpus": "{{ user `cpus` }}", + "disk_size": "{{user `disk_size`}}", + "guest_os_type": "debian8-64", + "headless": "{{ user `headless` }}", + "http_directory": "{{user `http_directory`}}", + "iso_checksum": "{{user `iso_checksum`}}", + "iso_url": "{{user `mirror`}}/{{user `mirror_directory`}}/{{user `iso_name`}}", + "memory": "{{ user `memory` }}", + "output_directory": "{{ user `build_directory` }}/packer-{{user `template`}}-vmware", + "shutdown_command": "echo 'joininbox' | sudo -S /sbin/shutdown -hP now", + "ssh_password": "joininbox", + "ssh_port": 22, + "ssh_timeout": "10000s", + "ssh_username": "joinmarket", + "tools_upload_flavor": "linux", + "type": "vmware-iso", + "vm_name": "{{ user `template` }}", + "vmx_data": { + "cpuid.coresPerSocket": "1", + "ethernet0.pciSlotNumber": "32" + }, + "vmx_remove_ethernet_interfaces": true + }, + { + "boot_command": "{{user `boot_command`}}", + "boot_wait": "5s", + "cpus": "{{ user `cpus` }}", + "disk_size": "{{user `disk_size`}}", + "guest_os_type": "debian", + "http_directory": "{{user `http_directory`}}", + "iso_checksum": "{{user `iso_checksum`}}", + "iso_url": "{{user `mirror`}}/{{user `mirror_directory`}}/{{user `iso_name`}}", + "memory": "{{ user `memory` }}", + "output_directory": "{{ user `build_directory` }}/packer-{{user `template`}}-parallels", + "parallels_tools_flavor": "lin", + "prlctl_version_file": ".prlctl_version", + "shutdown_command": "echo 'joininbox' | sudo -S /sbin/shutdown -hP now", + "ssh_password": "joininbox", + "ssh_port": 22, + "ssh_timeout": "10000s", + "ssh_username": "joinmarket", + "type": "parallels-iso", + "vm_name": "{{ user `template` }}" + } + ], + "provisioners": [ + { + "type": "shell", + "environment_vars": [ + "HOME_DIR=/home/joinmarket", + "http_proxy={{user `http_proxy`}}", + "https_proxy={{user `https_proxy`}}", + "no_proxy={{user `no_proxy`}}", + "github_user={{user `github_user`}}", + "branch={{user `branch`}}" + ], + "execute_command": "echo 'joininbox' | {{.Vars}} sudo -S -E sh -eux '{{.Path}}'", + "expect_disconnect": true, + "scripts": [ + "{{template_dir}}/scripts/update.sh", + "{{template_dir}}/../_common/sshd.sh", + "{{template_dir}}/scripts/networking.sh", + "{{template_dir}}/scripts/sudoers.sh", + "{{template_dir}}/scripts/systemd.sh", + "{{template_dir}}/scripts/joininbox.sh", + "{{template_dir}}/scripts/cleanup.sh" + ] + } + ] +} diff --git a/ci/amd64/debian/scripts/networking.sh b/ci/amd64/debian/scripts/networking.sh index ec32d77..a574c69 100644 --- a/ci/amd64/debian/scripts/networking.sh +++ b/ci/amd64/debian/scripts/networking.sh @@ -7,6 +7,3 @@ update-grub; # Adding a 2 sec delay to the interface up, to make the dhclient happy echo "pre-up sleep 2" >> /etc/network/interfaces - -echo "$(hostname -I | awk '{print $1}') $(hostname)" >>/etc/hosts -echo "127.0.1.1 $(hostname)" >>/etc/hosts diff --git a/ci/amd64/packer.build.amd64-debian.sh b/ci/amd64/packer.build.amd64-debian.sh index 776410d..6f6925a 100644 --- a/ci/amd64/packer.build.amd64-debian.sh +++ b/ci/amd64/packer.build.amd64-debian.sh @@ -1,135 +1,31 @@ #!/bin/bash -e +# Install packer +curl -fsSL https://apt.releases.hashicorp.com/gpg | sudo apt-key add - +sudo apt-add-repository "deb [arch=amd64] https://apt.releases.hashicorp.com $(lsb_release -cs) main" sudo apt-get update +echo -e "\nInstalling packer..." +sudo apt-get install -y packer -# install packer -if ! packer version 2>/dev/null; then - curl -fsSL https://apt.releases.hashicorp.com/gpg | sudo apt-key add - - sudo apt-add-repository -y "deb [arch=amd64] https://apt.releases.hashicorp.com $(lsb_release -cs) main" - sudo apt-get update - echo -e "\nInstalling packer..." - sudo apt-get install -y packer -else - echo "# Packer is installed" -fi +# Install qemu +echo -e "\nInstalling qemu..." +sudo apt-get install -y qemu-system -# install qemu and UEFI firmware -echo "# Install qemu ..." -sudo apt-get update -sudo apt-get install -y qemu-system ovmf - -# set vars from positional arguments (for backward compatibility with CI) if [ $# -gt 0 ]; then - github_user=$1 + github_user=$1 else - github_user=openoms + github_user=openoms fi if [ $# -gt 1 ]; then - branch=$2 + branch=$2 else - branch=master + branch=master fi -# Resolve latest Debian 13 amd64 netinst ISO from SHA256SUMS. -# This avoids 404s and checksum mismatches when Debian point releases rotate. -debian_major=${DEBIAN_MAJOR:-13} -debian_iso_dir="https://cdimage.debian.org/debian-cd/current/amd64/iso-cd" -debian_sums_url="${debian_iso_dir}/SHA256SUMS" -debian_sums_sig_url="${debian_iso_dir}/SHA256SUMS.sign" -debian_cd_key_urls=( - "https://www.debian.org/CD/key-DA87E80D6294BE9B.txt" - "https://www.debian.org/CD/key-988021A964E6EA7D.txt" -) -debian_cd_expected_fprs=( - "DF9B9C49EAA9298432589D76DA87E80D6294BE9B" - "10460DAD76165AD81FBC0CE9988021A964E6EA7D" -) - -if ! command -v gpgv >/dev/null 2>&1; then - echo "# Installing gpgv" - sudo apt-get install -y gpgv -fi - -if ! command -v gpgv >/dev/null 2>&1; then - echo "ERROR: gpgv is required for signature verification" - exit 1 -fi - -tmp_checksums_dir=$(mktemp -d) -trap 'rm -rf "${tmp_checksums_dir}"' EXIT - -echo "# Downloading checksum files" -curl -fsSL "${debian_sums_url}" -o "${tmp_checksums_dir}/SHA256SUMS" -curl -fsSL "${debian_sums_sig_url}" -o "${tmp_checksums_dir}/SHA256SUMS.sign" - -echo "# Verifying SHA256SUMS signature (PGP)" -cd_keyring="${tmp_checksums_dir}/debian-cd-signing-keys.gpg" -tmp_gnupg_home="${tmp_checksums_dir}/gnupg-home" -mkdir -p "${tmp_gnupg_home}" -chmod 700 "${tmp_gnupg_home}" - -for i in "${!debian_cd_key_urls[@]}"; do - key_url="${debian_cd_key_urls[$i]}" - expected_fpr="${debian_cd_expected_fprs[$i]}" - key_file="${tmp_checksums_dir}/cd-key-${i}.asc" - curl -fsSL "${key_url}" -o "${key_file}" - actual_fpr=$(gpg --homedir "${tmp_gnupg_home}" --show-keys --with-colons "${key_file}" 2>/dev/null | awk -F: '/^fpr:/ {print $10; exit}') - if [ -z "${actual_fpr}" ] || [ "${actual_fpr}" != "${expected_fpr}" ]; then - echo "# SHA256SUMS signature: FAIL" - echo "ERROR: Unexpected fingerprint for ${key_url}" - exit 1 - fi - gpg --homedir "${tmp_gnupg_home}" --no-default-keyring --keyring "${cd_keyring}" --import "${key_file}" >/dev/null 2>&1 -done - -if gpgv --keyring "${cd_keyring}" "${tmp_checksums_dir}/SHA256SUMS.sign" "${tmp_checksums_dir}/SHA256SUMS" >/dev/null 2>&1; then - echo "# SHA256SUMS signature: PASS" -else - echo "# SHA256SUMS signature: FAIL" - echo "ERROR: PGP signature verification failed for ${debian_sums_url}" - exit 1 -fi - -echo "# Resolving latest Debian ${debian_major} amd64 netinst ISO from ${debian_sums_url}" -latest_iso_line=$(awk -v major="${debian_major}" '$2 ~ ("^\\*?\\.?/?debian-" major "\\.[0-9]+\\.[0-9]+-amd64-netinst\\.iso$") {print $1 " " $2}' "${tmp_checksums_dir}/SHA256SUMS" | \ - sort -k2 -V | tail -1) - -if [ -z "${latest_iso_line}" ]; then - echo "ERROR: Could not resolve latest Debian ${debian_major} amd64 netinst ISO from ${debian_sums_url}" - exit 1 -fi - -latest_iso_checksum=$(echo "${latest_iso_line}" | awk '{print $1}') -latest_iso_name=$(echo "${latest_iso_line}" | awk '{print $2}' | sed 's#^\*##; s#^\./##; s#^/##') - -if [ -z "${latest_iso_name}" ] || [ -z "${latest_iso_checksum}" ]; then - echo "ERROR: Failed parsing ISO name/checksum from: ${latest_iso_line}" - exit 1 -fi - -resolved_checksum=$(awk -v iso="${latest_iso_name}" '($2 == iso || $2 == "*" iso || $2 == "./" iso || $2 == "/" iso) {print $1; exit}' "${tmp_checksums_dir}/SHA256SUMS") -if [ -z "${resolved_checksum}" ]; then - echo "ERROR: Could not find checksum entry for ${latest_iso_name} in ${debian_sums_url}" - exit 1 -fi - -echo "# Debian ISO selection" -echo "# ISO filename : ${latest_iso_name}" -echo "# SHA256 (selected) : ${latest_iso_checksum}" -echo "# SHA256 (resolved) : ${resolved_checksum}" -if [ "${latest_iso_checksum}" = "${resolved_checksum}" ]; then - echo "# Checksum verify : PASS" -else - echo "# Checksum verify : FAIL" - echo "ERROR: Checksum mismatch for ${latest_iso_name}" - exit 1 -fi - -vars="-var github_user=${github_user} -var branch=${branch} -var iso_name=${latest_iso_name} -var iso_checksum=${latest_iso_checksum}" - # Build the image -echo "# Build the image with: github_user=${github_user} branch=${branch}" +echo -e "\nBuilding image..." cd debian -packer init -upgrade . -PACKER_LOG=1 packer build ${vars} -only=qemu.debian build.amd64-debian.pkr.hcl || exit 1 +PACKER_LOG=1 packer build \ + -var github_user=${github_user} -var branch=${branch} \ + -only=qemu joininbox-amd64-debian.json diff --git a/ci/amd64/test.amd64-image-bats.sh b/ci/amd64/test.amd64-image-bats.sh deleted file mode 100755 index 5313656..0000000 --- a/ci/amd64/test.amd64-image-bats.sh +++ /dev/null @@ -1,138 +0,0 @@ -#!/usr/bin/env bash -set -euo pipefail - -image="${1:-${GITHUB_WORKSPACE:-$(pwd)}/ci/amd64/builds/joininbox-amd64-debian-qemu/joininbox-amd64-debian.qcow2}" -ssh_port="${SSH_PORT:-2222}" -ssh_password="${SSH_PASSWORD:-joininbox}" -qemu_pid_file="${RUNNER_TEMP:-/tmp}/joininbox-qemu.pid" -bats_core_dir="${BATS_CORE_DIR:-${GITHUB_WORKSPACE:-$(pwd)}/.bats-core}" - -if [ ! -f "${image}" ]; then - echo "Missing image: ${image}" >&2 - exit 1 -fi - -if [ ! -x "${bats_core_dir}/bin/bats" ]; then - echo "Missing bats-core checkout: ${bats_core_dir}" >&2 - exit 1 -fi - -sudo apt-get update -sudo apt-get install -y ovmf qemu-system-x86 sshpass - -ssh_opts=( - -o StrictHostKeyChecking=no - -o UserKnownHostsFile=/dev/null - -o ConnectTimeout=5 - -p "${ssh_port}" -) - -ovmf_code="${OVMF_CODE:-${OVMF_BIOS:-}}" -ovmf_vars_template="${OVMF_VARS:-}" -ovmf_vars="${RUNNER_TEMP:-/tmp}/joininbox-ovmf-vars.fd" -qemu_firmware_args=() - -if [ -z "${ovmf_code}" ]; then - for candidate in \ - /usr/share/OVMF/OVMF_CODE_4M.fd \ - /usr/share/OVMF/OVMF_CODE_4M.secboot.fd \ - /usr/share/OVMF/OVMF_CODE_4M.ms.fd \ - /usr/share/OVMF/OVMF_CODE.fd \ - /usr/share/OVMF/OVMF.fd \ - /usr/share/ovmf/OVMF_CODE_4M.fd \ - /usr/share/ovmf/OVMF_CODE_4M.secboot.fd \ - /usr/share/ovmf/OVMF_CODE_4M.ms.fd \ - /usr/share/ovmf/OVMF_CODE.fd \ - /usr/share/ovmf/OVMF.fd \ - OVMF.fd; do - if [ -f "${candidate}" ]; then - ovmf_code="${candidate}" - break - fi - done -fi - -if [ -z "${ovmf_code}" ] || [ ! -f "${ovmf_code}" ]; then - echo "No OVMF firmware found. Set OVMF_CODE or OVMF_BIOS to the firmware path." >&2 - find /usr/share/OVMF /usr/share/ovmf -maxdepth 1 -type f -name '*.fd' -print 2>/dev/null || true - exit 1 -fi - -case "${ovmf_code##*/}" in - *CODE*) - if [ -z "${ovmf_vars_template}" ]; then - for candidate in \ - "${ovmf_code/CODE/VARS}" \ - /usr/share/OVMF/OVMF_VARS_4M.fd \ - /usr/share/OVMF/OVMF_VARS.fd \ - /usr/share/ovmf/OVMF_VARS_4M.fd \ - /usr/share/ovmf/OVMF_VARS.fd; do - if [ -f "${candidate}" ]; then - ovmf_vars_template="${candidate}" - break - fi - done - fi - - if [ -z "${ovmf_vars_template}" ] || [ ! -f "${ovmf_vars_template}" ]; then - echo "No OVMF VARS template found for ${ovmf_code}. Set OVMF_VARS to the template path." >&2 - find /usr/share/OVMF /usr/share/ovmf -maxdepth 1 -type f -name '*.fd' -print 2>/dev/null || true - exit 1 - fi - - cp "${ovmf_vars_template}" "${ovmf_vars}" - qemu_firmware_args=( - -drive "if=pflash,format=raw,readonly=on,file=${ovmf_code}" - -drive "if=pflash,format=raw,file=${ovmf_vars}" - ) - ;; - *) - qemu_firmware_args=(-bios "${ovmf_code}") - ;; -esac - -cleanup() { - if [ -f "${qemu_pid_file}" ]; then - qemu_pid="$(cat "${qemu_pid_file}")" - if kill -0 "${qemu_pid}" 2>/dev/null; then - kill "${qemu_pid}" 2>/dev/null || true - timeout 30s tail --pid="${qemu_pid}" -f /dev/null 2>/dev/null || - kill -9 "${qemu_pid}" 2>/dev/null || - true - fi - fi -} -trap cleanup EXIT - -rm -f "${qemu_pid_file}" - -qemu-system-x86_64 \ - -m 2048 \ - -smp 2 \ - "${qemu_firmware_args[@]}" \ - -drive "file=${image},format=qcow2" \ - -netdev "user,id=net0,hostfwd=tcp:127.0.0.1:${ssh_port}-:22" \ - -device e1000,netdev=net0 \ - -display none \ - -snapshot \ - -pidfile "${qemu_pid_file}" \ - -daemonize - -echo "Waiting for SSH in the booted image" -for attempt in {1..120}; do - if sshpass -p "${ssh_password}" ssh "${ssh_opts[@]}" joinmarket@127.0.0.1 "true" 2>/dev/null; then - break - fi - if [ "${attempt}" -eq 120 ]; then - echo "Timed out waiting for SSH" >&2 - exit 1 - fi - sleep 5 -done - -tar -C "${bats_core_dir}" -cf - . | - sshpass -p "${ssh_password}" ssh "${ssh_opts[@]}" joinmarket@127.0.0.1 \ - "mkdir -p /tmp/bats-core && tar -C /tmp/bats-core -xf -" - -sshpass -p "${ssh_password}" ssh "${ssh_opts[@]}" joinmarket@127.0.0.1 \ - "PATH=/tmp/bats-core/bin:\$PATH /home/joinmarket/joininbox/test/run-bats-local.sh" diff --git a/ci/arm64-rpi/arm64-rpi.pkr.hcl b/ci/arm64-rpi/arm64-rpi.pkr.hcl index 5a1482d..4f7c294 100644 --- a/ci/arm64-rpi/arm64-rpi.pkr.hcl +++ b/ci/arm64-rpi/arm64-rpi.pkr.hcl @@ -3,10 +3,10 @@ variable "branch" {} source "arm" "joininbox-arm64-rpi" { file_checksum_type = "sha256" - file_checksum = "62d025b9bc7ca0e1facfec74ae56ac13978b6745c58177f081d39fbb8041ed45" + file_checksum = "a68cd2bfe7831c438d8a5d832803ae0db17afec9f3cd370d9e8748c7b5456283" file_target_extension = "xz" file_unarchive_cmd = ["xz", "--decompress", "$ARCHIVE_PATH"] - file_urls = ["https://downloads.raspberrypi.com/raspios_lite_arm64/images/raspios_lite_arm64-2025-05-13/2025-05-13-raspios-bookworm-arm64-lite.img.xz"] + file_urls = ["https://raspi.debian.net/tested/20230612_raspi_4_bookworm.img.xz"] image_build_method = "resize" image_chroot_env = ["PATH=/usr/local/bin:/usr/local/sbin:/usr/bin:/usr/sbin:/bin:/sbin"] image_partitions { @@ -39,8 +39,7 @@ build { inline = [ "echo 'nameserver 1.1.1.1' >/etc/resolv.conf", "echo 'nameserver 8.8.8.8' >>/etc/resolv.conf", - "echo $(hostname -I | awk '{print $1}') $(hostname) >>/etc/hosts", - "echo 127.0.1.1 $(hostname) >>/etc/hosts", + "echo $(hostname -I | awk '{print $1}') $(hostname) >>/etc/hosts", "echo 'debconf debconf/frontend select Noninteractive' | debconf-set-selections", "apt-get update", "apt-get install -y sudo wget", diff --git a/prepare_remote_node.md b/prepare_remote_node.md index f5c78bd..8c2fe41 100644 --- a/prepare_remote_node.md +++ b/prepare_remote_node.md @@ -26,7 +26,7 @@ Since the RaspiBlitz v1.6 run this script: To set up manually: * Edit the bitcoin.conf: -`$ sudo nano /mnt/hdd/app-data/bitcoin/bitcoin.conf` +`$ sudo nano /mnt/hdd/bitcoin/bitcoin.conf` * Change the disablewallet option to 0: ``` @@ -40,12 +40,12 @@ In the terminal of the node - allow remote RPC connections to Bitcoin Core This can be skipped if you [connect through Tor](#tor-connection) 1) Edit the bitcoin.conf - `$ sudo nano /mnt/hdd/app-data/bitcoin/bitcoin.conf` + `$ sudo nano /mnt/hdd/bitcoin/bitcoin.conf` Add the values: * `rpcallowip=JOININBOX_IP` or `RANGE` * either specify the LAN IP of the computer (here JoininBox) - * or use a range like: `192.168.1.0/24` - edit to your local subnet - the first 3 numbers of the LAN IP address, the example used here is: 192.168.1.x + * or use a range like: `192.168.1.0/24` - edit to your local subnet - the first 3 numbes of the LAN IP address, the example used here is: 192.168.1.x * `rpcbind=LAN_IP_OF_THE_NODE` * use the local IP of the bitcoin node in the example: `192.168.1.4` * can keep the other `rpcallowip` and `rpcbind` entries especially for the localhost: `127.0.0.1` @@ -109,8 +109,8 @@ Fill in the `Tor_Hidden_Service.onion` to the `rpc_host` in the `joinmarket.cfg` ### CONFIG -> CONNECT in JoininBox * Username: `raspibolt ` -* Password: `passwordB` or `sudo cat /mnt/hdd/bitcoin/app-data/bitcoin.conf | grep rpcpassword | cut -c 13-` -* Host: `LAN_IP_OF_THE_NODE` or `sudo cat /mnt/hdd/app-data/tor/bitcoinrpc/hostname` +* Password: `passwordB` or `sudo cat /mnt/hdd/bitcoin/bitcoin.conf | grep rpcpassword | cut -c 13-` +* Host: `LAN_IP_OF_THE_NODE` or `sudo cat /mnt/hdd/tor/bitcoinrpc/hostname` * Port: `8332` --- diff --git a/scripts/.dialogrc b/scripts/.dialogrc index e60c81a..23b648f 100644 --- a/scripts/.dialogrc +++ b/scripts/.dialogrc @@ -42,7 +42,7 @@ dialog_color = (CYAN,BLACK,OFF) title_color = (CYAN,BLACK,ON) # Dialog box border color -border_color = (CYAN,BLACK,ON) +border_color = (BLACK,BLACK,ON) # Active button color button_active_color = (BLACK,CYAN,ON) diff --git a/scripts/_commands.sh b/scripts/_commands.sh index 116a9a3..fa42c23 100755 --- a/scripts/_commands.sh +++ b/scripts/_commands.sh @@ -64,7 +64,7 @@ function torthistx() { # command: stats # shows the uptime and the fees earned as a Maker function stats() { - /home/joinmarket/info.stats.sh showAllEarned + /home/joinmarket/info.stats.sh } # command: qtgui diff --git a/scripts/_functions.bitcoincore.sh b/scripts/_functions.bitcoincore.sh index 4c1988c..5ab5b5c 100755 --- a/scripts/_functions.bitcoincore.sh +++ b/scripts/_functions.bitcoincore.sh @@ -9,7 +9,7 @@ joininConfPath="/home/joinmarket/joinin.conf" function downloadBitcoinCore() { # set version # https://bitcoincore.org/en/download/ - bitcoinVersion="29.2" + bitcoinVersion="25.0" if bitcoin-cli --version | grep $bitcoinVersion >/dev/null; then echo "# Bitcoin Core $bitcoinVersion is already installed" @@ -39,7 +39,7 @@ function downloadBitcoinCore() { echo else echo - echo "# BUILD FAILED --> the PGP verification failed" + echo "# BUILD FAILED --> the PGP verification failed / signature(${goodSignature}) " exit 1 fi @@ -155,44 +155,25 @@ function installSignet() { Description=Bitcoin daemon on signet [Service] -Environment='MALLOC_ARENA_MAX=1' -PIDFile=/home/joinmarket/bitcoin/bitcoind.pid -ExecStart=/home/joinmarket/bitcoin/bitcoind -signet -daemon \\ - -datadir=/home/joinmarket/.bitcoin \\ - -conf=/home/joinmarket/.bitcoin/bitcoin.conf \\ - -pid=/home/joinmarket/bitcoin/bitcoind.pid -PermissionsStartOnly=true - -# Process management -#################### -Type=forking -Restart=on-failure -TimeoutStartSec=infinity -TimeoutStopSec=600 - -# Directory creation and permissions -#################################### -# Run as joinmarket:joinmarket User=joinmarket Group=joinmarket - +Type=forking +PIDFile=/home/joinmarket/bitcoin/bitcoind.pid +ExecStart=/home/joinmarket/bitcoin/bitcoind -signet -daemon \ + -datadir=/home/joinmarket/.bitcoin \ + -conf=/home/joinmarket/.bitcoin/bitcoin.conf \ + -pid=/home/joinmarket/bitcoin/bitcoind.pid +Restart=always +TimeoutSec=120 +RestartSec=30 StandardOutput=null StandardError=journal # Hardening measures -#################### -# Provide a private /tmp and /var/tmp. PrivateTmp=true -# Mount /usr, /boot/ and /etc read-only for the process. ProtectSystem=full -# Disallow the process and all of its children to gain -# new privileges through execve(). NoNewPrivileges=true -# Use a new /dev namespace only populated with API pseudo devices -# such as /dev/null, /dev/zero and /dev/random. PrivateDevices=true -# Deny the creation of writable and executable memory mappings. -MemoryDenyWriteExecute=true [Install] WantedBy=multi-user.target @@ -247,8 +228,8 @@ setJMconfigToSignet() { sed -i "s/^rpc_password =.*/rpc_password = $RPCPWSIGNET/g" $JMcfgPath echo "# rpc_password = $RPCPWSIGNET" # rpc_wallet_file - sed -i "s/^rpc_wallet_file =.*/rpc_wallet_file = watch-only-descriptor-wallet/g" $JMcfgPath - echo "# using the bitcoind watch-only-descriptor-wallet" + sed -i "s/^rpc_wallet_file =.*/rpc_wallet_file = wallet.dat/g" $JMcfgPath + echo "# using the bitcoind wallet: wallet.dat" # rpc_host sed -i "s/^rpc_host =.*/rpc_host = 127.0.0.1/g" $JMcfgPath echo "# rpc_host = 127.0.0.1" @@ -321,79 +302,20 @@ function getRPC { fi } -# getConnectedBitcoinCoreVersion - read the numeric version over node RPC -function getConnectedBitcoinCoreVersion { - local tor="" - if [ "$(echo "$rpc_host" | grep -c .onion)" -gt 0 ]; then - tor="torsocks" - fi - $tor curl -sS --data-binary \ - '{"jsonrpc": "1.0", "id":"get_bitcoin_core_version", "method": "getnetworkinfo", "params": []}' \ - "http://$rpc_user:$rpc_pass@$rpc_host:$rpc_port/" 2>/dev/null | - jq -r '.result.version // empty' 2>/dev/null -} - -# migrateLegacyRPCWalletConfig - switch the persisted JoinMarket RPC wallet -# from the legacy wallet.dat name to the descriptor wallet used by JoininBox -# when the connected Bitcoin Core version is v30.0 or newer -function migrateLegacyRPCWalletConfig { - if [ "$rpc_wallet" != "wallet.dat" ]; then - return 0 - fi - - local bitcoinCoreVersion - bitcoinCoreVersion=$(getConnectedBitcoinCoreVersion) - if ! [[ "$bitcoinCoreVersion" =~ ^[0-9]+$ ]]; then - echo "# Could not determine the connected Bitcoin Core version; keeping wallet.dat" - return 0 - fi - # Bitcoin Core's numeric version is 290200 for v29.2 and 300000 for v30.0. - if [ "$bitcoinCoreVersion" -lt 300000 ]; then - echo "# Connected Bitcoin Core is v29.x or earlier; keeping wallet.dat" - return 0 - fi - - echo "# Migrating the configured Bitcoin Core wallet from wallet.dat to watch-only-descriptor-wallet" - local migrationConfigOutput - if ! migrationConfigOutput=$(mktemp "${JMcfgPath}.XXXXXX"); then - echo "# Failed to create a temporary descriptor wallet configuration" >&2 - return 1 - fi - if ! sed \ - "s/^rpc_wallet_file =.*/rpc_wallet_file = watch-only-descriptor-wallet/g" \ - "$JMcfgPath" >"$migrationConfigOutput"; then - rm -f "$migrationConfigOutput" - echo "# Failed to prepare the descriptor wallet configuration" >&2 - return 1 - fi - if ! mv "$migrationConfigOutput" "$JMcfgPath"; then - rm -f "$migrationConfigOutput" - echo "# Failed to update the descriptor wallet configuration" >&2 - return 1 - fi - getRPC - if [ "$rpc_wallet" != "watch-only-descriptor-wallet" ]; then - echo "# Failed to select the descriptor wallet configuration" >&2 - return 1 - fi -} - # checkRPCwallet function checkRPCwallet { getRPC - migrateLegacyRPCWalletConfig || return 1 if [ $# -eq 0 ]; then rpc_wallet=$rpc_wallet else rpc_wallet=$1 fi - echo "# Making sure the set $rpc_wallet wallet is present in bitcoind" trap 'rm -f "$connectionOutput"' EXIT connectionOutput=$(mktemp -p /dev/shm/) walletFound=$(customRPC "# Check wallet" "listwallets" 2>$connectionOutput | grep -c "$rpc_wallet") if [ $walletFound -eq 0 ]; then - echo "# Setting a watch-only-descriptor-wallet in Bitcoin Core named $rpc_wallet" + echo "# Setting a watch only wallet in Bitcoin Core named $rpc_wallet" tor="" if [ $(echo $rpc_host | grep -c .onion) -gt 0 ]; then tor="torsocks" @@ -402,8 +324,8 @@ function checkRPCwallet { fi #TODO rewrite customRPC to support multiple params $tor curl -sS --data-binary \ - '{"jsonrpc": "1.0", "id":"# Create the bitcoind wallet", "method": "createwallet", "params": {"wallet_name":"'"$rpc_wallet"'","descriptors":true,"disable_private_keys":true}}' \ - http://$rpc_user:$rpc_pass@$rpc_host:$rpc_port/ | jq . + '{"jsonrpc": "1.0", "id":"# Create the bitcoind wallet", "method": "createwallet", "params": {"wallet_name":"'"$rpc_wallet"'","descriptors":false}}' \ + http://$rpc_user:$rpc_pass@$rpc_host:$rpc_port/wallet/$rpc_wallet | jq . echo walletFound=$(customRPC "# Check wallet" "listwallets" 2>$connectionOutput | grep -c "$rpc_wallet") if [ $walletFound -eq 0 ]; then @@ -415,75 +337,6 @@ function checkRPCwallet { echo fi echo "# The wallet: $rpc_wallet is present and loaded in the connected bitcoind" - - # Check for wallet migration from legacy wallet.dat - checkWalletMigration -} - -# checkWalletMigration - detects legacy wallet.dat and guides user through migration -# This function checks if: -# 1. The old wallet.dat exists in Bitcoin Core -# 2. The new watch-only-descriptor-wallet is being used -# 3. Migration has not been completed yet -# If migration is needed, it prompts the user to rescan after opening their JM wallets -function checkWalletMigration { - # Skip if migration was already completed - if grep -q "walletMigrationDone=true" "${joininConfPath}" 2>/dev/null; then - return 0 - fi - - # Skip if we're not using the new descriptor wallet - if [ "$rpc_wallet" != "watch-only-descriptor-wallet" ]; then - return 0 - fi - - # RPC settings are already available from parent checkRPCwallet function - tor="" - if [ "$(echo "$rpc_host" | grep -c .onion)" -gt 0 ]; then - tor="torsocks" - fi - - # Check if old wallet.dat exists in bitcoind (try to load it to see if it exists) - # First check listwalletdir for wallet.dat - oldWalletExists=$($tor curl -sS --data-binary \ - '{"jsonrpc": "1.0", "id":"check_old_wallet", "method": "listwalletdir", "params": []}' \ - "http://$rpc_user:$rpc_pass@$rpc_host:$rpc_port/" 2>/dev/null | jq -r '.result.wallets[].name' 2>/dev/null | grep -c "^wallet.dat$") - - if [ "$oldWalletExists" -gt 0 ]; then - echo - echo "########################################################################" - echo "# WALLET MIGRATION NOTICE" - echo "########################################################################" - echo - echo "# A legacy wallet.dat was detected in Bitcoin Core." - echo "# JoininBox now uses descriptor wallets (watch-only-descriptor-wallet)" - echo "# for better compatibility with modern Bitcoin Core versions." - echo - echo "# To complete the migration and see your transaction history:" - echo - echo "# 1. Open each of your JoinMarket wallets once using:" - echo "# WALLET -> DISPLAY" - echo "# This imports the addresses into the new descriptor wallet." - echo - echo "# 2. After opening all wallets, run a blockchain rescan:" - echo "# WALLET -> RESCAN" - echo "# Use blockheight 481824 (first SegWit block) or later if you know when your wallet had its first deposit." - echo - echo "# The rescan may take several hours depending on wallet age." - echo "# You can monitor progress in the Bitcoin Core debug.log" - echo - echo "########################################################################" - echo - echo "# Press ENTER to continue..." - read -r - - # Mark migration notice as shown (user can still run rescan manually) - if ! grep -q "walletMigrationDone=" "${joininConfPath}" 2>/dev/null; then - echo "walletMigrationDone=true" >>"${joininConfPath}" - else - sed -i "s/^walletMigrationDone=.*/walletMigrationDone=true/g" "${joininConfPath}" - fi - fi } # customRPC - sends a custom RPC command @@ -545,16 +398,10 @@ function connectLocalNode() { elif [ "${network}" = testnet ]; then rpc_port="18332" fi - rpc_wallet="watch-only-descriptor-wallet" + rpc_wallet="wallet.dat" if [ $runningEnv = raspiblitz ]; then - if [ -f "/mnt/hdd/raspiblitz.conf" ]; then - rpc_user=$(sudo cat /mnt/hdd/bitcoin/bitcoin.conf | grep rpcuser | cut -c 9-) - rpc_pass=$(sudo cat /mnt/hdd/bitcoin/bitcoin.conf | grep rpcpassword | cut -c 13-) - else - rpc_user=$(sudo cat /mnt/hdd/app-data/bitcoin/bitcoin.conf | grep rpcuser | cut -c 9-) - rpc_pass=$(sudo cat /mnt/hdd/app-data/bitcoin/bitcoin.conf | grep rpcpassword | cut -c 13-) - fi - + rpc_user=$(sudo cat /mnt/hdd/bitcoin/bitcoin.conf | grep rpcuser | cut -c 9-) + rpc_pass=$(sudo cat /mnt/hdd/bitcoin/bitcoin.conf | grep rpcpassword | cut -c 13-) elif [ $runningEnv = mynode ]; then rpc_user=mynode rpc_pass=$(sudo cat /mnt/hdd/mynode/settings/.btcrpcpw) diff --git a/scripts/_functions.menu.sh b/scripts/_functions.menu.sh index aa6d247..a4b1519 100644 --- a/scripts/_functions.menu.sh +++ b/scripts/_functions.menu.sh @@ -37,7 +37,7 @@ function menu_MAKER() { sleep 3 dialog \ --title "Monitoring the Yield Generator - press CTRL+C to exit" \ - --prgbox "sudo journalctl -fn100 -u yg-privacyenhanced" -1 -1 + --prgbox "sudo journalctl -fn20 -u yg-privacyenhanced" 30 200 echo "# returning to the menu..." sleep 1 /home/joinmarket/menu.yg.sh diff --git a/scripts/_functions.sh b/scripts/_functions.sh index 318634c..c7541b6 100755 --- a/scripts/_functions.sh +++ b/scripts/_functions.sh @@ -7,21 +7,12 @@ currentJBcommit=$(cd /home/joinmarket/joininbox; git describe --tags) currentJBtag=$(cd /home/joinmarket/joininbox; git tag | sort -V | tail -1) currentJMversion=$(cd /home/joinmarket/joinmarket-clientserver 2>/dev/null; \ git describe --tags 2>/dev/null) -currentBTCversion=$(bitcoind --version | grep version) # paths walletPath="/home/joinmarket/.joinmarket/wallets/" JMcfgPath="/home/joinmarket/.joinmarket/joinmarket.cfg" joininConfPath="/home/joinmarket/joinin.conf" -## dialog fixes -# fallback for unknown terminal types (e.g., xterm-ghostty) -if ! infocmp "$TERM" &>/dev/null; then - export TERM=xterm-256color -fi -# fix dialog box drawing characters -export NCURSES_NO_UTF8_ACS=1 - # functions source /home/joinmarket/_functions.menu.sh source /home/joinmarket/_functions.bitcoincore.sh @@ -31,6 +22,7 @@ fi function activateJMvenv() { . /home/joinmarket/joinmarket-clientserver/jmvenv/bin/activate || exit 1 + /home/joinmarket/joinmarket-clientserver/jmvenv/bin/python -c "import PySide2" } function openMenuIfCancelled() { @@ -170,16 +162,16 @@ function stopYG() { function YGnickname() { # Retrieves nickname from the latest NickServ message in the newest logfile - newest_log=$(ls -td /home/joinmarket/.joinmarket/logs/*J5* 2>/dev/null | head -n 1) - if [ -n "$newest_log" ] && [ -f "$newest_log" ]; then - name=$(grep NickServ "$newest_log" 2>/dev/null | tail -1 | awk '{print $9}') - if [ ${#name} -eq 0 ]; then + if ls -td /home/joinmarket/.joinmarket/logs/* 1>&2>/dev/null ; then + newest_log=$(ls -td /home/joinmarket/.joinmarket/logs/* | grep J5 | head -n 1) + name=$(grep NickServ $newest_log | tail -1 | awk '{print $9}') + if [ ${#name} -eq 0 ];then name="no_Nick_see_LOGS" fi else name="waiting__to__run" fi - echo "$name" + echo $name } # copyJoininboxScripts @@ -257,33 +249,28 @@ function generateJMconfig() { setJMconfigToSignet - elif [ $runningEnv = "raspiblitz" ]; then + elif [ -f "/mnt/hdd/bitcoin/bitcoin.conf" ]; then echo echo "## editing the joinmarket.cfg with the local bitcoin RPC settings." - if [ -f "/mnt/hdd/bitcoin/bitcoin.conf" ]; then - RPCUSER=$(sudo cat /mnt/hdd/bitcoin/bitcoin.conf | grep rpcuser | cut -c 9-) - sed -i "s/^rpc_user =.*/rpc_user = $RPCUSER/g" $JMcfgPath - echo "# rpc_user = $RPCUSER" - PASSWORD_B=$(sudo cat /mnt/hdd/bitcoin/bitcoin.conf | grep rpcpassword | cut -c 13-) - sed -i "s/^rpc_password =.*/rpc_password = $PASSWORD_B/g" $JMcfgPath - echo "# rpc_password = $PASSWORD_B" - RPCPORT=$(sudo cat /mnt/hdd/bitcoin/bitcoin.conf | grep main.rpcport | cut -c 14-) - else - RPCUSER=$(sudo cat /mnt/hdd/app-data/bitcoin/bitcoin.conf | grep rpcuser | cut -c 9-) - sed -i "s/^rpc_user =.*/rpc_user = $RPCUSER/g" $JMcfgPath - echo "# rpc_user = $RPCUSER" - PASSWORD_B=$(sudo cat /mnt/hdd/app-data/bitcoin/bitcoin.conf | grep rpcpassword | cut -c 13-) - sed -i "s/^rpc_password =.*/rpc_password = $PASSWORD_B/g" $JMcfgPath - echo "# rpc_password = $PASSWORD_B" - RPCPORT=$(sudo cat /mnt/hdd/app-data/bitcoin/bitcoin.conf | grep main.rpcport | cut -c 14-) - fi - if [ ${#RPCPORT} -eq 0 ]; then + + RPCUSER=$(sudo cat /mnt/hdd/bitcoin/bitcoin.conf | grep rpcuser | cut -c 9-) + sed -i "s/^rpc_user =.*/rpc_user = $RPCUSER/g" $JMcfgPath + echo "# rpc_user = $RPCUSER" + + PASSWORD_B=$(sudo cat /mnt/hdd/bitcoin/bitcoin.conf | grep rpcpassword | cut -c 13-) + sed -i "s/^rpc_password =.*/rpc_password = $PASSWORD_B/g" $JMcfgPath + echo "# rpc_password = $PASSWORD_B" + + RPCPORT=$(sudo cat /mnt/hdd/bitcoin/bitcoin.conf | grep main.rpcport | cut -c 14-) + if [ ${#RPCPORT} -eq 0 ];then RPCPORT=8332 fi sed -i "s/^rpc_port =.*/rpc_port = $RPCPORT/g" $JMcfgPath echo "# rpc_port = $RPCPORT" - sed -i "s/^rpc_wallet_file =.*/rpc_wallet_file = watch-only-descriptor-wallet/g" $JMcfgPath - echo "# using the bitcoind watch-only-descriptor-wallet" + + sed -i "s/^rpc_wallet_file =.*/rpc_wallet_file = wallet.dat/g" $JMcfgPath + echo "# using the bitcoind wallet: wallet.dat" + # set joinin.conf value /home/joinmarket/set.value.sh set network mainnet ${joininConfPath} fi diff --git a/scripts/info.importwallet.sh b/scripts/info.importwallet.sh index d870ac1..de803ca 100755 --- a/scripts/info.importwallet.sh +++ b/scripts/info.importwallet.sh @@ -36,7 +36,7 @@ Instructions to COPY wallets from another computer You can use the wallets from another JoinMarket instance " if [ "${CHOICE}" = "LAN" ]; then - if [ -f "/mnt/hdd/raspiblitz.conf" ] || [ -f "/mnt/hdd/app-data/raspiblitz.conf" ] ; then + if [ -f "/mnt/hdd/raspiblitz.conf" ] ; then echo "Both computers (the RaspiBlitz and the source computer with the wallet(s))" else echo "Both computers (the JoininBox and the source computer with the wallet(s))" @@ -62,9 +62,9 @@ elif [ "${CHOICE}" = "TOR" ]; then echo "torsocks scp ./*.jmdat joinmarket@${TOR_ADDRESS}:~/.joinmarket/wallets/" fi echo "" -if [ -f "/mnt/hdd/raspiblitz.conf" ] || [ -f "/mnt/hdd/app-data/raspiblitz.conf" ] ; then +if [ -f "/mnt/hdd/raspiblitz.conf" ] ; then echo "Use the PASSWORD_B to authorize the file transfer -(same as the rpcpassword in the bitcoin.conf)." +(same as the rpcpassword in the /mnt/hdd/bitcoin/bitcoin.conf)." else echo "This command will ask for the SSH PASSWORD of the JoininBox." fi diff --git a/scripts/install.bitcoincore.sh b/scripts/install.bitcoincore.sh index 170f058..b29da0c 100755 --- a/scripts/install.bitcoincore.sh +++ b/scripts/install.bitcoincore.sh @@ -5,13 +5,13 @@ source /home/joinmarket/_functions.sh # check connectedRemoteNode var in joinin.conf if ! grep -Eq "^connectedRemoteNode=" $joininConfPath; then - echo "connectedRemoteNode=off" >>$joininConfPath + echo "connectedRemoteNode=off" >> $joininConfPath fi if [ "$1" = "signetOn" ]; then installBitcoinCore installSignet - if [ "$connectedRemoteNode" = "on" ]; then + if [ "$connectedRemoteNode" = "on" ];then backupJMconf fi generateJMconfig @@ -24,16 +24,16 @@ if [ "$1" = "signetOn" ]; then bitcoinUser="joinmarket" cliPath="/home/joinmarket/bitcoin/" fi - if [ ! -d /home/${bitcoinUser}/.bitcoin/signet/wallets/watch-only-descriptor-wallet ]; then - echo "# Create watch-only-descriptor-wallet for signet ..." + if [ ! -f /home/${bitcoinUser}/.bitcoin/signet/wallets/wallet.dat/wallet.dat ];then + echo "# Create wallet.dat for signet ..." sleep 10 - sudo -u ${bitcoinUser} ${cliPath}/bitcoin-cli -signet -named createwallet wallet_name=watch-only-descriptor-wallet descriptors=true disable_private_keys=true + sudo -u ${bitcoinUser} ${cliPath}/bitcoin-cli -signet -named createwallet wallet_name=wallet.dat descriptors=false fi elif [ "$1" = "signetOff" ]; then removeSignetdService - isSignet=$(grep -c "network = signet" <$JMcfgPath) - if [ $isSignet -gt 0 ]; then + isSignet=$(grep -c "network = signet" < $JMcfgPath) + if [ $isSignet -gt 0 ];then echo "# Removing the joinmarket.cfg with signet settings" rm -f $JMcfgPath else diff --git a/scripts/install.joinmarket.sh b/scripts/install.joinmarket.sh index 6cb3e81..5de3248 100755 --- a/scripts/install.joinmarket.sh +++ b/scripts/install.joinmarket.sh @@ -1,21 +1,14 @@ #!/bin/bash -# https://github.com/JoinMarket-Org/joinmarket-clientserver/releases -# Use tag for verification when available, otherwise use commit hash -testedJMversion="v0.9.12" +testedJMversion="v0.9.10" -# https://github.com/JoinMarket-Org/joinmarket-clientserver/commits/master/ -# Only used if testedJMversion is empty or not set -#testedJMcommit="ce32bafbb5d716bde61830f71266410249d43dbc" +PGPsigner="kristapsk" +PGPpkeys="https://github.com/kristapsk.gpg" +PGPcheck="33E472FE870C7E5D" -PGPsigner="AdamISZ" -PGPpkeys="https://github.com/AdamISZ.gpg" -# AdamISZ current primary code-signing key used for v0.9.12 -PGPcheck="0F1C7345D9193D1C8E3F21810C44134F93234873" - -#PGPsigner="kristapsk" -#PGPpkeys="https://github.com/kristapsk.gpg" -#PGPcheck="33E472FE870C7E5D" +#PGPsigner="waxwing" +#PGPpkeys="https://raw.githubusercontent.com/JoinMarket-Org/joinmarket-clientserver/master/pubkeys/AdamGibson.asc" +#PGPcheck="2B6FC204D9BF332D062B461A141001A1AF77F20B" me="${0##/*}" @@ -27,13 +20,13 @@ usage() { printf %s"${me} [--option ] a script to install, update or configure JoinMarket -the latest tested version: ${testedJMversion:-$testedJMcommit} is installed by default with the QT GUI +the latest tested version: $testedJMversion is installed by default with the QT GUI Options: -h, --help this help info -i, --install [install|config|update|testPR|commit] install options, use 'commit' for the latest master -v, --version [version|number-of-PR] the version to install or PR to test (default: ${testedJMversion}) --q, --qtgui [0|1] install the QT GUI and dependencies (default: 0) +-q, --qtgui [0|1] install the QT GUI and dependencies (default: 1) -u, --user [user] the linux user to install with (default: joinmarket) Notes: @@ -116,13 +109,10 @@ done : "${install:=install}" range_argument install "install" "config" "update" "testPR" "commit" -# Use tag if set, otherwise use commit hash -: "${version:=${testedJMversion:-$testedJMcommit}}" -# Only check GitHub releases if version looks like a tag (starts with 'v') -if [[ "${version}" == v* ]]; then - curl -s "https://github.com/JoinMarket-Org/joinmarket-clientserver/releases/tag/${version}" | grep -q "\"message\": \"Version not found\"" && error_msg "'There is no: https://github.com/JoinMarket-Org/joinmarket-clientserver/releases/tag/${version}'" -fi -: "${qtgui:=false}" +: "${version:=${testedJMversion}}" +curl -s "https://github.com/JoinMarket-Org/joinmarket-clientserver/release/tag/${version}" | grep -q "\"message\": \"Version not found\"" && error_msg "'There is no: https://github.com/JoinMarket-Org/joinmarket-clientserver/release/tag/${version}'" + +: "${qtgui:=true}" range_argument qtgui "0" "1" "false" "true" : "${user:=joinmarket}" @@ -133,9 +123,7 @@ source /home/joinmarket/joinin.conf # create user if not default if [ "${user}" != "joinmarket" ]; then echo "# add the '${user}' user" - sudo adduser --system --group --shell /bin/bash --home /home/${user} ${user} - echo "Copy the skeleton files for login" - sudo -u ${user} cp -r /etc/skel/. /home/${user}/ + sudo adduser --disabled-password --gecos "" ${user} sudo adduser ${user} sudo # add user to Tor group sudo usermod -a -G debian-tor ${user} @@ -150,6 +138,7 @@ if [ "${user}" != "joinmarket" ]; then echo " if [ -f \"/home/${user}/joinmarket-clientserver/jmvenv/bin/activate\" ]; then . /home/${user}/joinmarket-clientserver/jmvenv/bin/activate + /home/${user}/joinmarket-clientserver/jmvenv/bin/python -c \"import PySide2\" cd /home/${user}/joinmarket-clientserver/scripts/ fi " | sudo -u ${user} tee -a /home/${user}/.bashrc @@ -161,14 +150,22 @@ checkEntry=$(sudo -u ${user} cat /home/${user}/joinin.conf | grep -c "qtgui") if [ ${checkEntry} -eq 0 ]; then echo "qtgui=true" | sudo -u ${user} tee -a /home/${user}/joinin.conf fi -sudo -u ${user} sed -i "s/^qtgui=.*/qtgui=${qtgui}/g" /home/${user}/joinin.conf +if [ "${qtgui}" = "false" ]; then + sudo -u ${user} sed -i "s/^qtgui=.*/qtgui=false/g" /home/${user}/joinin.conf +fi # installJoinMarket [update|testPR |commit] function installJoinMarket() { + cpu=$(uname -m) cd /home/${user} || exit 1 + if [ "${qtgui}" = "true" ]; then + # PySide2 for armf: https://packages.debian.org/buster/python3-pyside2.qtcore + echo "# Installing ARM specific dependencies to run the QT GUI" + sudo apt-get install -y python3-pyside2.qtcore python3-pyside2.qtgui \ + python3-pyside2.qtwidgets zlib1g-dev libjpeg-dev python3-pyqt5 libltdl-dev + fi # https://github.com/JoinMarket-Org/joinmarket-clientserver/issues/668#issuecomment-717815719 sudo apt-get install -y build-essential automake pkg-config libffi-dev python3-dev - sudo -u ${user} pip config set global.break-system-packages true sudo -u ${user} pip install libtool asn1crypto cffi pycparser echo "# Installing JoinMarket" @@ -192,29 +189,37 @@ function installJoinMarket() { elif [ "$install" = "update" ] && [ ${#2} -gt 0 ]; then updateVersion="$2" sudo -u ${user} git reset --hard $updateVersion - echo "# Verifying signature for version: $updateVersion" - # Determine if it's a tag (starts with 'v') or commit hash - if [[ "$updateVersion" == v* ]]; then - sudo -u ${user} bash /home/joinmarket/joininbox/scripts/verify.git.sh \ - "${PGPsigner}" "${PGPpkeys}" "${PGPcheck}" "$updateVersion" || exit 1 - else - sudo -u ${user} bash /home/joinmarket/joininbox/scripts/verify.git.sh \ - "${PGPsigner}" "${PGPpkeys}" "${PGPcheck}" || exit 1 - fi else - # Decide whether to use tag or commit - if [ -n "${testedJMversion}" ]; then - echo "# Installing tested version: ${testedJMversion}" - sudo -u ${user} git reset --hard $testedJMversion - echo "# Verifying tag signature: ${testedJMversion}" - sudo -u ${user} bash /home/joinmarket/joininbox/scripts/verify.git.sh \ - "${PGPsigner}" "${PGPpkeys}" "${PGPcheck}" "${testedJMversion}" || exit 1 + sudo -u ${user} git reset --hard $testedJMversion + + sudo -u ${user} wget --prefer-family=ipv4 -O "pgp_keys.asc" ${PGPpkeys} + sudo -u ${user} gpg --import --import-options show-only ./pgp_keys.asc + fingerprint=$(sudo -u ${user} gpg "pgp_keys.asc" 2>/dev/null | grep "${PGPcheck}" -c) + if [ ${fingerprint} -lt 1 ]; then + echo + echo "# WARNING --> the PGP fingerprint is not as expected for ${PGPsigner}" + echo "# Should contain PGP: ${PGPcheck}" + echo "# PRESS ENTER to TAKE THE RISK if you think all is OK" + read key + fi + sudo -u ${user} gpg --import ./pgp_keys.asc + + verifyResult=$(sudo -u ${user} git verify-tag $testedJMversion 2>&1) + + goodSignature=$(echo ${verifyResult} | grep 'Good signature' -c) + echo "# goodSignature(${goodSignature})" + correctKey=$(echo ${verifyResult} | tr -d " \t\n\r" | grep "${PGPcheck}" -c) + echo "# correctKey(${correctKey})" + if [ ${correctKey} -lt 1 ] || [ ${goodSignature} -lt 1 ]; then + echo + echo "# BUILD FAILED --> PGP verification not OK / signature(${goodSignature}) verify(${correctKey})" + exit 1 else - echo "# Installing tested commit: ${testedJMcommit}" - sudo -u ${user} git reset --hard $testedJMcommit - echo "# Verifying commit signature: ${testedJMcommit}" - sudo -u ${user} bash /home/joinmarket/joininbox/scripts/verify.git.sh \ - "${PGPsigner}" "${PGPpkeys}" "${PGPcheck}" || exit 1 + echo + echo "#########################################################" + echo "# OK --> the PGP signature of the $testedJMversion tag is correct" + echo "#########################################################" + echo fi fi @@ -225,6 +230,30 @@ function installJoinMarket() { fi # do not clear screen during installation sudo -u ${user} sed -i 's/clear//g' install.sh + # do not stop at installing Debian dependencies + sudo -u ${user} sed -i \ + "s#^ if ! sudo apt-get install \${deb_deps\[@\]}; then#\ + if ! sudo apt-get install -y \${deb_deps\[@\]}; then#g" install.sh + + if [ ${cpu} != "x86_64" ]; then + echo "# Make install.sh set up jmvenv with -- system-site-packages on arm" + # and import the PySide2 armf package from the system + sudo -u ${user} sed -i "s#^ virtualenv -p \"\${python}\" \"\${jm_source}/jmvenv\" || return 1#\ + virtualenv --system-site-packages -p \"\${python}\" \"\${jm_source}/jmvenv\" || return 1 ;\ + /home/${user}/joinmarket-clientserver/jmvenv/bin/python -c \'import PySide2\'\ + #g" install.sh + # don't install PySide2 - using the system-site-package instead + sudo -u ${user} sed -i "s#^PySide2.*##g" requirements/gui.txt + # don't install PyQt5 - using the system package instead + sudo -u ${user} sed -i "s#^PyQt5.*##g" requirements/gui.txt + sudo -u ${user} sed -i "s#PyQt5!=5.15.0,!=5.15.1,!=5.15.2,!=6.0##g" jmqtui/setup.py + fi + + # pin werkzeug dependency to 2.2.0 as in: + # https://github.com/JoinMarket-Org/joinmarket-clientserver/pull/1485/files + if ! grep 'werkzeug==' jmclient/setup.py; then + sed -i "s/autobahn==20.12.3/&', 'werkzeug==2.2.0/g" jmclient/setup.py + fi if [ "${qtgui}" = "false" ]; then GUIchoice="--without-qt" diff --git a/scripts/jam-remote/README.md b/scripts/jam-remote/README.md index 9a73427..ed49029 100644 --- a/scripts/jam-remote/README.md +++ b/scripts/jam-remote/README.md @@ -1,38 +1,33 @@ # Install Jam and connect to a remote Joininbox -* tested on Debian Bullseye and Bookworm desktop - Ubuntu should also work +* tested on Debian Bullseye desktop - Ubuntu should also work -## Steps in your Joininbox terminal +### Download the repo +``` +git clone https://github.com/openoms/joininbox +cd joininbox +``` + +### Install Jam locally +* will be under the user: `jam` +``` +cd scripts/jam-remote +bash install.jam.sh on +``` + +### On your Joininbox * (optional) update the joininbox scripts: `UPDATE` - `ADVANCED` - `JBCOMMIT` * start the `API` from `TOOLS` * (optional) start the ob-watcher from `OFFERS` -## Steps on your desktop -### Download the repo -* move to a directory where the joininbox repo will be stored - ``` - git clone https://github.com/openoms/joininbox - cd joininbox - ``` - -### Install Jam locally -* will be under the user: `jam` - ``` - cd scripts/jam-remote - bash install.jam.sh on - ``` - ### Forward the API and ob-watcher ports with ssh from your Joininbox -* run the ssh-port-forward script in the `joininbox/scripts/jam-remote` folder - ``` - bash ./ssh-port-forward.sh $JOININBOX_LAN_IP - ``` +``` +bash ssh-portforward $JOININBOX_LAN_IP +``` * leave this terminal open until working with Jam * close when done to close the ssh connection +* Earn will continue to run on the Joininbox +* can check it's logs in the menu - `MAKER` - `LOGS` ### Open Jam locally using the wallets on your remote Joininbox -* open Jam at https://localhost:7501 -* accept the self-signed certificate served from your Joininbox -* Use Jam - docs: https://jamdocs.org/ -* Earn will continue to run on the Joininbox even after the terminal and Jam windows are closed -* can check the logs in the Joininbox menu - `MAKER` - `LOGS` +`https://localhost:7501` diff --git a/scripts/jam-remote/install.jam.sh b/scripts/jam-remote/install.jam.sh index 9d5af12..10c67e2 100644 --- a/scripts/jam-remote/install.jam.sh +++ b/scripts/jam-remote/install.jam.sh @@ -3,15 +3,15 @@ # https://github.com/joinmarket-webui/jam USERNAME=jam -WEBUI_VERSION="v0.4.0" +WEBUI_VERSION=0.1.5 REPO=joinmarket-webui/jam HOME_DIR=/home/${USERNAME} APP_DIR=webui SOURCEDIR=$(pwd) -PGPsigner="theborakompanioni" +PGPsigner="dergigi" PGPpubkeyLink="https://github.com/${PGPsigner}.gpg" -PGPpubkeyFingerprint="E8070AF0053AAC0D" +PGPpubkeyFingerprint="89C4A25E69A5DE7F" # command info if [ $# -eq 0 ] || [ "$1" = "-h" ] || [ "$1" = "-help" ]; then @@ -46,7 +46,7 @@ if [ "$1" = "on" ]; then echo "# Creating the ${USERNAME} user" echo - sudo adduser --system --group --home /home/${USERNAME} ${USERNAME} + sudo adduser --disabled-password --gecos "" ${USERNAME} # install nodeJS bash ${SOURCEDIR}/bonus.nodejs.sh on @@ -57,10 +57,10 @@ if [ "$1" = "on" ]; then sudo -u $USERNAME git clone https://github.com/$REPO cd jam || exit 1 - sudo -u $USERNAME git reset --hard ${WEBUI_VERSION} + sudo -u $USERNAME git reset --hard v${WEBUI_VERSION} sudo -u $USERNAME bash ${SOURCEDIR}/../verify.git.sh \ - "${PGPsigner}" "${PGPpubkeyLink}" "${PGPpubkeyFingerprint}" "${WEBUI_VERSION}" || exit 1 + "${PGPsigner}" "${PGPpubkeyLink}" "${PGPpubkeyFingerprint}" "v${WEBUI_VERSION}" || exit 1 cd $HOME_DIR || exit 1 sudo -u $USERNAME mv jam $APP_DIR @@ -134,15 +134,10 @@ if [ "$1" = "update" ]; then echo "FAIL - npm install did not run correctly, aborting" exit 1 fi + + sudo -u $USERNAME npm run build echo "*** JAM UPDATED to $version ***" fi - - if ! sudo -u $USERNAME npm install; then - echo "FAIL - npm install did not run correctly, aborting" - exit 1 - fi - sudo -u $USERNAME npm run build - else echo "*** JAM NOT INSTALLED ***" fi diff --git a/scripts/jam-remote/install.selfsignedcert.sh b/scripts/jam-remote/install.selfsignedcert.sh index ffc6b53..ebf40e5 100644 --- a/scripts/jam-remote/install.selfsignedcert.sh +++ b/scripts/jam-remote/install.selfsignedcert.sh @@ -3,10 +3,10 @@ USERNAME=jam -sudo apt-get install -y nginx +sudo apt install nginx if ! sudo ls /home/jam/nginx/tls.cert || ! sudo ls /home/jam/nginx/tls.key; then - sudo apt-get install -y openssl + sudo apt-get install openssl subj="/C=US/ST=Utah/L=Lehi/O=Your Company, Inc./OU=IT/CN=example.com" sudo -u $USERNAME mkdir -p /home/jam/nginx/ \ diff --git a/scripts/menu.config.sh b/scripts/menu.config.sh index 9387221..093daea 100755 --- a/scripts/menu.config.sh +++ b/scripts/menu.config.sh @@ -10,11 +10,7 @@ if [ ${#network} -eq 0 ] || [ "${network}" = "unknown" ] ;then elif [ "${runningEnv}" = mynode ];then network=mainnet elif [ "${runningEnv}" = raspiblitz ];then - if [ -f "/mnt/hdd/raspiblitz.conf" ]; then - source /mnt/hdd/raspiblitz.conf - else - source /mnt/hdd/app-data/raspiblitz.conf - fi + source /mnt/hdd/raspiblitz.conf if [ $network = bitcoin ];then network=${chain}net else diff --git a/scripts/menu.jam.sh b/scripts/menu.jam.sh index 7585874..4034e34 100644 --- a/scripts/menu.jam.sh +++ b/scripts/menu.jam.sh @@ -1,11 +1,7 @@ #!/bin/bash source /home/joinmarket/joinin.conf -if [ -f "/mnt/hdd/raspiblitz.conf" ]; then - source /mnt/hdd/raspiblitz.conf -else - source /mnt/hdd/app-data/raspiblitz.conf -fi +source /mnt/hdd/raspiblitz.conf # BASIC MENU INFO HEIGHT=8 diff --git a/scripts/menu.orderbook.sh b/scripts/menu.orderbook.sh index 952fa32..6c09bfd 100755 --- a/scripts/menu.orderbook.sh +++ b/scripts/menu.orderbook.sh @@ -90,7 +90,7 @@ function startOrderBook() { sleep 3 dialog \ --title "Monitoring the ob-watcher - press CTRL+C to exit" \ - --prgbox "sudo journalctl -fn100 -u ob-watcher" -1 -1 + --prgbox "sudo journalctl -fn20 -u ob-watcher" 30 200 } if [ "$1" = startOrderBookService ]; then diff --git a/scripts/menu.tools.sh b/scripts/menu.tools.sh index b849fa4..c159df8 100755 --- a/scripts/menu.tools.sh +++ b/scripts/menu.tools.sh @@ -26,6 +26,17 @@ function listCJcandidateTXNs { done } +function installBoltzmann { + if [ ! -f "/home/joinmarket/boltzmann/bvenv/bin/activate" ]; then + cd /home/joinmarket/ || exit 1 + git clone https://code.samourai.io/oxt/boltzmann.git + cd boltzmann || exit 1 + python3 -m venv bvenv + source bvenv/bin/activate || exit 1 + python setup.py install + fi +} + function dialog_inputbox { local title=$1 local text=$2 @@ -55,7 +66,7 @@ isLocalBitcoinCLI=$(sudo -u bitcoin bitcoin-cli -version | grep -c "Bitcoin Core isTxindex=$(sudo -u bitcoin cat /home/bitcoin/.bitcoin/bitcoin.conf | grep -c "txindex=1") # BASIC MENU INFO -HEIGHT=12 +HEIGHT=13 WIDTH=61 CHOICE_HEIGHT=7 TITLE="Tools" @@ -86,6 +97,8 @@ if [ "$isLocalBitcoinCLI" -gt 0 ] && [ "$isTxindex" -gt 0 ]; then CHOICE_HEIGHT=$((CHOICE_HEIGHT + 1)) fi fi +OPTIONS+=( + BOLTZMANN "Analyze the entropy of a transaction") if [ "${runningEnv}" != mynode ]; then OPTIONS+=( PASSWORD "Change the ssh password") @@ -173,6 +186,15 @@ CHECKTXN) echo "Press ENTER to return to the menu..." read key ;; +BOLTZMANN) + dialog_inputbox "Boltzmann transaction entropy analysis" "\nUsing: https://code.samourai.io/oxt/boltzmann\n\nPaste a TXID to analyze" 11 71 + clear + installBoltzmann + python /home/joinmarket/start.boltzmann.py --txid=$dialog_output + echo + echo "Press ENTER to return to the menu..." + read key + ;; CJFINDER) BLOCKHEIGHT=$(customRPC "" "getblockchaininfo" "" | grep blocks | awk '{print $2}' | cut -d, -f1) diff --git a/scripts/menu.update.advanced.sh b/scripts/menu.update.advanced.sh index 7b051db..b429c7e 100755 --- a/scripts/menu.update.advanced.sh +++ b/scripts/menu.update.advanced.sh @@ -3,16 +3,13 @@ source /home/joinmarket/_functions.sh # BASIC MENU INFO -HEIGHT=18 +HEIGHT=16 WIDTH=60 CHOICE_HEIGHT=7 TITLE="Advanced update options" MENU=" -Installed versions: -JoininBox $currentJBcommit -JoinMarket $currentJMversion -$currentBTCversion" - +Current JoininBox version: $currentJBcommit +Current JoinMarket version: $currentJMversion" OPTIONS=() BACKTITLE="JoininBox GUI" diff --git a/scripts/menu.update.sh b/scripts/menu.update.sh index c1321bf..071f0ce 100755 --- a/scripts/menu.update.sh +++ b/scripts/menu.update.sh @@ -3,34 +3,20 @@ source /home/joinmarket/_functions.sh # BASIC MENU INFO -HEIGHT=15 -WIDTH=57 -CHOICE_HEIGHT=4 +HEIGHT=12 +WIDTH=56 +CHOICE_HEIGHT=3 TITLE="Update options" MENU=" -Installed versions: -JoininBox $currentJBcommit -JoinMarket $currentJMversion -$currentBTCversion" +Current JoininBox version: $currentJBcommit +Current JoinMarket version: $currentJMversion" OPTIONS=() BACKTITLE="JoininBox GUI" # Basic Options -# Determine if using tag or commit for display -testedVersion=$(grep 'testedJMversion=' < ~/install.joinmarket.sh | grep -v '^#' | cut -d '"' -f 2) -if [ -z "$testedVersion" ]; then - testedVersion=$(grep 'testedJMcommit=' < ~/install.joinmarket.sh | cut -d '"' -f 2 | cut -c 1-12) - testedVersion="${testedVersion} (commit)" -fi OPTIONS+=( JOININBOX "Update the JoininBox scripts and menu" - JOINMARKET "Update/reinstall JoinMarket to ${testedVersion}") - -if [ "$runningEnv" = "standalone" ]; then - OPTIONS+=(\ - BITCOIN "Update Bitcoin Core to a chosen version") -fi -OPTIONS+=(\ + JOINMARKET "Update/reinstall JoinMarket to $(grep testedJMversion= < ~/install.joinmarket.sh | cut -d '"' -f 2)" ADVANCED "Advanced update options") CHOICE=$(dialog --clear \ @@ -61,14 +47,6 @@ case $CHOICE in echo echo "Press ENTER to return to the menu" read key;; - BITCOIN) - /home/joinmarket/standalone/bitcoin.update.sh custom - errorOnInstall $? - echo - echo "# Start bitcoind .. " - sudo systemctl start bitcoind - echo "# Monitoring the bitcoind logs .. " - showBitcoinLogs;; ADVANCED) /home/joinmarket/menu.update.advanced.sh;; esac diff --git a/scripts/menu.wallet.sh b/scripts/menu.wallet.sh index ea2801f..08e919f 100755 --- a/scripts/menu.wallet.sh +++ b/scripts/menu.wallet.sh @@ -194,7 +194,7 @@ Enter the new gap limit to be used" 16 60 2> "$gaplimit" echo /home/joinmarket/start.script.sh wallet-tool "$(cat $wallet)"|grep mixdepth|sed -n '1~2p'|awk '{print $3}' echo - echo "Import the master public keys to Specter Desktop or Electrum to create watch-only wallets." + echo "Import the master public keys to Specter Desktop or Electrum to create watch only wallets." echo echo "Press ENTER to return to the menu..." read key diff --git a/scripts/menu.yg.sh b/scripts/menu.yg.sh index 73fa9f5..a48929a 100755 --- a/scripts/menu.yg.sh +++ b/scripts/menu.yg.sh @@ -73,9 +73,9 @@ case $CHOICE in --msgbox " There are no stats because the Yield Generator was never run. -Start with the menu option: MAKER" 10 50 +Start with the menu option: RUN_YG" 10 50 else - dialog --prgbox "/home/joinmarket/info.stats.sh showAllEarned" 9 67 + dialog --prgbox "/home/joinmarket/info.stats.sh showAllEarned" 9 55 fi;; NICKNAME) name=$(YGnickname) diff --git a/scripts/set.ssh.sh b/scripts/set.ssh.sh index 21edcdd..2aee01c 100755 --- a/scripts/set.ssh.sh +++ b/scripts/set.ssh.sh @@ -1,6 +1,6 @@ #!/bin/bash -if [ ${#1} -eq 0 ] || [ $1 = "-h" ] || [ $1 = "--help" ]; then +if [ ${#1} -eq 0 ]||[ $1 = "-h" ]||[ $1 = "--help" ];then echo "Enable or disable ssh access with the joinmarket user" echo "sudo set.ssh.sh [off|on]" echo @@ -18,7 +18,7 @@ if ! grep -Eq "^joinmarketSSH=" /home/joinmarket/joinin.conf; then fi echo -if [ "$1" = "off" ]; then +if [ "$1" = "off" ];then echo "# Disable ssh access with the joinmarket user" if ! grep -Eq "^DenyUsers joinmarket" /etc/ssh/sshd_config; then echo "DenyUsers joinmarket" | tee -a /etc/ssh/sshd_config @@ -35,4 +35,4 @@ elif [ "$1" = "on" ]; then else echo "# Invalid option $*" exit 1 -fi +fi \ No newline at end of file diff --git a/scripts/set.value.sh b/scripts/set.value.sh index 4c28aaf..6b5ee39 100644 --- a/scripts/set.value.sh +++ b/scripts/set.value.sh @@ -30,7 +30,7 @@ if [ "$1" = "set" ]; then # check that config file exists raspiblitzConfExists=$(ls ${configFile} 2>/dev/null | grep -c "${configFile}") if [ ${raspiblitzConfExists} -eq 0 ]; then - echo "# blitz.conf.sh $*" + echo "# blitz.conf.sh $@" echo "# FAIL: missing config file: ${configFile}" exit 3 fi diff --git a/scripts/standalone/_functions.standalone.sh b/scripts/standalone/_functions.standalone.sh index d03ed66..42939e5 100755 --- a/scripts/standalone/_functions.standalone.sh +++ b/scripts/standalone/_functions.standalone.sh @@ -3,7 +3,7 @@ function addUserStore() { if [ ! -d /home/store/app-data ]; then echo "# Adding the user: store" - sudo adduser --system --group --home /home/store store + sudo adduser --disabled-password --gecos "" store sudo -u store mkdir /home/store/app-data echo "# Add the joinmarket user to the store group" sudo usermod -aG store joinmarket @@ -49,13 +49,13 @@ function downloadSnapShot() { echo "# Check available diskspace" FREE=$(df -k --output=avail "$PWD" | tail -n1) # df -k not df -h - if [ $FREE -lt 21000000 ]; then + if [ $FREE -lt 12582912 ]; then # 12G = 12*1024*1024k echo "# The free space is only $FREE bytes!" - echo "# Would need ~21GB free space to download and extract the snapshot." + echo "# Would need ~12GB free space to download and extract the snapshot." echo "# Press ENTER to continue to download regardless or CTRL+C to exit." read key else - echo "# OK, more than 21GB is free!" + echo "# OK, more than 12GB is free!" fi sudo -u joinmarket mkdir /home/joinmarket/download 2>/dev/null cd /home/joinmarket/download || exit 1 @@ -107,22 +107,20 @@ function downloadSnapShot() { echo "# Extracting to /home/store/app-data/.bitcoin ..." FREE=$(df -k --output=avail "$PWD" | tail -n1) # df -k not df -h - if [ $FREE -lt 11000000 ]; then + if [ $FREE -lt 7340032 ]; then # 7G = 7*1024*1024k echo "# The free space is only $FREE bytes!" - echo "# Would need ~11GB free space to extract the snapshot." - echo "# Press ENTER to continue to extract it regardless or CTRL+C to exit." + echo "# Would need ~7GB free space to extract the snapshot." + echo "# Press ENTER to continue to download regardless or CTRL+C to exit." read key else - echo "# OK, more than 11GB is free!" + echo "# OK, more than 7GB is free!" fi addUserStore if [ ! -d /home/store/app-data/.bitcoin ]; then sudo mkdir -p /home/store/app-data/.bitcoin fi echo "# Making sure user: bitcoin exists" - sudo adduser --system --group --shell /bin/bash --home /home/bitcoin bitcoin - echo "Copy the skeleton files for login" - sudo -u bitcoin cp -r /etc/skel/. /home/bitcoin/ + sudo adduser --disabled-password --gecos "" bitcoin sudo chown -R bitcoin:bitcoin /home/store/app-data/.bitcoin echo "# Add the joinmarket user to the bitcoin group" sudo usermod -aG bitcoin joinmarket @@ -140,11 +138,7 @@ function downloadSnapShot() { echo "# Unzip ..." sudo apt-get install -y unzip - sudo -u bitcoin unzip -o $downloadFileName -d /home/store/app-data/.bitcoin || exit 1 - echo "# OK - Decompressed successfully" - echo "# Removing the downloaded files" - rm -f $hashFileName - rm -f $downloadFileName + sudo -u bitcoin unzip -o $downloadFileName -d /home/store/app-data/.bitcoin if sudo -u bitcoin ls /home/bitcoin/.bitcoin/bitcoin.conf.backup; then echo "# Restore bitcoin.conf" sudo -u bitcoin mv -f /home/bitcoin/.bitcoin/bitcoin.conf.backup \ @@ -155,21 +149,24 @@ function downloadSnapShot() { function installBitcoinCoreStandalone() { downloadBitcoinCore - if [ -f /usr/local/bin/bitcoind ]; then - installedVersion=$(/usr/local/bin/bitcoind --version | grep version) + if [ -f /home/bitcoin/bitcoin/bitcoind ]; then + installedVersion=$(/home/bitcoin/bitcoin/bitcoind --version | grep version) echo "${installedVersion} is already installed" else echo "# Adding the user: bitcoin" - sudo adduser --system --group --shell /bin/bash --home /home/bitcoin bitcoin - echo "Copy the skeleton files for login" - sudo -u bitcoin cp -r /etc/skel/. /home/bitcoin/ + sudo adduser --disabled-password --gecos "" bitcoin echo "# Add the joinmarket user to the bitcoin group" sudo usermod -aG bitcoin joinmarket echo "# Installing Bitcoin Core v${bitcoinVersion}" + sudo -u bitcoin mkdir -p /home/bitcoin/bitcoin cd /home/joinmarket/download/bitcoin-${bitcoinVersion}/bin/ || exit 1 - sudo install -m 0755 -o root -g root -t /usr/local/bin/ ./* + sudo install -m 0755 -o root -g root -t /home/bitcoin/bitcoin ./* fi - if ! sudo -u bitcoin /usr/local/bin/bitcoind --version | grep "Bitcoin Core version"; then + if [ "$(grep -c "/home/bitcoin/bitcoin" Was not able to install Bitcoin Core)" exit 1 @@ -219,45 +216,24 @@ function installMainnet() { echo " [Unit] Description=Bitcoin daemon on mainnet - [Service] -Environment='MALLOC_ARENA_MAX=1' -ExecStart=/usr/local/bin/bitcoind \\ - -daemonwait \\ - -conf=/home/bitcoin/.bitcoin/bitcoin.conf \\ - -datadir=/home/bitcoin/.bitcoin -PermissionsStartOnly=true - -# Process management -#################### -Type=forking -Restart=on-failure -TimeoutStartSec=infinity -TimeoutStopSec=600 - -# Directory creation and permissions -#################################### -# Run as bitcoin:bitcoin User=bitcoin Group=bitcoin - +Type=forking +PIDFile=/home/bitcoin/bitcoin/bitcoind.pid +ExecStart=/home/bitcoin/bitcoin/bitcoind -daemon \ +-pid=/home/bitcoin/bitcoin/bitcoind.pid +Restart=always +TimeoutSec=120 +RestartSec=30 StandardOutput=null StandardError=journal # Hardening measures -#################### -# Provide a private /tmp and /var/tmp. PrivateTmp=true -# Mount /usr, /boot/ and /etc read-only for the process. ProtectSystem=full -# Disallow the process and all of its children to gain -# new privileges through execve(). NoNewPrivileges=true -# Use a new /dev namespace only populated with API pseudo devices -# such as /dev/null, /dev/zero and /dev/random. PrivateDevices=true -# Deny the creation of writable and executable memory mappings. -MemoryDenyWriteExecute=true [Install] WantedBy=multi-user.target @@ -267,17 +243,9 @@ WantedBy=multi-user.target echo "# OK - the bitcoind.service is now enabled" # add aliases - if ! grep "alias bitcoin-cli" /home/joinmarket/_aliases.sh; then - sudo bash -c "echo 'alias bitcoin-cli=\"sudo -u bitcoin /usr/local/bin/bitcoin-cli\"' >> /home/joinmarket/_aliases.sh" - fi - if ! grep "alias bitcoind" /home/joinmarket/_aliases.sh; then - sudo bash -c "echo 'alias bitcoind=\"sudo -u bitcoin /usr/local/bin/bitcoind\"' >> /home/joinmarket/_aliases.sh" - fi - if ! grep "alias bitcoinlog" /home/joinmarket/_aliases.sh; then - sudo bash -c "echo 'alias bitcoinlog=\"sudo tail -f /home/bitcoin/.bitcoin/debug.log\"' >> /home/joinmarket/_aliases.sh" - fi - if ! grep "alias bitcoinconf" /home/joinmarket/_aliases.sh; then - sudo bash -c "echo 'alias bitcoinconf=\"sudo nano /home/bitcoin/.bitcoin/bitcoin.conf\"' >> /home/joinmarket/_aliases.sh" + if [ $(alias | grep -c "sudo -u bitcoin /home/bitcoin/bitcoin/bitcoin-cli") -eq 0 ]; then + sudo bash -c "echo 'alias bitcoin-cli=\"sudo -u bitcoin /home/bitcoin/bitcoin/bitcoin-cli\"' >> /home/joinmarket/_aliases.sh" + sudo bash -c "echo 'alias bitcoind=\"sudo -u bitcoin /home/bitcoin/bitcoin/bitcoind\"' >> /home/joinmarket/_aliases.sh" fi # set joinin.conf value @@ -285,14 +253,14 @@ WantedBy=multi-user.target sudo systemctl start bitcoind echo - echo "# Installed $(sudo -u bitcoin /usr/local/bin/bitcoind --version | grep version)" + echo "# Installed $(sudo -u bitcoin /home/bitcoin/bitcoin/bitcoind --version | grep version)" echo echo "# Monitor the bitcoind with: sudo tail -f /home/bitcoin/.bitcoin/mainnet/debug.log" echo - if [ ! -d /home/bitcoin/.bitcoin/wallets/watch-only-descriptor-wallet ]; then - echo "# Create watch-only-descriptor-wallet ..." + if [ ! -f /home/bitcoin/.bitcoin/mainnet/wallets/wallet.dat/wallet.dat ]; then + echo "# Create wallet.dat ..." sleep 10 - sudo -u bitcoin /usr/local/bin/bitcoin-cli -named createwallet wallet_name=watch-only-descriptor-wallet descriptors=true disable_private_keys=true + sudo -u bitcoin /home/bitcoin/bitcoin/bitcoin-cli -named createwallet wallet_name=wallet.dat descriptors=false fi } diff --git a/scripts/standalone/bitcoin.update.sh b/scripts/standalone/bitcoin.update.sh deleted file mode 100644 index 2e9a9ce..0000000 --- a/scripts/standalone/bitcoin.update.sh +++ /dev/null @@ -1,219 +0,0 @@ -#!/bin/bash - -# command info -if [ $# -eq 0 ] || [ "$1" = "-h" ] || [ "$1" = "-help" ]; then - echo "Interim optional Bitcoin Core updates." - echo "bitcoin.update.sh [info|tested|reckless|custom]" - echo "info -> get actual state and possible actions" - echo "tested -> only do a tested update by the RaspiBlitz team" - echo "reckless -> the update was not tested by the RaspiBlitz team" - echo "custom -> update to a chosen version" - echo " the binary checksum and signatures will be checked in all cases" - echo " except when 'skipverify' is used" - echo - exit 1 -fi - -echo "# Running: bitcoin.update.sh $*" - -# 1. parameter [info|tested|reckless] -mode="$1" - -# RECOMMENDED UPDATE BY RASPIBLITZ TEAM (just possible once per sd card update) -# comment will be shown as "BEWARE Info" when option is chosen (can be multiple lines) -bitcoinVersion="" # example: 22.0 .. keep empty if no newer version as sd card build is available - -# GATHER DATA -# setting download directory to the current user -downloadDir="/home/$(whoami)/download/bitcoin.update" - -# bitcoinOSversion -if [ "$(uname -m | grep -c 'arm')" -gt 0 ]; then - bitcoinOSversion="arm-linux-gnueabihf" -elif [ "$(uname -m | grep -c 'aarch64')" -gt 0 ]; then - bitcoinOSversion="aarch64-linux-gnu" -elif [ "$(uname -m | grep -c 'x86_64')" -gt 0 ]; then - bitcoinOSversion="x86_64-linux-gnu" -fi - -# installed version -installedVersion=$(sudo -u bitcoin /usr/local/bin/bitcoind --version | head -n1 | cut -d" " -f4 | cut -c 2-) - -# test if the installed version already the tested/recommended update version -bitcoinUpdateInstalled=$(echo "${installedVersion}" | grep -c "${bitcoinVersion}") - -# get latest release from GitHub releases -bitcoinLatestVersion=$(curl --header "X-GitHub-Api-Version:2022-11-28" -s https://api.github.com/repos/bitcoin/bitcoin/releases | jq -r '.[].tag_name' | sort | tail -n1 | cut -c 2-) - -# INFO -function displayInfo() { - echo "# basic data" - echo "installedVersion='${installedVersion}'" - echo "bitcoinOSversion='${bitcoinOSversion}'" - - echo "# the tested/recommended update option" - echo "bitcoinUpdateInstalled='${bitcoinUpdateInstalled}'" - echo "bitcoinVersion='${bitcoinVersion}'" - - echo "# reckless update option (latest Bitcoin Core release from GitHub)" - echo "bitcoinLatestVersion='${bitcoinLatestVersion}'" -} - -if [ "${mode}" = "info" ]; then - displayInfo - exit 1 -fi - -# tested -if [ "${mode}" = "tested" ]; then - - echo "# bitcoin.update.sh tested" - -elif [ "${mode}" = "reckless" ]; then - # RECKLESS - # this mode is just for people running test and development nodes - its not recommended - # for production nodes. In a update/recovery scenario it will not install a fixed version - # it will always pick the latest release from the github - echo "# bitcoin.update.sh reckless" - bitcoinVersion=${bitcoinLatestVersion} - pathVersion=${bitcoinVersion} - -elif [ "${mode}" = "custom" ]; then - if [ $# -gt 1 ]; then - bitcoinVersion="$2" - else - clear - echo - echo "# Update Bitcoin Core to a chosen version." - echo - echo "# Input the version you would like to install and press ENTER." - echo "# Examples (versions below 22.1 are not supported):" - echo "24.0.1" - echo "26.0" - echo - read bitcoinVersion - fi - - if [ $(echo ${bitcoinVersion} | grep -c "rc") -gt 0 ]; then - cutVersion=$(echo ${bitcoinVersion} | awk -F"r" '{print $1}') - rcVersion=$(echo ${bitcoinVersion} | awk -F"r" '{print $2}') - # https://bitcoincore.org/bin/bitcoin-core-22.0/test.rc3/ - pathVersion=${cutVersion}/test.r${rcVersion} - else - pathVersion=${bitcoinVersion} - fi - - if curl --output /dev/null --silent --head --fail \ - https://bitcoincore.org/bin/bitcoin-core-${pathVersion}/SHA256SUMS.asc; then - echo "# OK version exists at https://bitcoincore.org/bin/bitcoin-core-${pathVersion}" - if [ "${mode}" = "custom" ] && [ "$3" = "skipverify" ]; then - echo "# skipping signature verification" - fi - echo "# Press ENTER to proceed to install Bitcoin Core $bitcoinVersion or CTRL+C to abort." - read key - else - echo "# FAIL $bitcoinVersion does not exist" - echo - echo "# Press ENTER to return to the main menu" - read key - exit 0 - fi -fi - -# JOINED INSTALL -if [ "${mode}" = "tested" ] || [ "${mode}" = "reckless" ] || [ "${mode}" = "custom" ]; then - - displayInfo - - if [ "$installedVersion" = "$bitcoinVersion" ]; then - echo "# installedVersion = bitcoinVersion" - echo "# exiting script" - exit 0 - fi - - echo - echo "# clean & change into download directory" - sudo rm -rf "${downloadDir}" - mkdir -p "${downloadDir}" - cd "${downloadDir}" || exit 1 - - echo "# Receive signer keys" - curl -s "https://api.github.com/repos/bitcoin-core/guix.sigs/contents/builder-keys" | - jq -r '.[].download_url' | while read url; do curl -s "$url" | gpg --import; done - - # download signed binary sha256 hash sum file - wget --prefer-family=ipv4 --progress=bar:force -O SHA256SUMS https://bitcoincore.org/bin/bitcoin-core-${bitcoinVersion}/SHA256SUMS - # download the signed binary sha256 hash sum file and check - wget --prefer-family=ipv4 --progress=bar:force -O SHA256SUMS.asc https://bitcoincore.org/bin/bitcoin-core-${bitcoinVersion}/SHA256SUMS.asc - - if [ "${mode}" = "custom" ] && [ "$3" = "skipverify" ]; then - echo "# skipping signature verification" - echo "# display the output of 'gpg --verify SHA256SUMS.asc'" - gpg --verify SHA256SUMS.asc - else - if gpg --verify SHA256SUMS.asc; then - echo - echo "****************************************" - echo "OK --> BITCOIN MANIFEST IS CORRECT" - echo "****************************************" - echo - else - echo - echo "# BUILD FAILED --> the PGP verification failed" - echo "# try again or with a different version" - echo "# if you want to skip verifying all signatures (and just show them) use the command:" - echo "# /home/admin/config.scripts/bonus.bitcoin.sh custom ${bitcoinVersion:-} skipverify" - exit 1 - fi - fi - - echo "# Downloading Bitcoin Core v${bitcoinVersion} for ${bitcoinOSversion} ..." - binaryName="bitcoin-${bitcoinVersion}-${bitcoinOSversion}.tar.gz" - wget https://bitcoincore.org/bin/bitcoin-core-${pathVersion}/${binaryName} - if [ ! -f "./${binaryName}" ]; then - echo "# FAIL # Downloading BITCOIN BINARY did not succeed." - exit 1 - fi - - echo "# Checking the binary checksum ..." - if ! sha256sum -c --ignore-missing SHA256SUMS; then - # get the sha256 value for the corresponding platform from signed hash sum file - bitcoinSHA256=$(grep -i "${binaryName}}" SHA256SUMS | cut -d " " -f1) - echo "# FAIL # Downloaded BITCOIN BINARY CHECKSUM:" - echo "$(sha256sum ${binaryName})" - echo "NOT matching SHA256 checksum:" - echo "${bitcoinSHA256}" - exit 1 - else - echo - echo "# OK --> VERIFIED BITCOIN CORE BINARY CHECKSUM IS CORRECT" - echo - fi -fi - -# JOINED INSTALL -if [ "${mode}" = "tested" ] || [ "${mode}" = "reckless" ] || [ "${mode}" = "custom" ]; then - - # install - echo "# Stopping bitcoind ..." - sudo systemctl stop bitcoind 2>/dev/null - sudo systemctl stop tbitcoind 2>/dev/null - sudo systemctl stop sbitcoind 2>/dev/null - echo - echo "# Installing Bitcoin Core v${bitcoinVersion}" - tar -xvf ${binaryName} - sudo install -m 0755 -o root -g root -t /usr/local/bin/ bitcoin-${bitcoinVersion}/bin/* - sleep 3 - if ! sudo /usr/local/bin/bitcoind --version | grep "${bitcoinVersion}"; then - echo - echo "# BUILD FAILED --> Was not able to install bitcoind version(${bitcoinVersion})" - exit 1 - fi - - echo "# OK Bitcoin Core ${bitcoinVersion} is installed" - exit 0 - -else - echo "# error='parameter not known'" - exit 1 -fi diff --git a/scripts/standalone/bootstrap.sh b/scripts/standalone/bootstrap.sh index 8bf6c4c..305d58d 100755 --- a/scripts/standalone/bootstrap.sh +++ b/scripts/standalone/bootstrap.sh @@ -21,7 +21,3 @@ echo "***********************************************" >> $logFile # make sure SSH server is configured & running sudo /home/joinmarket/standalone/ssh.sh checkrepair >> ${logFile} - -# fix ownership of possibly migrated files -sudo chown -R bitcoin:bitcoin /home/bitcoin/ -sudo chown -R joinmarket:joinmarket /home/joinmarket/ diff --git a/scripts/standalone/install.i2pd.sh b/scripts/standalone/install.i2pd.sh deleted file mode 100644 index 2c8561d..0000000 --- a/scripts/standalone/install.i2pd.sh +++ /dev/null @@ -1,296 +0,0 @@ -#!/bin/bash - -# https://i2pd.readthedocs.io - -if [ $# -eq 0 ] || [ "$1" = "-h" ] || [ "$1" = "-help" ]; then - echo "I2P Daemon install script" - echo "More info at https://i2pd.readthedocs.io" - echo "Usage:" - echo "install.i2pd.sh install -> Install i2pd" - echo "install.i2pd.sh on -> Switch on i2pd" - echo "install.i2pd.sh off -> Uninstall i2pd" - echo "install.i2pd.sh addseednodes -> Add 21 randonly selected I2P seed nodes from: https://github.com/bitcoin/bitcoin/blob/master/contrib/seeds/nodes_main.txt" - echo "install.i2pd.sh status -> I2P related logs from bitcoind, bitcoin-cli -netinfo 4 and webconsole access" - exit 1 -fi - -function confAdd { - # get parameters - keystr="$1" - valuestr=$(echo "$2" | sed 's/\//\\\//g') - configFile="$3" - - # check if key needs to be added (prepare new entry) - entryExists=$(grep -c "^${keystr}=" ${configFile}) - if [ ${entryExists} -eq 0 ]; then - echo "${keystr}=" | sudo tee -a ${configFile} 1>/dev/null - fi - - # add an extra key=value line (needs sudo to operate when user is not root) - echo "${keystr}=${valuestr}" | sudo tee -a ${configFile} -} - -function add_repo { - # Add repo for the latest version - # i2pd — https://repo.i2pd.xyz/.help/readme.txt - # https://repo.i2pd.xyz/.help/add_repo - - source /etc/os-release - DIST=$ID - case $ID in - debian | ubuntu | raspbian) - if [[ -n $DEBIAN_CODENAME ]]; then - VERSION_CODENAME=$DEBIAN_CODENAME - fi - if [[ -n $UBUNTU_CODENAME ]]; then - VERSION_CODENAME=$UBUNTU_CODENAME - fi - if [[ -z $VERSION_CODENAME ]]; then - echo "Couldn't find VERSION_CODENAME in your /etc/os-release file. Did your system supported? Please report issue to me by writing to email: 'r4sas i2pd.xyz'" - exit 1 - fi - RELEASE=$VERSION_CODENAME - ;; - *) - if [[ -z $ID_LIKE || "$ID_LIKE" != "debian" && "$ID_LIKE" != "ubuntu" ]]; then - echo "Your system is not supported by this script. Currently it supports debian-like and ubuntu-like systems." - exit 1 - else - DIST=$ID_LIKE - case $ID_LIKE in - debian) - if [[ "$ID" == "kali" ]]; then - if [[ "$VERSION" == "2019"* || "$VERSION" == "2020"* ]]; then - RELEASE="buster" - elif [[ "$VERSION" == "2021"* || "$VERSION" == "2022"* ]]; then - RELEASE="bullseye" - fi - else - RELEASE=$DEBIAN_CODENAME - fi - ;; - ubuntu) - RELEASE=$UBUNTU_CODENAME - ;; - esac - fi - ;; - esac - if [[ -z $RELEASE ]]; then - echo "Couldn't detect your system release. Please report issue to me by writing to email: 'r4sas i2pd.xyz'" - exit 1 - fi - echo "Importing signing key" - wget -q -O - https://repo.i2pd.xyz/r4sas.gpg | sudo apt-key --keyring /etc/apt/trusted.gpg.d/i2pd.gpg add - - echo "Adding APT repository" - echo "deb https://repo.i2pd.xyz/$DIST $RELEASE main" | sudo tee /etc/apt/sources.list.d/i2pd.list - echo "deb-src https://repo.i2pd.xyz/$DIST $RELEASE main" | sudo tee -a /etc/apt/sources.list.d/i2pd.list -} - -function bitcoinI2Pstatus { - echo "# I2P related logs from the bitcoin debug log" - echo "sudo tail -n 200 ${bitcoinLogPath} | grep i2p" - echo - sudo cat ${bitcoinLogPath} | grep i2p - echo - echo "# Running the command:" - echo "sudo -u bitcoin /home/bitcoin/bitcoin/bitcoin-cli -netinfo 4" - echo - sudo -u bitcoin /home/bitcoin/bitcoin/bitcoin-cli -netinfo 4 - echo - echo "# i2pd webconsole:" - localip=$(hostname -I | awk '{print $1}') - echo "http://${localip}:7070" - echo "# Username: i2pd" - echo "# Password: your passwordB" - echo -} - -echo "# Running: 'install.i2pd.sh $*'" -source /home/joinmarket/joinin.conf - -bitcoinConfPath="/home/bitcoin/.bitcoin/bitcoin.conf" -bitcoinLogPath="/home/bitcoin/.bitcoin/debug.log" - -# make sure to be present in PATH -if ! echo "$PATH" | grep "/usr/sbin" >/dev/null; then - export PATH=$PATH:/usr/sbin - echo "PATH=\$PATH:/usr/sbin" | sudo tee -a /etc/profile -fi - -if [ "$1" = "install" ]; then - - isInstalled=$(sudo systemctl list-unit-files | grep -c i2pd) - if [ "${isInstalled}" != "0" ]; then - echo "# i2pd is already installed." - else - echo "# Installing i2pd ..." - - add_repo - - sudo apt-get update - sudo apt-get install -y i2pd - - fi - exit 0 -fi - -if [ "$1" = "1" ] || [ "$1" = "on" ]; then - - isInstalled=$(sudo systemctl list-unit-files | grep -c i2pd) - if [ "${isInstalled}" != "0" ]; then - echo "# i2pd is installed." - else - /home/joinmarket/standalone/install.i2pd.sh install - fi - - if systemctl is-active --quiet i2pd.service; then - echo "# i2pd.service is already active." - else - echo "# sudo systemctl enable i2pd" - sudo systemctl enable i2pd - fi - - echo "# i2pd config" - /home/joinmarket/set.value.sh set debug tor ${bitcoinConfPath} noquotes - confAdd debug i2p ${bitcoinConfPath} - /home/joinmarket/set.value.sh set i2psam 127.0.0.1:7656 ${bitcoinConfPath} noquotes - /home/joinmarket/set.value.sh set i2pacceptincoming 1 ${bitcoinConfPath} noquotes - /home/joinmarket/set.value.sh set onlynet onion ${bitcoinConfPath} noquotes - confAdd onlynet i2p ${bitcoinConfPath} - PASSWORD_B=$(sudo cat ${bitcoinConfPath} | grep rpcpassword | cut -c 13-) - cat </dev/null - sleep 10 - - if i2pd --version; then - echo "# Installed i2pd" - else - echo "# i2pd is not installed" - exit 1 - fi - - # setting value in raspiblitz.conf - /home/joinmarket/set.value.sh set i2pd "on" - - localip=$(hostname -I | awk '{print $1}') - echo "# Config: /etc/i2pd/i2pd.conf" - echo "# i2pd web console: ${localip}:7070" - echo "# Monitor i2p in bitcoind:" - echo "sudo tail -n 100 ${bitcoinLogPath} | grep i2p" - echo "sudo -u bitcoin /home/bitcoin/bitcoin/bitcoin-cli -netinfo 4" - - exit 0 -fi - -if [ "$1" = "addseednodes" ]; then - - if ! sudo -u bitcoin /home/bitcoin/bitcoin/bitcoin-cli -netinfo 4 | grep i2p; then - echo "# i2pd is not running" - /home/joinmarket/standalone/install.i2pd.sh on - fi - - echo "Add 21 randomly selected I2P seed nodes from: https://github.com/bitcoin/bitcoin/blob/master/contrib/seeds/nodes_main.txt" - echo "Monitor in a new terminal with:" - echo "watch sudo -u bitcoin /home/bitcoin/bitcoin/bitcoin-cli -netinfo 4" - echo "This will take some time ..." - - # Fetch and filter the list of seed nodes - i2pSeedNodeList=$(curl -sS https://raw.githubusercontent.com/bitcoin/bitcoin/master/contrib/seeds/nodes_main.txt | grep .b32.i2p:0) - - # Shuffle the list and pick the first 21 nodes - selectedNodes=$(echo "$i2pSeedNodeList" | shuf | head -n 21) - - # Add each selected node - for i2pSeedNode in ${selectedNodes}; do - echo "# Add i2p seed node: ${i2pSeedNode} by running:" - echo "bitcoin-cli addnode $i2pSeedNode onetry" - sudo -u bitcoin /home/bitcoin/bitcoin/bitcoin-cli addnode "$i2pSeedNode" "onetry" - done - - echo - echo "# Display sudo tail -n 100 ${bitcoinLogPath} | grep i2p" - sudo tail -n 100 ${bitcoinLogPath} | grep i2p - echo - echo "# Display bitcoin-cli -netinfo 4" - sudo -u bitcoin /home/bitcoin/bitcoin/bitcoin-cli -netinfo 4 - - exit 0 -fi - -# switch off -if [ "$1" = "0" ] || [ "$1" = "off" ]; then - - echo "# stop & remove systemd service" - sudo systemctl stop i2pd 2>/dev/null - sudo systemctl disable i2pd.service - - echo "# Uninstall with apt" - sudo apt remove -y i2pd - - echo "# Remove settings from bitcoind" - /home/joinmarket/set.value.sh delete debug ${bitcoinConfPath} noquotes - /home/joinmarket/set.value.sh set debug tor ${bitcoinConfPath} noquotes - /home/joinmarket/set.value.sh delete i2psam ${bitcoinConfPath} noquotes - /home/joinmarket/set.value.sh delete i2pacceptincoming ${bitcoinConfPath} noquotes - /home/joinmarket/set.value.sh delete onlynet ${bitcoinConfPath} noquotes - /home/joinmarket/set.value.sh set onlynet onion ${bitcoinConfPath} noquotes - - sudo rm /etc/systemd/system/i2pd.service - - sudo ufw delete allow 7070 - - if ! i2pd --version 2>/dev/null; then - echo "# OK - i2pd is not installed now" - else - echo "# i2pd is still installed" - exit 1 - fi - - # setting value in raspiblitz.conf - /home/joinmarket/set.value.sh set i2pd "off" - - exit 0 -fi - -if [ "$1" = "status" ]; then - bitcoinI2Pstatus - exit 0 -fi - -echo "# FAIL - Unknown Parameter $1" -exit 1 diff --git a/scripts/standalone/install.specter.sh b/scripts/standalone/install.specter.sh index 954ecc3..dfb21eb 100755 --- a/scripts/standalone/install.specter.sh +++ b/scripts/standalone/install.specter.sh @@ -149,7 +149,7 @@ if [ "$1" = "1" ] || [ "$1" = "on" ]; then addUserStore - sudo adduser --system --group --home /home/specter specter + sudo adduser --disabled-password --gecos "" specter # store data with the store user sudo mkdir -p /home/store/app-data/.specter 2>/dev/null diff --git a/scripts/standalone/menu.specter.sh b/scripts/standalone/menu.specter.sh index 74abe9c..3e6324f 100755 --- a/scripts/standalone/menu.specter.sh +++ b/scripts/standalone/menu.specter.sh @@ -1,5 +1,3 @@ -#!/bin/bash - source /home/joinmarket/_functions.sh # add default value to config if needed diff --git a/scripts/start.boltzmann.py b/scripts/start.boltzmann.py new file mode 100755 index 0000000..100fcc5 --- /dev/null +++ b/scripts/start.boltzmann.py @@ -0,0 +1,62 @@ +#!/usr/bin/env python3 + +import configparser +import os +import sys +import getopt + +def main(argv): + + description = "\nBoltzmann - https://code.samourai.io/oxt/boltzmann/\n\ +A python script computing the entropy of Bitcoin transactions and the linkability of their inputs and outputs.\n\ +For a description of the metrics and related discussions:\n\ +Bitcoin Transactions & Privacy (part 1) : https://gist.github.com/LaurentMT/e758767ca4038ac40aaf\n\ +Bitcoin Transactions & Privacy (part 2) : https://gist.github.com/LaurentMT/d361bca6dc52868573a2\n\ +Bitcoin Transactions & Privacy (part 3) : https://gist.github.com/LaurentMT/e8644d5bc903f02613c6\n\ +\n\ +WARNING: this feature is highly experimental and not optimised to be used with JoinMarket." + os.system('clear') + print(description) + + txids = '' + try: + opts, args = getopt.getopt(argv,"t:",["txids="]) + except getopt.GetoptError: + print('python run.boltzmann.py --txids=TXID1,TXID2') + sys.exit(2) + + for opt, arg in opts: + if opt in ('-t', '--txids'): + txids = arg + config = configparser.ConfigParser(strict=False) + + config.read('/home/joinmarket/.joinmarket/joinmarket.cfg') + + rpc_user = config['BLOCKCHAIN']['rpc_user'] + rpc_password = config['BLOCKCHAIN']['rpc_password'] + rpc_host = config['BLOCKCHAIN']['rpc_host'] + rpc_port = config['BLOCKCHAIN']['rpc_port'] + + tor = '' + if rpc_host.find('.onion') >= 0: + print('# Connecting to bitcoind RPC over Tor') + tor = 'torsocks' + + boltzmannpath = "/home/joinmarket/boltzmann/" + + bvenv = ". "+boltzmannpath+"bvenv/bin/activate" + + boltzmann = tor+" python "+boltzmannpath+"boltzmann/ludwig.py -p -x 30 \ +--txids="+txids + + run = bvenv+";"+"export BOLTZMANN_RPC_USERNAME="+rpc_user+";\ + export BOLTZMANN_RPC_PASSWORD="+rpc_password+";\ + export BOLTZMANN_RPC_HOST="+rpc_host+";\ + export BOLTZMANN_RPC_PORT="+rpc_port+";"+boltzmann+" 2>/dev/null" + + print('# Exporting RPC connection details') + print('# Running the command:\n'+boltzmann+'\n') + os.system(run) + +if __name__ == "__main__": + main(sys.argv[1:]) diff --git a/scripts/start.joininbox.sh b/scripts/start.joininbox.sh index 0aec7f8..d95fdcb 100755 --- a/scripts/start.joininbox.sh +++ b/scripts/start.joininbox.sh @@ -2,7 +2,7 @@ echo "# starting JoininBox ..." -if [ ! -f /home/joinmarket/joinin.conf ]; then +if [ ! -f /home/joinmarket/joinin.conf ];then touch /home/joinmarket/joinin.conf fi @@ -12,44 +12,45 @@ source /home/joinmarket/_functions.sh # FIRST RUN # ############# -setupStepEntry=$(grep -c "setupStep" <$joininConfPath) -if [ "$setupStepEntry" -eq 0 ]; then - echo "setupStep=0" >>$joininConfPath +setupStepEntry=$(grep -c "setupStep" < $joininConfPath) +if [ "$setupStepEntry" -eq 0 ];then + echo "setupStep=0" >> $joininConfPath fi source /home/joinmarket/joinin.conf -if [ "$setupStep" -lt 100 ]; then - if [ "$setupStep" -lt 5 ]; then +if [ "$setupStep" -lt 100 ];then + if [ "$setupStep" -lt 5 ];then # identify running env - runningEnvEntry=$(grep -c "runningEnv" <$joininConfPath) - if [ "$runningEnvEntry" -eq 0 ]; then - if [ -f "/mnt/hdd/raspiblitz.conf" ] || [ -f "/mnt/hdd/app-data/raspiblitz.conf" ] ; then + runningEnvEntry=$(grep -c "runningEnv" < $joininConfPath) + if [ "$runningEnvEntry" -eq 0 ];then + if [ -f "/mnt/hdd/raspiblitz.conf" ];then runningEnv="raspiblitz" - elif [ -f "/usr/share/mynode/mynode_config.sh" ]; then + elif [ -f "/usr/share/mynode/mynode_config.sh" ];then runningEnv="mynode" else runningEnv="standalone" fi - echo "runningEnv=$runningEnv" >>$joininConfPath - sed -i "s#setupStep=.*#setupStep=1#g" $joininConfPath + echo "runningEnv=$runningEnv" >> $joininConfPath + sed -i "s#setupStep=.*#setupStep=1#g" $joininConfPath fi echo "# running in the environment: $runningEnv" # identify cpu architecture - cpuEntry=$(grep -c "cpu" <$joininConfPath) - if [ "$cpuEntry" -eq 0 ]; then + cpuEntry=$(grep -c "cpu" < $joininConfPath) + if [ "$cpuEntry" -eq 0 ];then cpu=$(uname -m) - echo "cpu=$cpu" >>$joininConfPath - sed -i "s#setupStep=.*#setupStep=2#g" $joininConfPath + echo "cpu=$cpu" >> $joininConfPath + sed -i "s#setupStep=.*#setupStep=2#g" $joininConfPath fi echo "# cpu=${cpu}" # check Tor - torEntry=$(grep -c "runBehindTor" <$joininConfPath) - if [ "$torEntry" -eq 0 ]; then + torEntry=$(grep -c "runBehindTor" < $joininConfPath) + if [ "$torEntry" -eq 0 ];then torTest=$(curl --socks5 localhost:9050 --socks5-hostname localhost:9050 -s \ - https://check.torproject.org/ | cat | grep -m 1 Congratulations | xargs) - if [ "$torTest" = "Congratulations. This browser is configured to use Tor." ]; then + https://check.torproject.org/ | cat | grep -m 1 Congratulations | xargs) + if [ "$torTest" = "Congratulations. This browser is configured to use Tor." ] + then runBehindTor=on else runBehindTor=off @@ -58,65 +59,65 @@ if [ "$setupStep" -lt 100 ]; then echo "# Press ENTER to continue without Tor or CTRL+C to cancel and try checking again with 'menu'" read key fi - echo "runBehindTor=$runBehindTor" >>$joininConfPath + echo "runBehindTor=$runBehindTor" >> $joininConfPath echo "# runBehindTor=$runBehindTor" fi # make sure Tor path is known - DirEntry=$(grep -c "HiddenServiceDir" <$joininConfPath) - if [ "$DirEntry" -eq 0 ]; then - if [ -d "/mnt/hdd/tor" ]; then + DirEntry=$(grep -c "HiddenServiceDir" < $joininConfPath) + if [ "$DirEntry" -eq 0 ];then + if [ -d "/mnt/hdd/tor" ];then HiddenServiceDir="/mnt/hdd/tor" else HiddenServiceDir="/var/lib/tor" fi - echo "HiddenServiceDir=$HiddenServiceDir" >>$joininConfPath - sed -i "s#setupStep=.*#setupStep=3#g" $joininConfPath + echo "HiddenServiceDir=$HiddenServiceDir" >> $joininConfPath + sed -i "s#setupStep=.*#setupStep=3#g" $joininConfPath fi # check for dialog - if [ "$(dialog | grep -c "ComeOn Dialog!")" -eq 0 ]; then + if [ "$(dialog | grep -c "ComeOn Dialog!")" -eq 0 ];then sudo apt-get install -y dialog fi # check for qrencode - if [ "$(qrencode -V 2>&1 | grep -c "not found")" -gt 0 ]; then + if [ "$(qrencode -V 2>&1 | grep -c "not found")" -gt 0 ];then sudo apt-get install -y qrencode fi - sed -i "s#setupStep=.*#setupStep=4#g" $joininConfPath + sed -i "s#setupStep=.*#setupStep=4#g" $joininConfPath # check if JoinMarket is installed - if [ "${cpu}" = x86_64 ]; then - /home/joinmarket/install.joinmarket.sh -i install - else - # no qtgui on arm + if [ "${runningEnv}" = raspiblitz ] && [ "$(lsb_release -sc)" = bullseye ]; then + # no qtgui for raspibliz on bullseye /home/joinmarket/install.joinmarket.sh -i install -q 0 + else + /home/joinmarket/install.joinmarket.sh -i install fi - sed -i "s#setupStep=.*#setupStep=5#g" $joininConfPath + sed -i "s#setupStep=.*#setupStep=5#g" $joininConfPath fi # change the ssh password if standalone - if [ "$runningEnv" = "standalone" ]; then + if [ "$runningEnv" = "standalone" ];then source /home/joinmarket/joinin.conf - if [ "$setupStep" -lt 6 ]; then + if [ "$setupStep" -lt 6 ];then # set ssh passwords on the first run sudo /home/joinmarket/set.password.sh - sed -i "s#setupStep=.*#setupStep=6#g" $joininConfPath + sed -i "s#setupStep=.*#setupStep=6#g" $joininConfPath fi source /home/joinmarket/joinin.conf - if [ "$setupStep" -lt 7 ] && [ ${cpu} != "x86_64" ]; then + if [ "$setupStep" -lt 7 ]&&[ ${cpu} != "x86_64" ];then # expand SDcard partition on ARM sudo /home/joinmarket/standalone/expand.rootfs.sh fi fi generateJMconfig - sudo sed -i "s#setupStep=.*#setupStep=10#g" $joininConfPath + sudo sed -i "s#setupStep=.*#setupStep=10#g" $joininConfPath source /home/joinmarket/joinin.conf - if [ "$setupStep" -lt 11 ]; then - if [ "$runningEnv" = "standalone" ]; then + if [ "$setupStep" -lt 11 ];then + if [ "$runningEnv" = "standalone" ];then # open the config menu if standalone /home/joinmarket/menu.config.sh else # setup finished - sudo sed -i "s#setupStep=.*#setupStep=100#g" $joininConfPath + sudo sed -i "s#setupStep=.*#setupStep=100#g" $joininConfPath fi fi fi @@ -127,11 +128,11 @@ fi # check bitcoind RPC setting # add default value to joinin config if needed -if ! grep -Eq "^RPCoverTor=" $joininConfPath; then - echo "RPCoverTor=off" >>$joininConfPath +if ! grep -Eq "^RPCoverTor=" $joininConfPath;then + echo "RPCoverTor=off" >> $joininConfPath fi # check if bitcoin RPC connection is over Tor -if grep -Eq "^rpc_host = .*.onion" $JMcfgPath; then +if grep -Eq "^rpc_host = .*.onion" $JMcfgPath;then echo "# RPC over Tor is on" sed -i "s/^RPCoverTor=.*/RPCoverTor=on/g" $joininConfPath else @@ -141,14 +142,14 @@ fi # check if there is only one joinmarket wallet and make default # add default value to joinin config if needed -if ! grep -Eq "^defaultWallet=" $joininConfPath; then - echo "defaultWallet=off" >>$joininConfPath +if ! grep -Eq "^defaultWallet=" $joininConfPath;then + echo "defaultWallet=off" >> $joininConfPath fi -if [ "$(ls -p /home/joinmarket/.joinmarket/wallets/ | grep -cv /)" -gt 1 ]; then +if [ "$(ls -p /home/joinmarket/.joinmarket/wallets/ | grep -cv /)" -gt 1 ];then echo "# Found more than one wallet file" echo "# Setting defaultWallet to off" sed -i "s#^defaultWallet=.*#defaultWallet=off#g" $joininConfPath -elif [ "$(ls -p /home/joinmarket/.joinmarket/wallets/ | grep -cv /)" -eq 1 ]; then +elif [ "$(ls -p /home/joinmarket/.joinmarket/wallets/ | grep -cv /)" -eq 1 ];then onlyWallet=$(ls -p /home/joinmarket/.joinmarket/wallets/ | grep -v /) echo "# Found only one wallet file: $onlyWallet" echo "# Using it as default" @@ -156,28 +157,28 @@ elif [ "$(ls -p /home/joinmarket/.joinmarket/wallets/ | grep -cv /)" -eq 1 ]; th fi # add default value to joinin config if needed -if ! grep -Eq "^network=" $joininConfPath; then - echo "network=unknown" >>$joininConfPath +if ! grep -Eq "^network=" $joininConfPath;then + echo "network=unknown" >> $joininConfPath fi -isMainnet=$(grep -c "network = mainnet" <$JMcfgPath) -isSignet=$(grep -c "network = signet" <$JMcfgPath) -isTestnet=$(grep -c "network = testnet" <$JMcfgPath) -if [ $isMainnet -gt 0 ]; then +isMainnet=$(grep -c "network = mainnet" < $JMcfgPath) +isSignet=$(grep -c "network = signet" < $JMcfgPath) +isTestnet=$(grep -c "network = testnet" < $JMcfgPath) +if [ $isMainnet -gt 0 ];then sed -i "s#^network=.*#network=mainnet#g" $joininConfPath -elif [ $isSignet -gt 0 ]; then +elif [ $isSignet -gt 0 ];then sed -i "s#^network=.*#network=signet#g" $joininConfPath -elif [ $isTestnet -gt 0 ]; then +elif [ $isTestnet -gt 0 ];then sed -i "s#^network=.*#network=testnet#g" $joininConfPath else sed -i "s#^network=.*#network=unknown#g" $joininConfPath fi # add default value to joinin config if needed -if ! grep -Eq "^localip=" $joininConfPath; then - echo "localip=unknown" >>$joininConfPath +if ! grep -Eq "^localip=" $joininConfPath;then + echo "localip=unknown" >> $joininConfPath fi localip=$(hostname -I | awk '{print $1}') sed -i "s#^localip=.*#localip=$localip#g" $joininConfPath -# change the onion_serving_port if LND is present (avoid collision with LND REST port) +# change the onion_serving_port if LND is present (avoid collusion with LND REST port) sed -i "s#^onion_serving_port = 8080#onion_serving_port = 8090#g" $JMcfgPath diff --git a/scripts/start.service.sh b/scripts/start.service.sh index a1b4c61..1156475 100755 --- a/scripts/start.service.sh +++ b/scripts/start.service.sh @@ -43,18 +43,6 @@ Type=simple TimeoutSec=infinity Restart=no -# Memory limits (DoS / OOM protection) -MemoryHigh=300M -MemoryMax=512M -MemorySwapMax=0 - -# Reduce OOM kill priority (lower = less likely to be killed) -OOMScoreAdjust=-500 -OOMPolicy=stop - -# CPU limit -CPUQuota=80% - # Hardening measures PrivateTmp=true ProtectSystem=full diff --git a/scripts/verify.git.sh b/scripts/verify.git.sh index 6360073..a687c04 100644 --- a/scripts/verify.git.sh +++ b/scripts/verify.git.sh @@ -15,7 +15,7 @@ fi # Example for commits created on GitHub: # PGPsigner="web-flow" # PGPpubkeyLink="https://github.com/${PGPsigner}.gpg" -# PGPpubkeyFingerprint="B5690EEEBB952194" +# PGPpubkeyFingerprint="4AEE18F83AFDEB23" # Example for commits signed with a personal PGP key: # PGPsigner="janoside" @@ -30,18 +30,9 @@ PGPsigner="$1" PGPpubkeyLink="$2" PGPpubkeyFingerprint="$3" -_temp_dir="$(mktemp -d -p /dev/shm/ 2>/dev/null || mktemp -d)" -trap 'rm -rf "$_temp_dir"' EXIT - -keyFile="${_temp_dir}/pgp_keys_${PGPsigner}.asc" -rawKeyFile="${keyFile}.raw" - -wget --prefer-family=ipv4 -O "${rawKeyFile}" "${PGPpubkeyLink}" -# GitHub can add a Note: armor header when an account key cannot be exported. -# GPG imports the key anyway, but prints a misleading "unknown armor header". -grep -v '^Note: ' "${rawKeyFile}" >"${keyFile}" -gpg --quiet --import --import-options show-only "${keyFile}" -fingerprint=$(gpg --show-keys --with-subkey-fingerprint "${keyFile}" 2>/dev/null | tr -d " \t\n\r" | grep "${PGPpubkeyFingerprint}" -c) +wget --prefer-family=ipv4 -O /dev/shm/pgp_keys_${PGPsigner}.asc "${PGPpubkeyLink}" +gpg --import --import-options show-only /dev/shm/pgp_keys_${PGPsigner}.asc +fingerprint=$(gpg --show-keys /dev/shm/pgp_keys_${PGPsigner}.asc 2>/dev/null | grep "${PGPpubkeyFingerprint}" -c) if [ "${fingerprint}" -lt 1 ]; then echo echo "# WARNING --> the PGP fingerprint is not as expected for ${PGPsigner}" >&2 @@ -49,9 +40,11 @@ if [ "${fingerprint}" -lt 1 ]; then echo "# Exiting" >&2 exit 7 fi -gpg --quiet --import "${keyFile}" +gpg --import /dev/shm/pgp_keys_${PGPsigner}.asc +rm /dev/shm/pgp_keys_${PGPsigner}.asc -_temp="${_temp_dir}/git-verify.out" +trap 'rm -f "$_temp"' EXIT +_temp="$(mktemp -p /dev/shm/)" if [ $# -eq 3 ] || [ -z "$4" ]; then commitHash="$(git log --oneline | head -1 | awk '{print $1}')" diff --git a/test/README.md b/test/README.md deleted file mode 100644 index 7196ac1..0000000 --- a/test/README.md +++ /dev/null @@ -1,34 +0,0 @@ -# JoininBox integration tests - -Run the local Bats suite with: - -```bash -test/run-bats-local.sh -``` - -The descriptor wallet tests require: - -- `bats` -- `bitcoind` -- `bitcoin-cli` -- `curl` -- `jq` - -The suite starts its own temporary `bitcoind -regtest` datadir and does not use -mainnet, signet, or any existing Bitcoin Core state. - -The `amd64-image-test` workflow downloads a previously built -`joininbox-amd64-image-*` artifact, verifies the compressed and raw checksums, -decompresses a runner-local qcow2 copy, boots it with QEMU in snapshot mode, -copies a pinned `bats-core` checkout into that temporary VM session, and runs -the same suite from the JoininBox checkout inside the image. This avoids -depending on the guest's configured APT repositories just to install test -tooling. - -The test workflow has two entry points: - -- `workflow_run`: runs after a successful `amd64-image-build` once this workflow - exists on the repository default branch. -- `workflow_dispatch`: reruns against a specific build artifact by providing the - `amd64-image-build` workflow run ID, as long as the artifact is still retained - by GitHub Actions. diff --git a/test/bats/descriptor-wallet.bats b/test/bats/descriptor-wallet.bats deleted file mode 100644 index 8cb1d9b..0000000 --- a/test/bats/descriptor-wallet.bats +++ /dev/null @@ -1,214 +0,0 @@ -#!/usr/bin/env bats - -root_dir="$(cd "$BATS_TEST_DIRNAME/../.." && pwd)" -PATH="/home/joinmarket/bitcoin:/usr/local/bin:$PATH" - -require_command() { - if ! command -v "$1" >/dev/null 2>&1; then - skip "$1 is required" - fi -} - -setup() { - require_command bitcoind - require_command bitcoin-cli - require_command curl - require_command jq - - rpc_user="joininbox" - rpc_pass="joininbox" - rpc_port="$((20000 + (RANDOM % 20000)))" - p2p_port="$((40000 + (RANDOM % 20000)))" - bitcoin_datadir="${BATS_TEST_TMPDIR}/bitcoin" - joinmarket_cfg="${BATS_TEST_TMPDIR}/joinmarket.cfg" - joinin_conf="${BATS_TEST_TMPDIR}/joinin.conf" - - mkdir -p "$bitcoin_datadir" - - bitcoind \ - -regtest \ - -datadir="$bitcoin_datadir" \ - -server \ - -daemonwait \ - -rpcuser="$rpc_user" \ - -rpcpassword="$rpc_pass" \ - -rpcport="$rpc_port" \ - -port="$p2p_port" \ - -fallbackfee=0.0001 - - cat >"$joinmarket_cfg" <"$joinin_conf" -} - -teardown() { - if [ -n "${bitcoin_datadir:-}" ] && [ -d "$bitcoin_datadir" ]; then - bitcoin-cli \ - -regtest \ - -datadir="$bitcoin_datadir" \ - -rpcuser="$rpc_user" \ - -rpcpassword="$rpc_pass" \ - -rpcport="$rpc_port" \ - stop >/dev/null 2>&1 || true - fi -} - -load_joininbox_bitcoin_functions() { - # shellcheck source=scripts/_functions.bitcoincore.sh - # shellcheck disable=SC1091 - source "$root_dir/scripts/_functions.bitcoincore.sh" - # shellcheck disable=SC2034 - JMcfgPath="$joinmarket_cfg" - # shellcheck disable=SC2034 - joininConfPath="$joinin_conf" - - mktemp() { - if [ "${1:-}" = "-p" ] && [ "${2:-}" = "/dev/shm/" ]; then - command mktemp "${BATS_TEST_TMPDIR}/joininbox.XXXXXX" - else - command mktemp "$@" - fi - } -} - -wallet_info() { - bitcoin-cli \ - -regtest \ - -datadir="$bitcoin_datadir" \ - -rpcuser="$rpc_user" \ - -rpcpassword="$rpc_pass" \ - -rpcport="$rpc_port" \ - -rpcwallet=watch-only-descriptor-wallet \ - getwalletinfo -} - -check_wallet_migration_with_enter() { - printf "\n" | checkWalletMigration -} - -check_rpc_wallet_with_enter() { - printf "\n" | checkRPCwallet -} - -@test "checkRPCwallet creates the configured descriptor watch-only wallet" { - load_joininbox_bitcoin_functions - - run checkRPCwallet - - [ "$status" -eq 0 ] - [[ "$output" == *"The wallet: watch-only-descriptor-wallet is present and loaded"* ]] - - run wallet_info - [ "$status" -eq 0 ] - [ "$(jq -r '.descriptors' <<<"$output")" = "true" ] - [ "$(jq -r '.private_keys_enabled' <<<"$output")" = "false" ] - run grep -q "walletMigrationDone" "$joinin_conf" - [ "$status" -ne 0 ] -} - -@test "customRPC uses the descriptor wallet RPC endpoint" { - bitcoin-cli \ - -regtest \ - -datadir="$bitcoin_datadir" \ - -rpcuser="$rpc_user" \ - -rpcpassword="$rpc_pass" \ - -rpcport="$rpc_port" \ - -named createwallet \ - wallet_name=watch-only-descriptor-wallet \ - descriptors=true \ - disable_private_keys=true >/dev/null - - load_joininbox_bitcoin_functions - - run customRPC "# Wallet info" "getwalletinfo" "" - - [ "$status" -eq 0 ] - [[ "$output" == *'"walletname": "watch-only-descriptor-wallet"'* ]] - [[ "$output" == *'"descriptors": true'* ]] - [[ "$output" == *'"private_keys_enabled": false'* ]] -} - -@test "checkRPCwallet migrates a persisted wallet.dat configuration on Bitcoin Core v30 or later" { - bitcoin-cli \ - -regtest \ - -datadir="$bitcoin_datadir" \ - -rpcuser="$rpc_user" \ - -rpcpassword="$rpc_pass" \ - -rpcport="$rpc_port" \ - -named createwallet \ - wallet_name=wallet.dat \ - descriptors=true \ - disable_private_keys=true >/dev/null - sed \ - "s/^rpc_wallet_file =.*/rpc_wallet_file = wallet.dat/" \ - "$joinmarket_cfg" >"${joinmarket_cfg}.legacy" - mv "${joinmarket_cfg}.legacy" "$joinmarket_cfg" - - load_joininbox_bitcoin_functions - - run check_rpc_wallet_with_enter - - [ "$status" -eq 0 ] - [[ "$output" == *"Migrating the configured Bitcoin Core wallet"* ]] - [[ "$output" == *"WALLET MIGRATION NOTICE"* ]] - grep -q "^rpc_wallet_file = watch-only-descriptor-wallet$" "$joinmarket_cfg" - grep -q "^walletMigrationDone=true$" "$joinin_conf" - - run wallet_info - [ "$status" -eq 0 ] - [ "$(jq -r '.descriptors' <<<"$output")" = "true" ] - [ "$(jq -r '.private_keys_enabled' <<<"$output")" = "false" ] -} - -@test "migrateLegacyRPCWalletConfig keeps wallet.dat on Bitcoin Core v29.2" { - sed \ - "s/^rpc_wallet_file =.*/rpc_wallet_file = wallet.dat/" \ - "$joinmarket_cfg" >"${joinmarket_cfg}.legacy" - mv "${joinmarket_cfg}.legacy" "$joinmarket_cfg" - - load_joininbox_bitcoin_functions - getConnectedBitcoinCoreVersion() { - echo 290200 - } - getRPC >/dev/null - - run migrateLegacyRPCWalletConfig - - [ "$status" -eq 0 ] - [[ "$output" == *"v29.x or earlier; keeping wallet.dat"* ]] - grep -q "^rpc_wallet_file = wallet.dat$" "$joinmarket_cfg" -} - -@test "checkWalletMigration shows the notice once when wallet.dat exists" { - bitcoin-cli \ - -regtest \ - -datadir="$bitcoin_datadir" \ - -rpcuser="$rpc_user" \ - -rpcpassword="$rpc_pass" \ - -rpcport="$rpc_port" \ - -named createwallet \ - wallet_name=wallet.dat \ - descriptors=true \ - disable_private_keys=true >/dev/null - - load_joininbox_bitcoin_functions - # shellcheck disable=SC2034 - rpc_host="127.0.0.1" - # shellcheck disable=SC2034 - rpc_wallet="watch-only-descriptor-wallet" - - run check_wallet_migration_with_enter - - [ "$status" -eq 0 ] - [[ "$output" == *"WALLET MIGRATION NOTICE"* ]] - grep -q "^walletMigrationDone=true$" "$joinin_conf" - - run checkWalletMigration - [ "$status" -eq 0 ] - [ "$output" = "" ] -} diff --git a/test/run-bats-local.sh b/test/run-bats-local.sh deleted file mode 100755 index ee7320b..0000000 --- a/test/run-bats-local.sh +++ /dev/null @@ -1,11 +0,0 @@ -#!/usr/bin/env bash -set -euo pipefail - -cd "$(dirname "$0")/.." - -if ! command -v bats >/dev/null 2>&1; then - echo "bats is required. Install bats-core, then rerun this script." >&2 - exit 127 -fi - -bats test/bats diff --git a/typos.toml b/typos.toml index b2ca07e..46ea55e 100644 --- a/typos.toml +++ b/typos.toml @@ -7,5 +7,4 @@ [default.extend-words] # don't correct these false positives ba = "ba" -ned = "ned" -fpr = "fpr" +ned = "ned" \ No newline at end of file