diff --git a/src/auth.rs b/src/auth.rs new file mode 100644 index 0000000..38d785d --- /dev/null +++ b/src/auth.rs @@ -0,0 +1,44 @@ +use actix_web::http::header::AUTHORIZATION; +use actix_web::http::HeaderMap; +use actix_web::{error, Error}; + +/// Checks the authorization header for the specified token. +/// +/// `Authorization: (type) ` +pub fn check(host: &str, headers: &HeaderMap, token: Option) -> Result<(), Error> { + if let Some(token) = token { + if !token.is_empty() { + let auth_header = headers + .get(AUTHORIZATION) + .map(|v| v.to_str().unwrap_or_default()) + .map(|v| v.split_whitespace().last().unwrap_or_default()); + if auth_header.unwrap_or_default() != token { + log::warn!( + "authorization failure for {} (header: {})", + host, + auth_header.unwrap_or("none"), + ); + return Err(error::ErrorUnauthorized("unauthorized")); + } + } + } + Ok(()) +} + +#[cfg(test)] +mod test { + use super::*; + use actix_web::http::HeaderValue; + + #[test] + fn test_check_auth() -> Result<(), Error> { + let mut headers = HeaderMap::new(); + headers.insert(AUTHORIZATION, HeaderValue::from_static("basic test_token")); + assert!(check("", &headers, Some(String::from("test_token"))).is_ok()); + assert!(check("", &headers, Some(String::from("invalid_token"))).is_err()); + assert!(check("", &headers, None).is_ok()); + assert!(check("", &HeaderMap::new(), None).is_ok()); + assert!(check("", &HeaderMap::new(), Some(String::from("token"))).is_err()); + Ok(()) + } +} diff --git a/src/lib.rs b/src/lib.rs index 586d2f1..f98fe74 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -7,8 +7,11 @@ pub mod config; /// Server routes. pub mod server; +/// HTTP headers. +pub mod header; + /// File handler. pub mod file; -/// HTTP headers. -pub mod header; +/// Auth handler. +pub mod auth; diff --git a/src/server.rs b/src/server.rs index 195f735..7a5fe1c 100644 --- a/src/server.rs +++ b/src/server.rs @@ -1,9 +1,9 @@ +use crate::auth; use crate::config::Config; use crate::file; use crate::header::ContentDisposition; use actix_files::NamedFile; use actix_multipart::Multipart; -use actix_web::http::header::AUTHORIZATION; use actix_web::{error, get, post, web, Error, HttpRequest, HttpResponse, Responder}; use byte_unit::Byte; use futures_util::stream::StreamExt; @@ -40,21 +40,7 @@ async fn upload( ) -> Result { let connection = request.connection_info(); let host = connection.remote_addr().unwrap_or("unknown host"); - if let Ok(token) = env::var("AUTH_TOKEN") { - let auth_header = request - .headers() - .get(AUTHORIZATION) - .map(|v| v.to_str().unwrap_or_default()) - .map(|v| v.split_whitespace().last().unwrap_or_default()); - if auth_header.unwrap_or_default() != token { - log::warn!( - "authorization failure for {} (header: {})", - host, - auth_header.unwrap_or("none"), - ); - return Err(error::ErrorUnauthorized("unauthorized")); - } - } + auth::check(host, request.headers(), env::var("AUTH_TOKEN").ok())?; let mut urls: Vec = Vec::new(); while let Some(item) = payload.next().await { let mut field = item?;