use std::collections::VecDeque;
use std::fs;
use std::path::{Path, PathBuf};
use std::time::SystemTime;
use chrono::{DateTime, Local};
use crate::core::data::{io, keys};
use crate::core::encryption::boxfile;
use crate::{log_debug, log_info, log_warn, new_err, Result};
pub mod utils;
pub mod error;
pub mod data;
pub mod encryption;
pub mod profile;
pub mod key;
pub mod options;
pub mod logs;
pub fn encrypt(
input_path: &Path,
password: &str,
keep_original_name: bool,
output_paths: &mut Option<VecDeque<PathBuf>>,
) -> Result<()> {
log_info!("Starting encryption...");
if let Some(extension) = input_path.extension() {
if extension == "box" {
return Err(new_err!(InvalidInput: InvalidFile, "Already encrypted"))
}
}
let mut boxfile = boxfile::Boxfile::new(input_path)?;
let key = keys::get_key(password)?;
boxfile.encrypt_data(&key)?;
let mut output_path = match output_paths {
Some(ref mut paths) => {
if let Some(mut path) = paths.pop_front() {
log_debug!("Writing to custom output path: {:?}", path);
if path.file_name() == None {
path.set_file_name(uuid::Uuid::new_v4().to_string());
}
path
} else {
input_path.to_path_buf()
}
},
None => input_path.to_path_buf()
};
if !keep_original_name {
output_path.set_file_name(uuid::Uuid::new_v4().to_string());
}
output_path.set_extension("box");
boxfile.save_to(&output_path)?;
fs::remove_file(&input_path)?;
Ok(())
}
pub fn decrypt(
input_path: &Path,
password: &str,
output_paths: &mut Option<VecDeque<PathBuf>>,
) -> Result<()> {
log_info!("Starting decryption...");
let mut boxfile = boxfile::Boxfile::parse(&input_path)?;
let key = keys::get_key(password)?;
boxfile.decrypt_data(&key)?;
let (original_name, original_extension) = boxfile.file_info();
let file_data = boxfile.file_data()?;
log_info!("Validating checksum...");
if boxfile.verify_checksum()? {
log_info!("Checksum verification successful");
} else {
log_warn!("Checksum verification failed. Data seems to be tampered with");
}
let output_path = match output_paths {
Some(ref mut paths) => {
if let Some(mut path) = paths.pop_front() {
log_debug!("Writing to custom output path: {:?}", path);
if path.file_name() == None {
path.set_file_name(original_name);
if let Some(extension) = original_extension {
path.set_extension(extension);
}
} else if path.extension() == None {
if let Some(extension) = original_extension {
path.set_extension(extension);
}
}
path
} else {
let mut path = input_path.to_path_buf();
path.set_file_name(original_name);
if let Some(extension) = original_extension {
path.set_extension(extension);
}
path
}
},
None => {
let mut path = input_path.to_path_buf();
path.set_file_name(original_name);
if let Some(extension) = original_extension {
path.set_extension(extension);
}
path
}
};
io::write_bytes(&output_path, &file_data, true)?;
fs::remove_file(&input_path)?;
Ok(())
}
pub fn get_information(
input_path: &Path,
show_unknown: bool
) -> Result<Vec<String>> {
fn format_time(system_time: SystemTime) -> String {
let time: DateTime<Local> = system_time.into();
format!("{}", time.format("%d.%m.%Y %T"))
}
log_info!("Getting file information...");
let boxfile = boxfile::Boxfile::parse(&input_path)?;
let header = boxfile.header;
let mut file_information = Vec::new();
file_information.push(format!("Name: {:?}", header.name));
if let Some(extension) = header.extension {
file_information.push(format!("Extension: {:?}", extension));
} else {
file_information.push("Extension: None".to_string());
}
if let Some(system_time) = header.create_time {
file_information.push(format!("Create time: {}", format_time(system_time)));
} else if show_unknown {
file_information.push("Create time: Unknown".to_string());
}
if let Some(system_time) = header.modify_time {
file_information.push(format!("Modify time: {}", format_time(system_time)));
} else if show_unknown {
file_information.push("Modify time: Unknown".to_string());
}
if let Some(system_time) = header.access_time {
file_information.push(format!("Access time: {}", format_time(system_time)));
} else if show_unknown {
file_information.push("Access time: Unknown".to_string());
}
Ok(file_information)
}