diff --git a/rootfs/standard/etc/systemd/system/jmg.service b/rootfs/standard/etc/systemd/system/jmg.service new file mode 100644 index 000000000..4c55915d7 --- /dev/null +++ b/rootfs/standard/etc/systemd/system/jmg.service @@ -0,0 +1,26 @@ +# JoinMarket GUI service +# /etc/systemd/system/jmg.service + +[Unit] +Description=JMG +Wants=bitcoin.service jmwalletd.service +After=bitcoin.service jmwalletd.service + +[Service] +ExecStartPre=/usr/bin/is_not_shutting_down.sh +ExecStartPre=/usr/bin/is_mainnet.sh +WorkingDirectory=/opt/mynode/jmg +ExecStart=/bin/sh -c 'cd /opt/mynode/jmg && ./jmg_venv/bin/python src/app.py' + +User=joinmarket +Group=joinmarket +Type=simple +TimeoutSec=120 +Restart=always +RestartSec=30 +StandardOutput=syslog +StandardError=syslog +SyslogIdentifier=jmg + +[Install] +WantedBy=multi-user.target \ No newline at end of file diff --git a/rootfs/standard/etc/systemd/system/jmwalletd.service b/rootfs/standard/etc/systemd/system/jmwalletd.service new file mode 100644 index 000000000..e68847ede --- /dev/null +++ b/rootfs/standard/etc/systemd/system/jmwalletd.service @@ -0,0 +1,26 @@ +# JoinMarket Wallet service +# /etc/systemd/system/jmwalletd.service + +[Unit] +Description=JoinMarketWallet +Wants=bitcoin.service +After=bitcoin.service + +[Service] +ExecStartPre=/usr/bin/is_not_shutting_down.sh +ExecStartPre=/usr/bin/is_mainnet.sh +WorkingDirectory=/home/joinmarket/joinmarket-clientserver +ExecStart=/bin/sh -c 'cd /home/joinmarket/joinmarket-clientserver && ./jmvenv/bin/python scripts/jmwalletd.py' + +User=joinmarket +Group=joinmarket +Type=simple +TimeoutSec=120 +Restart=always +RestartSec=30 +StandardOutput=syslog +StandardError=syslog +SyslogIdentifier=jmwalletd + +[Install] +WantedBy=multi-user.target \ No newline at end of file diff --git a/rootfs/standard/usr/bin/mynode_firewall.sh b/rootfs/standard/usr/bin/mynode_firewall.sh index 3ecfc3d0c..75fd3952d 100755 --- a/rootfs/standard/usr/bin/mynode_firewall.sh +++ b/rootfs/standard/usr/bin/mynode_firewall.sh @@ -48,6 +48,7 @@ ufw allow 4080 comment 'allow Mempool' ufw allow 4081 comment 'allow Mempool HTTPS' ufw allow 5000 comment 'allow LNBits' ufw allow 5001 comment 'allow LNBits HTTPS' +ufw allow 5002 comment 'allow Joinmarket GUI' ufw allow 5010 comment 'allow Warden Terminal' ufw allow 5011 comment 'allow Warden Terminal HTTPS' ufw allow 5353 comment 'allow Avahi' diff --git a/rootfs/standard/usr/bin/mynode_post_upgrade.sh b/rootfs/standard/usr/bin/mynode_post_upgrade.sh index 8387ccd96..8f502c2c9 100755 --- a/rootfs/standard/usr/bin/mynode_post_upgrade.sh +++ b/rootfs/standard/usr/bin/mynode_post_upgrade.sh @@ -634,6 +634,41 @@ if should_install_app "joininbox" ; then fi fi +# Install JoinMarket GUI +if should_install_app "jmg"; then + if [ $IS_RASPI = 1 ] || [ $IS_X86 = 1 ]; then + JMG_UPGRADE_URL=https://github.com/manasgandy/joinmarket-gui/archive/refs/tags/$JMG_VERSION.tar.gz + CURRENT="" + if [ -f $JMG_VERSION_FILE ]; then + CURRENT=$(cat $JMG_VERSION_FILE) + fi + if [ "$CURRENT" != "$JMG_VERSION" ]; then + # Download and build JoinMarket GUI + cd /opt/mynode + + # Delete previous version + rm -rf jmg + + sudo -u bitcoin wget $JMG_UPGRADE_URL -O jmg.tar.gz + sudo -u bitcoin tar -xvf jmg.tar.gz + sudo -u bitcoin rm jmg.tar.gz + mv joinmarket-gui-* jmg + cd jmg + + # Install dependencies + sudo -u bitcoin python3 -m venv jmg_venv + sudo -u bitcoin ./jmg_venv/bin/pip install -r requirements.txt + + # Setup TLS certificates + cd /home/joinmarket + sudo -u joinmarket mkdir -p .joinmarket/ssl + sudo -u joinmarket openssl req -newkey rsa:4096 -x509 -sha256 -days 3650 -nodes -batch -out /home/joinmarket/.joinmarket/ssl/cert.pem -keyout /home/joinmarket/.joinmarket/ssl/key.pem + + echo $JMG_VERSION > $JMG_VERSION_FILE + fi + fi +fi + # Install Whirlpool if should_install_app "whirlpool" ; then WHIRLPOOL_UPGRADE_URL=https://code.samourai.io/whirlpool/whirlpool-client-cli/uploads/$WHIRLPOOL_UPLOAD_FILE_ID/whirlpool-client-cli-$WHIRLPOOL_VERSION-run.jar @@ -1065,6 +1100,8 @@ systemctl enable loop systemctl enable pool systemctl enable rotate_logs systemctl enable corsproxy_btcrpc +systemctl enable jmwalletd +systemctl enable jmg # Disable any old services systemctl disable bitcoind || true diff --git a/rootfs/standard/usr/bin/mynode_uninstall_app.sh b/rootfs/standard/usr/bin/mynode_uninstall_app.sh index 4afa89d28..4cfb84db3 100755 --- a/rootfs/standard/usr/bin/mynode_uninstall_app.sh +++ b/rootfs/standard/usr/bin/mynode_uninstall_app.sh @@ -45,6 +45,8 @@ elif [ "$APP" = "joininbox" ]; then rm -rf /home/joinmarket/* rm -rf /home/joinmarket/joininbox-* rm -rf /home/joinmarket/.cache +elif [ "$APP" = "jmg" ]; then + rm -rf /home/joinmarket/jmg elif [ "$APP" = "lndhub" ]; then rm -rf /opt/mynode/LndHub elif [ "$APP" = "lndmanage" ]; then diff --git a/rootfs/standard/usr/bin/mynode_update_latest_version_files.sh b/rootfs/standard/usr/bin/mynode_update_latest_version_files.sh index 8ce25ca29..c6dc9c5ab 100755 --- a/rootfs/standard/usr/bin/mynode_update_latest_version_files.sh +++ b/rootfs/standard/usr/bin/mynode_update_latest_version_files.sh @@ -14,6 +14,7 @@ echo $CARAVAN_VERSION > $CARAVAN_LATEST_VERSION_FILE echo $CORSPROXY_VERSION > $CORSPROXY_LATEST_VERSION_FILE echo $JOINMARKET_VERSION > $JOINMARKET_LATEST_VERSION_FILE echo $JOININBOX_VERSION > $JOININBOX_LATEST_VERSION_FILE +echo $JMG_VERSION > $JMG_LATEST_VERSION_FILE echo $SECP256K1_VERSION > $SECP256K1_LATEST_VERSION_FILE echo $WHIRLPOOL_VERSION > $WHIRLPOOL_LATEST_VERSION_FILE echo $DOJO_VERSION > $DOJO_LATEST_VERSION_FILE diff --git a/rootfs/standard/usr/share/mynode/application_info.json b/rootfs/standard/usr/share/mynode/application_info.json index 7e1ae6559..5a02f5271 100644 --- a/rootfs/standard/usr/share/mynode/application_info.json +++ b/rootfs/standard/usr/share/mynode/application_info.json @@ -147,14 +147,12 @@ "can_uninstall": true, "show_on_homepage": true, "homepage_order": 24, - "can_enable_disable": false, - "is_premium": true + "can_enable_disable": false }, { "name": "Joinmarket", "short_name": "joinmarket", - "show_on_application_page": false, - "is_premium": true + "show_on_application_page": false }, { "name": "Thunderhub", @@ -319,5 +317,12 @@ "short_name": "ufw", "show_on_application_page": false, "journalctl_log_name": "ufw" + }, + { + "name": "Joinmarket GUI", + "short_name": "jmg", + "requires_bitcoin": true, + "show_on_homepage": true, + "requires_jmwalletd": true } ] \ No newline at end of file diff --git a/rootfs/standard/usr/share/mynode/mynode_app_versions.sh b/rootfs/standard/usr/share/mynode/mynode_app_versions.sh index 2751868fd..4a3d5ff7b 100644 --- a/rootfs/standard/usr/share/mynode/mynode_app_versions.sh +++ b/rootfs/standard/usr/share/mynode/mynode_app_versions.sh @@ -57,6 +57,10 @@ JOININBOX_VERSION="v0.6.4" JOININBOX_VERSION_FILE=/home/bitcoin/.mynode/joininbox_version JOININBOX_LATEST_VERSION_FILE=/home/bitcoin/.mynode/joininbox_version_latest +JMG_VERSION="v0.4.1" +JMG_VERSION_FILE=/home/bitcoin/.mynode/jmg_version +JMG_LATEST_VERSION_FILE=/home/bitcoin/.mynode/jmg_version_latest + SECP256K1_VERSION=486205aa68b7f1d4291f78fa20bc4485fd843e1c SECP256K1_VERSION_FILE=/home/bitcoin/.mynode/secp256k1_version SECP256K1_LATEST_VERSION_FILE=/home/bitcoin/.mynode/secp256k1_version_latest diff --git a/rootfs/standard/var/www/mynode/application_info.py b/rootfs/standard/var/www/mynode/application_info.py index 364ef595e..494c1ac1d 100644 --- a/rootfs/standard/var/www/mynode/application_info.py +++ b/rootfs/standard/var/www/mynode/application_info.py @@ -114,6 +114,7 @@ def initialize_application_defaults(app): if not "requires_electrs" in app: app["requires_electrs"] = False if not "requires_bitcoin" in app: app["requires_bitcoin"] = False if not "requires_docker_image_installation" in app: app["requires_docker_image_installation"] = False + if not "requires_jmwalletd" in app: app["requires_jmwalletd"] = False if not "supports_testnet" in app: app["supports_testnet"] = False if not "show_on_homepage" in app: app["show_on_homepage"] = False if not "show_on_application_page" in app: app["show_on_application_page"] = True @@ -287,6 +288,8 @@ def get_application_status(short_name): return to_string(app["app_tile_default_status_text"]) if app["requires_bitcoin"] and not is_bitcoin_synced(): return "Waiting on Bitcoin" + if app["requires_jmwalletd"] and not is_service_active('jmwalletd'): + return "Waiting on Joinmarket Daemon" # Check special cases @@ -337,6 +340,8 @@ def get_application_status_color(short_name): return "yellow" if app["requires_electrs"] and not is_electrs_active(): return "yellow" + if app["requires_jmwalletd"] and not is_service_active('jmwalletd'): + return "yellow" # Check special cases special_status_color = get_application_status_color_special(short_name) diff --git a/rootfs/standard/var/www/mynode/mynode.py b/rootfs/standard/var/www/mynode/mynode.py index e0e446f7e..cb7810488 100644 --- a/rootfs/standard/var/www/mynode/mynode.py +++ b/rootfs/standard/var/www/mynode/mynode.py @@ -431,6 +431,7 @@ def index(): lnd_status_color = "red" lnd_ready = is_lnd_ready() electrs_active = is_electrs_active() + jmwalletd_running = is_service_active('jmwalletd') bitcoin_status = "Inactive" lnd_status = "Inactive" electrs_status = "" @@ -546,6 +547,7 @@ def index(): "lnd_tx_display_limit": 6, "lnd_channels": get_lightning_channels(), "electrs_active": electrs_active, + "jmwalletd_running": jmwalletd_running, "btcpayserver_onion": get_onion_url_btcpay(), "lndhub_onion": get_onion_url_lndhub(), "lnbits_onion": get_onion_url_lnbits(), diff --git a/rootfs/standard/var/www/mynode/static/images/jmg.png b/rootfs/standard/var/www/mynode/static/images/jmg.png new file mode 100644 index 000000000..9076e7f4d Binary files /dev/null and b/rootfs/standard/var/www/mynode/static/images/jmg.png differ diff --git a/rootfs/standard/var/www/mynode/systemctl_info.py b/rootfs/standard/var/www/mynode/systemctl_info.py index 5ce80502d..b42312cd3 100644 --- a/rootfs/standard/var/www/mynode/systemctl_info.py +++ b/rootfs/standard/var/www/mynode/systemctl_info.py @@ -23,6 +23,14 @@ def is_service_enabled(service_name): service_enabled_cache[service_name] = False return False +def is_service_active(service_name): + try: + if subprocess.check_output("systemctl is-active {}".format(service_name), shell=True).decode('utf8') == 'active\n': + return True + except: + return False + return False + def get_service_status_code(service_name): code = os.system("systemctl status {} --no-pager > /dev/null".format(service_name)) return code @@ -31,7 +39,7 @@ def get_service_status_basic_text(service_name): if not is_service_enabled(service_name): return "Disabled" - code = os.system("systemctl status {} --no-pager > /dev/null".format(service_name)) + code = os.systm("systemctl status {} --no-pager > /dev/null".format(service_name)) if code == 0: return "Running" return "Error" diff --git a/rootfs/standard/var/www/mynode/templates/includes/apps.html b/rootfs/standard/var/www/mynode/templates/includes/apps.html index 78bf87aaa..6005f0511 100644 --- a/rootfs/standard/var/www/mynode/templates/includes/apps.html +++ b/rootfs/standard/var/www/mynode/templates/includes/apps.html @@ -20,6 +20,7 @@ {% if lnd_ready or ( not lnd_ready and not app.requires_lightning ) %} {% if electrs_active or ( not electrs_active and not app.requires_electrs ) %} {% if not is_installing_docker_images or ( is_installing_docker_images and not app.requires_docker_image_installation ) %} + {% if jmwalletd_running or (not jmwalletd_running and not app.requires_jmwalletd) %} {% if app.is_enabled or not app.can_enable_disable %} {{app.app_tile_button_text}} {% endif %} @@ -32,6 +33,7 @@ {% endif %} {% endif %} {% endif %} + {% endif %} {% endif %} diff --git a/rootfs/standard/var/www/mynode/templates/main.html b/rootfs/standard/var/www/mynode/templates/main.html index 9c0942362..157d8c182 100644 --- a/rootfs/standard/var/www/mynode/templates/main.html +++ b/rootfs/standard/var/www/mynode/templates/main.html @@ -474,6 +474,18 @@ window.open(url,'_blank'); }) + // Joinmarket GUI + $("#jmg").on("click", function() { + hostname=location.hostname + port="5002" + url = location.protocol+'//'+hostname+':'+port + window.open(url,'_blank'); + }) + + if ($("#jmg_status_icon").attr('class').split(' ').indexOf('yellow') != -1) { + $("#jmg").hide(); + } + $("#lnbits").on("click", function() { hostname=location.hostname port_string=""