Skip to main content

bitwarden_server_communication_config/wasm/
client.rs

1use wasm_bindgen::prelude::*;
2
3use crate::{
4    ServerCommunicationConfig, ServerCommunicationConfigClient,
5    wasm::{
6        JsServerCommunicationConfigPlatformApi, JsServerCommunicationConfigRepository,
7        RawJsServerCommunicationConfigPlatformApi, RawJsServerCommunicationConfigRepository,
8    },
9};
10
11/// JavaScript wrapper for ServerCommunicationConfigClient
12///
13/// This provides TypeScript access to the server communication configuration client,
14/// allowing clients to check bootstrap requirements and retrieve cookies for HTTP requests.
15#[wasm_bindgen(js_name = ServerCommunicationConfigClient)]
16pub struct JsServerCommunicationConfigClient {
17    client: ServerCommunicationConfigClient<
18        JsServerCommunicationConfigRepository,
19        JsServerCommunicationConfigPlatformApi,
20    >,
21}
22
23#[wasm_bindgen(js_class = ServerCommunicationConfigClient)]
24impl JsServerCommunicationConfigClient {
25    /// Creates a new ServerCommunicationConfigClient with a JavaScript repository and platform API
26    ///
27    /// The repository should be backed by StateProvider (or equivalent
28    /// storage mechanism) for persistence.
29    ///
30    /// # Arguments
31    ///
32    /// * `repository` - JavaScript implementation of the repository interface
33    /// * `platform_api` - JavaScript implementation of the platform API interface
34    #[wasm_bindgen(constructor)]
35    pub fn new(
36        repository: RawJsServerCommunicationConfigRepository,
37        platform_api: RawJsServerCommunicationConfigPlatformApi,
38    ) -> Self {
39        let js_repository = JsServerCommunicationConfigRepository::new(repository);
40        let js_platform_api = JsServerCommunicationConfigPlatformApi::new(platform_api);
41        Self {
42            client: ServerCommunicationConfigClient::new(js_repository, js_platform_api),
43        }
44    }
45
46    /// Retrieves the server communication configuration for a hostname
47    ///
48    /// If no configuration exists, returns a default Direct bootstrap configuration.
49    ///
50    /// # Arguments
51    ///
52    /// * `hostname` - The server hostname (e.g., "vault.acme.com")
53    ///
54    /// # Errors
55    ///
56    /// Returns an error if the repository fails to retrieve the configuration.
57    #[wasm_bindgen(js_name = getConfig)]
58    pub async fn get_config(&self, hostname: String) -> Result<ServerCommunicationConfig, String> {
59        self.client.get_config(hostname).await
60    }
61
62    /// Determines if cookie bootstrapping is needed for this hostname
63    ///
64    /// # Arguments
65    ///
66    /// * `hostname` - The server hostname (e.g., "vault.acme.com")
67    #[wasm_bindgen(js_name = needsBootstrap)]
68    pub async fn needs_bootstrap(&self, hostname: String) -> bool {
69        self.client.needs_bootstrap(hostname).await
70    }
71
72    /// Returns all cookies that should be included in requests to this server
73    ///
74    /// Returns an array of [cookie_name, cookie_value] pairs.
75    ///
76    /// # Arguments
77    ///
78    /// * `hostname` - The server hostname (e.g., "vault.acme.com")
79    #[wasm_bindgen(js_name = cookies)]
80    pub async fn cookies(&self, hostname: String) -> Result<JsValue, JsError> {
81        let cookies = self.client.cookies(hostname).await;
82        serde_wasm_bindgen::to_value(&cookies).map_err(|e| JsError::new(&e.to_string()))
83    }
84
85    /// Sets the server communication configuration for a hostname
86    ///
87    /// This method saves the provided communication configuration to the repository.
88    /// Typically called when receiving the `/api/config` response from the server.
89    ///
90    /// # Arguments
91    ///
92    /// * `hostname` - The server hostname (e.g., "vault.acme.com")
93    /// * `config` - The server communication configuration to store
94    ///
95    /// # Errors
96    ///
97    /// Returns an error if the repository save operation fails
98    #[wasm_bindgen(js_name = setCommunicationType)]
99    pub async fn set_communication_type(
100        &self,
101        hostname: String,
102        config: ServerCommunicationConfig,
103    ) -> Result<(), String> {
104        self.client.set_communication_type(hostname, config).await
105    }
106
107    /// Acquires a cookie from the platform and saves it to the repository
108    ///
109    /// This method calls the platform API to trigger cookie acquisition (e.g., browser
110    /// redirect to IdP), then validates and stores the acquired cookie in the repository.
111    ///
112    /// # Arguments
113    ///
114    /// * `hostname` - The server hostname (e.g., "vault.acme.com")
115    ///
116    /// # Errors
117    ///
118    /// Returns an error if:
119    /// - Cookie acquisition was cancelled by the user
120    /// - Server configuration doesn't support SSO cookies (Direct bootstrap)
121    /// - Acquired cookie name doesn't match expected name
122    /// - Repository operations fail
123    #[wasm_bindgen(js_name = acquireCookie)]
124    pub async fn acquire_cookie(&self, hostname: String) -> Result<(), String> {
125        self.client
126            .acquire_cookie(&hostname)
127            .await
128            .map_err(|e| e.to_string())
129    }
130}