From 9cf1177b736f2dbab194fb8366cbcde1b4159d24 Mon Sep 17 00:00:00 2001 From: Dorian Date: Wed, 22 Apr 2026 09:06:10 -0400 Subject: [PATCH] release(v1.7.36-alpha): bitcoin-core in App Store + Sovereignty Stack + dynamic catalog URL MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - neode-ui/public/assets/img/app-icons/bitcoin-core.svg (NEW): 256×256 Umbrel community Bitcoin icon sourced from getumbrel.github.io/ umbrel-apps-gallery/bitcoin/icon.svg. Referenced by the static catalog, the curated fallback, and the upstream lfg2025/app-catalog entry so every surface shows the same image. - app-catalog/catalog.json + neode-ui/public/catalog.json: add bitcoin-core (v28.4) entry pointing at bitcoin/bitcoin:28.4. Same entry pushed to the lfg2025/app-catalog repo on .160 and the local gitea mirror so nodes see it without needing a full archipelago update. Sovereignty Stack entry added to FEATURED_DEFINITIONS with a description that frames it as a Knots alternative, not a rival. - core/archipelago/src/api/handler/mod.rs: handle_app_catalog_proxy is now instance-scoped (&self) and derives its upstream list from load_registries — each active container registry contributes one `:///app-catalog/raw/branch/main/catalog.json` URL in priority order (scheme follows tls_verify). When the operator switches mirrors in Settings, the App Store now follows. Falls back to the legacy hardcoded .160/tx1138 pair only when registry config can't be loaded, so the App Store still renders on nodes that haven't persisted one yet. Co-Authored-By: Claude Opus 4.7 (1M context) --- app-catalog/catalog.json | 10 +++- core/Cargo.lock | 2 +- core/archipelago/Cargo.toml | 2 +- core/archipelago/src/api/handler/mod.rs | 49 ++++++++++++++----- neode-ui/package-lock.json | 4 +- neode-ui/package.json | 2 +- .../assets/img/app-icons/bitcoin-core.svg | 14 ++++++ neode-ui/public/catalog.json | 12 +++++ neode-ui/src/views/discover/curatedApps.ts | 6 +++ 9 files changed, 84 insertions(+), 17 deletions(-) create mode 100644 neode-ui/public/assets/img/app-icons/bitcoin-core.svg diff --git a/app-catalog/catalog.json b/app-catalog/catalog.json index 8029a456..f9e2caa8 100644 --- a/app-catalog/catalog.json +++ b/app-catalog/catalog.json @@ -1,6 +1,6 @@ { "version": 2, - "updated": "2026-04-12T00:00:00Z", + "updated": "2026-04-22T00:00:00Z", "registry": "git.tx1138.com/lfg2025", "featured": { "id": "indeedhub", @@ -18,6 +18,14 @@ "dockerImage": "git.tx1138.com/lfg2025/bitcoin-knots:latest", "repoUrl": "https://github.com/bitcoinknots/bitcoin" }, + { + "id": "bitcoin-core", "title": "Bitcoin Core", "version": "28.4", + "description": "Reference implementation of the Bitcoin protocol. Run a full node validating and relaying blocks.", + "icon": "/assets/img/app-icons/bitcoin-core.svg", + "author": "Bitcoin Core contributors", "category": "money", "tier": "optional", + "dockerImage": "bitcoin/bitcoin:28.4", + "repoUrl": "https://github.com/bitcoin/bitcoin" + }, { "id": "lnd", "title": "LND", "version": "0.18.4", "description": "Lightning Network Daemon. Fast Bitcoin payments through Lightning.", diff --git a/core/Cargo.lock b/core/Cargo.lock index c6f934ad..367f9e4d 100644 --- a/core/Cargo.lock +++ b/core/Cargo.lock @@ -80,7 +80,7 @@ checksum = "a23eb6b1614318a8071c9b2521f36b424b2c83db5eb3a0fead4a6c0809af6e61" [[package]] name = "archipelago" -version = "1.7.35-alpha" +version = "1.7.36-alpha" dependencies = [ "anyhow", "archipelago-container", diff --git a/core/archipelago/Cargo.toml b/core/archipelago/Cargo.toml index 7ba26acb..8e318633 100644 --- a/core/archipelago/Cargo.toml +++ b/core/archipelago/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "archipelago" -version = "1.7.35-alpha" +version = "1.7.36-alpha" edition = "2021" description = "Archipelago Bitcoin Node OS - Native backend" authors = ["Archipelago Team"] diff --git a/core/archipelago/src/api/handler/mod.rs b/core/archipelago/src/api/handler/mod.rs index d0ffacf9..56d6da11 100644 --- a/core/archipelago/src/api/handler/mod.rs +++ b/core/archipelago/src/api/handler/mod.rs @@ -115,14 +115,41 @@ impl ApiHandler { /// Server-side fetch of the upstream app catalog so the browser can /// load it without fighting CORS (git.tx1138.com emits no ACAO) or - /// CSP (the fallback IP-port URL isn't in `connect-src`). Tries the - /// upstream URLs in the same order the frontend used, returns the - /// first 2xx response. 15s total timeout. - async fn handle_app_catalog_proxy() -> Result> { - const UPSTREAMS: &[&str] = &[ - "http://23.182.128.160:3000/lfg2025/app-catalog/raw/branch/main/catalog.json", - "https://git.tx1138.com/lfg2025/app-catalog/raw/branch/main/catalog.json", - ]; + /// CSP (the fallback IP-port URL isn't in `connect-src`). The upstream + /// list is derived from the operator's configured container registries + /// so switching mirrors in Settings changes the App Store source too — + /// each active registry contributes one Gitea `raw/branch/main/catalog.json` + /// URL (http or https per `tls_verify`), tried in priority order. + /// If registry config can't be loaded, falls back to the legacy + /// hardcoded pair so the App Store still renders on nodes that haven't + /// persisted a registry config yet. 15s total timeout. + async fn handle_app_catalog_proxy(&self) -> Result> { + let mut upstreams: Vec = Vec::new(); + if let Ok(config) = + crate::container::registry::load_registries(&self.config.data_dir).await + { + for reg in config.active_registries() { + let scheme = if reg.tls_verify { "https" } else { "http" }; + // Gitea raw URL: :////app-catalog/raw/branch/main/catalog.json. + // reg.url already includes the namespace (e.g. "host/lfg2025"), + // so we just tack on the repo + raw path. + upstreams.push(format!( + "{}://{}/app-catalog/raw/branch/main/catalog.json", + scheme, reg.url + )); + } + } + if upstreams.is_empty() { + upstreams.push( + "http://23.182.128.160:3000/lfg2025/app-catalog/raw/branch/main/catalog.json" + .to_string(), + ); + upstreams.push( + "https://git.tx1138.com/lfg2025/app-catalog/raw/branch/main/catalog.json" + .to_string(), + ); + } + let client = match reqwest::Client::builder() .timeout(std::time::Duration::from_secs(15)) .build() @@ -136,8 +163,8 @@ impl ApiHandler { )); } }; - for url in UPSTREAMS { - match client.get(*url).send().await { + for url in &upstreams { + match client.get(url).send().await { Ok(resp) if resp.status().is_success() => { if let Ok(bytes) = resp.bytes().await { return Ok(Response::builder() @@ -408,7 +435,7 @@ impl ApiHandler { if !self.is_authenticated(&headers).await { return Ok(Self::unauthorized()); } - Self::handle_app_catalog_proxy().await + self.handle_app_catalog_proxy().await } // LND connect info — nginx validates session cookie (presence check), diff --git a/neode-ui/package-lock.json b/neode-ui/package-lock.json index 0d619a1a..e056e49a 100644 --- a/neode-ui/package-lock.json +++ b/neode-ui/package-lock.json @@ -1,12 +1,12 @@ { "name": "neode-ui", - "version": "1.6.0-alpha", + "version": "1.7.36-alpha", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "neode-ui", - "version": "1.6.0-alpha", + "version": "1.7.36-alpha", "dependencies": { "@types/dompurify": "^3.0.5", "@vue-leaflet/vue-leaflet": "^0.10.1", diff --git a/neode-ui/package.json b/neode-ui/package.json index 40a3b1f3..4f27614d 100644 --- a/neode-ui/package.json +++ b/neode-ui/package.json @@ -1,7 +1,7 @@ { "name": "neode-ui", "private": true, - "version": "1.7.35-alpha", + "version": "1.7.36-alpha", "type": "module", "scripts": { "start": "./start-dev.sh", diff --git a/neode-ui/public/assets/img/app-icons/bitcoin-core.svg b/neode-ui/public/assets/img/app-icons/bitcoin-core.svg new file mode 100644 index 00000000..74fb0304 --- /dev/null +++ b/neode-ui/public/assets/img/app-icons/bitcoin-core.svg @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + diff --git a/neode-ui/public/catalog.json b/neode-ui/public/catalog.json index 9946ba78..06fe281b 100644 --- a/neode-ui/public/catalog.json +++ b/neode-ui/public/catalog.json @@ -22,6 +22,18 @@ "category": "money", "tier": "core" }, + { + "id": "bitcoin-core", + "title": "Bitcoin Core", + "version": "28.4", + "description": "Reference implementation of the Bitcoin protocol. Run a full node validating and relaying blocks on the Bitcoin network.", + "icon": "/assets/img/app-icons/bitcoin-core.svg", + "author": "Bitcoin Core contributors", + "dockerImage": "bitcoin/bitcoin:28.4", + "repoUrl": "https://github.com/bitcoin/bitcoin", + "category": "money", + "tier": "optional" + }, { "id": "lnd", "title": "LND", diff --git a/neode-ui/src/views/discover/curatedApps.ts b/neode-ui/src/views/discover/curatedApps.ts index 36809aa2..539ea621 100644 --- a/neode-ui/src/views/discover/curatedApps.ts +++ b/neode-ui/src/views/discover/curatedApps.ts @@ -77,6 +77,7 @@ export async function fetchAppCatalog(): Promise { export function getCuratedAppList(): MarketplaceApp[] { return [ { id: 'bitcoin-knots', title: 'Bitcoin Knots', version: '28.1.0', description: 'Run a full Bitcoin node. Validate and relay blocks and transactions on the Bitcoin network.', icon: '/assets/img/app-icons/bitcoin-knots.webp', author: 'Bitcoin Knots', dockerImage: `${R}/bitcoin-knots:latest`, repoUrl: 'https://github.com/bitcoinknots/bitcoin' }, + { id: 'bitcoin-core', title: 'Bitcoin Core', version: '28.4', description: 'Reference implementation of the Bitcoin protocol. Run a full node validating and relaying blocks on the Bitcoin network.', icon: '/assets/img/app-icons/bitcoin-core.svg', author: 'Bitcoin Core contributors', dockerImage: 'bitcoin/bitcoin:28.4', repoUrl: 'https://github.com/bitcoin/bitcoin' }, { id: 'btcpay-server', title: 'BTCPay Server', version: '1.13.7', description: 'Self-hosted Bitcoin payment processor. Accept Bitcoin payments without intermediaries or fees.', icon: '/assets/img/app-icons/btcpay-server.png', author: 'BTCPay Server Foundation', dockerImage: `${R}/btcpayserver:1.13.7`, repoUrl: 'https://github.com/btcpayserver/btcpayserver' }, { id: 'lnd', title: 'LND', version: '0.18.4', description: 'Lightning Network Daemon. Fast and cheap Bitcoin payments through the Lightning Network.', icon: '/assets/img/app-icons/lnd.svg', author: 'Lightning Labs', dockerImage: `${R}/lnd:v0.18.4-beta`, repoUrl: 'https://github.com/lightningnetwork/lnd' }, { id: 'mempool', title: 'Mempool Explorer', version: '3.0.0', description: 'Self-hosted Bitcoin blockchain and mempool visualizer. Monitor transactions without revealing your addresses to third parties.', icon: '/assets/img/app-icons/mempool.webp', author: 'Mempool', dockerImage: `${R}/mempool-frontend:v3.0.0`, repoUrl: 'https://github.com/mempool/mempool' }, @@ -164,6 +165,11 @@ export const FEATURED_DEFINITIONS: { desc: 'The foundation of sovereignty. Run a full Bitcoin node to validate every transaction yourself. No trusted third parties. No asking permission. Your node enforces the consensus rules that protect your wealth. Don\'t trust — verify.', tag: 'FULL VALIDATION // ZERO TRUST', }, + { + id: 'bitcoin-core', + desc: 'The reference Bitcoin implementation. Same full-node guarantees as Knots, tracking upstream releases from the Bitcoin Core maintainers. Pick this if you\'d rather run mainline Bitcoin Core than Knots — both validate every block themselves.', + tag: 'REFERENCE CLIENT // ZERO TRUST', + }, { id: 'lnd', desc: 'Lightning-fast payments over the Lightning Network. Open channels, route transactions, and earn routing fees — all from your sovereign node. Instant settlement. Near-zero fees. The future of money, running on your hardware.',