Façade Rust, lot 2 : interface, authentification et /api/ping

L'interface (index, marked, service worker, manifeste, polices) est
désormais servie par loki-rs, embarquée par build.rs depuis la même source
que le go:embed — les deux binaires d'un build servent la même UI. Mêmes
en-têtes de cache que le Go, gzip à la première demande puis gardé en
mémoire, jamais sur les polices ni en HEAD.

L'authentification de pilotage est portée à l'identique (requireWebAuth,
crossSiteReject, localHostName, Bearer en temps constant, mêmes messages,
mêmes codes) ; les cas de TestCrossSiteReject sont repris un pour un. La
clé est demandée à l'API interne du Go à chaque requête ; si elle ne
répond pas proprement, la façade ferme (503). /api/ping est la première
route authentifiée servie par Rust.

Le jeton de l'API interne est tiré au hasard à chaque démarrage et passé
au Go par l'environnement. La façade rend 404 sur /internal/* venu de
l'extérieur et efface X-Loki-Internal entrant avant tout relais.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
MichaelandClaude Opus 5.5 committed 2026-10-13 22:40:10 +02:00
1 parent a99d988e70
commit d4fa4488cc
13 files changed
+1023 -18

No files matched your search

+27 -3
View File
@@ -7,7 +7,7 @@
//! loki-rs version
//! ```
use loki_rs::{child, proxy, update};
use loki_rs::{auth, child, proxy, update};
use std::net::SocketAddr;
use std::path::PathBuf;
use std::process::ExitCode;
@@ -89,7 +89,20 @@ fn serve() -> ExitCode {
"[loki-rs] serveur Go : {} web {go_port} (local)",
go_bin.display()
);
let sup = child::Supervisor::spawn(go_bin, go_port);
// Jeton de l'API interne du Go : tiré au hasard à chaque démarrage,
// connu seulement de la façade et du Go qu'elle lance.
let token = match internal_token() {
Ok(t) => t,
Err(e) => {
eprintln!("[loki-rs] aléa système indisponible : {e}");
return ExitCode::FAILURE;
}
};
let sup = child::Supervisor::spawn(
go_bin,
go_port,
vec![(auth::INTERNAL_ENV.to_string(), token.clone())],
);
wait_for(backend, Duration::from_secs(30)).await;
let addr = SocketAddr::from(([0, 0, 0, 0], web_port));
@@ -102,7 +115,12 @@ fn serve() -> ExitCode {
}
};
eprintln!("[loki-rs] façade : http://{addr} → {backend}");
let res = proxy::serve(listener, backend, shutdown_signal()).await;
let cfg = proxy::Config {
backend,
internal_token: token,
host_env: auth::HostEnv::from_env(),
};
let res = proxy::serve(listener, cfg, shutdown_signal()).await;
eprintln!("[loki-rs] arrêt demandé — arrêt du serveur Go");
sup.shutdown(Duration::from_secs(10)).await;
match res {
@@ -115,6 +133,12 @@ fn serve() -> ExitCode {
})
}
fn internal_token() -> Result<String, getrandom::Error> {
let mut b = [0u8; 32];
getrandom::fill(&mut b)?;
Ok(hex::encode(b))
}
/// Attend que le Go accepte les connexions, sans bloquer au-delà de `max` :
/// la façade ouvre quand même et répond 502 en attendant.
async fn wait_for(addr: SocketAddr, max: Duration) {