bitwarden-core 3.0.0

Internal crate for the bitwarden crate. Do not use.
Documentation
//! The state bridge is a temporary layer that allows quickly transitioning
//! non-repository shaped state to be accessible from within the SDK.
//!
//! This is not a public API that should be used by other teams. It will be
//! replaced by a `bitwarden-state` implementation as soon as that gains support
//! for non-repository state.

use std::sync::{Arc, Mutex};

use bitwarden_crypto::{EncString, SymmetricCryptoKey, safe::PasswordProtectedKeyEnvelope};
#[cfg(feature = "wasm")]
use wasm_bindgen::prelude::*;

use crate::{
    Client,
    key_management::{
        MasterPasswordUnlockData, V2UpgradeToken,
        account_cryptographic_state::WrappedAccountCryptographicState,
    },
};

/// Thread-safe wrapper around the registered [`StateBridgeImpl`] instance.
pub struct StateBridge {
    implementation: Mutex<Option<Arc<dyn StateBridgeImpl + Send + Sync>>>,
}

impl StateBridge {
    /// Creates an empty bridge with no registered implementation.
    pub fn new() -> Self {
        Self {
            implementation: Mutex::new(None),
        }
    }

    /// Returns true if an implementation has been registered.
    pub fn is_registered(&self) -> bool {
        self.implementation
            .lock()
            .expect("Mutex is not poisoned")
            .is_some()
    }

    /// Registers the host-supplied implementation. Replaces any prior registration.
    pub fn register(&self, implementation: Box<dyn StateBridgeImpl + Send + Sync>) {
        *self.implementation.lock().expect("Mutex is not poisoned") = Some(implementation.into());
    }
}

impl Default for StateBridge {
    fn default() -> Self {
        Self::new()
    }
}

/// Client for interacting with the key-management state bridge. This is used to read and write
/// state held by the clients
#[derive(Clone)]
#[cfg_attr(feature = "uniffi", derive(uniffi::Object))]
#[cfg_attr(feature = "wasm", wasm_bindgen)]
pub struct StateBridgeClient {
    pub(crate) client: crate::Client,
}

impl Client {
    /// A temporary client to bridge KM state into the SDK.
    pub fn km_state_bridge(&self) -> StateBridgeClient {
        StateBridgeClient {
            client: self.clone(),
        }
    }
}

impl StateBridgeClient {
    /// Returns true if a state bridge implementation has been registered.
    pub fn is_bridge_registered(&self) -> bool {
        self.client.internal.state_bridge.is_registered()
    }

    /// Registers a bridge implementation used to read and write temporary key-management state.
    pub fn register_bridge(&self, bridge_impl: Box<dyn StateBridgeImpl + Send + Sync>) {
        self.client.internal.state_bridge.register(bridge_impl);
    }
}

#[cfg(target_arch = "wasm32")]
#[wasm_bindgen]
extern "C" {
    /// Raw JavaScript-side state bridge implementation. The corresponding TypeScript
    /// interface (`WasmStateBridge`) and the per-method extern bindings are generated
    /// by the `state_bridge!` macro below.
    #[wasm_bindgen(typescript_type = "WasmStateBridge")]
    pub type RawWasmStateBridge;
}

#[cfg(target_arch = "wasm32")]
use bitwarden_threading::ThreadBoundRunner;

#[cfg(target_arch = "wasm32")]
/// Adapter that lets a JavaScript-supplied `WasmStateBridge` implement
/// [`StateBridgeImpl`]. The trait impl itself is generated by the
/// `state_bridge!` macro below.
pub struct WasmStateBridge(pub(crate) ThreadBoundRunner<RawWasmStateBridge>);

#[cfg(target_arch = "wasm32")]
#[wasm_bindgen]
impl StateBridgeClient {
    /// Registers a the state bridge implementation provided by the host environment.
    pub fn register_bridge_impl(&self, bridge_impl: RawWasmStateBridge) {
        self.client
            .internal
            .state_bridge
            .register(Box::new(WasmStateBridge(ThreadBoundRunner::new(
                bridge_impl,
            ))));
    }
}

// Generates the full state bridge surface for the listed fields.
//
// Each field expands to three methods on each of [`StateBridgeImpl`], [`StateBridge`], and
// [`StateBridgeClient`] (`set_$name`, `get_$name`, `clear_$name`); WASM extern bindings on
// [`RawWasmStateBridge`]; a [`StateBridgeImpl`] forwarder impl for [`WasmStateBridge`]; and the
// matching `WasmStateBridge` TypeScript interface.
bitwarden_state_bridge_macro::state_bridge! {
    user_key: SymmetricCryptoKey as ts "SymmetricKey",
    persistent_pin_envelope: PasswordProtectedKeyEnvelope as ts "PasswordProtectedKeyEnvelope",
    ephemeral_pin_envelope: PasswordProtectedKeyEnvelope as ts "PasswordProtectedKeyEnvelope",
    encrypted_pin: EncString as ts "EncString",
    v2_upgrade_token: V2UpgradeToken as ts "V2UpgradeToken",
    account_cryptographic_state: WrappedAccountCryptographicState as ts "WrappedAccountCryptographicState",
    masterpassword_unlock_data: MasterPasswordUnlockData as ts "MasterPasswordUnlockData",
}