implement secrets read from env vars
This commit is contained in:
@@ -2,6 +2,8 @@
|
|||||||
# will have compiled files and executables
|
# will have compiled files and executables
|
||||||
debug/
|
debug/
|
||||||
target/
|
target/
|
||||||
|
.env
|
||||||
|
successful_submissions.tsv
|
||||||
|
|
||||||
# Remove Cargo.lock from gitignore if creating an executable, leave it for libraries
|
# 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
|
# More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ leptos = { version = "0.8.0" }
|
|||||||
leptos_router = { version = "0.8.0" }
|
leptos_router = { version = "0.8.0" }
|
||||||
axum = { version = "0.8.0", optional = true }
|
axum = { version = "0.8.0", optional = true }
|
||||||
console_error_panic_hook = { version = "0.1", 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_axum = { version = "0.8.0", optional = true }
|
||||||
leptos_meta = { version = "0.8.0" }
|
leptos_meta = { version = "0.8.0" }
|
||||||
tokio = { version = "1", features = ["rt-multi-thread"], optional = true }
|
tokio = { version = "1", features = ["rt-multi-thread"], optional = true }
|
||||||
@@ -24,6 +25,7 @@ hydrate = [
|
|||||||
]
|
]
|
||||||
ssr = [
|
ssr = [
|
||||||
"dep:axum",
|
"dep:axum",
|
||||||
|
"dep:dotenvy",
|
||||||
"dep:tokio",
|
"dep:tokio",
|
||||||
"dep:leptos_axum",
|
"dep:leptos_axum",
|
||||||
"leptos/ssr",
|
"leptos/ssr",
|
||||||
|
|||||||
@@ -36,6 +36,18 @@ Additionally, Cargo.toml may need updating as new versions of the dependencies a
|
|||||||
cargo leptos watch
|
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
|
## 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.
|
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.
|
||||||
|
|||||||
@@ -87,7 +87,7 @@ type HistoryViewEntry = (String, String, bool, String, String);
|
|||||||
async fn get_submission_history(
|
async fn get_submission_history(
|
||||||
secret_key: String,
|
secret_key: String,
|
||||||
) -> Result<Vec<HistoryViewEntry>, ServerFnError> {
|
) -> 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"));
|
return Err(ServerFnError::new("Invalid secret key"));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -243,7 +243,7 @@ fn persist_submission(submission: &SuccessfulSubmission) -> Result<(), ServerFnE
|
|||||||
|
|
||||||
#[server]
|
#[server]
|
||||||
async fn clear_submission_history(secret_key: String) -> Result<(), ServerFnError> {
|
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"));
|
return Err(ServerFnError::new("Invalid secret key"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
pub mod app;
|
pub mod app;
|
||||||
pub mod codes;
|
pub mod codes;
|
||||||
pub mod manage;
|
pub mod manage;
|
||||||
|
#[cfg(feature = "ssr")]
|
||||||
|
pub mod secrets;
|
||||||
|
|
||||||
#[cfg(feature = "hydrate")]
|
#[cfg(feature = "hydrate")]
|
||||||
#[wasm_bindgen::prelude::wasm_bindgen]
|
#[wasm_bindgen::prelude::wasm_bindgen]
|
||||||
|
|||||||
+3
-2
@@ -1,12 +1,13 @@
|
|||||||
|
|
||||||
#[cfg(feature = "ssr")]
|
#[cfg(feature = "ssr")]
|
||||||
#[tokio::main]
|
#[tokio::main]
|
||||||
async fn main() {
|
async fn main() {
|
||||||
use axum::Router;
|
use axum::Router;
|
||||||
|
use code_submission::app::*;
|
||||||
use leptos::logging::log;
|
use leptos::logging::log;
|
||||||
use leptos::prelude::*;
|
use leptos::prelude::*;
|
||||||
use leptos_axum::{generate_route_list, LeptosRoutes};
|
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 conf = get_configuration(None).unwrap();
|
||||||
let addr = conf.leptos_options.site_addr;
|
let addr = conf.leptos_options.site_addr;
|
||||||
|
|||||||
+1
-9
@@ -12,14 +12,6 @@ pub(crate) fn server_live_state() -> bool {
|
|||||||
SERVER_LIVE.load(Ordering::SeqCst)
|
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]
|
#[server]
|
||||||
async fn get_live_state() -> Result<bool, ServerFnError> {
|
async fn get_live_state() -> Result<bool, ServerFnError> {
|
||||||
Ok(server_live_state())
|
Ok(server_live_state())
|
||||||
@@ -27,7 +19,7 @@ async fn get_live_state() -> Result<bool, ServerFnError> {
|
|||||||
|
|
||||||
#[server]
|
#[server]
|
||||||
async fn set_live_state(live: bool, secret_key: String) -> Result<(), ServerFnError> {
|
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()));
|
return Err(ServerFnError::ServerError("Invalid secret key".to_string()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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)
|
||||||
|
}
|
||||||
@@ -1,2 +0,0 @@
|
|||||||
1791318883 152713800 127.0.0.1 false code1
|
|
||||||
1791318908 161513000 127.0.0.1 true code1
|
|
||||||
|
Reference in New Issue
Block a user