use nuts_backend::Backend;
use std::rc::Rc;
use crate::cipher::Cipher;
use crate::digest::Digest;
use crate::error::ContainerResult;
use crate::kdf::{Kdf, KdfError};
use crate::password::CallbackFn;
#[cfg(doc)]
use crate::{error::Error, Container};
#[derive(Debug)]
pub(crate) enum KdfBuilder {
Pbkdf2(Digest, u32, u32),
Kdf(Kdf),
}
impl KdfBuilder {
pub(crate) fn build(&self) -> Result<Kdf, KdfError> {
match self {
KdfBuilder::Pbkdf2(digest, iterations, salt_len) => {
Kdf::generate_pbkdf2(*digest, *iterations, *salt_len)
}
KdfBuilder::Kdf(ref kdf) => Ok(kdf.clone()),
}
}
}
pub struct CreateOptions {
pub(crate) callback: Option<Rc<CallbackFn>>,
pub(crate) cipher: Cipher,
pub(crate) kdf: KdfBuilder,
pub(crate) overwrite: bool,
}
pub struct CreateOptionsBuilder(CreateOptions);
impl CreateOptionsBuilder {
pub fn new(cipher: Cipher) -> Self {
let kdf = if cipher == Cipher::None {
KdfBuilder::Kdf(Kdf::None)
} else {
KdfBuilder::Pbkdf2(Digest::Sha256, 65536, 16)
};
CreateOptionsBuilder(CreateOptions {
callback: None,
cipher,
kdf,
overwrite: false,
})
}
pub fn with_password_callback<Cb: Fn() -> Result<Vec<u8>, String> + 'static>(
mut self,
callback: Cb,
) -> Self {
self.0.callback = Some(Rc::new(callback));
self
}
pub fn with_kdf(mut self, kdf: Kdf) -> Self {
if self.0.cipher != Cipher::None {
self.0.kdf = KdfBuilder::Kdf(kdf);
}
self
}
pub fn with_overwrite(mut self, overwrite: bool) -> Self {
self.0.overwrite = overwrite;
self
}
pub fn build<B: Backend>(self) -> ContainerResult<CreateOptions, B> {
Ok(self.0)
}
}
pub struct OpenOptions {
pub(crate) callback: Option<Rc<CallbackFn>>,
}
pub struct OpenOptionsBuilder(OpenOptions);
impl OpenOptionsBuilder {
pub fn new() -> Self {
OpenOptionsBuilder(OpenOptions { callback: None })
}
pub fn with_password_callback<Cb: Fn() -> Result<Vec<u8>, String> + 'static>(
mut self,
callback: Cb,
) -> Self {
self.0.callback = Some(Rc::new(callback));
self
}
pub fn build<B: Backend>(self) -> ContainerResult<OpenOptions, B> {
Ok(self.0)
}
}
impl Default for OpenOptionsBuilder {
fn default() -> Self {
Self::new()
}
}
pub struct ModifyOptions {
pub(crate) kdf: Option<Kdf>,
pub(crate) password: Option<Rc<CallbackFn>>,
}
pub struct ModifyOptionsBuilder(ModifyOptions);
impl ModifyOptionsBuilder {
pub fn change_kdf(mut self, kdf: Kdf) -> Self {
self.0.kdf = Some(kdf);
self
}
pub fn change_password<Cb: Fn() -> Result<Vec<u8>, String> + 'static>(
mut self,
callback: Cb,
) -> Self {
self.0.password = Some(Rc::new(callback));
self
}
pub fn build(self) -> ModifyOptions {
self.0
}
}
impl Default for ModifyOptionsBuilder {
fn default() -> Self {
Self(ModifyOptions {
kdf: None,
password: None,
})
}
}