use reqwest::header::HeaderMap;
use crate::models;
#[derive(Debug, Clone, Copy, Serialize, PartialEq, Eq, Hash)]
#[serde(rename_all = "camelCase")]
pub enum DownloadFileBy<'a> {
FileId(&'a str),
FileName(&'a str),
}
#[derive(Default, Debug, Clone, Copy, Serialize, typed_builder::TypedBuilder)]
#[serde(rename_all = "camelCase")]
#[builder(doc)]
pub struct ListFiles<'a> {
#[serde(skip_serializing)]
#[builder(default)]
pub all_versions: bool,
#[builder(default, setter(into))]
pub bucket_id: Option<&'a str>,
#[builder(default, setter(into))]
#[serde(skip_serializing_if = "Option::is_none")]
pub start_file_name: Option<&'a str>,
#[builder(default, setter(into))]
#[serde(skip_serializing_if = "Option::is_none")]
pub start_file_id: Option<&'a str>,
#[builder(default, setter(into))]
#[serde(skip_serializing_if = "Option::is_none")]
pub max_file_count: Option<usize>,
#[builder(default, setter(into))]
#[serde(skip_serializing_if = "Option::is_none")]
pub prefix: Option<&'a str>,
#[builder(default, setter(into))]
#[serde(skip_serializing_if = "Option::is_none")]
pub delimiter: Option<&'a str>,
}
#[derive(Default, Debug, Clone, Serialize, typed_builder::TypedBuilder)]
#[serde(rename_all = "camelCase")]
#[builder(doc)]
pub struct FileRetention {
#[builder(default, setter(into))]
pub mode: Option<models::B2FileRetentionMode>,
#[serde(skip_serializing_if = "Option::is_none")]
pub retain_until_timestamp: Option<u64>,
#[serde(skip_serializing)]
pub bypass_governance: bool,
}
impl FileRetention {
pub const fn new(mode: Option<models::B2FileRetentionMode>) -> Self {
Self {
mode,
retain_until_timestamp: None,
bypass_governance: false,
}
}
pub const fn none() -> Self {
Self::new(None)
}
pub const fn compliance() -> Self {
Self::new(Some(models::B2FileRetentionMode::Compliance))
}
pub const fn governance() -> Self {
Self::new(Some(models::B2FileRetentionMode::Governance))
}
pub const fn bypass_governance(mut self) -> Self {
self.bypass_governance = true;
self
}
pub const fn retain_until_timestamp(mut self, timestamp: Option<u64>) -> Self {
self.retain_until_timestamp = timestamp;
self
}
}
#[derive(Debug, typed_builder::TypedBuilder)]
#[builder(doc, mutators(
/// Sets the SSE-C encryption type with the given key.
pub fn encrypt_custom_aes256(&mut self, key: &[u8]) {
self.encryption = sse::ServerSideEncryption::customer_aes256(key);
}
pub fn encryption(&mut self, encryption: impl Into<sse::ServerSideEncryption>) {
self.encryption = encryption.into();
}
))]
pub struct NewFileInfo {
#[builder(setter(into))]
pub file_name: String,
pub content_length: u64,
#[builder(default, setter(into))]
pub content_type: Option<String>,
#[builder(setter(into))]
pub content_sha1: String,
#[builder(default, via_mutators)]
pub encryption: sse::ServerSideEncryption,
#[builder(default, setter(into))]
pub retention: Option<FileRetention>,
#[builder(default)]
pub legal_hold: Option<bool>,
}
#[derive(Debug, typed_builder::TypedBuilder)]
#[builder(doc, mutators(
/// Sets the SSE-C encryption type with the given key.
pub fn encrypt_custom_aes256(&mut self, key: &[u8]) {
self.encryption = sse::ServerSideEncryption::customer_aes256(key);
}
pub fn encryption(&mut self, encryption: impl Into<sse::ServerSideEncryption>) {
self.encryption = encryption.into();
}
))]
pub struct NewLargeFileInfo {
#[builder(setter(into))]
pub file_name: String,
#[builder(default, setter(into))]
pub content_type: Option<String>,
#[builder(default, via_mutators)]
pub encryption: sse::ServerSideEncryption,
#[builder(default, setter(into))]
pub retention: Option<FileRetention>,
#[builder(default)]
pub legal_hold: Option<bool>,
}
#[derive(Debug, typed_builder::TypedBuilder)]
#[builder(doc, mutators(
/// Sets the SSE-C encryption type with the given key.
pub fn encrypt_custom_aes256(&mut self, key: &[u8]) {
self.encryption = sse::ServerSideEncryption::customer_aes256(key);
}
pub fn encryption(&mut self, encryption: impl Into<sse::ServerSideEncryption>) {
self.encryption = encryption.into();
}
))]
pub struct NewPartInfo {
#[builder(setter(into))]
pub part_number: std::num::NonZeroU32,
pub content_length: u64,
#[builder(setter(into))]
pub content_sha1: String,
#[builder(default, via_mutators)]
pub encryption: sse::ServerSideEncryption,
}
impl NewFileInfo {
pub(crate) fn add_headers(&self, headers: &mut HeaderMap) {
h!(headers."x-bz-file-name" => &self.file_name);
h!(headers."content-type" => self.content_type.as_deref().unwrap_or("application/octet-stream"));
h!(headers."content-length" => &self.content_length.to_string());
h!(headers."x-bz-content-sha1" => &self.content_sha1);
if let Some(ref retention) = self.retention {
if let Some(ref mode) = retention.mode {
h!(headers."x-bz-file-retention-mode" => mode.as_ref());
if let Some(timestamp) = retention.retain_until_timestamp {
h!(headers."x-bz-file-retention-retain-until-timestamp" => ×tamp.to_string());
}
}
}
if let Some(legal_hold) = self.legal_hold {
h!(headers."x-bz-file-legal-hold" => if legal_hold { "on" } else { "off" });
}
self.encryption.add_headers(headers);
}
}
impl NewPartInfo {
pub(crate) fn add_headers(&self, headers: &mut HeaderMap) {
h!(headers."x-bz-part-number" => &self.part_number.to_string());
h!(headers."content-length" => &self.content_length.to_string());
h!(headers."x-bz-content-sha1" => &self.content_sha1);
self.encryption.add_headers(headers);
}
}
pub mod sse {
use std::borrow::Cow;
use reqwest::header::HeaderMap;
#[derive(Debug, Clone, Serialize)]
pub struct ServerSideEncryptionCustomer {
pub algorithm: Cow<'static, str>,
pub key: String,
pub key_md5: String,
}
impl ServerSideEncryptionCustomer {
pub fn aes256(key: &[u8]) -> Self {
use base64::{engine::general_purpose::STANDARD, Engine as _};
use md5::{Digest, Md5};
Self {
algorithm: Cow::Borrowed("AES256"),
key: STANDARD.encode(key),
key_md5: STANDARD.encode(Md5::new().chain_update(key).finalize()),
}
}
}
#[derive(Default, Debug, Clone, Serialize)]
#[serde(tag = "mode")]
pub enum ServerSideEncryption {
#[default]
Default,
#[serde(rename = "SSE-B2")]
Standard {
algorithm: Cow<'static, str>,
},
#[serde(rename = "SSE-C")]
Customer(ServerSideEncryptionCustomer),
}
impl ServerSideEncryption {
pub const fn default() -> Self {
Self::Default
}
pub const fn standard_aes256() -> Self {
Self::Standard {
algorithm: Cow::Borrowed("AES256"),
}
}
pub fn customer_aes256(key: &[u8]) -> Self {
Self::Customer(ServerSideEncryptionCustomer::aes256(key))
}
pub const fn is_default(&self) -> bool {
matches!(self, Self::Default)
}
pub const fn is_standard(&self) -> bool {
matches!(self, Self::Standard { .. })
}
pub const fn is_customer(&self) -> bool {
matches!(self, Self::Customer { .. })
}
}
impl From<ServerSideEncryptionCustomer> for ServerSideEncryption {
fn from(sse_c: ServerSideEncryptionCustomer) -> Self {
ServerSideEncryption::Customer(sse_c)
}
}
impl From<Option<ServerSideEncryptionCustomer>> for ServerSideEncryption {
fn from(sse_c: Option<ServerSideEncryptionCustomer>) -> Self {
sse_c.map_or(ServerSideEncryption::Default, ServerSideEncryption::Customer)
}
}
impl From<Option<ServerSideEncryption>> for ServerSideEncryption {
fn from(sse: Option<ServerSideEncryption>) -> Self {
sse.unwrap_or(ServerSideEncryption::Default)
}
}
impl From<()> for ServerSideEncryption {
fn from(_: ()) -> Self {
ServerSideEncryption::Default
}
}
impl ServerSideEncryptionCustomer {
pub(crate) fn add_headers(&self, headers: &mut HeaderMap) {
h!(headers."x-bz-server-side-encryption-customer-algorithm" => &self.algorithm);
h!(headers."x-bz-server-side-encryption-customer-key" => &self.key);
h!(headers."x-bz-server-side-encryption-customer-key-md5" => &self.key_md5);
}
}
impl ServerSideEncryption {
pub(crate) fn add_headers(&self, headers: &mut HeaderMap) {
match self {
ServerSideEncryption::Default => {}
ServerSideEncryption::Standard { algorithm } => {
h!(headers."x-bz-server-side-encryption" => algorithm);
}
ServerSideEncryption::Customer(sse_c) => sse_c.add_headers(headers),
}
}
}
}