Compare commits
3 Commits
v1.7.22-al
...
v1.7.25-al
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5c634baa6d | ||
|
|
41474047bf | ||
|
|
005bbd9a9a |
2
core/Cargo.lock
generated
2
core/Cargo.lock
generated
@@ -80,7 +80,7 @@ checksum = "a23eb6b1614318a8071c9b2521f36b424b2c83db5eb3a0fead4a6c0809af6e61"
|
||||
|
||||
[[package]]
|
||||
name = "archipelago"
|
||||
version = "1.7.22-alpha"
|
||||
version = "1.7.25-alpha"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"archipelago-container",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "archipelago"
|
||||
version = "1.7.22-alpha"
|
||||
version = "1.7.25-alpha"
|
||||
edition = "2021"
|
||||
description = "Archipelago Bitcoin Node OS - Native backend"
|
||||
authors = ["Archipelago Team"]
|
||||
|
||||
@@ -13,22 +13,27 @@ use anyhow::{Context, Result};
|
||||
use std::path::Path;
|
||||
use tokio::process::Command;
|
||||
|
||||
use super::{DAEMON_CONFIG_PATH, DAEMON_KEY_PATH, DAEMON_PUB_PATH, DEFAULT_UDP_PORT};
|
||||
use super::{DAEMON_CONFIG_PATH, DAEMON_KEY_PATH, DAEMON_PUB_PATH, DEFAULT_TCP_PORT, DEFAULT_UDP_PORT};
|
||||
|
||||
/// Write the FIPS daemon config based on the local npub and default
|
||||
/// transports. Overwrites any existing file — callers are expected to
|
||||
/// re-run this whenever the key or daemon version changes.
|
||||
///
|
||||
/// Schema is intentionally minimal: node identity comes from the key
|
||||
/// file on disk (the daemon handles it), transports enable UDP + Tor,
|
||||
/// IPv6 TUN + DNS on defaults. Static peer list is empty — archipelago
|
||||
/// feeds peers dynamically via federation updates.
|
||||
/// file on disk (the daemon handles it), transports enable UDP + TCP
|
||||
/// (matching upstream factory default), IPv6 TUN + DNS on defaults.
|
||||
/// Static peer list is empty — archipelago feeds peers dynamically via
|
||||
/// the seed-anchors apply loop and federation-invite hooks.
|
||||
pub fn render_config_yaml() -> String {
|
||||
// Schema matches upstream jmcorgan/fips as of 2026-04. With
|
||||
// `node.identity.persistent: true` the daemon reuses the key file at
|
||||
// config-dir/fips.key (= DAEMON_KEY_PATH). Transports take `bind_addr`
|
||||
// rather than `enabled: true / port: N`, and the upstream no longer
|
||||
// has a `tor:` transport — archipelago's own Tor fallback handles that.
|
||||
// rather than `enabled: true / port: N`. Both UDP and TCP are
|
||||
// enabled by default because the public anchor (fips.v0l.io)
|
||||
// currently answers on TCP/8443 only, and networks that block UDP
|
||||
// outbound can still bootstrap via TCP. Upstream fips no longer
|
||||
// has a `tor:` transport variant — archipelago's own Tor fallback
|
||||
// handles that layer.
|
||||
format!(
|
||||
"# Generated by archipelago — do not edit by hand.\n\
|
||||
# Regenerated on every key change and daemon upgrade.\n\
|
||||
@@ -44,9 +49,12 @@ pub fn render_config_yaml() -> String {
|
||||
bind_addr: \"127.0.0.1\"\n\
|
||||
transports:\n \
|
||||
udp:\n \
|
||||
bind_addr: \"0.0.0.0:{port}\"\n\
|
||||
bind_addr: \"0.0.0.0:{udp}\"\n \
|
||||
tcp:\n \
|
||||
bind_addr: \"0.0.0.0:{tcp}\"\n\
|
||||
peers: []\n",
|
||||
port = DEFAULT_UDP_PORT,
|
||||
udp = DEFAULT_UDP_PORT,
|
||||
tcp = DEFAULT_TCP_PORT,
|
||||
)
|
||||
}
|
||||
|
||||
@@ -185,7 +193,9 @@ mod tests {
|
||||
let yaml = render_config_yaml();
|
||||
assert!(yaml.contains("persistent: true"));
|
||||
assert!(yaml.contains(&format!("0.0.0.0:{}", DEFAULT_UDP_PORT)));
|
||||
assert!(yaml.contains(&format!("0.0.0.0:{}", DEFAULT_TCP_PORT)));
|
||||
assert!(yaml.contains("udp:"));
|
||||
assert!(yaml.contains("tcp:"));
|
||||
assert!(yaml.contains("tun:"));
|
||||
assert!(yaml.contains("name: fips0"));
|
||||
// Upstream fips dropped the `tor:` transport variant; archipelago
|
||||
|
||||
@@ -53,6 +53,14 @@ pub const UPSTREAM_REPO: &str = "jmcorgan/fips";
|
||||
/// Default UDP port the daemon listens on.
|
||||
pub const DEFAULT_UDP_PORT: u16 = 8668;
|
||||
|
||||
/// Default TCP port the daemon listens on. Used as a fallback when a
|
||||
/// peer can't be reached over UDP — common on networks that block UDP
|
||||
/// (corporate/guest wifi) and the path the public fips.v0l.io anchor
|
||||
/// currently accepts. Upstream factory default enables both transports
|
||||
/// and archipelago intentionally matches that baseline so fresh nodes
|
||||
/// can reach the broader FIPS mesh without operator config.
|
||||
pub const DEFAULT_TCP_PORT: u16 = 8443;
|
||||
|
||||
/// Upstream systemd unit shipped by the `fips` debian package. Archipelago
|
||||
/// prefers its own supervision (`archipelago-fips.service`) but respects an
|
||||
/// already-running upstream unit so legacy/dev nodes — where no seed-derived
|
||||
|
||||
@@ -510,10 +510,37 @@ impl Server {
|
||||
tracing::warn!("FIPS key load/migrate failed: {}", e);
|
||||
return;
|
||||
}
|
||||
// Check if the installed fips.yaml matches what we'd
|
||||
// render now. If not, we need to restart the daemon after
|
||||
// reinstalling so it picks up schema changes (e.g. the
|
||||
// v1.7.25 re-addition of the TCP transport). Without this,
|
||||
// OTA'd nodes would be stuck on the old UDP-only config
|
||||
// until someone manually clicked Reconnect.
|
||||
let expected = crate::fips::config::render_config_yaml();
|
||||
let installed = tokio::fs::read_to_string("/etc/fips/fips.yaml")
|
||||
.await
|
||||
.ok();
|
||||
let config_changed = installed.as_deref() != Some(expected.as_str());
|
||||
|
||||
if let Err(e) = crate::fips::config::install(&identity_dir).await {
|
||||
tracing::warn!("FIPS config install failed on startup: {}", e);
|
||||
return;
|
||||
}
|
||||
if config_changed {
|
||||
tracing::info!(
|
||||
"FIPS config schema changed on disk — restarting daemon to pick up new transports"
|
||||
);
|
||||
// Restart whichever unit is actually supervising
|
||||
// the daemon (archipelago-fips vs upstream fips).
|
||||
let unit = crate::fips::service::active_unit().await;
|
||||
if let Err(e) = crate::fips::service::restart(unit).await {
|
||||
tracing::warn!(
|
||||
"FIPS restart after config migration failed on {}: {} — user can retry via fips.reconnect",
|
||||
unit,
|
||||
e
|
||||
);
|
||||
}
|
||||
}
|
||||
if let Err(e) = crate::fips::service::activate(crate::fips::SERVICE_UNIT).await {
|
||||
tracing::warn!(
|
||||
"archipelago-fips activate failed on startup: {} — user can retry via fips.install RPC",
|
||||
|
||||
@@ -9,15 +9,53 @@
|
||||
<div class="flex-1">
|
||||
<div class="flex items-start justify-between gap-4 mb-2">
|
||||
<h2 class="text-xl font-semibold text-white">FIPS Mesh</h2>
|
||||
<div class="flex items-center gap-2" :title="statusLabel">
|
||||
<span class="w-2 h-2 rounded-full" :class="statusDotColor"></span>
|
||||
<span class="text-sm font-medium" :class="statusTextColor">{{ statusLabel }}</span>
|
||||
<div class="flex items-center gap-3">
|
||||
<div class="flex items-center gap-2" :title="statusLabel">
|
||||
<span class="w-2 h-2 rounded-full" :class="statusDotColor"></span>
|
||||
<span class="text-sm font-medium" :class="statusTextColor">{{ statusLabel }}</span>
|
||||
</div>
|
||||
<button
|
||||
type="button"
|
||||
class="p-1.5 rounded-md text-white/50 hover:text-white hover:bg-white/10 transition-colors"
|
||||
title="Seed anchors"
|
||||
aria-label="Open FIPS seed anchors settings"
|
||||
@click="showAnchorsModal = true"
|
||||
>
|
||||
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M10.325 4.317c.426-1.756 2.924-1.756 3.35 0a1.724 1.724 0 002.573 1.066c1.543-.94 3.31.826 2.37 2.37a1.724 1.724 0 001.065 2.572c1.756.426 1.756 2.924 0 3.35a1.724 1.724 0 00-1.066 2.573c.94 1.543-.826 3.31-2.37 2.37a1.724 1.724 0 00-2.572 1.065c-.426 1.756-2.924 1.756-3.35 0a1.724 1.724 0 00-2.573-1.066c-1.543.94-3.31-.826-2.37-2.37a1.724 1.724 0 00-1.065-2.572c-1.756-.426-1.756-2.924 0-3.35a1.724 1.724 0 001.066-2.573c-.94-1.543.826-3.31 2.37-2.37.996.608 2.296.07 2.572-1.065z" />
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 12a3 3 0 11-6 0 3 3 0 016 0z" />
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<p class="text-white/70 text-sm mb-4">Fast Nostr-keyed mesh routing</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Seed anchors modal — operator-editable list of peers this node
|
||||
dials to bootstrap the mesh. Tucked behind the gear so it
|
||||
doesn't crowd the card but is still one click away. Close
|
||||
button and layout mirror the What's New modal (and the rest
|
||||
of the app) so it feels like a first-class modal. -->
|
||||
<Teleport to="body">
|
||||
<Transition name="fade">
|
||||
<div
|
||||
v-if="showAnchorsModal"
|
||||
class="fixed inset-0 z-[3000] flex items-center justify-center p-4"
|
||||
@click="showAnchorsModal = false"
|
||||
>
|
||||
<div class="absolute inset-0 bg-black/60 backdrop-blur-sm"></div>
|
||||
<div
|
||||
class="relative z-10 max-w-xl w-full"
|
||||
style="max-height: 90vh; overflow-y: auto"
|
||||
@click.stop
|
||||
>
|
||||
<FipsSeedAnchorsCard closable @close="showAnchorsModal = false" />
|
||||
</div>
|
||||
</div>
|
||||
</Transition>
|
||||
</Teleport>
|
||||
|
||||
<div class="grid grid-cols-1 sm:grid-cols-2 gap-3 mb-3 shrink-0">
|
||||
<div class="p-3 bg-white/5 rounded-lg">
|
||||
<p class="text-xs text-white/60 mb-1">Daemon version</p>
|
||||
@@ -84,6 +122,7 @@
|
||||
import { computed, onMounted, ref } from 'vue'
|
||||
import { rpcClient } from '@/api/rpc-client'
|
||||
import { safeClipboardWrite } from '@/views/web5/utils'
|
||||
import FipsSeedAnchorsCard from './FipsSeedAnchorsCard.vue'
|
||||
|
||||
interface FipsStatus {
|
||||
installed: boolean
|
||||
@@ -113,6 +152,7 @@ const reconnecting = ref(false)
|
||||
const statusMessage = ref('')
|
||||
const statusIsError = ref(false)
|
||||
const copied = ref(false)
|
||||
const showAnchorsModal = ref(false)
|
||||
|
||||
async function copyNpub() {
|
||||
if (!status.value.npub) return
|
||||
|
||||
@@ -1,9 +1,23 @@
|
||||
<template>
|
||||
<div data-controller-container tabindex="0" class="glass-card p-6 flex flex-col transition-all hover:-translate-y-1">
|
||||
<div class="flex items-start gap-4 mb-4 shrink-0">
|
||||
<div data-controller-container tabindex="0" class="glass-card p-6 flex flex-col transition-all hover:-translate-y-1 relative">
|
||||
<button
|
||||
v-if="closable"
|
||||
type="button"
|
||||
class="absolute top-4 right-4 p-2 rounded-lg hover:bg-white/10 text-white/70 hover:text-white transition-colors z-10"
|
||||
aria-label="Close"
|
||||
@click="$emit('close')"
|
||||
>
|
||||
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12" />
|
||||
</svg>
|
||||
</button>
|
||||
<div class="flex items-start gap-4 mb-4 shrink-0" :class="{ 'pr-10': closable }">
|
||||
<div class="flex-shrink-0 w-12 h-12 rounded-lg bg-white/10 flex items-center justify-center">
|
||||
<!-- Radio/broadcast icon — three concentric arcs radiating from a
|
||||
dot. Reads as mesh, signal, anchor-reaching-peers. -->
|
||||
<svg class="w-6 h-6 text-white/80" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 11c0 3.517-1.009 6.799-2.753 9.571m-3.44-2.04.054-.09A13.916 13.916 0 0 0 8 11a4 4 0 1 1 8 0c0 1.017-.07 2.019-.203 3M9.497 10.997 14 18m-9.41-3.41L4 18.5" />
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8.288 15.038a5.25 5.25 0 017.424 0M5.106 11.856c3.807-3.808 9.98-3.808 13.788 0M1.924 8.674c5.565-5.565 14.587-5.565 20.152 0" />
|
||||
<circle cx="12" cy="18" r="1.25" fill="currentColor" stroke="none" />
|
||||
</svg>
|
||||
</div>
|
||||
<div class="flex-1">
|
||||
@@ -70,6 +84,9 @@
|
||||
import { onMounted, reactive, ref } from 'vue'
|
||||
import { rpcClient } from '@/api/rpc-client'
|
||||
|
||||
defineProps<{ closable?: boolean }>()
|
||||
defineEmits<{ (e: 'close'): void }>()
|
||||
|
||||
interface SeedAnchor {
|
||||
npub: string
|
||||
address: string
|
||||
|
||||
@@ -180,6 +180,40 @@ init()
|
||||
</button>
|
||||
</div>
|
||||
<div class="overflow-y-auto flex-1 min-h-0 space-y-6 pr-1">
|
||||
<!-- v1.7.25-alpha -->
|
||||
<div>
|
||||
<div class="flex items-center gap-2 mb-3">
|
||||
<span class="text-xs font-mono px-2 py-0.5 rounded bg-orange-500/20 text-orange-300">v1.7.25-alpha</span>
|
||||
<span class="text-xs text-white/40">Apr 21, 2026</span>
|
||||
</div>
|
||||
<div class="space-y-3 text-sm text-white/80 pl-3 border-l border-white/10">
|
||||
<p>Your node can now reach the broader FIPS public mesh, not just your own federated cluster. The FIPS daemon now binds both UDP (fast mesh forwarding) and TCP (NAT-friendly bootstrap) transports — matching the upstream factory default. The public anchor currently answers on TCP, so UDP-only nodes couldn't reach it; this fixes that without any action needed on your end.</p>
|
||||
<p>Upgrading the config happens automatically. On next startup, if the installed FIPS yaml doesn't match the new two-transport schema, the node reinstalls and restarts the daemon so the TCP transport comes online. No manual Reconnect required.</p>
|
||||
<p>Side benefit: TCP also helps on networks that block outbound UDP (corporate, some guest wifi) — your node falls back to TCP/8443 automatically and still joins the mesh.</p>
|
||||
</div>
|
||||
</div>
|
||||
<!-- v1.7.24-alpha -->
|
||||
<div>
|
||||
<div class="flex items-center gap-2 mb-3">
|
||||
<span class="text-xs font-mono px-2 py-0.5 rounded bg-orange-500/20 text-orange-300">v1.7.24-alpha</span>
|
||||
<span class="text-xs text-white/40">Apr 21, 2026</span>
|
||||
</div>
|
||||
<div class="space-y-3 text-sm text-white/80 pl-3 border-l border-white/10">
|
||||
<p>Frontend updates now actually ship. Since roughly v1.7.17 the release pipeline had been rebuilding the backend every version but silently skipping the frontend bundle — a permissions issue on the build server meant vue-tsc failed before vite ever ran, and nobody noticed because the published tarballs still extracted cleanly. The result was the backend moving forward while the UI stayed frozen at its v1.7.9-era state, which is why the FIPS gear icon and the What's New entries for every release since then had been missing on your node.</p>
|
||||
<p>Once this update applies, your node gets the real v1.7.24 frontend: the FIPS Seed Anchors modal (gear icon on the FIPS Mesh card), the current What's New history, the cancel-download button, and every other UI touch from the releases in between.</p>
|
||||
</div>
|
||||
</div>
|
||||
<!-- v1.7.23-alpha -->
|
||||
<div>
|
||||
<div class="flex items-center gap-2 mb-3">
|
||||
<span class="text-xs font-mono px-2 py-0.5 rounded bg-orange-500/20 text-orange-300">v1.7.23-alpha</span>
|
||||
<span class="text-xs text-white/40">Apr 21, 2026</span>
|
||||
</div>
|
||||
<div class="space-y-3 text-sm text-white/80 pl-3 border-l border-white/10">
|
||||
<p>FIPS Seed Anchors are now one click away. A small gear icon sits next to the status pill on the FIPS Mesh card — click it to open a modal where you can add, remove, and re-apply anchors. No more needing to go digging for the card or editing JSON by hand.</p>
|
||||
<p>The modal lists each anchor with its label, truncated npub, address, and transport, plus an Apply button to force-redial the full list and a Remove button per entry. The add form right below validates that the address is host:port and the npub is bech32 before saving.</p>
|
||||
</div>
|
||||
</div>
|
||||
<!-- v1.7.22-alpha -->
|
||||
<div>
|
||||
<div class="flex items-center gap-2 mb-3">
|
||||
|
||||
@@ -1,27 +1,28 @@
|
||||
{
|
||||
"version": "1.7.22-alpha",
|
||||
"version": "1.7.25-alpha",
|
||||
"release_date": "2026-04-21",
|
||||
"changelog": [
|
||||
"FIPS Reconnect and Restart buttons now work on every node, regardless of which systemd unit is actually supervising the daemon. Previously they targeted only the archipelago-managed unit — nodes on the upstream unit saw the buttons silently do nothing. Both paths auto-detect which unit is up and act on that one.",
|
||||
"FIPS anchor status no longer shows red just because a specific public anchor is unreachable. It now lights green whenever any authenticated peer is a recognised anchor — public or one you added under Seed Anchors. Federated clusters that route through their own seed anchors finally report the truth.",
|
||||
"Reconnect also re-pushes your seed anchors after the restart, so you don't have to wait five minutes for the background apply loop to re-dial them."
|
||||
"Your node can now reach the broader FIPS public mesh, not just your own federated cluster. The FIPS daemon now binds both UDP (fast mesh forwarding) and TCP (NAT-friendly bootstrap) transports — matching the upstream factory default. The public anchor currently answers on TCP, so UDP-only nodes couldn't reach it; this fixes that without any action needed on your end.",
|
||||
"Config upgrade is automatic. On next startup, if the installed FIPS yaml doesn't match the new two-transport schema, the node reinstalls and restarts the daemon so the TCP transport comes online. No manual Reconnect required.",
|
||||
"Side benefit: TCP also helps on networks that block outbound UDP (corporate, some guest wifi) — your node falls back to TCP/8443 automatically and still joins the mesh.",
|
||||
"The FIPS Seed Anchors modal got a design cleanup: new radio/mesh icon in the card header, and a matching close button styled like the rest of the app's modals instead of the earlier off-design placeholder."
|
||||
],
|
||||
"components": [
|
||||
{
|
||||
"name": "archipelago",
|
||||
"current_version": "1.7.21-alpha",
|
||||
"new_version": "1.7.22-alpha",
|
||||
"download_url": "https://git.tx1138.com/lfg2025/archy/raw/branch/main/releases/v1.7.22-alpha/archipelago",
|
||||
"sha256": "43d632c7de75b5619b20dcb59ca5e561708fe7f8d0138b3bda7accb109a61ef6",
|
||||
"size_bytes": 40818136
|
||||
"current_version": "1.7.24-alpha",
|
||||
"new_version": "1.7.25-alpha",
|
||||
"download_url": "https://git.tx1138.com/lfg2025/archy/raw/branch/main/releases/v1.7.25-alpha/archipelago",
|
||||
"sha256": "912e3baa0c97672e775e256adef97cf62be4873132bcd339738c6ee44cf940a0",
|
||||
"size_bytes": 40833768
|
||||
},
|
||||
{
|
||||
"name": "archipelago-frontend-1.7.22-alpha.tar.gz",
|
||||
"current_version": "1.7.21-alpha",
|
||||
"new_version": "1.7.22-alpha",
|
||||
"download_url": "https://git.tx1138.com/lfg2025/archy/raw/branch/main/releases/v1.7.22-alpha/archipelago-frontend-1.7.22-alpha.tar.gz",
|
||||
"sha256": "402ba9af8d6bbbfc649a1cf62c4df4f44d9e48c78136dae7c29721d816e478e9",
|
||||
"size_bytes": 162082789
|
||||
"name": "archipelago-frontend-1.7.25-alpha.tar.gz",
|
||||
"current_version": "1.7.24-alpha",
|
||||
"new_version": "1.7.25-alpha",
|
||||
"download_url": "https://git.tx1138.com/lfg2025/archy/raw/branch/main/releases/v1.7.25-alpha/archipelago-frontend-1.7.25-alpha.tar.gz",
|
||||
"sha256": "5d8aebfc72a3eacd76d74a3bd258cbadadaaf8079c590218186013de77139eb8",
|
||||
"size_bytes": 162089259
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
BIN
releases/v1.7.23-alpha/archipelago
Executable file
BIN
releases/v1.7.23-alpha/archipelago
Executable file
Binary file not shown.
BIN
releases/v1.7.23-alpha/archipelago-frontend-1.7.23-alpha.tar.gz
Normal file
BIN
releases/v1.7.23-alpha/archipelago-frontend-1.7.23-alpha.tar.gz
Normal file
Binary file not shown.
BIN
releases/v1.7.24-alpha/archipelago
Executable file
BIN
releases/v1.7.24-alpha/archipelago
Executable file
Binary file not shown.
BIN
releases/v1.7.24-alpha/archipelago-frontend-1.7.24-alpha.tar.gz
Normal file
BIN
releases/v1.7.24-alpha/archipelago-frontend-1.7.24-alpha.tar.gz
Normal file
Binary file not shown.
BIN
releases/v1.7.25-alpha/archipelago
Executable file
BIN
releases/v1.7.25-alpha/archipelago
Executable file
Binary file not shown.
BIN
releases/v1.7.25-alpha/archipelago-frontend-1.7.25-alpha.tar.gz
Normal file
BIN
releases/v1.7.25-alpha/archipelago-frontend-1.7.25-alpha.tar.gz
Normal file
Binary file not shown.
Reference in New Issue
Block a user