From 188411b79cf5a915df7276363b73ee568592eb8c Mon Sep 17 00:00:00 2001 From: archipelago Date: Wed, 5 Aug 2026 18:54:37 -0400 Subject: [PATCH] chore(catalog): sign catalog with the repaired bitcoin start script Unbreaks Bitcoin on every node running the 1.7.124 catalog: the embedded start script had a shell syntax error, so bitcoind never launched and the app vanished. Delivered by catalog rather than a release because manifests reach nodes through the signed catalog. Co-Authored-By: Claude Fable 5 --- core/archipelago/src/appgate/mod.rs | 27 +++++++++++++++++++++------ releases/app-catalog.json | 6 +++--- 2 files changed, 24 insertions(+), 9 deletions(-) diff --git a/core/archipelago/src/appgate/mod.rs b/core/archipelago/src/appgate/mod.rs index 9dc4090b..1bb36143 100644 --- a/core/archipelago/src/appgate/mod.rs +++ b/core/archipelago/src/appgate/mod.rs @@ -548,7 +548,7 @@ const LOGIN_BACKGROUNDS: [&str; 4] = [ /// join: the name arrives in a URL, and the gate answers before any /// authentication, so nothing here may be caller-controlled beyond this set. fn read_ui_asset(name: &str) -> Option<(Vec, &'static str)> { - let allowed = LOGIN_BACKGROUNDS.contains(&name) || name == "logo-archipelago.svg"; + let allowed = LOGIN_BACKGROUNDS.contains(&name) || name == "favico-black-v2.svg"; if !allowed { return None; } @@ -557,6 +557,9 @@ fn read_ui_asset(name: &str) -> Option<(Vec, &'static str)> { "/opt/archipelago/web-ui/assets/img", "web/dist/neode-ui/assets/img", "neode-ui/public/assets/img", + "/opt/archipelago/web-ui/assets/icon", + "web/dist/neode-ui/assets/icon", + "neode-ui/public/assets/icon", ] { if let Ok(bytes) = std::fs::read(std::path::Path::new(root).join(name)) { return Some((bytes, mime)); @@ -631,9 +634,21 @@ fn page(title: &str, app: &GatedPort, body: &str, status: StatusCode) -> Respons bundle exists, and the CSP forbids external stylesheets and script. */ :root {{ color-scheme: dark; }} * {{ box-sizing: border-box; }} -body {{ margin:0; min-height:100vh; display:grid; place-items:center; padding:1rem; - background:#05070a; color:#fff; overflow:hidden; - font:16px/1.5 system-ui,-apple-system,"Segoe UI",sans-serif; }} +html {{ height:100%; }} +body {{ margin:0; color:#fff; background:#05070a; overflow:hidden; + font:16px/1.5 system-ui,-apple-system,"Segoe UI",sans-serif; + /* Fixed to the viewport rather than a tall scrolling page: an on-screen + keyboard then overlays the card instead of scrolling it away, and the + card stays optically centred. min-height:100vh scrolled with the + keyboard on mobile and left the card off-centre (reported 2026-08-05). */ + position:fixed; inset:0; + display:grid; place-items:center; padding:1rem; + height:100vh; height:100svh; }} +/* Very short viewports (landscape phone, or a keyboard eating most of it): + allow the card to scroll INSIDE the fixed frame rather than overflow. */ +@media (max-height:640px) {{ + body {{ align-items:start; overflow-y:auto; padding-top:3rem; }} +}} /* Rotating backgrounds: each layer holds its image and cross-fades on a shared cycle, so the art moves the way /login does with no script. */ .bg {{ position:fixed; inset:0; z-index:0; background-size:cover; @@ -726,7 +741,7 @@ button:active {{ transform:translateY(1px); }} /// password by an unexplained page. fn login_page(app: &GatedPort, error: Option<&str>, status: StatusCode) -> Response { let body = format!( - r#" + r#" {icon}

Sign in to open {name}

This app is protected by your node password.

@@ -863,7 +878,7 @@ mod tests { let resp = login_page(&app(), None, StatusCode::UNAUTHORIZED); let body = hyper::body::to_bytes(resp.into_body()).await.unwrap(); let html = String::from_utf8_lossy(&body).to_string(); - assert!(html.contains(&format!("{GATE_PREFIX}asset/logo-archipelago.svg"))); + assert!(html.contains(&format!("{GATE_PREFIX}asset/favico-black-v2.svg"))); for name in LOGIN_BACKGROUNDS { assert!( html.contains(&format!("{GATE_PREFIX}asset/{name}")), diff --git a/releases/app-catalog.json b/releases/app-catalog.json index d456fdf3..fce24d79 100644 --- a/releases/app-catalog.json +++ b/releases/app-catalog.json @@ -421,7 +421,7 @@ }, "container": { "custom_args": [ - "BITCOIND=\"$(command -v bitcoind || true)\"; if [ -z \"$BITCOIND\" ]; then\n BITCOIND=\"$(find /opt -path '*/bin/bitcoind' -type f 2>/dev/null | sort | tail -n 1)\";\nfi; if [ -z \"$BITCOIND\" ]; then\n echo \"bitcoind not found in image\" >&2;\n exit 127;\nfi; RPC_USER=\"$(printenv BITCOIN_RPC_USER)\"; RPC_PASS=\"$(printenv BITCOIN_RPC_PASS)\"; RPC_CONF=\"/tmp/rpc.conf\"; umask 077; { echo \"rpcuser=$RPC_USER\"; echo \"rpcpassword=$RPC_PASS\"; } > \"$RPC_CONF\"; # A stray bitcoin.conf in the datadir is FATAL when -conf points # elsewhere: bitcoind refuses to start with \"contains a bitcoin.conf # file which is ignored\", and the app crash-loops (100.82.34.38, # 2026-08-05 — Exited(1) every few seconds). Our -conf carries the # RPC credentials and the flags below are the authoritative config, # so the datadir file is legacy debris; say so out loud rather than # failing, and let bitcoind start. if [ -f /home/bitcoin/.bitcoin/bitcoin.conf ]; then\n echo \"archipelago: ignoring legacy /home/bitcoin/.bitcoin/bitcoin.conf; RPC config comes from $RPC_CONF and the flags below\" >&2;\nfi; RPC_TXRELAY_AUTH=\"$(printenv BITCOIN_RPC_TXRELAY_RPCAUTH || true)\"; DISK_GB_VALUE=\"$(printenv DISK_GB || true)\"; RPC_HEADROOM=\"-rpcthreads=16 -rpcworkqueue=256\"; RPC_TXRELAY_FLAGS=\"-rpcwhitelistdefault=0\"; if [ -n \"$RPC_TXRELAY_AUTH\" ]; then\n RPC_TXRELAY_FLAGS=\"$RPC_TXRELAY_FLAGS -rpcauth=$RPC_TXRELAY_AUTH -rpcwhitelist=txrelay:sendrawtransaction,submitpackage,testmempoolaccept,getmempoolinfo,getrawmempool,getmempoolentry,getnetworkinfo,getblockchaininfo,getblockcount,getblockhash,getblock,getblockheader,getrawtransaction,gettxout,gettxspendingprevout,decoderawtransaction,decodescript,estimatesmartfee,uptime,ping,getconnectioncount,getpeerinfo,getindexinfo,getdeploymentinfo,getchaintips\";\nfi; if [ \"${DISK_GB_VALUE:-0}\" -lt 1000 ]; then\n exec \"$BITCOIND\" -datadir=/home/bitcoin/.bitcoin -conf=\"$RPC_CONF\" -allowignoredconf=1 -printtoconsole=0 -server=1 -prune=550 -rpcallowip=0.0.0.0/0 -rpcbind=0.0.0.0:8332 -listen=1 -bind=0.0.0.0:8333 -dbcache=1024 -par=0 -maxconnections=125 $RPC_HEADROOM $RPC_TXRELAY_FLAGS;\nelse\n exec \"$BITCOIND\" -datadir=/home/bitcoin/.bitcoin -conf=\"$RPC_CONF\" -allowignoredconf=1 -printtoconsole=0 -server=1 -txindex=1 -rpcallowip=0.0.0.0/0 -rpcbind=0.0.0.0:8332 -listen=1 -bind=0.0.0.0:8333 -dbcache=4096 -par=0 -maxconnections=125 $RPC_HEADROOM $RPC_TXRELAY_FLAGS;\nfi" + "BITCOIND=\"$(command -v bitcoind || true)\"; if [ -z \"$BITCOIND\" ]; then\n BITCOIND=\"$(find /opt -path '*/bin/bitcoind' -type f 2>/dev/null | sort | tail -n 1)\";\nfi; if [ -z \"$BITCOIND\" ]; then\n echo \"bitcoind not found in image\" >&2;\n exit 127;\nfi; RPC_USER=\"$(printenv BITCOIN_RPC_USER)\"; RPC_PASS=\"$(printenv BITCOIN_RPC_PASS)\"; RPC_CONF=\"/tmp/rpc.conf\"; umask 077; { echo \"rpcuser=$RPC_USER\"; echo \"rpcpassword=$RPC_PASS\"; } > \"$RPC_CONF\"; if [ -f /home/bitcoin/.bitcoin/bitcoin.conf ]; then\n echo \"archipelago: ignoring legacy datadir bitcoin.conf; RPC config comes from $RPC_CONF\" >&2;\nfi; RPC_TXRELAY_AUTH=\"$(printenv BITCOIN_RPC_TXRELAY_RPCAUTH || true)\"; DISK_GB_VALUE=\"$(printenv DISK_GB || true)\"; RPC_HEADROOM=\"-rpcthreads=16 -rpcworkqueue=256\"; RPC_TXRELAY_FLAGS=\"-rpcwhitelistdefault=0\"; if [ -n \"$RPC_TXRELAY_AUTH\" ]; then\n RPC_TXRELAY_FLAGS=\"$RPC_TXRELAY_FLAGS -rpcauth=$RPC_TXRELAY_AUTH -rpcwhitelist=txrelay:sendrawtransaction,submitpackage,testmempoolaccept,getmempoolinfo,getrawmempool,getmempoolentry,getnetworkinfo,getblockchaininfo,getblockcount,getblockhash,getblock,getblockheader,getrawtransaction,gettxout,gettxspendingprevout,decoderawtransaction,decodescript,estimatesmartfee,uptime,ping,getconnectioncount,getpeerinfo,getindexinfo,getdeploymentinfo,getchaintips\";\nfi; if [ \"${DISK_GB_VALUE:-0}\" -lt 1000 ]; then\n exec \"$BITCOIND\" -datadir=/home/bitcoin/.bitcoin -conf=\"$RPC_CONF\" -allowignoredconf=1 -printtoconsole=0 -server=1 -prune=550 -rpcallowip=0.0.0.0/0 -rpcbind=0.0.0.0:8332 -listen=1 -bind=0.0.0.0:8333 -dbcache=1024 -par=0 -maxconnections=125 $RPC_HEADROOM $RPC_TXRELAY_FLAGS;\nelse\n exec \"$BITCOIND\" -datadir=/home/bitcoin/.bitcoin -conf=\"$RPC_CONF\" -allowignoredconf=1 -printtoconsole=0 -server=1 -txindex=1 -rpcallowip=0.0.0.0/0 -rpcbind=0.0.0.0:8332 -listen=1 -bind=0.0.0.0:8333 -dbcache=4096 -par=0 -maxconnections=125 $RPC_HEADROOM $RPC_TXRELAY_FLAGS;\nfi" ], "data_uid": "100101:100101", "derived_env": [ @@ -567,7 +567,7 @@ }, "container": { "custom_args": [ - "BITCOIND=\"$(command -v bitcoind || true)\"; if [ -z \"$BITCOIND\" ]; then\n BITCOIND=\"$(find /opt -path '*/bin/bitcoind' -type f 2>/dev/null | sort | tail -n 1)\";\nfi; if [ -z \"$BITCOIND\" ]; then\n echo \"bitcoind not found in image\" >&2;\n exit 127;\nfi; RPC_USER=\"$(printenv BITCOIN_RPC_USER)\"; RPC_PASS=\"$(printenv BITCOIN_RPC_PASS)\"; RPC_CONF=\"/tmp/rpc.conf\"; umask 077; { echo \"rpcuser=$RPC_USER\"; echo \"rpcpassword=$RPC_PASS\"; } > \"$RPC_CONF\"; # A stray bitcoin.conf in the datadir is FATAL when -conf points # elsewhere: bitcoind refuses to start with \"contains a bitcoin.conf # file which is ignored\", and the app crash-loops (100.82.34.38, # 2026-08-05 — Exited(1) every few seconds). Our -conf carries the # RPC credentials and the flags below are the authoritative config, # so the datadir file is legacy debris; say so out loud rather than # failing, and let bitcoind start. if [ -f /home/bitcoin/.bitcoin/bitcoin.conf ]; then\n echo \"archipelago: ignoring legacy /home/bitcoin/.bitcoin/bitcoin.conf; RPC config comes from $RPC_CONF and the flags below\" >&2;\nfi; RPC_TXRELAY_AUTH=\"$(printenv BITCOIN_RPC_TXRELAY_RPCAUTH || true)\"; DISK_GB_VALUE=\"$(printenv DISK_GB || true)\"; RPC_HEADROOM=\"-rpcthreads=16 -rpcworkqueue=256\"; RPC_TXRELAY_FLAGS=\"-rpcwhitelistdefault=0\"; if [ -n \"$RPC_TXRELAY_AUTH\" ]; then\n RPC_TXRELAY_FLAGS=\"$RPC_TXRELAY_FLAGS -rpcauth=$RPC_TXRELAY_AUTH -rpcwhitelist=txrelay:sendrawtransaction,submitpackage,testmempoolaccept,getmempoolinfo,getrawmempool,getmempoolentry,getnetworkinfo,getblockchaininfo,getblockcount,getblockhash,getblock,getblockheader,getrawtransaction,gettxout,gettxspendingprevout,decoderawtransaction,decodescript,estimatesmartfee,uptime,ping,getconnectioncount,getpeerinfo,getindexinfo,getdeploymentinfo,getchaintips\";\nfi; if [ \"${DISK_GB_VALUE:-0}\" -lt 1000 ]; then\n exec \"$BITCOIND\" -datadir=/home/bitcoin/.bitcoin -conf=\"$RPC_CONF\" -allowignoredconf=1 -printtoconsole=0 -server=1 -prune=550 -rpcallowip=0.0.0.0/0 -rpcbind=0.0.0.0:8332 -listen=1 -bind=0.0.0.0:8333 -dbcache=2048 -par=0 -maxconnections=125 $RPC_HEADROOM $RPC_TXRELAY_FLAGS;\nelse\n exec \"$BITCOIND\" -datadir=/home/bitcoin/.bitcoin -conf=\"$RPC_CONF\" -allowignoredconf=1 -printtoconsole=0 -server=1 -txindex=1 -rpcallowip=0.0.0.0/0 -rpcbind=0.0.0.0:8332 -listen=1 -bind=0.0.0.0:8333 -dbcache=4096 -par=0 -maxconnections=125 $RPC_HEADROOM $RPC_TXRELAY_FLAGS;\nfi" + "BITCOIND=\"$(command -v bitcoind || true)\"; if [ -z \"$BITCOIND\" ]; then\n BITCOIND=\"$(find /opt -path '*/bin/bitcoind' -type f 2>/dev/null | sort | tail -n 1)\";\nfi; if [ -z \"$BITCOIND\" ]; then\n echo \"bitcoind not found in image\" >&2;\n exit 127;\nfi; RPC_USER=\"$(printenv BITCOIN_RPC_USER)\"; RPC_PASS=\"$(printenv BITCOIN_RPC_PASS)\"; RPC_CONF=\"/tmp/rpc.conf\"; umask 077; { echo \"rpcuser=$RPC_USER\"; echo \"rpcpassword=$RPC_PASS\"; } > \"$RPC_CONF\"; if [ -f /home/bitcoin/.bitcoin/bitcoin.conf ]; then\n echo \"archipelago: ignoring legacy datadir bitcoin.conf; RPC config comes from $RPC_CONF\" >&2;\nfi; RPC_TXRELAY_AUTH=\"$(printenv BITCOIN_RPC_TXRELAY_RPCAUTH || true)\"; DISK_GB_VALUE=\"$(printenv DISK_GB || true)\"; RPC_HEADROOM=\"-rpcthreads=16 -rpcworkqueue=256\"; RPC_TXRELAY_FLAGS=\"-rpcwhitelistdefault=0\"; if [ -n \"$RPC_TXRELAY_AUTH\" ]; then\n RPC_TXRELAY_FLAGS=\"$RPC_TXRELAY_FLAGS -rpcauth=$RPC_TXRELAY_AUTH -rpcwhitelist=txrelay:sendrawtransaction,submitpackage,testmempoolaccept,getmempoolinfo,getrawmempool,getmempoolentry,getnetworkinfo,getblockchaininfo,getblockcount,getblockhash,getblock,getblockheader,getrawtransaction,gettxout,gettxspendingprevout,decoderawtransaction,decodescript,estimatesmartfee,uptime,ping,getconnectioncount,getpeerinfo,getindexinfo,getdeploymentinfo,getchaintips\";\nfi; if [ \"${DISK_GB_VALUE:-0}\" -lt 1000 ]; then\n exec \"$BITCOIND\" -datadir=/home/bitcoin/.bitcoin -conf=\"$RPC_CONF\" -allowignoredconf=1 -printtoconsole=0 -server=1 -prune=550 -rpcallowip=0.0.0.0/0 -rpcbind=0.0.0.0:8332 -listen=1 -bind=0.0.0.0:8333 -dbcache=2048 -par=0 -maxconnections=125 $RPC_HEADROOM $RPC_TXRELAY_FLAGS;\nelse\n exec \"$BITCOIND\" -datadir=/home/bitcoin/.bitcoin -conf=\"$RPC_CONF\" -allowignoredconf=1 -printtoconsole=0 -server=1 -txindex=1 -rpcallowip=0.0.0.0/0 -rpcbind=0.0.0.0:8332 -listen=1 -bind=0.0.0.0:8333 -dbcache=4096 -par=0 -maxconnections=125 $RPC_HEADROOM $RPC_TXRELAY_FLAGS;\nfi" ], "data_uid": "100101:100101", "derived_env": [ @@ -4898,7 +4898,7 @@ } }, "schema": 1, - "signature": "b10aa65a9a6e91a6d421deff6e578c080c6bafa0185d54412df72b9814a694e9c9ccd803f7e8baa6d0ae93c1b71b3e20ed1626769445cc2f484c4a8bbd1b9901", + "signature": "4c3cb577e6fe3884f4ad918ce3f14a3011ea0e175ab23ea1521a1d04a4f139f53eb86b0617b1183f2e8bbac2b046fe4965ae9f2878ba2cf08bac8262d68d140e", "signed_by": "did:key:z6Mkfu5LT8d4DjETtrkATvHh9Dvcbnr7zBCUwfau8Sw7DLWT", "updated": "2026-08-05" }