Compare commits
6 Commits
69eb3a5e80
...
fa9ea95657
| Author | SHA1 | Date | |
|---|---|---|---|
|
fa9ea95657
|
|||
|
3ec07c0469
|
|||
|
f41f4f8d80
|
|||
|
c9b7bbfece
|
|||
|
9de0b13ee8
|
|||
|
8b00db60eb
|
32
Cargo.lock
generated
32
Cargo.lock
generated
@@ -1096,7 +1096,7 @@ dependencies = [
|
||||
"tokio-tungstenite 0.28.0",
|
||||
"tokio-util",
|
||||
"tower",
|
||||
"tower-http",
|
||||
"tower-http 0.6.11",
|
||||
"tower-layer",
|
||||
"tracing",
|
||||
"tungstenite 0.27.0",
|
||||
@@ -1374,7 +1374,7 @@ dependencies = [
|
||||
"tokio-tungstenite 0.28.0",
|
||||
"tokio-util",
|
||||
"tower",
|
||||
"tower-http",
|
||||
"tower-http 0.6.11",
|
||||
"tracing",
|
||||
"tracing-futures",
|
||||
"url",
|
||||
@@ -2427,6 +2427,7 @@ dependencies = [
|
||||
"rand 0.10.1",
|
||||
"serde",
|
||||
"thiserror 2.0.18",
|
||||
"tower-http 0.7.0",
|
||||
"tower-sessions-redis-store",
|
||||
"tracing",
|
||||
]
|
||||
@@ -3293,7 +3294,7 @@ dependencies = [
|
||||
"tokio-rustls",
|
||||
"tokio-util",
|
||||
"tower",
|
||||
"tower-http",
|
||||
"tower-http 0.6.11",
|
||||
"tower-service",
|
||||
"url",
|
||||
"wasm-bindgen",
|
||||
@@ -4182,6 +4183,31 @@ dependencies = [
|
||||
"url",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tower-http"
|
||||
version = "0.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b11f75e912b0c2be01b63d8cf8057b8c3f97cf34abb3d431a3a4c8675498e233"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"bytes",
|
||||
"futures-core",
|
||||
"futures-util",
|
||||
"http",
|
||||
"http-body",
|
||||
"http-body-util",
|
||||
"http-range-header",
|
||||
"httpdate",
|
||||
"mime",
|
||||
"mime_guess",
|
||||
"percent-encoding",
|
||||
"pin-project-lite",
|
||||
"tokio",
|
||||
"tokio-util",
|
||||
"tower-layer",
|
||||
"tower-service",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tower-layer"
|
||||
version = "0.3.3"
|
||||
|
||||
@@ -24,6 +24,7 @@ pbkdf2 = { version = "0.13.0", optional = true, features = ["getrandom", "phc"]
|
||||
rand = "0.10.1"
|
||||
serde = { version = "1.0.228", features = ["derive"] }
|
||||
thiserror = "2.0.18"
|
||||
tower-http = { version = "0.7.0", optional = true, features = ["fs"] }
|
||||
tower-sessions-redis-store = { version = "0.16.0", optional = true }
|
||||
tracing = "0.1.44"
|
||||
|
||||
@@ -40,6 +41,7 @@ server = [
|
||||
"dep:dotenvy",
|
||||
"dep:fred",
|
||||
"dep:pbkdf2",
|
||||
"dep:tower-http",
|
||||
"dep:tower-sessions-redis-store",
|
||||
]
|
||||
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
use std::path::PathBuf;
|
||||
|
||||
use serde::Deserialize;
|
||||
|
||||
/// Enable secure cookies by default only in release mode
|
||||
@@ -141,12 +143,18 @@ impl KeyValStoreConfig {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Deserialize)]
|
||||
pub struct ServerConfig {
|
||||
pub public_path: PathBuf,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Deserialize)]
|
||||
/// Top-level application configuration
|
||||
pub struct Config {
|
||||
pub auth: AuthConfig,
|
||||
pub database: DatabaseConfig,
|
||||
pub key_val_store: KeyValStoreConfig,
|
||||
pub server: ServerConfig,
|
||||
}
|
||||
|
||||
/// Parse configuration from the expected files and environment variables
|
||||
@@ -159,6 +167,7 @@ pub fn load_config() -> Result<Config, config::ConfigError> {
|
||||
.set_default("server.port", 8080)?
|
||||
.set_default("auth.open_signup", false)?
|
||||
.set_default("auth.cookies_secure", DEFAULT_COOKIES_SECURE)?
|
||||
.set_default("server.public_path", default_public_dir())?
|
||||
.add_source(File::with_name(&format!("/etc/{pkg_name}/config")).required(false))
|
||||
.add_source(File::with_name(&format!("/etc/{pkg_name}")).required(false))
|
||||
.add_source(File::with_name("config").required(false))
|
||||
@@ -166,3 +175,19 @@ pub fn load_config() -> Result<Config, config::ConfigError> {
|
||||
.build()?
|
||||
.try_deserialize()
|
||||
}
|
||||
|
||||
/// Provide a sane default for the public path, using the same sources as Dioxus does internally.
|
||||
/// Checks the `DIOXUS_PUBLIC_PATH` environment variable, then tries relative to the path of this
|
||||
/// executable
|
||||
fn default_public_dir() -> Option<String> {
|
||||
std::env::var("DIOXUS_PUBLIC_PATH").ok().or_else(|| {
|
||||
std::env::current_exe().ok().and_then(|path| {
|
||||
path.parent()
|
||||
.expect("current executable path must have a parent")
|
||||
.join("public")
|
||||
.into_os_string()
|
||||
.into_string()
|
||||
.ok()
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
@@ -2,8 +2,10 @@ use dioxus::{
|
||||
fullstack::axum::{Router, middleware::from_fn},
|
||||
server::axum::Extension,
|
||||
};
|
||||
use tower_http::services::ServeFile;
|
||||
|
||||
use crate::App;
|
||||
use crate::app::LOGO_ICO;
|
||||
use crate::server::{
|
||||
auth::build_auth_layer,
|
||||
config::{self, Config},
|
||||
@@ -22,6 +24,14 @@ pub fn main() -> Result<std::convert::Infallible> {
|
||||
.map_err(|e| Error::message_here(e.to_string()))
|
||||
.err_context("Failed to load config")?;
|
||||
|
||||
// Dioxus doesn't expose a way to configure the public path other than this environment
|
||||
// variable, and also doesn't provide a way to read what the public path is. As a workaround we
|
||||
// expose a config option and set this variable that Dioxus expects.
|
||||
// SAFETY: "This function is safe to call in a single-threaded program."
|
||||
unsafe {
|
||||
std::env::set_var("DIOXUS_PUBLIC_PATH", config.server.public_path.clone());
|
||||
}
|
||||
|
||||
// `Ok(...?)` is because `dioxus::serve` expects an `anyhow::Result`
|
||||
dioxus::serve(move || {
|
||||
let config = config.clone();
|
||||
@@ -39,13 +49,28 @@ async fn router_setup(config: Config) -> Result<Router> {
|
||||
.await
|
||||
.err_context("Failed key-value store setup")?;
|
||||
|
||||
let favicon_path = {
|
||||
// Resolve the favicon path
|
||||
let asset_path = LOGO_ICO.resolve();
|
||||
|
||||
// If the asset path starts with "/", strip it. Otherwise it behaves as an "absolute path"
|
||||
// and replaces the base path in the join operation. This is necessary because Dioxus will
|
||||
// produce a path like "/assets/" in the call to `resolve`
|
||||
let asset_path_rel = asset_path.strip_prefix("/").unwrap_or(&asset_path);
|
||||
|
||||
config.server.public_path.join(asset_path_rel)
|
||||
};
|
||||
|
||||
tracing::debug!("Favicon path: {}", favicon_path.display());
|
||||
|
||||
let auth_layer = build_auth_layer(db_pool.clone(), key_val_pool, config.auth.cookies_secure);
|
||||
|
||||
let router = dioxus::server::router(App)
|
||||
.layer(from_fn(require_auth_middleware))
|
||||
.layer(Extension(config))
|
||||
.layer(Extension(db_pool))
|
||||
.layer(auth_layer);
|
||||
.layer(auth_layer)
|
||||
.nest_service("/favicon.ico", ServeFile::new(favicon_path));
|
||||
|
||||
tracing::info!("Setup complete, returning Router...");
|
||||
Ok(router)
|
||||
|
||||
@@ -13,13 +13,12 @@ const ALLOWED_PATH_PREFIX: [&str; 1] = ["/assets/"];
|
||||
#[cfg(debug_assertions)]
|
||||
const ALLOWED_PATH_PREFIX: [&str; 2] = ["/assets/", "/wasm/"];
|
||||
|
||||
const ALLOWED_PATHS: [&str; 6] = [
|
||||
const ALLOWED_PATHS: [&str; 5] = [
|
||||
"/login",
|
||||
"/signup",
|
||||
"/api/v1/auth/login",
|
||||
"/api/v1/auth/signup",
|
||||
"/api/v1/auth/user",
|
||||
"/favicon.ico",
|
||||
];
|
||||
|
||||
/// Axum middleware to redirect an unauthenticated request to /login unless it matches one of the allowed paths
|
||||
|
||||
Reference in New Issue
Block a user