feat: Phase 4 backend hardening — container reliability + security audit
Container Management (CONT-01 through CONT-06): - Fix needs_archy_net: add lnd, nbxplorer to archy-net list - Add StartupTier dependency ordering to health monitor (DB→Core→Dependent→App→UI) - Add exponential backoff (10s/30s/90s) with 1hr stability reset - Add get_health_check_args() with health checks for 20+ apps - Add get_memory_limit() with per-app limits (128m-4g vs blanket 2g) - Create docs/network-topology.md - Fix fedimint containers on both nodes (moved to archy-net) Security Audit (SEC-01 through SEC-06): - Add sanitize_error_message() — strips internal paths from RPC errors - Add validate_identity_id() — blocks path traversal on identity operations - Add validate_did() — blocks path traversal on federation operations - Add message size limits: node-send-message (1MB), dwn.write-message (10MB) - Add rate limits for federation endpoints (join: 5/60s, invite: 10/300s) - Configure journald (500MB max, 7 day retention) on both nodes - Add /etc/logrotate.d/archipelago for backend + crowdsec logs - Verify all 4 nginx security headers on both nodes Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.6
parent
f9a47a2602
commit
6335ea17ee
@@ -4,6 +4,20 @@ use crate::identity;
|
||||
use anyhow::Result;
|
||||
use tracing::info;
|
||||
|
||||
/// Validate a DID parameter: must start with "did:", max 256 chars, no path traversal.
|
||||
fn validate_did(did: &str) -> Result<()> {
|
||||
if did.is_empty() || did.len() > 256 {
|
||||
anyhow::bail!("Invalid DID: must be 1-256 characters");
|
||||
}
|
||||
if !did.starts_with("did:") {
|
||||
anyhow::bail!("Invalid DID: must start with 'did:'");
|
||||
}
|
||||
if did.contains("..") || did.contains('/') || did.contains('\\') || did.contains('\0') {
|
||||
anyhow::bail!("Invalid DID: contains forbidden characters");
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
impl RpcHandler {
|
||||
/// federation.invite — Generate an invite code containing our DID + onion for a peer.
|
||||
pub(super) async fn handle_federation_invite(&self) -> Result<serde_json::Value> {
|
||||
@@ -107,6 +121,7 @@ impl RpcHandler {
|
||||
.get("did")
|
||||
.and_then(|v| v.as_str())
|
||||
.ok_or_else(|| anyhow::anyhow!("Missing 'did' parameter"))?;
|
||||
validate_did(did)?;
|
||||
|
||||
let nodes = federation::remove_node(&self.config.data_dir, did).await?;
|
||||
info!(did = %did, "Removed node from federation");
|
||||
@@ -127,6 +142,7 @@ impl RpcHandler {
|
||||
.get("did")
|
||||
.and_then(|v| v.as_str())
|
||||
.ok_or_else(|| anyhow::anyhow!("Missing 'did' parameter"))?;
|
||||
validate_did(did)?;
|
||||
let trust_str = params
|
||||
.get("trust_level")
|
||||
.and_then(|v| v.as_str())
|
||||
|
||||
Reference in New Issue
Block a user