diff options
-rw-r--r-- | Cargo.lock | 45 | ||||
-rw-r--r-- | Cargo.toml | 8 | ||||
-rw-r--r-- | src/args.rs | 18 | ||||
-rw-r--r-- | src/auth.rs | 64 | ||||
-rw-r--r-- | src/errors.rs | 13 | ||||
-rw-r--r-- | src/main.rs | 31 | ||||
-rw-r--r-- | tests/cli.rs | 4 |
7 files changed, 67 insertions, 116 deletions
@@ -565,9 +565,9 @@ dependencies = [ [[package]] name = "clap" -version = "3.0.0-beta.4" +version = "3.0.0-beta.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fcd70aa5597dbc42f7217a543f9ef2768b2ef823ba29036072d30e1d88e98406" +checksum = "feff3878564edb93745d58cf63e17b63f24142506e7a20c87a5521ed7bfb1d63" dependencies = [ "atty", "bitflags", @@ -579,14 +579,14 @@ dependencies = [ "termcolor", "terminal_size", "textwrap 0.14.2", - "vec_map", + "unicase", ] [[package]] name = "clap_derive" -version = "3.0.0-beta.4" +version = "3.0.0-beta.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b5bb0d655624a0b8770d1c178fb8ffcb1f91cc722cb08f451e3dc72465421ac" +checksum = "8b15c6b4f786ffb6192ffe65a36855bc1fc2444bcd0945ae16748dcd6ed7d0d3" dependencies = [ "heck", "proc-macro-error", @@ -597,11 +597,11 @@ dependencies = [ [[package]] name = "clap_generate" -version = "3.0.0-beta.4" +version = "3.0.0-beta.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d9b1abef93569f290952eff3c4a0a92d6767bb5158db095b4dc9a512b1c3643" +checksum = "097ab5db1c3417442270cd57c8dd39f6c3114d3ce09d595f9efddbb1fcfaa799" dependencies = [ - "clap 3.0.0-beta.4", + "clap 3.0.0-beta.5", ] [[package]] @@ -1407,7 +1407,7 @@ dependencies = [ "bytesize", "chrono", "chrono-humanize", - "clap 3.0.0-beta.4", + "clap 3.0.0-beta.5", "clap_generate", "futures", "get_if_addrs", @@ -1571,9 +1571,12 @@ checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" [[package]] name = "os_str_bytes" -version = "3.1.0" +version = "4.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6acbef58a60fe69ab50510a55bc8cdd4d6cf2283d27ad338f54cb52747a9cf2d" +checksum = "addaa943333a514159c80c97ff4a93306530d965d27e139188283cd13e06a799" +dependencies = [ + "memchr", +] [[package]] name = "output_vt100" @@ -2004,9 +2007,9 @@ dependencies = [ [[package]] name = "reqwest" -version = "0.11.5" +version = "0.11.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "51c732d463dd300362ffb44b7b125f299c23d2990411a4253824630ebc7467fb" +checksum = "66d2927ca2f685faf0fc620ac4834690d29e7abb153add10f5812eef20b5e280" dependencies = [ "base64", "bytes", @@ -2420,15 +2423,15 @@ checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" [[package]] name = "strum" -version = "0.21.0" +version = "0.22.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aaf86bbcfd1fa9670b7a129f64fc0c9fcbbfe4f1bc4210e9e98fe71ffc12cde2" +checksum = "f7ac893c7d471c8a21f31cfe213ec4f6d9afeed25537c772e08ef3f005f8729e" [[package]] name = "strum_macros" -version = "0.21.1" +version = "0.22.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d06aaeeee809dbc59eb4556183dd927df67db1540de5be8d3ec0b6636358a5ec" +checksum = "339f799d8b549e3744c7ac7feb216383e4005d94bdb22561b3ab8f3b808ae9fb" dependencies = [ "heck", "proc-macro2", @@ -2523,18 +2526,18 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.29" +version = "1.0.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "602eca064b2d83369e2b2f34b09c70b605402801927c65c11071ac911d299b88" +checksum = "854babe52e4df1653706b98fcfc05843010039b406875930a70e4d9644e5c417" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.29" +version = "1.0.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bad553cc2c78e8de258400763a647e80e6d1b31ee237275d756f6836d204494c" +checksum = "aa32fd3f627f367fe16f893e2597ae3c05020f8bba2666a4e6ea73d377e5714b" dependencies = [ "proc-macro2", "quote", @@ -30,8 +30,8 @@ port_check = "0.1" bytesize = "1" nanoid = "0.4" alphanumeric-sort = "1" -clap = { version = "3.0.0-beta.4", features = ["wrap_help"] } -clap_generate = "3.0.0-beta.4" +clap = { version = "3.0.0-beta.5", features = ["wrap_help"] } +clap_generate = "3.0.0-beta.5" chrono = "0.4" chrono-humanize = "0.2" serde = { version = "1", features = ["derive"] } @@ -41,8 +41,8 @@ libflate = "1" thiserror = "1" anyhow = "1" log = "0.4" -strum = "0.21" -strum_macros = "0.21" +strum = "0.22" +strum_macros = "0.22" sha2 = "0.9" hex = "0.4" zip = "0.5.11" diff --git a/src/args.rs b/src/args.rs index 5595bea..40d34e9 100644 --- a/src/args.rs +++ b/src/args.rs @@ -1,4 +1,4 @@ -use clap::{Clap, ValueHint}; +use clap::{Parser, ValueHint}; use clap_generate::Shell; use http::header::{HeaderMap, HeaderName, HeaderValue}; use std::net::IpAddr; @@ -8,14 +8,8 @@ use crate::auth; use crate::errors::ContextualError; use crate::renderer; -#[derive(Clap)] -#[clap( - name = "miniserve", - author, - about, - version, - setting = clap::AppSettings::ColoredHelp, -)] +#[derive(Parser)] +#[clap(name = "miniserve", author, about, version)] pub struct CliArgs { /// Be verbose, includes emitting access logs #[clap(short = 'v', long = "verbose")] @@ -83,7 +77,7 @@ pub struct CliArgs { short = 'c', long = "color-scheme", default_value = "squirrel", - possible_values = &renderer::THEME_SLUGS, + possible_values = &*renderer::THEME_SLUGS, case_insensitive = true, )] pub color_scheme: String, @@ -93,7 +87,7 @@ pub struct CliArgs { short = 'd', long = "color-scheme-dark", default_value = "archlinux", - possible_values = &renderer::THEME_SLUGS, + possible_values = &*renderer::THEME_SLUGS, case_insensitive = true, )] pub color_scheme_dark: String, @@ -155,7 +149,7 @@ pub struct CliArgs { pub show_wget_footer: bool, /// Generate completion file for a shell - #[clap(long = "print-completions", value_name = "shell", possible_values = &Shell::variants())] + #[clap(long = "print-completions", value_name = "shell", arg_enum)] pub print_completions: Option<Shell>, /// TLS certificate to use diff --git a/src/auth.rs b/src/auth.rs index 82b407c..b4717d1 100644 --- a/src/auth.rs +++ b/src/auth.rs @@ -1,8 +1,7 @@ -use actix_web::dev::{Service, ServiceRequest, ServiceResponse}; -use actix_web::{HttpRequest, ResponseError}; -use futures::future::Either; +use actix_web::dev::ServiceRequest; +use actix_web::HttpMessage; +use actix_web_httpauth::extractors::basic::BasicAuth; use sha2::{Digest, Sha256, Sha512}; -use std::future::{ready, Future}; use crate::errors::ContextualError; @@ -13,16 +12,12 @@ pub struct BasicAuthParams { pub password: String, } -impl BasicAuthParams { - fn try_from_request(req: &HttpRequest) -> actix_web::Result<Self> { - use actix_web::http::header::Header; - use actix_web_httpauth::headers::authorization::{Authorization, Basic}; - - let auth = Authorization::<Basic>::parse(req)?.into_scheme(); - Ok(Self { +impl From<BasicAuth> for BasicAuthParams { + fn from(auth: BasicAuth) -> Self { + Self { username: auth.user_id().to_string(), password: auth.password().unwrap_or(&"".into()).to_string(), - }) + } } } @@ -74,47 +69,24 @@ pub fn get_hash<T: Digest>(text: &str) -> Vec<u8> { hasher.update(text); hasher.finalize().to_vec() } + pub struct CurrentUser { pub name: String, } -fn handle_auth(req: &HttpRequest) -> Result<(), ContextualError> { +pub async fn handle_auth( + req: ServiceRequest, + cred: BasicAuth, +) -> actix_web::Result<ServiceRequest> { let required_auth = &req.app_data::<crate::MiniserveConfig>().unwrap().auth; - if required_auth.is_empty() { - // auth is disabled by configuration - return Ok(()); - } - - match BasicAuthParams::try_from_request(req) { - Ok(cred) => match match_auth(&cred, required_auth) { - true => { - req.extensions_mut().insert(CurrentUser { - name: cred.username, - }); - Ok(()) - } - false => Err(ContextualError::InvalidHttpCredentials), - }, - Err(_) => Err(ContextualError::RequireHttpCredentials), - } -} + req.extensions_mut().insert(CurrentUser { + name: cred.user_id().to_string(), + }); -pub fn auth_middleware<S>( - mut req: ServiceRequest, - srv: &S, -) -> impl Future<Output = actix_web::Result<ServiceResponse>> + 'static -where - S: Service<ServiceRequest, Response = ServiceResponse, Error = actix_web::Error>, - S::Future: 'static, -{ - match handle_auth(req.parts_mut().0) { - Ok(_) => Either::Left(srv.call(req)), - Err(err) => { - let resp = req.into_response(err.error_response()); - Either::Right(ready(Ok(resp))) - } - } + match_auth(&cred.into(), required_auth) + .then(|| req) + .ok_or_else(|| ContextualError::InvalidHttpCredentials.into()) } #[rustfmt::skip] diff --git a/src/errors.rs b/src/errors.rs index 25d0529..c6fcce3 100644 --- a/src/errors.rs +++ b/src/errors.rs @@ -58,10 +58,6 @@ pub enum ContextualError { #[error("{0}")] ArchiveCreationDetailError(String), - /// Might occur when the HTTP credentials are not provided - #[error("Access requires HTTP authentication")] - RequireHttpCredentials, - /// Might occur when the HTTP credentials are not correct #[error("Invalid credentials for HTTP authentication")] InvalidHttpCredentials, @@ -90,20 +86,17 @@ impl ResponseError for ContextualError { Self::ArchiveCreationError(_, err) => err.status_code(), Self::RouteNotFoundError(_) => StatusCode::NOT_FOUND, Self::InsufficientPermissionsError(_) => StatusCode::FORBIDDEN, - Self::InvalidHttpCredentials | Self::RequireHttpCredentials => StatusCode::UNAUTHORIZED, + Self::InvalidHttpCredentials => StatusCode::UNAUTHORIZED, Self::InvalidHttpRequestError(_) => StatusCode::BAD_REQUEST, _ => StatusCode::INTERNAL_SERVER_ERROR, } } fn error_response(&self) -> HttpResponse { - if let Self::RequireHttpCredentials = self { - } else { - log_error_chain(self.to_string()); - } + log_error_chain(self.to_string()); let mut resp = HttpResponse::build(self.status_code()); - if let Self::RequireHttpCredentials | Self::InvalidHttpCredentials = self { + if let Self::InvalidHttpCredentials = self { resp.append_header(( header::WWW_AUTHENTICATE, header::HeaderValue::from_static("Basic realm=\"miniserve\""), diff --git a/src/main.rs b/src/main.rs index eb159a2..205fac5 100644 --- a/src/main.rs +++ b/src/main.rs @@ -9,10 +9,10 @@ use actix_files::NamedFile; use actix_web::web; use actix_web::{http::header::ContentType, Responder}; use actix_web::{middleware, App, HttpRequest, HttpResponse}; -use anyhow::{bail, Result}; -use clap::{crate_version, Clap, IntoApp}; -use clap_generate::generators::{Bash, Elvish, Fish, PowerShell, Zsh}; -use clap_generate::{generate, Shell}; +use actix_web_httpauth::middleware::HttpAuthentication; +use anyhow::Result; +use clap::{crate_version, IntoApp, Parser}; +use clap_generate::generate; use log::{error, warn}; use qrcodegen::{QrCode, QrCodeEcc}; use yansi::{Color, Paint}; @@ -35,18 +35,8 @@ fn main() -> Result<()> { if let Some(shell) = args.print_completions { let mut clap_app = args::CliArgs::into_app(); - match shell { - Shell::Bash => generate::<Bash, _>(&mut clap_app, "miniserve", &mut std::io::stdout()), - Shell::Elvish => { - generate::<Elvish, _>(&mut clap_app, "miniserve", &mut std::io::stdout()) - } - Shell::Fish => generate::<Fish, _>(&mut clap_app, "miniserve", &mut std::io::stdout()), - Shell::PowerShell => { - generate::<PowerShell, _>(&mut clap_app, "miniserve", &mut std::io::stdout()) - } - Shell::Zsh => generate::<Zsh, _>(&mut clap_app, "miniserve", &mut std::io::stdout()), - _ => bail!("Invalid shell provided!"), - } + let app_name = clap_app.get_name().to_string(); + generate(shell, &mut clap_app, app_name, &mut io::stdout()); return Ok(()); } @@ -207,11 +197,10 @@ async fn run(miniserve_config: MiniserveConfig) -> Result<(), ContextualError> { .route(&format!("/{}", inside_config.css_route), web::get().to(css)) .service( web::scope(inside_config.random_route.as_deref().unwrap_or("")) - // we should use `actix_web_httpauth::middleware::HttpAuthentication` - // but it is unfortuantrly broken - // see: https://github.com/actix/actix-extras/issues/127 - // TODO replace this when fixed upstream - .wrap_fn(auth::auth_middleware) + .wrap(middleware::Condition::new( + !inside_config.auth.is_empty(), + HttpAuthentication::basic(auth::handle_auth), + )) .configure(|c| configure_app(c, &inside_config)), ) .default_service(web::get().to(error_404)) diff --git a/tests/cli.rs b/tests/cli.rs index 8c88c93..7c3c972 100644 --- a/tests/cli.rs +++ b/tests/cli.rs @@ -32,10 +32,10 @@ fn version_shows() -> Result<(), Error> { #[test] /// Print completions and exit. fn print_completions() -> Result<(), Error> { - for shell in &Shell::variants() { + for shell in Shell::arg_values() { Command::cargo_bin("miniserve")? .arg("--print-completions") - .arg(&shell) + .arg(shell.get_name()) .assert() .success(); } |