feat: v1.2.0-alpha — E2E encrypted mesh relay, steganography, relay status polling

Phase 5 mesh networking:
- E2E encrypted TX relay (X25519 + ChaCha20-Poly1305) — non-Archy nodes
  relay encrypted blobs transparently via Meshcore native routing
- Steganographic encoding modes (WeatherStation, SensorNetwork) — traffic
  looks like sensor data on the wire, 0xAA marker, configurable per-node
- Pre-flight Bitcoin Core health check on relay node — specific error codes
  (bitcoin_unreachable, bitcoin_syncing, tx_rejected) instead of generic fails
- mesh.relay-status RPC endpoint — frontend polls for relay result every 3s
- On-Chain / Lightning tabs in Off-Grid Bitcoin panel
- Archy Peers vs Mesh Broadcast relay mode selector
- Mesh view fills viewport (no page scroll), internal panel scrolling
- Version bump to 1.2.0-alpha

Also includes: deploy hardening, container fixes, IndeedHub updates,
boot screen, dashboard improvements, MASTER_PLAN task tracking

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Dorian
2026-03-17 23:56:37 +00:00
parent d1ac098edb
commit f273816405
48 changed files with 3432 additions and 438 deletions

View File

@@ -27,6 +27,8 @@ pub mod ratchet;
#[allow(dead_code)]
pub mod session;
#[allow(dead_code)]
pub mod steganography;
#[allow(dead_code)]
pub mod x3dh;
pub use types::*;
@@ -68,6 +70,9 @@ pub struct MeshConfig {
/// Announce new Bitcoin block headers over mesh (internet-connected nodes only).
#[serde(default)]
pub announce_block_headers: bool,
/// Steganographic encoding mode for mesh messages (Normal = disabled).
#[serde(default)]
pub steganography_mode: steganography::SteganographyMode,
}
impl Default for MeshConfig {
@@ -80,6 +85,7 @@ impl Default for MeshConfig {
advert_name: None,
mesh_only_mode: None,
announce_block_headers: false,
steganography_mode: steganography::SteganographyMode::Normal,
}
}
}
@@ -154,7 +160,14 @@ impl MeshService {
.clone()
.unwrap_or_else(|| "archipelago".to_string());
let (state, _rx, cmd_rx) = MeshState::new(&channel_name);
let block_header_cache = Arc::new(BlockHeaderCache::new());
let relay_tracker = Arc::new(RelayTracker::new());
let (state, _rx, cmd_rx) = MeshState::new(
&channel_name,
Arc::clone(&block_header_cache),
Some(Arc::clone(&relay_tracker)),
config.steganography_mode,
);
// Derive X25519 keys from Ed25519 identity
let x25519_secret = crypto::ed25519_secret_to_x25519(signing_key);
@@ -162,9 +175,6 @@ impl MeshService {
&signing_key.verifying_key().to_bytes(),
)?;
let x25519_pubkey_hex = hex::encode(x25519_pubkey);
let block_header_cache = Arc::new(BlockHeaderCache::new());
let relay_tracker = Arc::new(RelayTracker::new());
let dead_man_switch = Arc::new(
DeadManSwitch::new(data_dir)
.await
@@ -670,6 +680,7 @@ mod tests {
channel_name: Some("test".to_string()),
broadcast_identity: false,
advert_name: Some("MyNode".to_string()),
..Default::default()
};
let json = serde_json::to_string(&config).unwrap();
let parsed: MeshConfig = serde_json::from_str(&json).unwrap();
@@ -694,6 +705,7 @@ mod tests {
channel_name: Some("archy".to_string()),
broadcast_identity: true,
advert_name: None,
..Default::default()
};
save_config(dir.path(), &config).await.unwrap();
let loaded = load_config(dir.path()).await.unwrap();