diff --git a/src/server/mod.rs b/src/server/mod.rs index 8139517..481c51f 100644 --- a/src/server/mod.rs +++ b/src/server/mod.rs @@ -95,6 +95,13 @@ pub struct ServerArgs { // #[cfg(feature = "ui")] #[arg(long, default_value_t = false)] open: bool, + + /// Enable cors verification + /// + /// When enabled, the POST /new path require a seemless + /// Origin and Host header. + #[arg(long = "no-cors", action = clap::ArgAction::SetFalse)] + cors: bool, } impl ServerArgs { @@ -310,6 +317,7 @@ fn build_state(ctx: Context, args: ServerArgs) -> Result> { aisle_path, pantry_path, url_prefix, + cors: args.cors, checked_log_lock: Arc::new(tokio::sync::Mutex::new(())), shopping_list_events, #[cfg(feature = "sync")] @@ -358,6 +366,7 @@ pub struct AppState { pub aisle_path: Option, pub pantry_path: Option, pub url_prefix: String, + pub cors: bool, /// Serializes access to `.shopping-checked` within this process. /// File-level `flock` doesn't prevent two tasks in the *same* process /// from racing on the file (the kernel treats them as one lock owner), diff --git a/src/server/ui.rs b/src/server/ui.rs index 7d39ac2..08f12f3 100644 --- a/src/server/ui.rs +++ b/src/server/ui.rs @@ -300,7 +300,7 @@ async fn create_recipe( Form(form): Form, ) -> impl IntoResponse { // CSRF protection: verify request came from same origin - if !validate_same_origin(&headers, &host) { + if state.cors && !validate_same_origin(&headers, &host) { tracing::warn!("CSRF validation failed for create_recipe request"); return (StatusCode::FORBIDDEN, "Invalid request origin").into_response(); }