diff --git a/crates/bitwarden-core/src/client/client.rs b/crates/bitwarden-core/src/client/client.rs index b9bf4c51..788ee99f 100644 --- a/crates/bitwarden-core/src/client/client.rs +++ b/crates/bitwarden-core/src/client/client.rs @@ -18,6 +18,19 @@ pub struct Client { } impl Client { + /// Constructs a new `Client` with the given `settings_input`. + /// + /// # Examples + /// ```rust + /// use bitwarden_core::{Client, ClientSettings, DeviceType}; + /// + /// let client = Client::new(Some(ClientSettings { + /// identity_url: "https://identity.bitwarden.com".to_owned(), + /// api_url: "https://api.bitwarden.com".to_owned(), + /// user_agent: "Bitwarden Rust-SDK".to_owned(), + /// device_type: DeviceType::ChromeBrowser, + /// })); + /// ``` pub fn new(settings_input: Option) -> Self { let settings = settings_input.unwrap_or_default(); diff --git a/crates/bitwarden-core/src/client/encryption_settings.rs b/crates/bitwarden-core/src/client/encryption_settings.rs index 467ad61c..a8e34844 100644 --- a/crates/bitwarden-core/src/client/encryption_settings.rs +++ b/crates/bitwarden-core/src/client/encryption_settings.rs @@ -30,10 +30,20 @@ pub enum EncryptionSettingsError { MissingPrivateKey, } +/// A struct containing the core keys of a Bitwarden user. #[derive(Clone)] pub struct EncryptionSettings { + /// The users symmetric key, stored on the server after being + /// encrypted with another key. user_key: SymmetricCryptoKey, + /// The users private key, stored on the server + /// encrypted with the users symmetric key. pub(crate) private_key: Option, + /// A map of the users organization keys with the key being + /// the ID of the organization and the value being the symmetric + /// key. This map may be empty if the user is not a part of + /// any organizations. These keys are stored on the server + /// encrypted with the users private key. org_keys: HashMap, } diff --git a/crates/bitwarden-core/src/client/flags.rs b/crates/bitwarden-core/src/client/flags.rs index 0fc17534..ea03bdf9 100644 --- a/crates/bitwarden-core/src/client/flags.rs +++ b/crates/bitwarden-core/src/client/flags.rs @@ -1,5 +1,7 @@ +/// A struct containing fields of all known feature flags and their values. #[derive(Debug, Default, Clone, serde::Deserialize)] pub struct Flags { + /// A `bool` indicating whether or not cipher key encryption is enabled. #[serde(default, rename = "enableCipherKeyEncryption")] pub enable_cipher_key_encryption: bool, } diff --git a/crates/bitwarden-core/src/client/internal.rs b/crates/bitwarden-core/src/client/internal.rs index d64ac75b..026748d6 100644 --- a/crates/bitwarden-core/src/client/internal.rs +++ b/crates/bitwarden-core/src/client/internal.rs @@ -41,6 +41,9 @@ pub(crate) struct Tokens { pub(crate) refresh_token: Option, } +/// A struct contains various internal actions. Everything on this type +/// should be considered unstable and subject to change at any time. Use +/// with caution. #[derive(Debug)] pub struct InternalClient { pub(crate) tokens: RwLock, diff --git a/crates/bitwarden-core/src/client/test_accounts.rs b/crates/bitwarden-core/src/client/test_accounts.rs index 858e1d2f..44d9090f 100644 --- a/crates/bitwarden-core/src/client/test_accounts.rs +++ b/crates/bitwarden-core/src/client/test_accounts.rs @@ -12,6 +12,12 @@ use crate::{ }; impl Client { + /// Creates a client initialized with a hard coded test account. + /// Useful for examples. + pub async fn test_account() -> Self { + Self::init_test_account(test_bitwarden_com_account()).await + } + pub async fn init_test_account(account: TestAccount) -> Self { let client = Client::new(None); @@ -187,3 +193,13 @@ pub fn test_legacy_user_key_account() -> TestAccount { org: None, } } + +pub const PUBLIC_KEY: &str = "-----BEGIN PUBLIC KEY----- +MIIBITANBgkqhkiG9w0BAQEFAAOCAQ4AMIIBCQKCAQB6x0WIywZ7ys/5lFBNOWqP +uwtnCuX58vPVOOUttuaK1AfgZnCIpTbkaJUPKqZbeEi2uWlrDBQ5K0gEX9ASTXCw +i3ij1mVifAJgjI698VTS2Xn9vitYhBT8V0EQstUW0jIlng7qRyrHQ9owBzGUsv4s +1pGHKhgJcbQkh+hagu0s8cpA0BQl6L2BFi/H4DjD94m3LcJVj+z6FepQYJlLte+W +T3DjuHhwXWWRXiYP0/d/QeCBMMP72N4Xw25LmXOxN035JlKHuRazg0lHDj5C1BDY +nH4lWuWbVrLUBNzETLUAGJX6JEuVbwLWEb4R1yJHXecUueyPSCSxksY4rUedSGoP +AgMBAAE= +-----END PUBLIC KEY-----"; diff --git a/crates/bitwarden-core/src/platform/client_platform.rs b/crates/bitwarden-core/src/platform/client_platform.rs index 1f117d5f..b2395d6c 100644 --- a/crates/bitwarden-core/src/platform/client_platform.rs +++ b/crates/bitwarden-core/src/platform/client_platform.rs @@ -5,15 +5,58 @@ use super::{ }; use crate::{error::Result, Client}; +/// A struct containing platform utilities. pub struct ClientPlatform<'a> { pub(crate) client: &'a Client, } impl<'a> ClientPlatform<'a> { + /// Will generate a fingerprint based on the `input`. Given the same `input` This + /// method will always result in the exact same output. + /// + /// # Examples + /// ```rust + /// # use bitwarden_core::client::test_accounts::PUBLIC_KEY; + /// use base64::{engine::general_purpose::STANDARD, Engine}; + /// use bitwarden_core::{Client, platform::FingerprintRequest}; + /// + /// fn test(client: Client) { + /// let fingerprint_response = client.platform() + /// .fingerprint(&FingerprintRequest { + /// fingerprint_material: "my_material".to_owned(), + /// public_key: STANDARD.encode(PUBLIC_KEY), + /// }) + /// .unwrap(); + /// + /// assert_eq!(fingerprint_response.fingerprint, "unsure-unethical-bruising-semester-subscript"); + /// } + /// + /// # tokio::runtime::Builder::new_current_thread().enable_all().build().unwrap().block_on( + /// # async { test(Client::test_account().await) }); + /// ``` pub fn fingerprint(&self, input: &FingerprintRequest) -> Result { generate_fingerprint(input) } + /// Will generate a fingerprint based on the given `fingerprint_material` + /// and the users public key. Given the same `fingerprint_material` and + /// the same user this method will always result in the exact same output. + /// + /// The returned fingerprint is a string of 5 words seperated by hyphens. + /// + /// # Examples + /// ```rust + /// use bitwarden_core::Client; + /// + /// async fn test() { + /// let client = Client::test_account().await; + /// let fingerprint = client.platform() + /// .user_fingerprint("my_material".to_owned()) + /// .unwrap(); + /// + /// assert_eq!(fingerprint, "dreamland-desecrate-corrosive-ecard-retry"); + /// } + /// ``` pub fn user_fingerprint(self, fingerprint_material: String) -> Result { generate_user_fingerprint(self.client, fingerprint_material) } @@ -27,6 +70,7 @@ impl<'a> ClientPlatform<'a> { } impl<'a> Client { + /// Retrieves a [`ClientPlatform`] for accessing Platform APIs. pub fn platform(&'a self) -> ClientPlatform<'a> { ClientPlatform { client: self } } diff --git a/crates/bitwarden-core/src/platform/generate_fingerprint.rs b/crates/bitwarden-core/src/platform/generate_fingerprint.rs index 5d31a1af..f632cafc 100644 --- a/crates/bitwarden-core/src/platform/generate_fingerprint.rs +++ b/crates/bitwarden-core/src/platform/generate_fingerprint.rs @@ -6,6 +6,7 @@ use serde::{Deserialize, Serialize}; use crate::error::Result; +/// A struct containing the parts for making a fingerprint request. #[derive(Serialize, Deserialize, Debug, JsonSchema)] #[serde(rename_all = "camelCase", deny_unknown_fields)] #[cfg_attr(feature = "uniffi", derive(uniffi::Record))] @@ -16,9 +17,11 @@ pub struct FingerprintRequest { pub public_key: String, } +/// A struct containing the details of a successful request to generate a fingerprint. #[derive(Serialize, Deserialize, Debug, JsonSchema)] #[serde(rename_all = "camelCase", deny_unknown_fields)] pub struct FingerprintResponse { + /// A `String` containing 5 words seperated by hyphens. pub fingerprint: String, }