use crate::context::EnkryptitContext;
use crate::diagnostic::EnkryptitOutput;
use crate::errors::EnkryptitError;
use crate::metadatas::{ArchiveHeader, MAGIC};
use crate::parameters::params::EnkryptitParams;
use crate::treatment::file_case::{decrypt_file_case, encrypt_file_case};
use crate::treatment::folder_case::{decrypt_folder_case, encrypt_folder_case};
use postcard::from_bytes;
use std::fs::File;
use std::io::{BufReader, Read, Seek, SeekFrom};
use std::path::Path;
#[allow(dead_code)]
pub enum ParsedFile {
Enkryptit {
meta: Vec<u8>,
version: u8,
payload_offset: u64,
is_folder_archive: bool,
},
Plain,
}
pub fn treat_object(
parameters: &EnkryptitParams,
path: &str,
context: &mut EnkryptitContext,
) -> EnkryptitOutput {
let keytype = parameters.key_params.to_type();
if Path::new(path).is_dir() {
return encrypt_folder_case(path, context, &keytype);
}
match read_file(path) {
Ok(ParsedFile::Enkryptit {
meta,
payload_offset,
is_folder_archive,
version,
}) => {
if is_folder_archive {
decrypt_folder_case(path, context, meta, payload_offset, version)
} else {
decrypt_file_case(path, meta, context, payload_offset)
}
}
Ok(ParsedFile::Plain) => encrypt_file_case(path, context, &keytype),
Err(e) => *e,
}
}
pub fn read_file(path: &str) -> Result<ParsedFile, Box<EnkryptitOutput>> {
let file = match File::open(path) {
Ok(f) => f,
Err(e) => {
let err: EnkryptitError = e.into();
return Err(Box::new(err.into()));
}
};
let file_len = match file.metadata() {
Ok(m) => m.len(),
Err(e) => {
let err: EnkryptitError = e.into();
return Err(Box::new(err.into()));
}
};
let mut reader = BufReader::new(file);
let mut len_buf = [0u8; 1];
if reader.read_exact(&mut len_buf).is_err() {
return Ok(ParsedFile::Plain);
}
let header_len = len_buf[0] as usize;
if header_len == 0 || header_len > 1024 {
return Ok(ParsedFile::Plain);
}
let mut header_bytes = vec![0u8; header_len];
if reader.read_exact(&mut header_bytes).is_err() {
return Ok(ParsedFile::Plain);
}
let archive_header: ArchiveHeader = match from_bytes(&header_bytes) {
Ok(h) => h,
Err(_) => return Ok(ParsedFile::Plain),
};
if archive_header.magic != MAGIC {
return Ok(ParsedFile::Plain);
}
let meta_len = archive_header.meta_len as usize;
let mut meta = vec![0u8; meta_len];
if archive_header.is_folder_archive && archive_header.version >= 2 {
if file_len < meta_len as u64 {
return Err(Box::new(
EnkryptitOutput::error(
"Error while reading & parsing the file.",
EnkryptitError::CorruptedFile,
)
.with_help(
"File may be corrupted. For more informations, please refeer to the doc. To try to fix it, wait for `eck recover <path>`.",
)
.with_location("object_treatment.rs::read_file()"),
));
}
let meta_start = file_len - meta_len as u64;
if let Err(e) = reader.seek(SeekFrom::Start(meta_start)) {
let err: EnkryptitError = e.into();
return Err(Box::new(err.into()));
}
if reader.read_exact(&mut meta).is_err() {
return Err(Box::new(
EnkryptitOutput::error(
"Error while reading & parsing the file.",
EnkryptitError::CorruptedFile,
)
.with_help(
"File may be corrupted. For more informations, please refeer to the doc. To try to fix it, wait for `eck recover <path>`.",
)
.with_location("object_treatment.rs::read_file()"),
));
}
} else {
if reader.read_exact(&mut meta).is_err() {
return Err(Box::new(
EnkryptitOutput::error(
"Error while reading & parsing the file.",
EnkryptitError::CorruptedFile,
)
.with_help(
"File may be corrupted. For more informations, please refeer to the doc. To try to fix it, wait for `eck recover <path>`.",
)
.with_location("object_treatment.rs::read_file()"),
));
}
}
let payload_offset = (1 + header_len as u64 + meta_len as u64) as u64;
Ok(ParsedFile::Enkryptit {
meta,
version: archive_header.version,
payload_offset,
is_folder_archive: archive_header.is_folder_archive,
})
}