Skip to content

Commit

Permalink
update
Browse files Browse the repository at this point in the history
  • Loading branch information
Tim-Leon committed Nov 19, 2024
1 parent 1c9238b commit 36002f9
Show file tree
Hide file tree
Showing 15 changed files with 103 additions and 85 deletions.
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ serde_with = "3.4.0"
convert_case = "0.6.0"
prost-types = "0.13.1"
logos = "0.14.0"

pbkdf2 = "0.12.2"
generic-array = { version = "1.1.0", optional = true }
argon2 = {version = "*", optional = true }
zeroize = {version = "1.8.1", features = ["derive", "simd"] }
Expand Down
6 changes: 3 additions & 3 deletions src/bucket/bucket_guid.rs
Original file line number Diff line number Diff line change
Expand Up @@ -151,14 +151,14 @@ mod tests {
assert_eq!(BucketGuid::size(), 32);
}

// Test the `as_slice` method to ensure it correctly converts to a slice of bytes
// Test the `to_bytes` method to ensure it correctly converts to a slice of bytes
#[test]
fn test_as_slice() {
fn test_to_bytes() {
let user_id = Uuid::new_v4();
let bucket_id = Uuid::new_v4();
let bucket_guid = BucketGuid::new(user_id, bucket_id);

let slice = bucket_guid.as_slice();
let slice = bucket_guid.to_bytes();
assert_eq!(slice.len(), 32); // Ensure the slice is 32 bytes
assert_eq!(&slice[0..16], user_id.as_bytes()); // First 16 bytes are user_id
assert_eq!(&slice[16..32], bucket_id.as_bytes()); // Last 16 bytes are bucket_id
Expand Down
64 changes: 57 additions & 7 deletions src/bucket/bucket_path.rs
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,6 @@ impl FromStr for BucketRelativePath {
}
}


#[cfg(test)]
mod tests {
use super::*;
Expand Down Expand Up @@ -105,26 +104,62 @@ mod tests {
fn test_path_with_invalid_characters() {
// Path with invalid characters should return an error
let path = BucketRelativePath::from_str("/invalid!@#$%");
assert_eq!(path, Err(BucketRelativePathParserError::PathContainsInvalidCharacters));
assert_eq!(
path,
Err(BucketRelativePathParserError::PathContainsInvalidCharacter {
position: 8,
invalid_char: '!'
})
);

// Path containing spaces
let path = BucketRelativePath::from_str("/invalid path");
assert_eq!(path, Err(BucketRelativePathParserError::PathContainsInvalidCharacters));
assert_eq!(
path,
Err(BucketRelativePathParserError::PathContainsInvalidCharacter {
position: 8,
invalid_char: ' '
})
);

// Path with a backslash
let path = BucketRelativePath::from_str("/invalid\\path");
assert_eq!(path, Err(BucketRelativePathParserError::PathContainsInvalidCharacters));
assert_eq!(
path,
Err(BucketRelativePathParserError::PathContainsInvalidCharacter {
position: 8,
invalid_char: '\\'
})
);

// Path with restricted patterns like ".." or "."
let path = BucketRelativePath::from_str("/invalid/..");
assert_eq!(path, Err(BucketRelativePathParserError::PathContainsInvalidCharacters));
assert_eq!(
path,
Err(BucketRelativePathParserError::PathContainsInvalidCharacter {
position: 9,
invalid_char: '.'
})
);

let path = BucketRelativePath::from_str("/invalid/.");
assert_eq!(path, Err(BucketRelativePathParserError::PathContainsInvalidCharacters));
assert_eq!(
path,
Err(BucketRelativePathParserError::PathContainsInvalidCharacter {
position: 9,
invalid_char: '.'
})
);

// Path with colon
let path = BucketRelativePath::from_str("/invalid:path");
assert_eq!(path, Err(BucketRelativePathParserError::PathContainsInvalidCharacters));
assert_eq!(
path,
Err(BucketRelativePathParserError::PathContainsInvalidCharacter {
position: 8,
invalid_char: ':'
})
);
}

#[test]
Expand All @@ -137,4 +172,19 @@ mod tests {
let path = BucketRelativePath::from_str("/path123_with-numbers_and_letters");
assert_eq!(path, Ok(BucketRelativePath { path: "/path123_with-numbers_and_letters".to_string() }));
}

#[test]
fn test_path_too_long() {
// Generate a path exceeding the max length
let long_path = format!("/{}", "a".repeat(BUCKET_RELATIVE_PATH_MAX_LENGTH));
let too_long_path = format!("/{}", "a".repeat(BUCKET_RELATIVE_PATH_MAX_LENGTH + 1));

// Valid path within max length
let path = BucketRelativePath::from_str(&long_path);
assert_eq!(path, Ok(BucketRelativePath { path: long_path }));

// Path exceeding max length should return an error
let path = BucketRelativePath::from_str(&too_long_path);
assert_eq!(path, Err(BucketRelativePathParserError::RelativePathTooLong));
}
}
File renamed without changes.
1 change: 0 additions & 1 deletion src/key/derived_key.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ use secrecy::ExposeSecret;
use sha3::digest;
use sha3::digest::Update;
use sha3::Sha3_256;
use crate::encryption::EncryptionAlgorithm;
use crate::key::{CryptoHashDerivedKeyType, CryptoMasterKey, SecureGenericArray};

/// 256-bit key
Expand Down
2 changes: 1 addition & 1 deletion src/key/master_key.rs
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ mod tests {
let argon2 = Argon2::default();
let nonce = "";
let password = "";
let salt = SaltString::from();
let salt = SaltString::from("asd".to_string());
let master_key_from_plaintext = MasterKey256::new(&argon2, nonce, password, salt ).unwrap();
let master_key_from_phc = MasterKey256::from_phc_string();
}
Expand Down
4 changes: 2 additions & 2 deletions src/key/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -146,9 +146,9 @@ pub enum MasterKeyErrors {


mod tests {
use rand::rngs::StdRng;
use rand::{rngs::{OsRng, StdRng}, SeedableRng};

use super::CryptoHashDerivedKeyType;
use super::{derived_key::Sha3_256CryptoHashDerivedKey, master_key::MasterKey256, CryptoHashDerivedKeyType, CryptoMasterKey};

#[test]
fn master_key_to_derived_key_test() {
Expand Down
2 changes: 0 additions & 2 deletions src/key/shard_master_key_generator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,6 @@ use argon2::password_hash::Salt;
use argon2::{Argon2, PasswordHash, PasswordHasher, PasswordVerifier};
use vsss_rs::{combine_shares, shamir::split_secret, Gf256};
use rand::thread_rng;
use crate::encryption::Argon2IdParams;
use crate::key::{CryptoMasterKey, MasterKey256};

#[derive(Clone, Debug, PartialEq, Eq)]
pub enum VerifiableSecretSharingSchemeAlgorithm {
Expand Down
15 changes: 0 additions & 15 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ pub mod bucket_search_query;
#[cfg(feature = "unix_timestamp")]
pub mod unix_timestamp;
pub mod util;
pub mod encryption;
pub mod webhook;
pub mod region;
#[cfg(feature = "middleware")]
Expand Down Expand Up @@ -63,20 +62,6 @@ pub enum VideoCodec {
}


#[derive(Debug, Clone, Eq, PartialEq)]
enum BucketAvailabilityStatus {
Creating,
Available,
Deleting,
Deleted,
Updating,
Archiving,
Restoring,
Unavailable,
Unreachable,
Corrupted,
}

#[derive(
Debug, Clone, Eq, PartialEq, strum::EnumString, strum::Display, Serialize, Deserialize,
)]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ use crate::key::derived_key::CryptoHashDerivedKeySha3_256;
use crate::region::RegionCluster;
use crate::share::decentralized::decentralized_secrete_share_token::DecentralizedSecretShareToken;
use crate::share::decentralized::decentralized_share_token::{DecentralizedShareToken, TokenSignature};
use crate::share::fully_qualified_domain_name::FullyQualifiedDomainName;
use crate::share::share_link_token::ShareLinkTokens::SecreteShareLinkToken;
use crate::share::versioning::SharingApiPath;
use crate::util::{DOMAIN_NAME, DOMAIN_URL, SECRET_SHARE_PATH_URL};
Expand All @@ -34,6 +35,17 @@ use crate::util::{DOMAIN_NAME, DOMAIN_URL, SECRET_SHARE_PATH_URL};
pub struct DecentralizedSecretShareLink {
pub scheme: Scheme,
pub region_cluster: Option<RegionCluster>,
pub fqdn: FullyQualifiedDomainName,
pub path: DecentralizedSecretesPath,
}

#[derive(Clone, Debug)]
pub struct DecentralizedSecretesPath {
// Depending on what encryption used, the bucket_key might be different.
// Note that the encryption algorithm chosen should have built in integrity check such as AES256-GCM to be considered fully secure or need an external source of integrity check.
// Only the official supported bucket encryption can be used on the website,
// any encryption that fal under custom will only be supported by client
// that has the implementation necessary.
pub version: SharingApiPath,
pub bucket_guid: BucketGuid,
// Depending on what encryption used, the bucket_key might be different.
Expand All @@ -54,44 +66,25 @@ pub struct DecentralizedSecretShareLink {
pub signature: TokenSignature,
}






// Hash the secret share link to get a unique identifier that is then signed with an ed22219 key to create the signature.
// Does not include the signature in the hash.
// https://github.com/RustCrypto/hashes
fn hash_secret_share_link<D: Digest + OutputSizeUser>(
region_cluster: RegionCluster,
user_id: uuid::Uuid,
bucket_id: uuid::Uuid,
bucket_key: aes_gcm::Key<Aes256Gcm>,
permission: BucketPermissionFlags,
expires: OffsetDateTime,
output: &mut GenericArray<u8, <D as OutputSizeUser>::OutputSize>, //[u8;64],
) {
let mut hasher = D::new();
hasher.update(region_cluster.to_string());
hasher.update(user_id.as_bytes());
hasher.update(bucket_id.as_bytes());
hasher.update(bucket_key.as_slice());
hasher.update(permission.bits().to_be_bytes());
hasher.update(bincode::serialize(&expires).unwrap());
hasher.finalize_into(output)
impl Display for DecentralizedSecretesPath {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.version, self.bucket_guid, self.expires, self.permission, self.bucket_key self.signature);
}
}


impl Display for DecentralizedSecretShareLink {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
let region_cluster = match self.region_cluster {
Some(region_cluster) => { write!()},
None => "",
write!(f, "{}://",self.scheme);
match self.region_cluster {
Some(region_cluster) => { write!(f, "{}.", region_cluster)},
None => {},
};


write!(
f,
"{}{}.{}/{}/{}#{}#{}#{}#{}",
"https://",
region_cluster,
"{}/{}/{}#{}#{}#{}#{}",
DOMAIN_URL,
SECRET_SHARE_PATH_URL,
general_purpose::URL_SAFE_NO_PAD.encode(self.bucket_guid.as_slice()),
Expand Down Expand Up @@ -202,17 +195,8 @@ impl DecentralizedSecretShareLink {
&self,
public_signing_key: ed25519_compact::PublicKey,
) -> Result<(), SecretShareLinkVerifySignatureError> {
let mut hash_output = GenericArray::default(); //[0; 64];
self.compute_hash::<Sha3_224>(
self.region_cluster,
self.bucket_guid,
self.bucket_key,
self.permission,
self.expires,
&mut hash_output,
);
assert_eq!(hash_output.len(), 32);
Ok(public_signing_key.verify(hash_output, &self.signature)?)
self.token.verify(&public_signing_key, &self.signature)?;
Ok(())
}

const VERSION: SharingApiPath = SharingApiPath::V1;
Expand Down Expand Up @@ -240,6 +224,10 @@ impl DecentralizedSecretShareLink {
signature,
}
}

pub fn get_token(&self) -> &DecentralizedSecretShareToken {
&self.token
}
}

#[derive(Debug, thiserror::Error)]
Expand Down
4 changes: 2 additions & 2 deletions src/share/decentralized/decentralized_secrete_share_token.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ impl DecentralizedSecretShareToken
hasher.update(region_cluster.to_string());
}
};
hasher.update(bucket_guid.as_slice());
hasher.update(bucket_guid.to_bytes());
hasher.update(bucket_key.as_slice());
hasher.update(permission.bits().to_be_bytes());
hasher.update(bincode::serialize(&expires).unwrap());
Expand Down Expand Up @@ -65,7 +65,7 @@ impl DecentralizedSecretShareToken

pub fn sign(&self, secrete_key: &SecretKey, bucket_guid: &BucketGuid) -> TokenSignature {
//let noise = Noise::from_slice(self.region);
let noise = Noise::from_slice(bucket_guid.to_bytes()).unwrap();
let noise = Noise::from_slice(&bucket_guid.to_bytes()).unwrap();
TokenSignature(secrete_key.sign(&self.token.0.as_slice(),Some(noise)))
}

Expand Down
4 changes: 0 additions & 4 deletions src/share/decentralized/decentralized_share_link.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,4 @@ impl DecentralizedShareLink {
pub fn get_token(&self) -> DecentralizedShareToken {
self.token.clone()
}




}
8 changes: 5 additions & 3 deletions src/share/decentralized/decentralized_share_token.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,12 @@ use crate::bucket::bucket_guid::BucketGuid;
use crate::bucket::bucket_permission::BucketPermissionFlags;
use crate::region::RegionCluster;
use crate::share::share_link_token::{SecreteShareLinkToken, ShareLinkToken};
use crate::token;
use core::slice::SlicePattern;
use digest::generic_array::GenericArray;
use digest::{Digest, OutputSizeUser};
use ed25519_compact::{Noise, PublicKey, SecretKey, Signature};
use sha3::{Sha3_256, Sha3_256Core};
use time::OffsetDateTime;

#[derive(Clone, Eq, PartialEq, Debug)]
Expand All @@ -25,7 +27,7 @@ impl DecentralizedShareToken {
) -> GenericArray<u8, <TDigest as OutputSizeUser>::OutputSize> {
let mut output = GenericArray::default();
let mut hasher = TDigest::new();
hasher.update(bucket_guid.as_slice());
hasher.update(bucket_guid.to_bytes());
hasher.update(permission.bits().to_be_bytes());
hasher.update(bincode::serialize(&expires_at).unwrap());
hasher.finalize_into(&mut output);
Expand All @@ -35,7 +37,7 @@ impl DecentralizedShareToken {
permission: &BucketPermissionFlags,
expires_at: &OffsetDateTime,
region: &Option<RegionCluster>) -> Self {
let token = Self::hash(&bucket_guid,
let token = Self::hash::<Sha3_256>(&bucket_guid,
&permission,
&expires_at);
assert_eq!(token.len(), 32);
Expand All @@ -47,7 +49,7 @@ impl DecentralizedShareToken {

pub fn sign(&self, secrete_key: &SecretKey, bucket_guid: &BucketGuid) -> TokenSignature {
//let noise = Noise::from_slice(self.region);
let noise = Noise::from_slice(bucket_guid.to_bytes()).unwrap();
let noise = Noise::from_slice(&bucket_guid.to_bytes()).unwrap();
TokenSignature(secrete_key.sign(&self.token.0.as_slice(),Some(noise)))
}

Expand Down
2 changes: 1 addition & 1 deletion src/share/fully_qualified_domain_name.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use std::fmt::{Display, Formatter};
use std::str::FromStr;

/// Represents a fully qualified domain name with up to 3 levels using owned, boxed strings.
#[derive(Debug)]
#[derive(Debug, Clone)]
pub struct FullyQualifiedDomainName {
pub subdomain: Option<Box<str>>,
pub domain: Box<str>,
Expand Down
2 changes: 1 addition & 1 deletion src/share/token_path.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,6 @@ impl FromStr for TokenPath {
let version = SharingApiPath::from_str(parts[0])
.map_err(|_| PathVersionParseError::InvalidVersionFormat)?;
// Return the successfully parsed PathVersion
Ok(TokenPath { version, token: ShareLinkToken::from_base64_url_safe(parts[1]).unwrap() })
Ok(TokenPath { version, token: ShareLinkTokens::ShareLinkToken(ShareLinkToken::from_base64_url_safe(parts[1]).unwrap()) })
}
}

0 comments on commit 36002f9

Please sign in to comment.