Use clap for configuration
This commit is contained in:
parent
bcbb7dfc67
commit
1f852ef219
55
Cargo.lock
generated
55
Cargo.lock
generated
|
@ -540,6 +540,46 @@ dependencies = [
|
||||||
"inout",
|
"inout",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "clap"
|
||||||
|
version = "4.5.10"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "8f6b81fb3c84f5563d509c59b5a48d935f689e993afa90fe39047f05adef9142"
|
||||||
|
dependencies = [
|
||||||
|
"clap_builder",
|
||||||
|
"clap_derive",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "clap_builder"
|
||||||
|
version = "4.5.10"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5ca6706fd5224857d9ac5eb9355f6683563cc0541c7cd9d014043b57cbec78ac"
|
||||||
|
dependencies = [
|
||||||
|
"anstream",
|
||||||
|
"anstyle",
|
||||||
|
"clap_lex",
|
||||||
|
"strsim",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "clap_derive"
|
||||||
|
version = "4.5.8"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "2bac35c6dafb060fd4d275d9a4ffae97917c13a6327903a8be2153cd964f7085"
|
||||||
|
dependencies = [
|
||||||
|
"heck 0.5.0",
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn 2.0.68",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "clap_lex"
|
||||||
|
version = "0.7.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "4b82cf0babdbd58558212896d1a4272303a57bdb245c2bf1147185fb45640e70"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "colorchoice"
|
name = "colorchoice"
|
||||||
version = "1.0.1"
|
version = "1.0.1"
|
||||||
|
@ -1016,6 +1056,12 @@ dependencies = [
|
||||||
"unicode-segmentation",
|
"unicode-segmentation",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "heck"
|
||||||
|
version = "0.5.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "hex"
|
name = "hex"
|
||||||
version = "0.4.3"
|
version = "0.4.3"
|
||||||
|
@ -1170,6 +1216,7 @@ dependencies = [
|
||||||
"actix-web",
|
"actix-web",
|
||||||
"barcoders",
|
"barcoders",
|
||||||
"base64 0.22.1",
|
"base64 0.22.1",
|
||||||
|
"clap",
|
||||||
"datamatrix",
|
"datamatrix",
|
||||||
"enum-iterator",
|
"enum-iterator",
|
||||||
"env_logger",
|
"env_logger",
|
||||||
|
@ -2042,7 +2089,7 @@ checksum = "5833ef53aaa16d860e92123292f1f6a3d53c34ba8b1969f152ef1a7bb803f3c8"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"dotenvy",
|
"dotenvy",
|
||||||
"either",
|
"either",
|
||||||
"heck",
|
"heck 0.4.1",
|
||||||
"hex",
|
"hex",
|
||||||
"once_cell",
|
"once_cell",
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
|
@ -2180,6 +2227,12 @@ dependencies = [
|
||||||
"unicode-properties",
|
"unicode-properties",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "strsim"
|
||||||
|
version = "0.11.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "subtle"
|
name = "subtle"
|
||||||
version = "2.6.1"
|
version = "2.6.1"
|
||||||
|
|
|
@ -15,6 +15,7 @@ actix-session = { version = "0.9.0", features = ["cookie-session"] }
|
||||||
actix-web = { version = "4.8.0", features = ["cookies"] }
|
actix-web = { version = "4.8.0", features = ["cookies"] }
|
||||||
barcoders = { version = "2.0.0", default-features = false, features = ["std"] }
|
barcoders = { version = "2.0.0", default-features = false, features = ["std"] }
|
||||||
base64 = "0.22.1"
|
base64 = "0.22.1"
|
||||||
|
clap = { version = "4.5.10", features = ["derive", "env"] }
|
||||||
datamatrix = "0.3.1"
|
datamatrix = "0.3.1"
|
||||||
enum-iterator = "2.1.0"
|
enum-iterator = "2.1.0"
|
||||||
env_logger = "0.11.3"
|
env_logger = "0.11.3"
|
||||||
|
|
34
src/config.rs
Normal file
34
src/config.rs
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
// SPDX-FileCopyrightText: 2024 Simon Bruder <simon@sbruder.de>
|
||||||
|
//
|
||||||
|
// SPDX-License-Identifier: AGPL-3.0-or-later
|
||||||
|
|
||||||
|
use std::net::{IpAddr, Ipv6Addr};
|
||||||
|
|
||||||
|
use clap::Parser;
|
||||||
|
|
||||||
|
/// A lightweight inventory management system
|
||||||
|
#[derive(Clone, Parser, Debug)]
|
||||||
|
#[command(version, about)]
|
||||||
|
pub struct Config {
|
||||||
|
/// Database URL of PostgreSQL database
|
||||||
|
#[arg(long, env)]
|
||||||
|
pub database_url: String,
|
||||||
|
|
||||||
|
/// Secret key for encrypting session cookie
|
||||||
|
///
|
||||||
|
/// Can be generated with head -c 64 /dev/urandom | base64 -w0
|
||||||
|
#[arg(long, env)]
|
||||||
|
pub secret_key: Option<String>,
|
||||||
|
|
||||||
|
/// Address for HTTP server to listen on
|
||||||
|
#[arg(long, env, default_value_t = IpAddr::V6(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1)))]
|
||||||
|
pub listen_address: std::net::IpAddr,
|
||||||
|
|
||||||
|
/// Port for HTTP server to listen on
|
||||||
|
#[arg(long, env, default_value_t = 8080)]
|
||||||
|
pub listen_port: u16,
|
||||||
|
|
||||||
|
/// Superuser password
|
||||||
|
#[arg(long, env)]
|
||||||
|
pub superuser_password: String,
|
||||||
|
}
|
|
@ -59,12 +59,10 @@ async fn login(
|
||||||
req: HttpRequest,
|
req: HttpRequest,
|
||||||
form: web::Form<LoginForm>,
|
form: web::Form<LoginForm>,
|
||||||
query: web::Query<LoginQuery>,
|
query: web::Query<LoginQuery>,
|
||||||
|
config: web::Data<crate::Config>,
|
||||||
) -> Result<impl Responder, error::Error> {
|
) -> Result<impl Responder, error::Error> {
|
||||||
// Very basic authentication for now (only password, hardcoded in environment variable)
|
// Very basic authentication for now (only password, hardcoded in configuration)
|
||||||
if form.password
|
if form.password == config.superuser_password {
|
||||||
== std::env::var("SUPERUSER_PASSWORD")
|
|
||||||
.map_err(|_| error::ErrorInternalServerError("login disabled (no password set)"))?
|
|
||||||
{
|
|
||||||
Identity::login(&req.extensions(), "superuser".into())
|
Identity::login(&req.extensions(), "superuser".into())
|
||||||
.map_err(error::ErrorInternalServerError)?;
|
.map_err(error::ErrorInternalServerError)?;
|
||||||
Ok(
|
Ok(
|
||||||
|
|
|
@ -2,6 +2,9 @@
|
||||||
//
|
//
|
||||||
// SPDX-License-Identifier: AGPL-3.0-or-later
|
// SPDX-License-Identifier: AGPL-3.0-or-later
|
||||||
|
|
||||||
|
mod config;
|
||||||
pub mod frontend;
|
pub mod frontend;
|
||||||
pub mod label;
|
pub mod label;
|
||||||
pub mod middleware;
|
pub mod middleware;
|
||||||
|
|
||||||
|
pub use config::Config;
|
||||||
|
|
28
src/main.rs
28
src/main.rs
|
@ -2,17 +2,18 @@
|
||||||
//
|
//
|
||||||
// SPDX-License-Identifier: AGPL-3.0-or-later
|
// SPDX-License-Identifier: AGPL-3.0-or-later
|
||||||
|
|
||||||
use std::env;
|
|
||||||
|
|
||||||
use actix_identity::IdentityMiddleware;
|
use actix_identity::IdentityMiddleware;
|
||||||
use actix_session::{storage::CookieSessionStore, SessionMiddleware};
|
use actix_session::{storage::CookieSessionStore, SessionMiddleware};
|
||||||
use actix_web::middleware::ErrorHandlers;
|
use actix_web::middleware::ErrorHandlers;
|
||||||
use actix_web::{cookie::Key, http::StatusCode, web, App, HttpResponse, HttpServer};
|
use actix_web::{cookie::Key, http::StatusCode, web, App, HttpResponse, HttpServer};
|
||||||
use base64::prelude::{Engine as _, BASE64_STANDARD};
|
use base64::prelude::{Engine as _, BASE64_STANDARD};
|
||||||
|
use clap::Parser;
|
||||||
use log::{info, warn};
|
use log::{info, warn};
|
||||||
use mime_guess::from_path;
|
use mime_guess::from_path;
|
||||||
use rust_embed::Embed;
|
use rust_embed::Embed;
|
||||||
|
|
||||||
|
use li7y::Config;
|
||||||
|
|
||||||
#[derive(Embed)]
|
#[derive(Embed)]
|
||||||
#[folder = "static"]
|
#[folder = "static"]
|
||||||
struct Static;
|
struct Static;
|
||||||
|
@ -21,39 +22,38 @@ struct Static;
|
||||||
async fn main() -> std::io::Result<()> {
|
async fn main() -> std::io::Result<()> {
|
||||||
env_logger::Builder::from_env(env_logger::Env::default().default_filter_or("info")).init();
|
env_logger::Builder::from_env(env_logger::Env::default().default_filter_or("info")).init();
|
||||||
|
|
||||||
|
let config = Config::parse();
|
||||||
|
|
||||||
// generate a secret key with head -c 64 /dev/urandom | base64 -w0
|
// generate a secret key with head -c 64 /dev/urandom | base64 -w0
|
||||||
let secret_key = match env::var("SECRET_KEY") {
|
let secret_key = match config.secret_key {
|
||||||
Ok(encoded) => Key::from(
|
Some(ref encoded) => Key::from(
|
||||||
&BASE64_STANDARD
|
&BASE64_STANDARD
|
||||||
.decode(encoded)
|
.decode(encoded)
|
||||||
.expect("failed to decode base64 in SECRET_KEY"),
|
.expect("failed to decode base64 in SECRET_KEY"),
|
||||||
),
|
),
|
||||||
Err(_) => {
|
None => {
|
||||||
warn!("SECRET_KEY was not specified, using randomly generated key");
|
warn!("SECRET_KEY was not specified, using randomly generated key");
|
||||||
Key::generate()
|
Key::generate()
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let pool: sqlx::PgPool = sqlx::Pool::<sqlx::postgres::Postgres>::connect(
|
let pool: sqlx::PgPool = sqlx::Pool::<sqlx::postgres::Postgres>::connect(&config.database_url)
|
||||||
&env::var("DATABASE_URL").expect("DATABASE_URL must be set"),
|
.await
|
||||||
)
|
.expect("failed to connect to database");
|
||||||
.await
|
|
||||||
.expect("failed to connect to database");
|
|
||||||
|
|
||||||
sqlx::migrate!()
|
sqlx::migrate!()
|
||||||
.run(&pool)
|
.run(&pool)
|
||||||
.await
|
.await
|
||||||
.expect("failed to run migrations");
|
.expect("failed to run migrations");
|
||||||
|
|
||||||
let address = env::var("LISTEN_ADDRESS").unwrap_or("::1".to_string());
|
let address = config.listen_address;
|
||||||
let port = env::var("LISTEN_PORT").map_or(8080, |s| {
|
let port = config.listen_port;
|
||||||
s.parse::<u16>().expect("failed to parse LISTEN_PORT")
|
|
||||||
});
|
|
||||||
|
|
||||||
info!("Starting on {address}:{port}");
|
info!("Starting on {address}:{port}");
|
||||||
|
|
||||||
HttpServer::new(move || {
|
HttpServer::new(move || {
|
||||||
App::new()
|
App::new()
|
||||||
|
.app_data(web::Data::new(config.clone()))
|
||||||
.app_data(web::Data::new(pool.clone()))
|
.app_data(web::Data::new(pool.clone()))
|
||||||
.service(web::scope("/static").route(
|
.service(web::scope("/static").route(
|
||||||
"/{_:.*}",
|
"/{_:.*}",
|
||||||
|
|
Loading…
Reference in a new issue