1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
//! Contains the traits and data for different CipherStash clients.
//!
//! Client "data" structs can implement different combinations of traits defined in this module to
//! change what methods can be called on the client. For example if the [`GetNamingKey`] trait is
//! not implemented then the client cannot get or create collections.

use async_trait::async_trait;
use envelopers::{EnvelopeCipher, KeyProvider};
use thiserror::Error;

use crate::async_value::AsyncAccessor;

use crate::{data_service_credentials::DataServiceCredentials, utils::StdError};

/// Trait for allowing clients to get an access token.
#[async_trait(?Send)]
pub trait GetAccessToken {
    async fn get_access_token(&self) -> Result<DataServiceCredentials, StdError>;
}

/// Trait for allowing clients to access the cipher engine for encrypting records and metadata
pub trait GetCipherEngine {
    fn get_cipher_engine(&self) -> &EnvelopeCipher<Box<dyn KeyProvider>>;
}

#[derive(Error, Debug, Clone)]
pub enum GetNamingKeyError {
    #[error("DecodeError: {0}")]
    DecodeError(#[from] base64::DecodeError),
    #[error("Error parsing the naming_key into a record: {0}")]
    RecordError(String),
    #[error("DecryptionError: {0}")]
    DecryptionError(String),
}

/// Trait for allowing clients to access the decrypted naming key
#[async_trait(?Send)]
pub trait GetNamingKey {
    async fn get_naming_key(&self) -> Result<Vec<u8>, GetNamingKeyError>;
}

/// Data that is required by the browser / WASM client.
///
/// Since the browser client cannot create collections it doesn't need to access the naming key.
pub struct BrowserClientData {
    pub cipher_engine: EnvelopeCipher<Box<dyn KeyProvider>>,
    pub access_token: DataServiceCredentials,
}

#[async_trait(?Send)]
impl GetAccessToken for BrowserClientData {
    async fn get_access_token(&self) -> Result<DataServiceCredentials, StdError> {
        Ok(self.access_token.clone())
    }
}

impl GetCipherEngine for BrowserClientData {
    fn get_cipher_engine(&self) -> &EnvelopeCipher<Box<dyn KeyProvider>> {
        &self.cipher_engine
    }
}

/// Data that is required by the native client.
pub struct NativeClientData {
    pub cipher_engine: EnvelopeCipher<Box<dyn KeyProvider>>,
    pub access_token: Box<dyn AsyncAccessor<Value = DataServiceCredentials, Error = StdError>>,
    pub naming_key: Box<dyn AsyncAccessor<Value = Vec<u8>, Error = GetNamingKeyError>>,
}

#[async_trait(?Send)]
impl GetNamingKey for NativeClientData {
    async fn get_naming_key(&self) -> Result<Vec<u8>, GetNamingKeyError> {
        self.naming_key.get_value().await
    }
}

#[async_trait(?Send)]
impl GetAccessToken for NativeClientData {
    async fn get_access_token(&self) -> Result<DataServiceCredentials, StdError> {
        self.access_token.get_value().await
    }
}

impl GetCipherEngine for NativeClientData {
    fn get_cipher_engine(&self) -> &EnvelopeCipher<Box<dyn KeyProvider>> {
        &self.cipher_engine
    }
}