Skip to content

Commit

Permalink
Merge pull request #80 from sokorototo/main
Browse files Browse the repository at this point in the history
Just some polishing...
  • Loading branch information
zeskeertwee authored Nov 21, 2022
2 parents 3c9d682 + 9d6cf1c commit ad2710d
Show file tree
Hide file tree
Showing 16 changed files with 194 additions and 226 deletions.
223 changes: 117 additions & 106 deletions Cargo.lock

Large diffs are not rendered by default.

File renamed without changes.
5 changes: 2 additions & 3 deletions vach/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
name = "vach"

# NOTE: Make sure spec.txt and vach::VERSION constants are all synced up
version = "0.4.1"
version = "0.4.5"

edition = "2021"
authors = [
Expand Down Expand Up @@ -39,7 +39,6 @@ brotli = { version = "3.3.4", optional = true }
# Multithreaded features
parking_lot = { version = "0.12.1" }
rayon = { version = "1.5.2", optional = true }
num_cpus = { version = "1.13.1", optional = true }

[features]
default = ["builder", "archive"]
Expand All @@ -48,7 +47,7 @@ archive = []
builder = []

crypto = ["ed25519-dalek", "aes-gcm", "rand"]
multithreaded = ["rayon", "num_cpus"]
multithreaded = ["rayon"]
compression = ["snap", "lz4_flex", "brotli"]

[package.metadata.docs.rs]
Expand Down
20 changes: 5 additions & 15 deletions vach/src/crypto.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ pub use ed25519_dalek::{Keypair, PublicKey, SecretKey, Signature};

use crate::prelude::{InternalResult, InternalError};

// Encryption - Decryption, A convenient wrapper around aes encryption and decryption
/// Encryption - Decryption, A convenient wrapper around aes encryption and decryption
pub(crate) struct Encryptor {
cipher: Aes256Gcm,
nonce: Nonce<U12>,
Expand All @@ -29,8 +29,8 @@ impl Encryptor {

// Build Nonce
let key = Key::from_slice(bytes);
let mut v = vec![178, 5, 239, 228, 165, 44, 169];
v.extend_from_slice(&magic);
let mut v = [178, 5, 239, 228, 165, 44, 169, 0, 0, 0, 0, 0];
(&mut v[7..12]).copy_from_slice(&magic);

Encryptor {
cipher: Aes256Gcm::new(key),
Expand All @@ -40,20 +40,10 @@ impl Encryptor {

// The meat and the mass of this struct
pub(crate) fn encrypt(&self, data: &[u8]) -> InternalResult<Vec<u8>> {
let res = match self.cipher.encrypt(&self.nonce, data) {
Ok(data) => data,
Err(err) => return Err(InternalError::CryptoError(err)),
};

Ok(res)
self.cipher.encrypt(&self.nonce, data).map_err(InternalError::CryptoError)
}

pub(crate) fn decrypt(&self, data: &[u8]) -> InternalResult<Vec<u8>> {
let res = match self.cipher.decrypt(&self.nonce, data) {
Ok(data) => data,
Err(err) => return Err(InternalError::CryptoError(err)),
};

Ok(res)
self.cipher.decrypt(&self.nonce, data).map_err(InternalError::CryptoError)
}
}
16 changes: 6 additions & 10 deletions vach/src/global/compressor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,26 +49,22 @@ impl<T: Read> Compressor<T> {
)),
}
}

/// Pass in a compression algorithm to use, sit back and let the decompressor do it's job. That is if the compressed data *is* compressed with the adjacent algorithm
pub fn decompress(&mut self, algo: CompressionAlgorithm, output: &mut dyn Write) -> InternalResult {
/// Contains the number of bytes decompressed from the source
pub fn decompress(&mut self, algo: CompressionAlgorithm, output: &mut Vec<u8>) -> InternalResult<usize> {
match algo {
CompressionAlgorithm::LZ4 => {
let mut rdr = lz4::frame::FrameDecoder::new(&mut self.data);
io::copy(&mut rdr, output)?;

Ok(())
rdr.read_to_end(output).map_err(InternalError::IOError)
},
CompressionAlgorithm::Snappy => {
let mut rdr = snap::read::FrameDecoder::new(&mut self.data);
io::copy(&mut rdr, output)?;

Ok(())
rdr.read_to_end(output).map_err(InternalError::IOError)
},
CompressionAlgorithm::Brotli(_) => {
let mut rdr = brotli::Decompressor::new(&mut self.data, 4096);
io::copy(&mut rdr, output)?;

Ok(())
rdr.read_to_end(output).map_err(InternalError::IOError)
},
}
}
Expand Down
11 changes: 2 additions & 9 deletions vach/src/global/flags.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,6 @@ impl Flags {
pub const SIGNED_FLAG: u32 = 0b_0000_1000_0000_0000_0000_0000_0000_0000;
/// The flag that shows data in the leaf in encrypted
pub const ENCRYPTED_FLAG: u32 = 0b_0000_0010_0000_0000_0000_0000_0000_0000;
/// A flag that is set if the registry has space reserved for more entries
pub const MUTABLE_REGISTRY_FLAG: u32 = 0b_0000_0001_0000_0000_0000_0000_0000_0000;

#[inline(always)]
/// Construct a `Flags` struct from a `u32` number
Expand Down Expand Up @@ -82,7 +80,7 @@ impl Flags {
/// ### Errors
/// - Trying to set a bit in the forbidden section of the flags
pub fn set(&mut self, bit: u32, toggle: bool) -> InternalResult<u32> {
if Flags::_contains(Flags::RESERVED_MASK, bit) {
if (Flags::RESERVED_MASK & bit) != 0 {
return Err(InternalError::RestrictedFlagAccessError);
} else {
self.force_set(bit, toggle)
Expand All @@ -109,12 +107,7 @@ impl Flags {
/// assert!(flag.contains(0b1000_0000_0000_0000));
/// ```
pub fn contains(&self, bit: u32) -> bool {
Flags::_contains(self.bits, bit)
}

// Auxillary function
fn _contains(first: u32, other: u32) -> bool {
(first & other) != 0
(self.bits & bit) != 0
}
}

Expand Down
5 changes: 3 additions & 2 deletions vach/src/global/reg_entry.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ impl RegistryEntry {
/// Given a read handle, will proceed to read and parse bytes into a [`RegistryEntry`] struct. (de-serialization)
/// ### Errors
/// Produces `io` errors and if the bytes in the id section is not valid UTF-8
pub(crate) fn from_handle<T: Read>(mut handle: T) -> InternalResult<(Self, String)> {
pub(crate) fn from_handle<T: Read>(mut handle: T) -> InternalResult<(RegistryEntry, String)> {
let mut buffer: [u8; RegistryEntry::MIN_SIZE] = [0u8; RegistryEntry::MIN_SIZE];
handle.read_exact(&mut buffer)?;

Expand Down Expand Up @@ -97,7 +97,8 @@ impl RegistryEntry {

/// Serializes a [`RegistryEntry`] struct into an array of bytes
pub(crate) fn bytes(&self, id_length: &u16) -> Vec<u8> {
let mut buffer = Vec::new();
let mut buffer = Vec::with_capacity(RegistryEntry::MIN_SIZE + 64);

buffer.extend_from_slice(&self.flags.bits().to_le_bytes());
buffer.extend_from_slice(&self.content_version.to_le_bytes());
buffer.extend_from_slice(&self.location.to_le_bytes());
Expand Down
85 changes: 40 additions & 45 deletions vach/src/loader/archive.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use std::{
str,
io::{Read, Seek, SeekFrom},
collections::BTreeMap,
collections::HashMap,
};

use super::resource::Resource;
Expand Down Expand Up @@ -37,7 +37,7 @@ pub struct Archive<T> {

// Archive metadata
header: Header,
entries: BTreeMap<String, RegistryEntry>,
entries: HashMap<String, RegistryEntry>,

// Optional parts
#[cfg(feature = "crypto")]
Expand Down Expand Up @@ -75,11 +75,10 @@ impl<T> Archive<T> {

// Decompress and|or decrypt the data
#[inline(never)]
fn process(&self, values: (&RegistryEntry, &str, Vec<u8>)) -> InternalResult<(Vec<u8>, bool)> {
fn process(&self, entry: &RegistryEntry, id: &str, mut raw: Vec<u8>) -> InternalResult<(Vec<u8>, bool)> {
/* Literally the hottest function in the block (🕶) */

// buffer_a originally contains the raw data
let (entry, id, mut raw) = values;
let mut decrypted = None;
let mut is_secure = false;

Expand Down Expand Up @@ -110,9 +109,7 @@ impl<T> Archive<T> {
}

#[cfg(not(feature = "crypto"))]
{
return Err(InternalError::MissingFeatureError("crypto"));
}
return Err(InternalError::MissingFeatureError("crypto"));
}

// 2: Decompression layer
Expand All @@ -127,7 +124,7 @@ impl<T> Archive<T> {
},
// data was not decrypted nor stored.
None => {
let capacity = raw.len();
let capacity = raw.capacity();
(raw, Vec::with_capacity(capacity))
},
};
Expand Down Expand Up @@ -190,7 +187,7 @@ where
Header::validate(config, &header)?;

// Generate and store Registry Entries
let mut entries = BTreeMap::new();
let mut entries = HashMap::new();

// Construct entries map
for _ in 0..header.capacity {
Expand All @@ -206,12 +203,14 @@ where
.any(|(_, entry)| entry.flags.contains(Flags::ENCRYPTED_FLAG));

// Errors where no decryptor has been instantiated will be returned once a fetch is made to an encrypted resource
let mut decryptor = None;
if use_decryption {
if let Some(pk) = config.public_key {
decryptor = Some(crypto::Encryptor::new(&pk, config.magic))
}
}
let decryptor = use_decryption
.then(|| {
config
.public_key
.as_ref()
.map(|pk| crypto::Encryptor::new(pk, config.magic))
})
.flatten();

Ok(Archive {
header,
Expand All @@ -232,17 +231,6 @@ where
}
}

/// Given a data source and a [`RegistryEntry`], gets the adjacent raw data
pub(crate) fn fetch_raw(handle: &mut T, entry: &RegistryEntry) -> InternalResult<Vec<u8>> {
let mut buffer = Vec::with_capacity(entry.offset as usize + 64);
handle.seek(SeekFrom::Start(entry.location))?;

let mut take = handle.take(entry.offset);
take.read_to_end(&mut buffer)?;

Ok(buffer)
}

/// Fetch a [`RegistryEntry`] from this [`Archive`].
/// This can be used for debugging, as the [`RegistryEntry`] holds information on data with the adjacent ID.
pub fn fetch_entry(&self, id: impl AsRef<str>) -> Option<RegistryEntry> {
Expand All @@ -251,7 +239,7 @@ where

/// Returns an immutable reference to the underlying [`HashMap`]. This hashmap stores [`RegistryEntry`] values and uses `String` keys.
#[inline(always)]
pub fn entries(&self) -> &BTreeMap<String, RegistryEntry> {
pub fn entries(&self) -> &HashMap<String, RegistryEntry> {
&self.entries
}

Expand All @@ -262,25 +250,32 @@ where
}
}

/// Given a data source and a [`RegistryEntry`], gets the adjacent raw data
pub(crate) fn read_entry<T: Seek + Read>(handle: &mut T, entry: &RegistryEntry) -> InternalResult<Vec<u8>> {
let mut buffer = Vec::with_capacity(entry.offset as usize + 64);
handle.seek(SeekFrom::Start(entry.location))?;

let mut take = handle.take(entry.offset);
take.read_to_end(&mut buffer)?;

Ok(buffer)
}

impl<T> Archive<T>
where
T: Read + Seek,
{
/// Fetch a [`Resource`] with the given `ID`.
/// Locks the underlying [`Mutex`], for a cheaper non-locking operation refer to `Archive::fetch_mut`
pub fn fetch(&self, id: impl AsRef<str>) -> InternalResult<Resource> {
/// Cheaper alternative to `fetch` that works best for single threaded applications.
/// It does not lock the underlying [Mutex], since it requires a mutable reference.
/// Therefore the borrow checker statically guarantees the operation is safe. Refer to [`Mutex::get_mut`](Mutex).
pub fn fetch_mut(&mut self, id: impl AsRef<str>) -> InternalResult<Resource> {
// The reason for this function's unnecessary complexity is it uses the provided functions independently, thus preventing an unnecessary allocation [MAYBE TOO MUCH?]
if let Some(entry) = self.fetch_entry(&id) {
let raw = {
let mut guard = self.handle.lock();
Archive::<T>::fetch_raw(&mut guard, &entry)?
};
let raw = read_entry(self.handle.get_mut(), &entry)?;

// Prepare contextual variables
let independent = (&entry, id.as_ref(), raw);

// Decompress and|or decrypt the data
let (buffer, is_secure) = self.process(independent)?;
let (buffer, is_secure) = self.process(&entry, id.as_ref(), raw)?;

Ok(Resource {
content_version: entry.content_version,
Expand All @@ -293,19 +288,19 @@ where
}
}

/// Cheaper alternative to `fetch` that works best for single threaded applications.
/// It does not lock the underlying [Mutex], since it requires a mutable reference.
/// Therefore the borrow checker statically guarantees the operation is safe. Refer to [`Mutex::get_mut`](Mutex).
pub fn fetch_mut(&mut self, id: impl AsRef<str>) -> InternalResult<Resource> {
/// Fetch a [`Resource`] with the given `ID`.
/// > Locks the underlying [`Mutex`], for a cheaper non-locking operation refer to `Archive::fetch_mut`
pub fn fetch(&self, id: impl AsRef<str>) -> InternalResult<Resource> {
// The reason for this function's unnecessary complexity is it uses the provided functions independently, thus preventing an unnecessary allocation [MAYBE TOO MUCH?]
if let Some(entry) = self.fetch_entry(&id) {
let raw = Archive::<T>::fetch_raw(self.handle.get_mut(), &entry)?;
let raw = {
let mut guard = self.handle.lock();
read_entry(guard.by_ref(), &entry)?
};

// Prepare contextual variables
let independent = (&entry, id.as_ref(), raw);

// Decompress and|or decrypt the data
let (buffer, is_secure) = self.process(independent)?;
let (buffer, is_secure) = self.process(&entry, id.as_ref(), raw)?;

Ok(Resource {
content_version: entry.content_version,
Expand Down
4 changes: 1 addition & 3 deletions vach/src/loader/resource.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
use std::fmt;
use crate::{
global::{flags::Flags},
};
use crate::global::flags::Flags;

/// Basically processed data obtained from an archive.
/// Contains `data`, `flags` and `content_version` fields.
Expand Down
1 change: 1 addition & 0 deletions vach/src/tests/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -218,6 +218,7 @@ fn edcryptor_test() -> InternalResult {

assert_ne!(&plaintext, &ciphertext);
assert_eq!(&plaintext, &data);

Ok(())
}

Expand Down
3 changes: 1 addition & 2 deletions vach/src/writer/builder/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -106,8 +106,7 @@ impl<'a> BuilderConfig<'a> {
/// If the call to `::utils::read_keypair()` fails to parse the data from the handle
#[cfg(feature = "crypto")]
pub fn load_keypair<T: std::io::Read>(&mut self, handle: T) -> crate::global::result::InternalResult {
self.keypair = Some(crate::crypto_utils::read_keypair(handle)?);
Ok(())
crate::crypto_utils::read_keypair(handle).map(|kp| self.keypair = Some(kp))
}
}

Expand Down
Loading

0 comments on commit ad2710d

Please sign in to comment.