From d3457f81cdd2aa09f0c29e60302f136c9326b246 Mon Sep 17 00:00:00 2001 From: kenshin-samourai Date: Thu, 23 Apr 2020 15:21:05 +0200 Subject: [PATCH] expose whirlpool api as a hidden service --- doc/DOCKER_advanced_setups.md | 60 +++--- docker/my-dojo/conf/docker-whirlpool.conf.tpl | 8 - docker/my-dojo/docker-compose.yaml | 1 + docker/my-dojo/dojo.sh | 10 +- docker/my-dojo/install/install-scripts.sh | 13 ++ docker/my-dojo/install/upgrade-scripts.sh | 13 ++ docker/my-dojo/nginx/Dockerfile | 1 + docker/my-dojo/nginx/whirlpool.conf | 15 ++ .../my-dojo/overrides/whirlpool.install.yaml | 9 +- docker/my-dojo/tor/restart.sh | 7 + docker/my-dojo/whirlpool/Dockerfile | 11 +- docker/my-dojo/whirlpool/restart.sh | 2 + docker/my-dojo/whirlpool/wait-for-it.sh | 178 ------------------ 13 files changed, 99 insertions(+), 229 deletions(-) create mode 100644 docker/my-dojo/nginx/whirlpool.conf delete mode 100644 docker/my-dojo/whirlpool/wait-for-it.sh diff --git a/doc/DOCKER_advanced_setups.md b/doc/DOCKER_advanced_setups.md index a463267..f82f653 100644 --- a/doc/DOCKER_advanced_setups.md +++ b/doc/DOCKER_advanced_setups.md @@ -124,7 +124,7 @@ nano ./conf/docker-node.conf This setup allows to install and run a [Whirlpool client](https://github.com/Samourai-Wallet/whirlpool-client-cli) inside MyDojo. -Note: In order to interact with the Whirlpool client, you'll need to install the [Whirlpool GUI application]((https://github.com/Samourai-Wallet/whirlpool-gui)) on a computer (either the machine running MyDojo or any computer connected to your LAN). +The client can be configured and controlled through a REST API exposed as a Tor hidden service. ### Procedure ### @@ -138,14 +138,15 @@ nano ./conf/docker-whirlpool.conf # # Set the value of WHIRLPOOL_INSTALL to "on" -# If you plan to run whirlpool-gui on a machine than isn't the machine running MyDojo, set the value of WHIRLPOOL_RPC_EXTERNAL_IP with the IP address of the machine hosting MyDojo. Do not use the public IP address of the machine, use its address on your LAN (192.168.xXX.xxx). -# Save and exit nano +## Save and exit nano # ``` -### Initialization with Whirlppol GUI ### +### Installation of Whirlppol GUI ### + +The [Whirlpool GUI application]((https://github.com/Samourai-Wallet/whirlpool-gui)) provides a graphical interface for your Whirlpool client. -These steps describe how to connect the Whirlpool GUI application ([whirlpool-gui](https://github.com/Samourai-Wallet/whirlpool-gui/releases)) to your Whirlpool client. +These steps describe how to install the Whirlpool GUI application how a computer and how to connect it to your Whirlpool client. **Requirements** @@ -154,27 +155,42 @@ These steps describe how to connect the Whirlpool GUI application ([whirlpool-gu - Whirlpool client has been activated in MyDojo, - Your Samourai Wallet is paired to MyDojo, - MyDojo is running. +- Tor browser is installed on the computer that will run the Whirlpool GUI application. **Procedure** -``` -# Install the Whirlpool GUI application on a computer and launch it. - -# Select 'Connect to remote CLI'. -# Insert the value of WHIRLPOOL_RPC_EXTERNAL_IP in the first block -# For example, you should insert `https://172.30.1.8` if WHIRLPOOL_RPC_EXTERNAL_IP is set to `172.30.1.8` -# Keep the Port 8899 and API pairing key BLANK. Click 'Connect'. - -# Paste the pairing payload from your mobile device when prompted: -# Select the Samourai Wallet Menu (3 dots top right), -# Go to Settings -> Transactions -> Pair to Whirlpool GUI, -# Copy the payload and send to your main computer using any method you prefer, -# Paste the payload. - -# The GUI will restart and prompt for you to enter your Samourai Wallet passphrase. -# You are all set and ready to mix! -``` +- Retrieve the onion address of the API provided by your Whirlpool client + + ``` + # Open a terminal console on the computer hosting your Dojo + + # Retrieve the onion address of the Whirlpool API + ./dojo.sh onion + ``` + +- Install and configure the Whirlpool GUI application + + ``` + # If needed, install Tor browser on the computer that will run the Whirlpool GUI application + + # Install the Whirlpool GUI application on the computer and launch it. + + # Select 'Connect to remote CLI'. + # Insert the onion address of the Whirlpool API, **prefixed by HTTP**, in the first block + # Set the port to 80 + # Let the API pairing key BLANK. + # Click 'Connect'. + + # Paste the pairing payload from your mobile device when prompted: + # Select the Samourai Wallet Menu (3 dots top right), + # Go to Settings -> Transactions -> Pair to Whirlpool GUI, + # Copy the payload and send to your main computer using any method you prefer, + # Paste the payload. + + # The GUI will restart and prompt for you to enter your Samourai Wallet passphrase. + # You are all set and ready to mix! + ``` diff --git a/docker/my-dojo/conf/docker-whirlpool.conf.tpl b/docker/my-dojo/conf/docker-whirlpool.conf.tpl index b12fde6..763be16 100644 --- a/docker/my-dojo/conf/docker-whirlpool.conf.tpl +++ b/docker/my-dojo/conf/docker-whirlpool.conf.tpl @@ -5,11 +5,3 @@ # Install and run an instance of whirlpool-cli inside Docker # Value: on | off WHIRLPOOL_INSTALL=off - -# IP address used to expose the RPC API of whirlpool-cli to external apps -# Warning: Do not expose your RPC API to internet! -# Recommended value: -# if whirlpool-gui runs on the machine hosting dojo: 172.30.1.8 (default) -# otherwise: IP address on the LAN of the machine running dojo -# Type: string -WHIRLPOOL_RPC_EXTERNAL_IP=172.30.1.8 diff --git a/docker/my-dojo/docker-compose.yaml b/docker/my-dojo/docker-compose.yaml index 07b2cf2..7c0d69e 100644 --- a/docker/my-dojo/docker-compose.yaml +++ b/docker/my-dojo/docker-compose.yaml @@ -81,6 +81,7 @@ services: env_file: - ./.env - ./conf/docker-explorer.conf + - ./conf/docker-whirlpool.conf - ./conf/docker-tor.conf restart: always command: /restart.sh diff --git a/docker/my-dojo/dojo.sh b/docker/my-dojo/dojo.sh index a7cb363..c845e07 100755 --- a/docker/my-dojo/dojo.sh +++ b/docker/my-dojo/dojo.sh @@ -23,7 +23,6 @@ source_file "$DIR/.env" # Export some variables for compose export BITCOIND_RPC_EXTERNAL_IP -export WHIRLPOOL_RPC_EXTERNAL_IP # Select YAML files select_yaml_files() { @@ -315,10 +314,6 @@ upgrade() { # Load env vars for compose files source_file "$DIR/conf/docker-bitcoind.conf" export BITCOIND_RPC_EXTERNAL_IP - if [ "$WHIRLPOOL_INSTALL" == "on" ]; then - source_file "$DIR/conf/docker-whirlpool.conf" - export WHIRLPOOL_RPC_EXTERNAL_IP - fi # Rebuild the images (with or without cache) if [ $noCache -eq 0 ]; then eval "docker-compose $yamlFiles build --no-cache" @@ -346,6 +341,11 @@ onion() { V3_ADDR=$( docker exec -it tor cat /var/lib/tor/hsv3dojo/hostname ) echo "Maintenance Tool hidden service address = $V3_ADDR" + if [ "$WHIRLPOOL_INSTALL" == "on" ]; then + V3_ADDR_WHIRLPOOL=$( docker exec -it tor cat /var/lib/tor/hsv3whirlpool/hostname ) + echo "Whirlpool API hidden service address = $V3_ADDR_WHIRLPOOL" + fi + if [ "$BITCOIND_INSTALL" == "on" ]; then V2_ADDR_BTCD=$( docker exec -it tor cat /var/lib/tor/hsv2bitcoind/hostname ) echo "bitcoind hidden service address = $V2_ADDR_BTCD" diff --git a/docker/my-dojo/install/install-scripts.sh b/docker/my-dojo/install/install-scripts.sh index 1a348df..50170f5 100755 --- a/docker/my-dojo/install/install-scripts.sh +++ b/docker/my-dojo/install/install-scripts.sh @@ -12,6 +12,12 @@ else source ./conf/docker-explorer.conf.tpl fi +if [ -f ./conf/docker-whirlpool.conf ]; then + source ./conf/docker-whirlpool.conf +else + source ./conf/docker-whirlpool.conf.tpl +fi + if [ -f ./conf/docker-common.conf ]; then source ./conf/docker-common.conf else @@ -86,6 +92,13 @@ init_config_files() { fi echo "Initialized dojo-explorer.conf (nginx)" + if [ "$WHIRLPOOL_INSTALL" == "on" ]; then + cp ./nginx/whirlpool.conf ./nginx/dojo-whirlpool.conf + else + cp /dev/null ./nginx/dojo-ewhirlpool.conf + fi + echo "Initialized dojo-whirlpool.conf (nginx)" + # Initialize config files for nginx and the maintenance tool if [ "$COMMON_BTC_NETWORK" == "testnet" ]; then cp ./nginx/testnet.conf ./nginx/dojo.conf diff --git a/docker/my-dojo/install/upgrade-scripts.sh b/docker/my-dojo/install/upgrade-scripts.sh index db54460..40795ed 100755 --- a/docker/my-dojo/install/upgrade-scripts.sh +++ b/docker/my-dojo/install/upgrade-scripts.sh @@ -12,6 +12,12 @@ else source ./conf/docker-explorer.conf.tpl fi +if [ -f ./conf/docker-whirlpool.conf ]; then + source ./conf/docker-whirlpool.conf +else + source ./conf/docker-whirlpool.conf.tpl +fi + source ./conf/docker-bitcoind.conf # Confirm upgrade operation @@ -71,6 +77,13 @@ update_config_files() { fi echo "Initialized dojo-explorer.conf (nginx)" + if [ "$WHIRLPOOL_INSTALL" == "on" ]; then + cp ./nginx/whirlpool.conf ./nginx/dojo-whirlpool.conf + else + cp /dev/null ./nginx/dojo-ewhirlpool.conf + fi + echo "Initialized dojo-whirlpool.conf (nginx)" + if [ "$COMMON_BTC_NETWORK" == "testnet" ]; then cp ./nginx/testnet.conf ./nginx/dojo.conf echo "Initialized dojo.conf (nginx)" diff --git a/docker/my-dojo/nginx/Dockerfile b/docker/my-dojo/nginx/Dockerfile index 93db47a..1c440e4 100644 --- a/docker/my-dojo/nginx/Dockerfile +++ b/docker/my-dojo/nginx/Dockerfile @@ -10,6 +10,7 @@ RUN mkdir -p "$LOGS_DIR" && \ COPY ./nginx.conf /etc/nginx/nginx.conf COPY ./dojo.conf /etc/nginx/sites-enabled/dojo.conf COPY ./dojo-explorer.conf /etc/nginx/sites-enabled/dojo-explorer.conf +COPY ./dojo-whirlpool.conf /etc/nginx/sites-enabled/dojo-whirlpool.conf # Copy wait-for script COPY ./wait-for /wait-for diff --git a/docker/my-dojo/nginx/whirlpool.conf b/docker/my-dojo/nginx/whirlpool.conf new file mode 100644 index 0000000..a10dc98 --- /dev/null +++ b/docker/my-dojo/nginx/whirlpool.conf @@ -0,0 +1,15 @@ +server { + listen 8898; + server_name _; + resolver 127.0.0.11 valid=30s; + + location / { + set $upstream http://whirlpool:8898; + proxy_pass $upstream; + proxy_http_version 1.1; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection 'upgrade'; + proxy_set_header Host $host; + proxy_cache_bypass $http_upgrade; + } +} diff --git a/docker/my-dojo/overrides/whirlpool.install.yaml b/docker/my-dojo/overrides/whirlpool.install.yaml index e879dbe..2e35673 100644 --- a/docker/my-dojo/overrides/whirlpool.install.yaml +++ b/docker/my-dojo/overrides/whirlpool.install.yaml @@ -9,18 +9,13 @@ services: env_file: - ./.env - ./conf/docker-common.conf - - ./conf/docker-node.conf - ./conf/docker-whirlpool.conf restart: always - command: "/wait-for-it.sh nginx:80 --timeout=720 --strict -- /restart.sh" + command: /restart.sh expose: - - "8899" - ports: - - "${WHIRLPOOL_RPC_EXTERNAL_IP}:8899:8899" + - "8898" volumes: - data-whirlpool:/home/whirlpool - depends_on: - - nginx networks: whirlnet: ipv4_address: 172.30.1.8 diff --git a/docker/my-dojo/tor/restart.sh b/docker/my-dojo/tor/restart.sh index e99aa1e..1cf4458 100644 --- a/docker/my-dojo/tor/restart.sh +++ b/docker/my-dojo/tor/restart.sh @@ -32,6 +32,13 @@ if [ "$EXPLORER_INSTALL" == "on" ]; then tor_options+=(--HiddenServiceDirGroupReadable 1) fi +if [ "$WHIRLPOOL_INSTALL" == "on" ]; then + tor_options+=(--HiddenServiceDir /var/lib/tor/hsv3whirlpool) + tor_options+=(--HiddenServiceVersion 3) + tor_options+=(--HiddenServicePort "80 172.29.1.3:8898") + tor_options+=(--HiddenServiceDirGroupReadable 1) +fi + if [ "$TOR_USE_BRIDGES" == "on" ]; then tor_options+=(--ClientTransportPlugin "obfs4 exec /usr/local/bin/obfs4proxy") tor_options+=(--UseBridges 1) diff --git a/docker/my-dojo/whirlpool/Dockerfile b/docker/my-dojo/whirlpool/Dockerfile index 1e4b2a6..4620070 100644 --- a/docker/my-dojo/whirlpool/Dockerfile +++ b/docker/my-dojo/whirlpool/Dockerfile @@ -71,15 +71,8 @@ RUN chown whirlpool:whirlpool /restart.sh && \ chmod u+x /restart.sh && \ chmod g+x /restart.sh -# Copy wait-for-it script -COPY ./wait-for-it.sh /wait-for-it.sh - -RUN chown whirlpool:whirlpool /wait-for-it.sh && \ - chmod u+x /wait-for-it.sh && \ - chmod g+x /wait-for-it.sh - -# Expose API port -EXPOSE 8899 +# Expose HTTP API port +EXPOSE 8898 # Switch to user whirlpool USER whirlpool diff --git a/docker/my-dojo/whirlpool/restart.sh b/docker/my-dojo/whirlpool/restart.sh index 9354a69..dd08d71 100644 --- a/docker/my-dojo/whirlpool/restart.sh +++ b/docker/my-dojo/whirlpool/restart.sh @@ -3,6 +3,8 @@ set -e whirlpool_options=( --listen + --cli.api.http-enable=true + --cli.api.http-port=8898 --cli.dojo.enabled=true --cli.tor=true --cli.torConfig.executable=/usr/local/bin/tor diff --git a/docker/my-dojo/whirlpool/wait-for-it.sh b/docker/my-dojo/whirlpool/wait-for-it.sh deleted file mode 100644 index 071c2be..0000000 --- a/docker/my-dojo/whirlpool/wait-for-it.sh +++ /dev/null @@ -1,178 +0,0 @@ -#!/usr/bin/env bash -# Use this script to test if a given TCP host/port are available - -WAITFORIT_cmdname=${0##*/} - -echoerr() { if [[ $WAITFORIT_QUIET -ne 1 ]]; then echo "$@" 1>&2; fi } - -usage() -{ - cat << USAGE >&2 -Usage: - $WAITFORIT_cmdname host:port [-s] [-t timeout] [-- command args] - -h HOST | --host=HOST Host or IP under test - -p PORT | --port=PORT TCP port under test - Alternatively, you specify the host and port as host:port - -s | --strict Only execute subcommand if the test succeeds - -q | --quiet Don't output any status messages - -t TIMEOUT | --timeout=TIMEOUT - Timeout in seconds, zero for no timeout - -- COMMAND ARGS Execute command with args after the test finishes -USAGE - exit 1 -} - -wait_for() -{ - if [[ $WAITFORIT_TIMEOUT -gt 0 ]]; then - echoerr "$WAITFORIT_cmdname: waiting $WAITFORIT_TIMEOUT seconds for $WAITFORIT_HOST:$WAITFORIT_PORT" - else - echoerr "$WAITFORIT_cmdname: waiting for $WAITFORIT_HOST:$WAITFORIT_PORT without a timeout" - fi - WAITFORIT_start_ts=$(date +%s) - while : - do - if [[ $WAITFORIT_ISBUSY -eq 1 ]]; then - nc -z $WAITFORIT_HOST $WAITFORIT_PORT - WAITFORIT_result=$? - else - (echo > /dev/tcp/$WAITFORIT_HOST/$WAITFORIT_PORT) >/dev/null 2>&1 - WAITFORIT_result=$? - fi - if [[ $WAITFORIT_result -eq 0 ]]; then - WAITFORIT_end_ts=$(date +%s) - echoerr "$WAITFORIT_cmdname: $WAITFORIT_HOST:$WAITFORIT_PORT is available after $((WAITFORIT_end_ts - WAITFORIT_start_ts)) seconds" - break - fi - sleep 1 - done - return $WAITFORIT_result -} - -wait_for_wrapper() -{ - # In order to support SIGINT during timeout: http://unix.stackexchange.com/a/57692 - if [[ $WAITFORIT_QUIET -eq 1 ]]; then - timeout $WAITFORIT_BUSYTIMEFLAG $WAITFORIT_TIMEOUT $0 --quiet --child --host=$WAITFORIT_HOST --port=$WAITFORIT_PORT --timeout=$WAITFORIT_TIMEOUT & - else - timeout $WAITFORIT_BUSYTIMEFLAG $WAITFORIT_TIMEOUT $0 --child --host=$WAITFORIT_HOST --port=$WAITFORIT_PORT --timeout=$WAITFORIT_TIMEOUT & - fi - WAITFORIT_PID=$! - trap "kill -INT -$WAITFORIT_PID" INT - wait $WAITFORIT_PID - WAITFORIT_RESULT=$? - if [[ $WAITFORIT_RESULT -ne 0 ]]; then - echoerr "$WAITFORIT_cmdname: timeout occurred after waiting $WAITFORIT_TIMEOUT seconds for $WAITFORIT_HOST:$WAITFORIT_PORT" - fi - return $WAITFORIT_RESULT -} - -# process arguments -while [[ $# -gt 0 ]] -do - case "$1" in - *:* ) - WAITFORIT_hostport=(${1//:/ }) - WAITFORIT_HOST=${WAITFORIT_hostport[0]} - WAITFORIT_PORT=${WAITFORIT_hostport[1]} - shift 1 - ;; - --child) - WAITFORIT_CHILD=1 - shift 1 - ;; - -q | --quiet) - WAITFORIT_QUIET=1 - shift 1 - ;; - -s | --strict) - WAITFORIT_STRICT=1 - shift 1 - ;; - -h) - WAITFORIT_HOST="$2" - if [[ $WAITFORIT_HOST == "" ]]; then break; fi - shift 2 - ;; - --host=*) - WAITFORIT_HOST="${1#*=}" - shift 1 - ;; - -p) - WAITFORIT_PORT="$2" - if [[ $WAITFORIT_PORT == "" ]]; then break; fi - shift 2 - ;; - --port=*) - WAITFORIT_PORT="${1#*=}" - shift 1 - ;; - -t) - WAITFORIT_TIMEOUT="$2" - if [[ $WAITFORIT_TIMEOUT == "" ]]; then break; fi - shift 2 - ;; - --timeout=*) - WAITFORIT_TIMEOUT="${1#*=}" - shift 1 - ;; - --) - shift - WAITFORIT_CLI=("$@") - break - ;; - --help) - usage - ;; - *) - echoerr "Unknown argument: $1" - usage - ;; - esac -done - -if [[ "$WAITFORIT_HOST" == "" || "$WAITFORIT_PORT" == "" ]]; then - echoerr "Error: you need to provide a host and port to test." - usage -fi - -WAITFORIT_TIMEOUT=${WAITFORIT_TIMEOUT:-15} -WAITFORIT_STRICT=${WAITFORIT_STRICT:-0} -WAITFORIT_CHILD=${WAITFORIT_CHILD:-0} -WAITFORIT_QUIET=${WAITFORIT_QUIET:-0} - -# check to see if timeout is from busybox? -WAITFORIT_TIMEOUT_PATH=$(type -p timeout) -WAITFORIT_TIMEOUT_PATH=$(realpath $WAITFORIT_TIMEOUT_PATH 2>/dev/null || readlink -f $WAITFORIT_TIMEOUT_PATH) -if [[ $WAITFORIT_TIMEOUT_PATH =~ "busybox" ]]; then - WAITFORIT_ISBUSY=1 - WAITFORIT_BUSYTIMEFLAG="-t" - -else - WAITFORIT_ISBUSY=0 - WAITFORIT_BUSYTIMEFLAG="" -fi - -if [[ $WAITFORIT_CHILD -gt 0 ]]; then - wait_for - WAITFORIT_RESULT=$? - exit $WAITFORIT_RESULT -else - if [[ $WAITFORIT_TIMEOUT -gt 0 ]]; then - wait_for_wrapper - WAITFORIT_RESULT=$? - else - wait_for - WAITFORIT_RESULT=$? - fi -fi - -if [[ $WAITFORIT_CLI != "" ]]; then - if [[ $WAITFORIT_RESULT -ne 0 && $WAITFORIT_STRICT -eq 1 ]]; then - echoerr "$WAITFORIT_cmdname: strict mode, refusing to execute subprocess" - exit $WAITFORIT_RESULT - fi - exec "${WAITFORIT_CLI[@]}" -else - exit $WAITFORIT_RESULT -fi