fix(dashboard): bind the server to loopback
Restrict the local dashboard listener to 127.0.0.1 instead of exposing it on every interface, with a listener-address regression test.
This commit is contained in:
parent
8c39ac0440
commit
3fc43cc311
1 changed files with 12 additions and 1 deletions
|
|
@ -25,12 +25,16 @@ pub(crate) struct AppState {
|
||||||
pub shutdown_notify: Arc<tokio::sync::Notify>,
|
pub shutdown_notify: Arc<tokio::sync::Notify>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async fn bind_listener(port: u16) -> std::io::Result<tokio::net::TcpListener> {
|
||||||
|
tokio::net::TcpListener::bind(("127.0.0.1", port)).await
|
||||||
|
}
|
||||||
|
|
||||||
pub(crate) async fn run_server(state: AppState, port: u16) {
|
pub(crate) async fn run_server(state: AppState, port: u16) {
|
||||||
run_server_with_routes(state, port, Router::new()).await;
|
run_server_with_routes(state, port, Router::new()).await;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) async fn run_server_with_routes(state: AppState, port: u16, extra: Router) {
|
pub(crate) async fn run_server_with_routes(state: AppState, port: u16, extra: Router) {
|
||||||
let listener = tokio::net::TcpListener::bind(format!("0.0.0.0:{port}"))
|
let listener = bind_listener(port)
|
||||||
.await
|
.await
|
||||||
.expect("failed to bind HTTP server");
|
.expect("failed to bind HTTP server");
|
||||||
let shutdown = Arc::clone(&state.shutdown_notify);
|
let shutdown = Arc::clone(&state.shutdown_notify);
|
||||||
|
|
@ -342,6 +346,13 @@ mod tests {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn dashboard_listener_is_loopback_only() {
|
||||||
|
let listener = bind_listener(0).await.expect("bind dashboard listener");
|
||||||
|
let address = listener.local_addr().expect("read dashboard address");
|
||||||
|
assert!(address.ip().is_loopback(), "dashboard bound to {address}");
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn registered_plugin_page_appears_in_shared_navigation() {
|
fn registered_plugin_page_appears_in_shared_navigation() {
|
||||||
let state = state_with_plugin(PluginPage::new(
|
let state = state_with_plugin(PluginPage::new(
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue