implement secrets read from env vars

This commit is contained in:
2026-10-06 16:00:51 -05:00
parent 576199b1e9
commit 370fe2e4aa
10 changed files with 49 additions and 17 deletions
+2
View File
@@ -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
+2
View File
@@ -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",
+12
View File
@@ -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.
+1
View File
@@ -0,0 +1 @@
DEV_SECRET_KEY=replace-with-a-unique-secret
+2 -2
View File
@@ -87,7 +87,7 @@ type HistoryViewEntry = (String, String, bool, String, String);
async fn get_submission_history(
secret_key: String,
) -> Result<Vec<HistoryViewEntry>, 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"));
}
+2
View File
@@ -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]
+5 -4
View File
@@ -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::<std::net::SocketAddr>(),
)
.await
.unwrap();
.await
.unwrap();
}
#[cfg(not(feature = "ssr"))]
+1 -9
View File
@@ -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<bool, ServerFnError> {
Ok(server_live_state())
@@ -27,7 +19,7 @@ async fn get_live_state() -> Result<bool, ServerFnError> {
#[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()));
}
+22
View File
@@ -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<bool, ServerFnError> {
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)
}
-2
View File
@@ -1,2 +0,0 @@
1791318883 152713800 127.0.0.1 false code1
1791318908 161513000 127.0.0.1 true code1
1 1791318883 152713800 127.0.0.1 false code1
2 1791318908 161513000 127.0.0.1 true code1