From 8440d59dd69594d8f09e640a02f0494544385d61 Mon Sep 17 00:00:00 2001 From: boastful-squirrel Date: Fri, 26 Apr 2019 19:05:59 +0200 Subject: Cargo fmt --- src/args.rs | 21 +++++++++++++-------- src/auth.rs | 9 +++++++-- src/errors.rs | 5 ++++- 3 files changed, 24 insertions(+), 11 deletions(-) (limited to 'src') diff --git a/src/args.rs b/src/args.rs index 4077f35..b769a9b 100644 --- a/src/args.rs +++ b/src/args.rs @@ -80,9 +80,7 @@ fn parse_interface(src: &str) -> Result { /// Checks wether the auth string is valid, i.e. it follows the syntax username:password fn parse_auth(src: &str) -> Result { let mut split = src.splitn(3, ':'); - let invalid_auth_format = Err( - ContextualError::new(ContextualErrorKind::InvalidAuthFormat) - ); + let invalid_auth_format = Err(ContextualError::new(ContextualErrorKind::InvalidAuthFormat)); let username = match split.next() { Some(username) => username, @@ -100,7 +98,9 @@ fn parse_auth(src: &str) -> Result { let hash_bin = if let Ok(hash_bin) = hex::decode(hash_hex) { hash_bin } else { - return Err(ContextualError::new(ContextualErrorKind::InvalidPasswordHash)) + return Err(ContextualError::new( + ContextualErrorKind::InvalidPasswordHash, + )); }; match second_part { @@ -108,16 +108,18 @@ fn parse_auth(src: &str) -> Result { "sha512" => auth::RequiredAuthPassword::Sha512(hash_bin.to_owned()), _ => { return Err(ContextualError::new( - ContextualErrorKind::InvalidHashMethod(second_part.to_owned()) + ContextualErrorKind::InvalidHashMethod(second_part.to_owned()), )) - }, + } } } else { // To make it Windows-compatible, the password needs to be shorter than 255 characters. // After 255 characters, Windows will truncate the value. // As for the username, the spec does not mention a limit in length if second_part.len() > 255 { - return Err(ContextualError::new(ContextualErrorKind::PasswordTooLongError)); + return Err(ContextualError::new( + ContextualErrorKind::PasswordTooLongError, + )); } auth::RequiredAuthPassword::Plain(second_part.to_owned()) @@ -189,7 +191,10 @@ mod tests { } #[rstest_parametrize( - auth_string, username, password, encrypt, + auth_string, + username, + password, + encrypt, case("username:password", "username", "password", "plain"), case("username:sha256:abcd", "username", "abcd", "sha256"), case("username:sha512:abcd", "username", "abcd", "sha512") diff --git a/src/auth.rs b/src/auth.rs index e75f498..d8de30e 100644 --- a/src/auth.rs +++ b/src/auth.rs @@ -165,13 +165,18 @@ mod tests { } #[rstest_parametrize( - should_pass, param_username, param_password, required_username, required_password, encrypt, + should_pass, + param_username, + param_password, + required_username, + required_password, + encrypt, case(true, "obi", "hello there", "obi", "hello there", "plain"), case(false, "obi", "hello there", "obi", "hi!", "plain"), case(true, "obi", "hello there", "obi", "hello there", "sha256"), case(false, "obi", "hello there", "obi", "hi!", "sha256"), case(true, "obi", "hello there", "obi", "hello there", "sha512"), - case(false, "obi", "hello there", "obi", "hi!", "sha512"), + case(false, "obi", "hello there", "obi", "hi!", "sha512") )] fn test_auth( should_pass: bool, diff --git a/src/errors.rs b/src/errors.rs index 833e9c4..9f0a418 100644 --- a/src/errors.rs +++ b/src/errors.rs @@ -33,7 +33,10 @@ pub enum ContextualErrorKind { InvalidAuthFormat, /// This error might occure if the hash method is neither sha256 nor sha512 - #[fail(display = "{} is not a valid hashing method. Expected sha256 or sha512", _0)] + #[fail( + display = "{} is not a valid hashing method. Expected sha256 or sha512", + _0 + )] InvalidHashMethod(String), /// This error might occur if the HTTP auth hash password is not a valid hex code -- cgit v1.2.3 From 111a3dc44730e0e24a5aa4218e8e385b236a619d Mon Sep 17 00:00:00 2001 From: boastful-squirrel Date: Fri, 26 Apr 2019 19:09:17 +0200 Subject: Merged query parameter structs + improved file upload errors --- src/errors.rs | 4 ++++ src/file_upload.rs | 54 +++++++++++++++++++++++++++++++++--------------------- src/listing.rs | 5 +++-- 3 files changed, 40 insertions(+), 23 deletions(-) (limited to 'src') diff --git a/src/errors.rs b/src/errors.rs index 9f0a418..d34b447 100644 --- a/src/errors.rs +++ b/src/errors.rs @@ -68,6 +68,10 @@ pub enum ContextualErrorKind { _0 )] HTTPAuthenticationError(Box), + + /// This error might occur when an HTTP request is invalid + #[fail(display = "Invalid HTTP request\ncaused by: {}", _0)] + InvalidHTTPRequestError(String), } pub fn log_error_chain(description: String) { diff --git a/src/file_upload.rs b/src/file_upload.rs index 1618617..f444396 100644 --- a/src/file_upload.rs +++ b/src/file_upload.rs @@ -3,22 +3,16 @@ use actix_web::{ HttpResponse, Query, }; use futures::{future, future::FutureResult, Future, Stream}; -use serde::Deserialize; use std::{ fs, io::Write, path::{Component, PathBuf}, }; -use crate::errors::{self, ContextualErrorKind}; +use crate::errors::{self, ContextualError, ContextualErrorKind}; +use crate::listing::QueryParameters; use crate::renderer; -/// Query parameters -#[derive(Debug, Deserialize)] -struct QueryParameters { - path: PathBuf, -} - /// Create future to save file. fn save_file( field: multipart::Field, @@ -127,31 +121,49 @@ pub fn upload_file(req: &HttpRequest) -> FutureResponse< } else { "/".to_string() }; - let app_root_dir = if let Ok(dir) = req.state().path.canonicalize() { - dir - } else { - return Box::new(create_error_response("Internal server error", &return_path)); + + let app_root_dir = match req.state().path.canonicalize() { + Ok(dir) => dir, + Err(e) => { + let err = ContextualError::new(ContextualErrorKind::IOError( + "Failed to resolve path served by miniserve".to_string(), + e, + )); + return Box::new(create_error_response(&err.to_string(), &return_path)); + } }; + let path = match Query::::extract(req) { Ok(query) => { - if let Ok(stripped_path) = query.path.strip_prefix(Component::RootDir) { - stripped_path.to_owned() + if let Some(path) = query.path.clone() { + if let Ok(stripped_path) = path.strip_prefix(Component::RootDir) { + stripped_path.to_owned() + } else { + path.clone() + } } else { - query.path.clone() + let err = ContextualError::new(ContextualErrorKind::InvalidHTTPRequestError( + "Missing query parameter 'path'".to_string(), + )); + return Box::new(create_error_response(&err.to_string(), &return_path)); } } - Err(_) => { - return Box::new(create_error_response( - "Unspecified parameter path", - &return_path, - )) + Err(e) => { + let err = + ContextualError::new(ContextualErrorKind::InvalidHTTPRequestError(e.to_string())); + return Box::new(create_error_response(&err.to_string(), &return_path)); } }; // If the target path is under the app root directory, save the file. let target_dir = match &app_root_dir.clone().join(path).canonicalize() { Ok(path) if path.starts_with(&app_root_dir) => path.clone(), - _ => return Box::new(create_error_response("Invalid path", &return_path)), + _ => { + let err = ContextualError::new(ContextualErrorKind::InvalidHTTPRequestError( + "Invalid value for 'path' parameter".to_string(), + )); + return Box::new(create_error_response(&err.to_string(), &return_path)); + } }; let overwrite_files = req.state().overwrite_files; Box::new( diff --git a/src/listing.rs b/src/listing.rs index a030feb..e718702 100644 --- a/src/listing.rs +++ b/src/listing.rs @@ -5,7 +5,7 @@ use htmlescape::encode_minimal as escape_html_entity; use percent_encoding::{utf8_percent_encode, DEFAULT_ENCODE_SET}; use serde::Deserialize; use std::io; -use std::path::Path; +use std::path::{Path, PathBuf}; use std::time::SystemTime; use strum_macros::{Display, EnumString}; @@ -16,7 +16,8 @@ use crate::themes; /// Query parameters #[derive(Deserialize)] -struct QueryParameters { +pub struct QueryParameters { + pub path: Option, sort: Option, order: Option, download: Option, -- cgit v1.2.3 From 4a9711b71674c6b62512dd6286869690d4497bcc Mon Sep 17 00:00:00 2001 From: boastful-squirrel Date: Fri, 26 Apr 2019 20:08:16 +0200 Subject: Made ColorScheme, SortingMethod and SortingOrder enums derive Copy --- src/listing.rs | 16 ++++++------ src/main.rs | 4 +-- src/renderer.rs | 80 ++++++++++++++++++++++++++++----------------------------- src/themes.rs | 10 ++++---- 4 files changed, 55 insertions(+), 55 deletions(-) (limited to 'src') diff --git a/src/listing.rs b/src/listing.rs index e718702..7cc125d 100644 --- a/src/listing.rs +++ b/src/listing.rs @@ -25,7 +25,7 @@ pub struct QueryParameters { } /// Available sorting methods -#[derive(Deserialize, Clone, EnumString, Display)] +#[derive(Deserialize, Clone, EnumString, Display, Copy)] #[serde(rename_all = "snake_case")] #[strum(serialize_all = "snake_case")] pub enum SortingMethod { @@ -40,7 +40,7 @@ pub enum SortingMethod { } /// Available sorting orders -#[derive(Deserialize, Clone, EnumString, Display)] +#[derive(Deserialize, Clone, EnumString, Display, Copy)] pub enum SortingOrder { /// Ascending order #[serde(alias = "asc")] @@ -146,10 +146,10 @@ pub fn directory_listing( let (sort_method, sort_order, download, color_scheme) = if let Ok(query) = Query::::extract(req) { ( - query.sort.clone(), - query.order.clone(), + query.sort, + query.order, query.download.clone(), - query.theme.clone(), + query.theme, ) } else { (None, None, None, None) @@ -211,7 +211,7 @@ pub fn directory_listing( } } - if let Some(sorting_method) = &sort_method { + if let Some(sorting_method) = sort_method { match sorting_method { SortingMethod::Name => entries .sort_by(|e1, e2| alphanumeric_sort::compare_str(e1.name.clone(), e2.name.clone())), @@ -235,13 +235,13 @@ pub fn directory_listing( entries.sort_by(|e1, e2| alphanumeric_sort::compare_str(e1.name.clone(), e2.name.clone())) } - if let Some(sorting_order) = &sort_order { + if let Some(sorting_order) = sort_order { if let SortingOrder::Descending = sorting_order { entries.reverse() } } - let color_scheme = color_scheme.unwrap_or_else(|| default_color_scheme.clone()); + let color_scheme = color_scheme.unwrap_or_else(|| default_color_scheme); if let Some(compression_method) = &download { log::info!( diff --git a/src/main.rs b/src/main.rs index bc8f3f0..a9d44df 100644 --- a/src/main.rs +++ b/src/main.rs @@ -239,7 +239,7 @@ fn configure_app(app: App) -> App { let path = &app.state().path; let no_symlinks = app.state().no_symlinks; let random_route = app.state().random_route.clone(); - let default_color_scheme = app.state().default_color_scheme.clone(); + let default_color_scheme = app.state().default_color_scheme; let file_upload = app.state().file_upload; upload_route = if let Some(random_route) = app.state().random_route.clone() { format!("/{}/upload", random_route) @@ -261,7 +261,7 @@ fn configure_app(app: App) -> App { no_symlinks, file_upload, random_route.clone(), - default_color_scheme.clone(), + default_color_scheme, u_r.clone(), ) }), diff --git a/src/renderer.rs b/src/renderer.rs index b292e70..76990de 100644 --- a/src/renderer.rs +++ b/src/renderer.rs @@ -23,7 +23,7 @@ pub fn page( current_dir: &str, ) -> Markup { html! { - (page_header(serve_path, &color_scheme, file_upload)) + (page_header(serve_path, color_scheme, file_upload)) body#drop-container { @if file_upload { div.drag-form { @@ -32,7 +32,7 @@ pub fn page( } } } - (color_scheme_selector(&sort_method, &sort_order, &color_scheme, &default_color_scheme, serve_path)) + (color_scheme_selector(sort_method, sort_order, color_scheme, default_color_scheme, serve_path)) div.container { span#top { } h1.title { "Index of " (serve_path) } @@ -56,9 +56,9 @@ pub fn page( } table { thead { - th { (build_link("name", "Name", &sort_method, &sort_order, &color_scheme, &default_color_scheme)) } - th { (build_link("size", "Size", &sort_method, &sort_order, &color_scheme, &default_color_scheme)) } - th { (build_link("date", "Last modification", &sort_method, &sort_order, &color_scheme, &default_color_scheme)) } + th { (build_link("name", "Name", sort_method, sort_order, color_scheme, default_color_scheme)) } + th { (build_link("size", "Size", sort_method, sort_order, color_scheme, default_color_scheme)) } + th { (build_link("date", "Last modification", sort_method, sort_order, color_scheme, default_color_scheme)) } } tbody { @if !is_root { @@ -66,7 +66,7 @@ pub fn page( tr { td colspan="3" { span.root-chevron { (chevron_left()) } - a.root href=(parametrized_link(&parent, &sort_method, &sort_order, &color_scheme, &default_color_scheme)) { + a.root href=(parametrized_link(&parent, sort_method, sort_order, color_scheme, default_color_scheme)) { "Parent directory" } } @@ -74,7 +74,7 @@ pub fn page( } } @for entry in entries { - (entry_row(entry, &sort_method, &sort_order, &color_scheme, &default_color_scheme)) + (entry_row(entry, sort_method, sort_order, color_scheme, default_color_scheme)) } } } @@ -88,10 +88,10 @@ pub fn page( /// Partial: color scheme selector fn color_scheme_selector( - sort_method: &Option, - sort_order: &Option, - active_color_scheme: &ColorScheme, - default_color_scheme: &ColorScheme, + sort_method: Option, + sort_order: Option, + active_color_scheme: ColorScheme, + default_color_scheme: ColorScheme, serve_path: &str, ) -> Markup { html! { @@ -103,13 +103,13 @@ fn color_scheme_selector( } ul { @for color_scheme in ColorScheme::iter() { - @if active_color_scheme == &color_scheme { + @if active_color_scheme == color_scheme { li.active { - (color_scheme_link(&sort_method, &sort_order, &color_scheme, &default_color_scheme, serve_path)) + (color_scheme_link(sort_method, sort_order, color_scheme, default_color_scheme, serve_path)) } } @else { li { - (color_scheme_link(&sort_method, &sort_order, &color_scheme, &default_color_scheme, serve_path)) + (color_scheme_link(sort_method, sort_order, color_scheme, default_color_scheme, serve_path)) } } } @@ -122,18 +122,18 @@ fn color_scheme_selector( /// Partial: color scheme link fn color_scheme_link( - sort_method: &Option, - sort_order: &Option, - color_scheme: &ColorScheme, - default_color_scheme: &ColorScheme, + sort_method: Option, + sort_order: Option, + color_scheme: ColorScheme, + default_color_scheme: ColorScheme, serve_path: &str, ) -> Markup { let link = parametrized_link( serve_path, - &sort_method, - &sort_order, - &color_scheme, - &default_color_scheme, + sort_method, + sort_order, + color_scheme, + default_color_scheme, ); let title = format!("Switch to {} theme", color_scheme); @@ -165,10 +165,10 @@ fn archive_button(compress_method: CompressionMethod) -> Markup { /// If they are set, adds query parameters to links to keep them across pages fn parametrized_link( link: &str, - sort_method: &Option, - sort_order: &Option, - color_scheme: &ColorScheme, - default_color_scheme: &ColorScheme, + sort_method: Option, + sort_order: Option, + color_scheme: ColorScheme, + default_color_scheme: ColorScheme, ) -> String { if let Some(method) = sort_method { if let Some(order) = sort_order { @@ -193,10 +193,10 @@ fn parametrized_link( fn build_link( name: &str, title: &str, - sort_method: &Option, - sort_order: &Option, - color_scheme: &ColorScheme, - default_color_scheme: &ColorScheme, + sort_method: Option, + sort_order: Option, + color_scheme: ColorScheme, + default_color_scheme: ColorScheme, ) -> Markup { let mut link = format!("?sort={}&order=asc", name); let mut help = format!("Sort by {} in ascending order", name); @@ -231,17 +231,17 @@ fn build_link( /// Partial: row for an entry fn entry_row( entry: Entry, - sort_method: &Option, - sort_order: &Option, - color_scheme: &ColorScheme, - default_color_scheme: &ColorScheme, + sort_method: Option, + sort_order: Option, + color_scheme: ColorScheme, + default_color_scheme: ColorScheme, ) -> Markup { html! { tr { td { p { @if entry.is_dir() { - a.directory href=(parametrized_link(&entry.link, &sort_method, &sort_order, &color_scheme, &default_color_scheme)) { + a.directory href=(parametrized_link(&entry.link, sort_method, sort_order, color_scheme, default_color_scheme)) { (entry.name) "/" } } @else if entry.is_file() { @@ -256,7 +256,7 @@ fn entry_row( } } } @else if entry.is_symlink() { - a.symlink href=(parametrized_link(&entry.link, &sort_method, &sort_order, &color_scheme, &default_color_scheme)) { + a.symlink href=(parametrized_link(&entry.link, sort_method, sort_order, color_scheme, default_color_scheme)) { (entry.name) span.symlink-symbol { "⇢" } } } @@ -286,8 +286,8 @@ fn entry_row( } /// Partial: CSS -fn css(color_scheme: &ColorScheme) -> Markup { - let theme = color_scheme.clone().get_theme(); +fn css(color_scheme: ColorScheme) -> Markup { + let theme = color_scheme.get_theme(); let css = format!(" html {{ @@ -686,7 +686,7 @@ fn chevron_down() -> Markup { } /// Partial: page header -fn page_header(serve_path: &str, color_scheme: &ColorScheme, file_upload: bool) -> Markup { +fn page_header(serve_path: &str, color_scheme: ColorScheme, file_upload: bool) -> Markup { html! { (DOCTYPE) html { @@ -694,7 +694,7 @@ fn page_header(serve_path: &str, color_scheme: &ColorScheme, file_upload: bool) meta http-equiv="X-UA-Compatible" content="IE=edge"; meta name="viewport" content="width=device-width, initial-scale=1"; title { "Index of " (serve_path) } - style { (css(&color_scheme)) } + style { (css(color_scheme)) } @if file_upload { (PreEscaped(r#"