Skip to content

Commit

Permalink
Keep secure index consistent and include in startup validations
Browse files Browse the repository at this point in the history
  • Loading branch information
dormant-user committed Mar 12, 2024
1 parent 9c3f601 commit 3c78473
Show file tree
Hide file tree
Showing 14 changed files with 207 additions and 40 deletions.
2 changes: 0 additions & 2 deletions src/constant.rs
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,6 @@ pub fn build_info() -> Cargo {
pub struct Session {
pub tracker: Mutex<HashMap<String, String>>,
pub mapping: Mutex<HashMap<String, String>>,
pub secured_dir: Mutex<HashMap<String, String>>
}


Expand All @@ -78,7 +77,6 @@ pub fn session_info() -> Arc<Session> {
Arc::new(Session {
tracker: Mutex::new(HashMap::new()),
mapping: Mutex::new(HashMap::new()),
secured_dir: Mutex::new(HashMap::new())
})
}

Expand Down
31 changes: 31 additions & 0 deletions src/echo/display.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
#[allow(dead_code)]
pub struct Format {
pub bold: &'static str,
pub underline: &'static str,
pub italic: &'static str,
}

pub struct Colors {
pub green: &'static str,
pub yellow: &'static str,
pub red: &'static str,
pub end: &'static str,
pub light_green: &'static str,
}

#[allow(dead_code)]
pub fn format() -> Format {
let bold = "\x1B[1m";
let underline = "\x1B[4m";
let italic = "\x1B[3m";
Format { bold, underline, italic }
}

pub fn colors() -> Colors {
let green = "\x1B[92m";
let yellow = "\x1B[93m";
let red = "\x1B[91m";
let end = "\x1B[0m";
let light_green = "\x1B[32m";
Colors { green, yellow, red, end, light_green }
}
40 changes: 40 additions & 0 deletions src/echo/functions.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
use chrono::{Local, Utc};
use crate::echo::display;

fn get_time(utc: bool) -> String {
if utc {
Utc::now().to_rfc3339_opts(chrono::SecondsFormat::Secs, true)
} else {
Local::now().to_rfc3339_opts(chrono::SecondsFormat::Secs, true)
}
}

#[allow(dead_code)]
pub fn debug_func(msg: &str, utc: bool) {
let colors = display::colors();
println!("[{} {}DEBUG{} {}] {}", get_time(utc), colors.light_green, colors.end, env!("CARGO_CRATE_NAME"), msg)
}

pub fn info_func(msg: &str, utc: bool) {
let colors = display::colors();
println!("[{} {}INFO{} {}] {}", get_time(utc), colors.green, colors.end, env!("CARGO_CRATE_NAME"), msg)
}

#[allow(dead_code)]
pub fn warn_func(msg: &str, utc: bool) {
let colors = display::colors();
println!("[{} {}WARN{} {}] {}", get_time(utc), colors.yellow, colors.end, env!("CARGO_CRATE_NAME"), msg)
}

#[allow(dead_code)]
pub fn error_func(msg: &str, utc: bool) {
let colors = display::colors();
println!("[{} {}ERROR{} {}] {}", get_time(utc), colors.red, colors.end, env!("CARGO_CRATE_NAME"), msg)
}

#[allow(dead_code)]
pub fn critical_func(msg: &str, utc: bool) {
let colors = display::colors();
let format = display::format();
println!("[{} {}{}CRITICAL{} {}] {}", get_time(utc), format.bold, colors.red, colors.end, env!("CARGO_CRATE_NAME"), msg)
}
49 changes: 49 additions & 0 deletions src/echo/macros.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
#[macro_export]
macro_rules! debug {
($msg:expr) => {
$crate::echo::functions::debug_func($msg, false)
};
($msg:expr, $flag:expr) => {
$crate::echo::functions::debug_func($msg, $flag)
};
}

#[macro_export]
macro_rules! info {
($msg:expr) => {
$crate::echo::functions::info_func($msg, false)
};
($msg:expr, $flag:expr) => {
$crate::echo::functions::info_func($msg, $flag)
};
}

#[macro_export]
macro_rules! warn {
($msg:expr) => {
$crate::echo::functions::warn_func($msg, false)
};
($msg:expr, $flag:expr) => {
$crate::echo::functions::warn_func($msg, $flag)
};
}

#[macro_export]
macro_rules! error {
($msg:expr) => {
$crate::echo::functions::error_func($msg, false)
};
($msg:expr, $flag:expr) => {
$crate::echo::functions::error_func($msg, $flag)
};
}

#[macro_export]
macro_rules! critical {
($msg:expr) => {
$crate::echo::functions::critical_func($msg, false)
};
($msg:expr, $flag:expr) => {
$crate::echo::functions::critical_func($msg, $flag)
};
}
5 changes: 5 additions & 0 deletions src/echo/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
pub mod functions;

#[macro_use]
pub mod macros;
pub mod display;
3 changes: 2 additions & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ mod routes;
mod squire;
/// Module to load all the templates for the UI.
mod templates;
mod echo;

/// Contains entrypoint and initializer settings to trigger the asynchronous `HTTPServer`
///
Expand All @@ -39,7 +40,7 @@ pub async fn start() -> io::Result<()> {
let cargo = constant::build_info();
let config = squire::startup::get_config(&cargo);

squire::startup::init_logger(config.debug, &cargo.crate_name);
squire::startup::init_logger(config.debug, config.utc_logging, &cargo.crate_name);
println!("{}[v{}] - {}", &cargo.pkg_name, &cargo.pkg_version, &cargo.description);
squire::ascii_art::random();

Expand Down
21 changes: 1 addition & 20 deletions src/routes/auth.rs
Original file line number Diff line number Diff line change
Expand Up @@ -164,32 +164,13 @@ pub async fn home(request: HttpRequest,
let listing_page = squire::content::get_all_stream_content(&config, &auth_response);
let listing = template.get_template("listing").unwrap();

// Can do a one-liner like below, but it will be ugly
//
// let secure_dir = listing_page.secured_directories
// .first().unwrap_or(&HashMap::from([("".to_string(), "".to_string())]))
// .get("path").unwrap_or(&"home".to_string())

let secure_dir = if listing_page.secured_directories.len() == 1 {
let dir = listing_page.secured_directories.first().unwrap().get("path").unwrap();
log::debug!("Secure Directory: {}", &dir);
dir
} else {
log::debug!("Secure Directory unknown/multiple");
"home"
};
let mut stored_secure_dir = session.secured_dir.lock().unwrap();
if !stored_secure_dir.is_empty() {
stored_secure_dir.remove("href");
}
stored_secure_dir.insert("href".to_string(), secure_dir.to_string());
HttpResponse::build(StatusCode::OK)
.content_type("text/html; charset=utf-8")
.body(
listing.render(minijinja::context!(
files => listing_page.files,
user => auth_response.username,
secure_index => secure_dir,
secure_index => constant::SECURE_INDEX,
directories => listing_page.directories,
secured_directories => listing_page.secured_directories
)).unwrap()
Expand Down
2 changes: 1 addition & 1 deletion src/routes/media.rs
Original file line number Diff line number Diff line change
Expand Up @@ -236,7 +236,7 @@ pub async fn stream(request: HttpRequest,
custom_title => custom_title,
files => listing_page.files,
user => auth_response.username,
secure_index => session.secured_dir.lock().unwrap().get("href").unwrap_or(&"home".to_string()),
secure_index => constant::SECURE_INDEX,
directories => listing_page.directories,
secured_directories => listing_page.secured_directories
)).unwrap());
Expand Down
11 changes: 1 addition & 10 deletions src/routes/upload.rs
Original file line number Diff line number Diff line change
Expand Up @@ -99,20 +99,11 @@ pub async fn upload_files(request: HttpRequest,
if !auth_response.ok {
return routes::auth::failed_auth(auth_response, &config);
}
let upload_path = config.media_source.join(format!("{}_{}", &auth_response.username, constant::SECURE_INDEX));
if !upload_path.exists() {
// todo: either remove this and use session's secure_dir (but that will work if only one is available) - convenient regardless of user BS
// or totally remove the session specific secure_dir logic and create one for each user upon login - more precise but may lead to multiple
match std::fs::create_dir(&upload_path) {
Ok(_) => log::info!("'{}' has been created", &upload_path.to_str().unwrap()),
Err(err) => log::error!("{}", err)
}
}
let landing = template.get_template("upload").unwrap();
HttpResponse::build(http::StatusCode::OK)
.content_type("text/html; charset=utf-8")
.body(landing.render(minijinja::context!(
user => auth_response.username,
secure_index => session.secured_dir.lock().unwrap().get("href").unwrap_or(&"home".to_string())
secure_index => constant::SECURE_INDEX
)).unwrap())
}
5 changes: 5 additions & 0 deletions src/squire/settings.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ pub struct Config {

/// Debug flag to enable debug level logging.
pub debug: bool,
/// Boolean flag to enable UTC timezone in logging. Defaults to local timezone.
pub utc_logging: bool,
/// Host IP address for media streaming.
pub media_host: String,
/// Port number for hosting the application.
Expand Down Expand Up @@ -39,6 +41,9 @@ pub struct Config {
/// Returns the default value for debug flag
pub fn default_debug() -> bool { false }

/// Returns the default value for utc_logging
pub fn default_utc_logging() -> bool { false }

/// Returns the default value for ssl files
pub fn default_ssl() -> path::PathBuf { path::PathBuf::new() }

Expand Down
72 changes: 69 additions & 3 deletions src/squire/startup.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
use std;
use std::ffi::OsStr;
use std::io::Write;
use chrono::{DateTime, Local};
use walkdir::WalkDir;

use crate::constant::Cargo;
use crate::squire;
use crate::{constant, info, squire};
use crate::squire::settings;

/// Initializes the logger based on the provided debug flag and cargo information.
Expand All @@ -10,7 +14,7 @@ use crate::squire::settings;
///
/// * `debug` - A flag indicating whether to enable debug mode for detailed logging.
/// * `crate_name` - Name of the crate loaded during compile time.
pub fn init_logger(debug: bool, crate_name: &String) {
pub fn init_logger(debug: bool, utc: bool, crate_name: &String) {
if debug {
std::env::set_var("RUST_LOG", format!(
"actix_web=debug,actix_server=info,{}=debug", crate_name
Expand All @@ -23,7 +27,23 @@ pub fn init_logger(debug: bool, crate_name: &String) {
));
std::env::set_var("RUST_BACKTRACE", "0");
}
env_logger::init();
if utc {
env_logger::init();
} else {
env_logger::Builder::from_default_env()
.format(|buf, record| {
let local_time: DateTime<Local> = Local::now();
writeln!(
buf,
"[{} {}] [{}] - {}",
local_time.format("%Y-%m-%d %H:%M:%S"),
record.level(),
record.target(),
record.args()
)
})
.init();
}
}

/// Extracts the mandatory env vars by key and parses it as `HashMap<String, String>` and `PathBuf`
Expand Down Expand Up @@ -167,6 +187,7 @@ fn parse_path(key: &str) -> Option<std::path::PathBuf> {
fn load_env_vars() -> settings::Config {
let (authorization, media_source) = mandatory_vars();
let debug = parse_bool("debug").unwrap_or(settings::default_debug());
let utc_logging = parse_bool("utc_logging").unwrap_or(settings::default_utc_logging());
let media_host = std::env::var("media_host").unwrap_or(settings::default_media_host());
let media_port = parse_i32("media_port").unwrap_or(settings::default_media_port());
let session_duration = parse_i32("session_duration").unwrap_or(settings::default_session_duration());
Expand All @@ -181,6 +202,7 @@ fn load_env_vars() -> settings::Config {
authorization,
media_source,
debug,
utc_logging,
media_host,
media_port,
session_duration,
Expand All @@ -194,6 +216,49 @@ fn load_env_vars() -> settings::Config {
}
}

fn validate_dir_structure(config: &settings::Config) {
let source = &config.media_source.to_string_lossy().to_string();
let mut errors = String::new();
for entry in WalkDir::new(&config.media_source).into_iter().filter_map(|e| e.ok()) {
let entry_path = entry.path();
if entry_path.is_dir() && entry_path.to_str().unwrap().ends_with(constant::SECURE_INDEX) {
let secure_index = entry_path.strip_prefix(source).unwrap();
let depth = secure_index.iter().count();
if depth != 1usize {
let index_vec = secure_index.iter().collect::<Vec<_>>();
let secure_dir = index_vec.last().unwrap();
// secure_parent_path is the secure index's location
let secure_parent_path = &index_vec[0..index_vec.len() - 1]
.join(OsStr::new(std::path::MAIN_SEPARATOR_STR));
errors.push_str(&format!(
"\n{:?}\n\tSecure index directory [{:?}] should be at the root [{:?}] [depth={}, valid=1]\n\
\t> Hint: Either move {:?} within {:?}, [OR] set the 'media_source' to {:?}\n",
secure_index,
secure_dir,
config.media_source,
depth,
secure_dir,
config.media_source,
config.media_source.join(secure_parent_path)
));
}
}
}
if errors.is_empty() {
for (username, _) in &config.authorization {
let secure_path = &config.media_source.join(format!("{}_{}", &username, constant::SECURE_INDEX));
if !secure_path.exists() {
match std::fs::create_dir(&secure_path) {
Ok(_) => info!(&format!("'{}' has been created", &secure_path.to_str().unwrap()).as_str()),
Err(err) => panic!("{}", err)
}
}
}
} else {
panic!("{}", errors)
}
}

/// Validates all the required environment variables with the required settings.
///
/// # Returns
Expand Down Expand Up @@ -228,6 +293,7 @@ fn validate_vars() -> settings::Config {
if !errors.is_empty() {
panic!("{}", errors);
}
validate_dir_structure(&config);
config
}

Expand Down
2 changes: 1 addition & 1 deletion src/templates/landing.rs
Original file line number Diff line number Diff line change
Expand Up @@ -284,7 +284,7 @@ pub fn get_content() -> String {
window.location.href = "/home";
}
function goSecure() {
window.location.href = '/{{ secure_index }}';
window.location.href = '/stream/{{ user }}_{{ secure_index }}';
}
function logOut() {
window.location.href = "/logout";
Expand Down
2 changes: 1 addition & 1 deletion src/templates/listing.rs
Original file line number Diff line number Diff line change
Expand Up @@ -199,7 +199,7 @@ pub fn get_content() -> String {
window.location.href = "/home";
}
function goSecure() {
window.location.href = '/{{ secure_index }}';
window.location.href = '/stream/{{ user }}_{{ secure_index }}';
}
function logOut() {
window.location.href = "/logout";
Expand Down
2 changes: 1 addition & 1 deletion src/templates/upload.rs
Original file line number Diff line number Diff line change
Expand Up @@ -489,7 +489,7 @@ pub fn get_content() -> String {
window.location.href = "/home";
}
function goSecure() {
window.location.href = '/{{ secure_index }}';
window.location.href = '/stream/{{ user }}_{{ secure_index }}';
}
function logOut() {
window.location.href = "/logout";
Expand Down

0 comments on commit 3c78473

Please sign in to comment.