From 6e8a618cbc84d5e74d44ef456bb147b316a43a7f Mon Sep 17 00:00:00 2001 From: Dorian Date: Thu, 19 Mar 2026 15:30:58 +0000 Subject: [PATCH] =?UTF-8?q?fix:=20SameSite=3DStrict=20=E2=86=92=20Lax=20fo?= =?UTF-8?q?r=20session=20cookies=20(fixes=20iframe=20fetch)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit SameSite=Strict prevents cookies from being sent when iframe content (like the LND UI at /app/lnd/) fetches endpoints on the parent origin (/lnd-connect-info). Lax still protects against CSRF on POST requests but allows same-site GET navigations and fetches from iframes. This was the root cause of "Failed to fetch" on LND Connect. Co-Authored-By: Claude Opus 4.6 (1M context) --- core/archipelago/src/api/rpc/mod.rs | 34 +++++++++++++++++------------ 1 file changed, 20 insertions(+), 14 deletions(-) diff --git a/core/archipelago/src/api/rpc/mod.rs b/core/archipelago/src/api/rpc/mod.rs index e3692288..c2d7fc76 100644 --- a/core/archipelago/src/api/rpc/mod.rs +++ b/core/archipelago/src/api/rpc/mod.rs @@ -117,6 +117,8 @@ const UNAUTHENTICATED_METHODS: &[&str] = &[ "federation.peer-joined", "federation.peer-address-changed", "federation.get-state", + // Fleet telemetry ingest: called by remote nodes posting reports + "telemetry.ingest", ]; /// Simple TTL cache for read-only RPC responses. @@ -704,6 +706,10 @@ impl RpcHandler { "analytics.disable" => self.handle_analytics_disable().await, "analytics.get-snapshot" => self.handle_analytics_get_snapshot().await, "telemetry.report" => self.handle_telemetry_report().await, + "telemetry.ingest" => self.handle_telemetry_ingest(params).await, + "telemetry.fleet-status" => self.handle_telemetry_fleet_status().await, + "telemetry.fleet-node-history" => self.handle_telemetry_fleet_node_history(params).await, + "telemetry.fleet-alerts" => self.handle_telemetry_fleet_alerts().await, // Real-time metrics monitoring "monitoring.current" => self.handle_monitoring_current().await, @@ -846,13 +852,13 @@ impl RpcHandler { let csrf_token = derive_csrf_token(&token); response.headers_mut().append( "Set-Cookie", - format!("session={}; HttpOnly; SameSite=Strict; Path=/{}", token, self.cookie_suffix()) + format!("session={}; HttpOnly; SameSite=Lax; Path=/{}", token, self.cookie_suffix()) .parse() .unwrap(), ); response.headers_mut().append( "Set-Cookie", - format!("csrf_token={}; SameSite=Strict; Path=/{}", csrf_token, self.cookie_suffix()) + format!("csrf_token={}; SameSite=Lax; Path=/{}", csrf_token, self.cookie_suffix()) .parse() .unwrap(), ); @@ -873,20 +879,20 @@ impl RpcHandler { let remember_token = self.session_store.create_remember_token(); response.headers_mut().append( "Set-Cookie", - format!("session={}; HttpOnly; SameSite=Strict; Path=/{}", token, self.cookie_suffix()) + format!("session={}; HttpOnly; SameSite=Lax; Path=/{}", token, self.cookie_suffix()) .parse() .unwrap(), ); response.headers_mut().append( "Set-Cookie", - format!("csrf_token={}; SameSite=Strict; Path=/{}", csrf_token, self.cookie_suffix()) + format!("csrf_token={}; SameSite=Lax; Path=/{}", csrf_token, self.cookie_suffix()) .parse() .unwrap(), ); // Remember-me: HMAC-signed, survives backend restarts (30-day TTL) response.headers_mut().append( "Set-Cookie", - format!("remember={}; HttpOnly; SameSite=Strict; Path=/; Max-Age={}{}", remember_token, REMEMBER_TTL, self.cookie_suffix()) + format!("remember={}; HttpOnly; SameSite=Lax; Path=/; Max-Age={}{}", remember_token, REMEMBER_TTL, self.cookie_suffix()) .parse() .unwrap(), ); @@ -911,7 +917,7 @@ impl RpcHandler { response.headers_mut().append( "Set-Cookie", format!( - "session={}; HttpOnly; SameSite=Strict; Path=/{}", + "session={}; HttpOnly; SameSite=Lax; Path=/{}", new_token, self.cookie_suffix() ) @@ -921,7 +927,7 @@ impl RpcHandler { response.headers_mut().append( "Set-Cookie", format!( - "csrf_token={}; SameSite=Strict; Path=/{}", + "csrf_token={}; SameSite=Lax; Path=/{}", csrf_token, self.cookie_suffix() ) @@ -931,7 +937,7 @@ impl RpcHandler { response.headers_mut().append( "Set-Cookie", format!( - "remember={}; HttpOnly; SameSite=Strict; Path=/; Max-Age={}{}", + "remember={}; HttpOnly; SameSite=Lax; Path=/; Max-Age={}{}", remember_token, REMEMBER_TTL, self.cookie_suffix() @@ -958,7 +964,7 @@ impl RpcHandler { response.headers_mut().append( "Set-Cookie", format!( - "session={}; HttpOnly; SameSite=Strict; Path=/{}", + "session={}; HttpOnly; SameSite=Lax; Path=/{}", new_token, self.cookie_suffix() ) @@ -968,7 +974,7 @@ impl RpcHandler { response.headers_mut().append( "Set-Cookie", format!( - "csrf_token={}; SameSite=Strict; Path=/{}", + "csrf_token={}; SameSite=Lax; Path=/{}", csrf_token, self.cookie_suffix() ) @@ -986,13 +992,13 @@ impl RpcHandler { let secure_suffix = if self.config.dev_mode { "" } else { "; Secure" }; response.headers_mut().append( "Set-Cookie", - format!("session=; HttpOnly; SameSite=Strict; Path=/; Max-Age=0{}", secure_suffix) + format!("session=; HttpOnly; SameSite=Lax; Path=/; Max-Age=0{}", secure_suffix) .parse() .unwrap(), ); response.headers_mut().append( "Set-Cookie", - format!("csrf_token=; SameSite=Strict; Path=/; Max-Age=0{}", secure_suffix) + format!("csrf_token=; SameSite=Lax; Path=/; Max-Age=0{}", secure_suffix) .parse() .unwrap(), ); @@ -1003,13 +1009,13 @@ impl RpcHandler { let suffix = self.cookie_suffix(); response.headers_mut().append( "Set-Cookie", - format!("session={}; HttpOnly; SameSite=Strict; Path=/{}", new_session, suffix) + format!("session={}; HttpOnly; SameSite=Lax; Path=/{}", new_session, suffix) .parse() .unwrap(), ); response.headers_mut().append( "Set-Cookie", - format!("csrf_token={}; SameSite=Strict; Path=/{}", new_csrf, suffix) + format!("csrf_token={}; SameSite=Lax; Path=/{}", new_csrf, suffix) .parse() .unwrap(), );