use crate::error::KeyAes256Error;
use base64::{Engine, prelude::BASE64_STANDARD};
use sha2::{Digest, Sha256};
mod open_object_request;
pub use open_object_request::OpenObjectRequest;
#[derive(Clone, Debug, Default, PartialEq)]
#[non_exhaustive]
pub struct ObjectHighlights {
pub generation: i64,
pub metageneration: i64,
pub size: i64,
pub content_encoding: String,
pub checksums: std::option::Option<crate::model::ObjectChecksums>,
pub storage_class: String,
pub content_language: String,
pub content_type: String,
pub content_disposition: String,
pub etag: String,
}
#[derive(Debug, Clone)]
pub struct KeyAes256 {
key: [u8; 32],
}
impl KeyAes256 {
pub fn new(key: &[u8]) -> std::result::Result<Self, KeyAes256Error> {
match key.len() {
32 => Ok(Self {
key: key[..32].try_into().unwrap(),
}),
_ => Err(KeyAes256Error::InvalidLength),
}
}
}
impl std::convert::From<KeyAes256> for crate::model::CommonObjectRequestParams {
fn from(value: KeyAes256) -> Self {
#[allow(deprecated)]
crate::model::CommonObjectRequestParams::new()
.set_encryption_algorithm("AES256")
.set_encryption_key_bytes(value.key.to_vec())
.set_encryption_key_sha256_bytes(Sha256::digest(value.key).as_slice().to_owned())
}
}
impl std::fmt::Display for KeyAes256 {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", BASE64_STANDARD.encode(self.key))
}
}
#[derive(Clone, Debug, PartialEq)]
pub struct ReadRange(pub(crate) RequestedRange);
impl ReadRange {
pub fn all() -> Self {
Self::offset(0)
}
pub fn offset(offset: u64) -> Self {
Self(RequestedRange::Offset(offset))
}
pub fn tail(count: u64) -> Self {
Self(RequestedRange::Tail(count))
}
pub fn head(count: u64) -> Self {
Self::segment(0, count)
}
pub fn segment(offset: u64, count: u64) -> Self {
Self(RequestedRange::Segment {
offset,
limit: count,
})
}
}
impl crate::model::ReadObjectRequest {
pub(crate) fn with_range(&mut self, range: ReadRange) {
match range.0 {
RequestedRange::Offset(o) => {
self.read_offset = o.clamp(0, i64::MAX as u64) as i64;
}
RequestedRange::Tail(t) => {
self.read_offset = -(t.clamp(0, i64::MAX as u64) as i64);
}
RequestedRange::Segment { offset, limit } => {
self.read_offset = offset.clamp(0, i64::MAX as u64) as i64;
self.read_limit = limit.clamp(0, i64::MAX as u64) as i64;
}
}
}
}
#[derive(Clone, Copy, Debug, PartialEq)]
pub(crate) enum RequestedRange {
Offset(u64),
Tail(u64),
Segment { offset: u64, limit: u64 },
}
#[derive(Debug, PartialEq)]
#[non_exhaustive]
#[allow(dead_code)]
pub struct WriteObjectRequest {
pub spec: crate::model::WriteObjectSpec,
pub params: Option<crate::model::CommonObjectRequestParams>,
}
#[cfg(test)]
pub(crate) mod tests {
use super::*;
use crate::model::ReadObjectRequest;
use base64::{Engine, prelude::BASE64_STANDARD};
use test_case::test_case;
type Result = anyhow::Result<()>;
pub(crate) fn create_key_helper() -> (Vec<u8>, String, Vec<u8>, String) {
let key = vec![b'a'; 32];
let key_base64 = BASE64_STANDARD.encode(key.clone());
let key_sha256 = Sha256::digest(key.clone());
let key_sha256_base64 = BASE64_STANDARD.encode(key_sha256);
(key, key_base64, key_sha256.to_vec(), key_sha256_base64)
}
#[test]
fn test_key_aes_256() -> Result {
let v_slice: &[u8] = &[b'c'; 32];
KeyAes256::new(v_slice)?;
let v_vec: Vec<u8> = vec![b'a'; 32];
KeyAes256::new(&v_vec)?;
let v_array: [u8; 32] = [b'a'; 32];
KeyAes256::new(&v_array)?;
let v_bytes: bytes::Bytes = bytes::Bytes::copy_from_slice(&v_array);
KeyAes256::new(&v_bytes)?;
Ok(())
}
#[test_case(&[b'a'; 0]; "no bytes")]
#[test_case(&[b'a'; 1]; "not enough bytes")]
#[test_case(&[b'a'; 33]; "too many bytes")]
fn test_key_aes_256_err(input: &[u8]) {
KeyAes256::new(input).unwrap_err();
}
#[test]
fn test_key_aes_256_to_control_model_object() -> Result {
let (key, _, key_sha256, _) = create_key_helper();
let key_aes_256 = KeyAes256::new(&key)?;
let params = crate::model::CommonObjectRequestParams::from(key_aes_256);
assert_eq!(params.encryption_algorithm, "AES256");
assert_eq!(params.encryption_key_bytes, key);
assert_eq!(params.encryption_key_sha256_bytes, key_sha256);
Ok(())
}
#[test_case(100, 100)]
#[test_case(u64::MAX, i64::MAX)]
#[test_case(0, 0)]
fn apply_offset(input: u64, want: i64) {
let range = ReadRange::offset(input);
let mut request = ReadObjectRequest::new();
request.with_range(range);
assert_eq!(request.read_offset, want);
assert_eq!(request.read_limit, 0);
}
#[test_case(100, 100)]
#[test_case(u64::MAX, i64::MAX)]
#[test_case(0, 0)]
fn apply_head(input: u64, want: i64) {
let range = ReadRange::head(input);
let mut request = ReadObjectRequest::new();
request.with_range(range);
assert_eq!(request.read_offset, 0);
assert_eq!(request.read_limit, want);
}
#[test_case(100, -100)]
#[test_case(u64::MAX, -i64::MAX)]
#[test_case(0, 0)]
fn apply_tail(input: u64, want: i64) {
let range = ReadRange::tail(input);
let mut request = ReadObjectRequest::new();
request.with_range(range);
assert_eq!(request.read_offset, want);
assert_eq!(request.read_limit, 0);
}
#[test_case(100, 100)]
#[test_case(u64::MAX, i64::MAX)]
#[test_case(0, 0)]
fn apply_segment_offset(input: u64, want: i64) {
let range = ReadRange::segment(input, 2000);
let mut request = ReadObjectRequest::new();
request.with_range(range);
assert_eq!(request.read_offset, want);
assert_eq!(request.read_limit, 2000);
}
#[test_case(100, 100)]
#[test_case(u64::MAX, i64::MAX)]
#[test_case(0, 0)]
fn apply_segment_limit(input: u64, want: i64) {
let range = ReadRange::segment(1000, input);
let mut request = ReadObjectRequest::new();
request.with_range(range);
assert_eq!(request.read_offset, 1000);
assert_eq!(request.read_limit, want);
}
#[test]
fn test_key_aes_256_display() -> Result {
let (key, key_base64, _, _) = create_key_helper();
let key_aes_256 = KeyAes256::new(&key)?;
assert_eq!(key_aes_256.to_string(), key_base64);
Ok(())
}
}