From 370fe2e4aa0a18fc62b5571317d8e2dd3d03a1f2 Mon Sep 17 00:00:00 2001 From: Mitchell M Date: Tue, 6 Oct 2026 16:00:51 -0500 Subject: [PATCH] implement secrets read from env vars --- .gitignore | 2 ++ Cargo.toml | 2 ++ README.md | 12 ++++++++++++ dev.env | 1 + src/codes/history.rs | 4 ++-- src/lib.rs | 2 ++ src/main.rs | 9 +++++---- src/manage.rs | 10 +--------- src/secrets.rs | 22 ++++++++++++++++++++++ successful_submissions.tsv | 2 -- 10 files changed, 49 insertions(+), 17 deletions(-) create mode 100644 dev.env create mode 100644 src/secrets.rs delete mode 100644 successful_submissions.tsv diff --git a/.gitignore b/.gitignore index 6985cf1..dfd8490 100644 --- a/.gitignore +++ b/.gitignore @@ -2,6 +2,8 @@ # will have compiled files and executables debug/ target/ +.env +successful_submissions.tsv # Remove Cargo.lock from gitignore if creating an executable, leave it for libraries # More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html diff --git a/Cargo.toml b/Cargo.toml index 2a71df6..55c2930 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,6 +11,7 @@ leptos = { version = "0.8.0" } leptos_router = { version = "0.8.0" } axum = { version = "0.8.0", optional = true } console_error_panic_hook = { version = "0.1", optional = true } +dotenvy = { version = "0.15", optional = true } leptos_axum = { version = "0.8.0", optional = true } leptos_meta = { version = "0.8.0" } tokio = { version = "1", features = ["rt-multi-thread"], optional = true } @@ -24,6 +25,7 @@ hydrate = [ ] ssr = [ "dep:axum", + "dep:dotenvy", "dep:tokio", "dep:leptos_axum", "leptos/ssr", diff --git a/README.md b/README.md index 5bf3b19..6484d36 100644 --- a/README.md +++ b/README.md @@ -36,6 +36,18 @@ Additionally, Cargo.toml may need updating as new versions of the dependencies a cargo leptos watch ``` +Copy `dev.env` to `.env`, then replace the placeholder with a unique secret +before starting the server. The `.env` file is loaded automatically at startup +and is ignored by Git. `DEV_SECRET_KEY` authorizes server status changes and +submission-history access: + +```powershell +Copy-Item dev.env .env +``` + +You can also provide `DEV_SECRET_KEY` through the process environment. Do not +commit secrets or expose them in client-side code. + ## Installing Additional Tools By default, `cargo-leptos` uses `nightly` Rust, `cargo-generate`, and `sass`. If you run into any trouble, you may need to install one or more of these tools. diff --git a/dev.env b/dev.env new file mode 100644 index 0000000..e627afb --- /dev/null +++ b/dev.env @@ -0,0 +1 @@ +DEV_SECRET_KEY=replace-with-a-unique-secret diff --git a/src/codes/history.rs b/src/codes/history.rs index 1869638..38edd24 100644 --- a/src/codes/history.rs +++ b/src/codes/history.rs @@ -87,7 +87,7 @@ type HistoryViewEntry = (String, String, bool, String, String); async fn get_submission_history( secret_key: String, ) -> Result, ServerFnError> { - if !crate::manage::valid_status_secret_key(&secret_key) { + if !crate::secrets::validate_dev_secret_key(&secret_key)? { return Err(ServerFnError::new("Invalid secret key")); } @@ -243,7 +243,7 @@ fn persist_submission(submission: &SuccessfulSubmission) -> Result<(), ServerFnE #[server] async fn clear_submission_history(secret_key: String) -> Result<(), ServerFnError> { - if !crate::manage::valid_status_secret_key(&secret_key) { + if !crate::secrets::validate_dev_secret_key(&secret_key)? { return Err(ServerFnError::new("Invalid secret key")); } diff --git a/src/lib.rs b/src/lib.rs index b9d274a..6ad335e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,6 +1,8 @@ pub mod app; pub mod codes; pub mod manage; +#[cfg(feature = "ssr")] +pub mod secrets; #[cfg(feature = "hydrate")] #[wasm_bindgen::prelude::wasm_bindgen] diff --git a/src/main.rs b/src/main.rs index 90eb9c7..7eb05c2 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,12 +1,13 @@ - #[cfg(feature = "ssr")] #[tokio::main] async fn main() { use axum::Router; + use code_submission::app::*; use leptos::logging::log; use leptos::prelude::*; use leptos_axum::{generate_route_list, LeptosRoutes}; - use code_submission::app::*; + + code_submission::secrets::load_dotenv().expect("Unable to load .env configuration"); let conf = get_configuration(None).unwrap(); let addr = conf.leptos_options.site_addr; @@ -30,8 +31,8 @@ async fn main() { listener, app.into_make_service_with_connect_info::(), ) - .await - .unwrap(); + .await + .unwrap(); } #[cfg(not(feature = "ssr"))] diff --git a/src/manage.rs b/src/manage.rs index a1b407c..b11458e 100644 --- a/src/manage.rs +++ b/src/manage.rs @@ -12,14 +12,6 @@ pub(crate) fn server_live_state() -> bool { SERVER_LIVE.load(Ordering::SeqCst) } -#[cfg(feature = "ssr")] -const STATUS_SECRET_KEY: &str = "password"; - -#[cfg(feature = "ssr")] -pub(crate) fn valid_status_secret_key(secret_key: &str) -> bool { - secret_key == STATUS_SECRET_KEY -} - #[server] async fn get_live_state() -> Result { Ok(server_live_state()) @@ -27,7 +19,7 @@ async fn get_live_state() -> Result { #[server] async fn set_live_state(live: bool, secret_key: String) -> Result<(), ServerFnError> { - if !valid_status_secret_key(&secret_key) { + if !crate::secrets::validate_dev_secret_key(&secret_key)? { return Err(ServerFnError::ServerError("Invalid secret key".to_string())); } diff --git a/src/secrets.rs b/src/secrets.rs new file mode 100644 index 0000000..954567b --- /dev/null +++ b/src/secrets.rs @@ -0,0 +1,22 @@ +use leptos::prelude::ServerFnError; +use std::io::ErrorKind; + +pub(crate) const DEV_SECRET_KEY: &str = "DEV_SECRET_KEY"; + +pub fn load_dotenv() -> Result<(), String> { + match dotenvy::dotenv() { + Ok(_) => Ok(()), + Err(dotenvy::Error::Io(error)) if error.kind() == ErrorKind::NotFound => Ok(()), + Err(error) => Err(format!("Unable to load .env file: {error}")), + } +} + +pub(crate) fn validate_dev_secret_key(provided_key: &str) -> Result { + let expected_key = std::env::var(DEV_SECRET_KEY).map_err(|_| { + ServerFnError::new(format!( + "Required server secret {DEV_SECRET_KEY} is not configured" + )) + })?; + + Ok(provided_key == expected_key) +} diff --git a/successful_submissions.tsv b/successful_submissions.tsv deleted file mode 100644 index 3a64f4d..0000000 --- a/successful_submissions.tsv +++ /dev/null @@ -1,2 +0,0 @@ -1791318883 152713800 127.0.0.1 false code1 -1791318908 161513000 127.0.0.1 true code1