bitwarden_server_communication_config/wasm/client.rs
1use wasm_bindgen::prelude::*;
2
3use crate::{
4 AcquiredCookie, ServerCommunicationConfig, ServerCommunicationConfigClient,
5 SetCommunicationTypeRequest,
6 wasm::{
7 JsServerCommunicationConfigPlatformApi, JsServerCommunicationConfigRepository,
8 RawJsServerCommunicationConfigPlatformApi, RawJsServerCommunicationConfigRepository,
9 },
10};
11
12/// JavaScript wrapper for ServerCommunicationConfigClient
13///
14/// This provides TypeScript access to the server communication configuration client,
15/// allowing clients to check bootstrap requirements and retrieve cookies for HTTP requests.
16#[wasm_bindgen(js_name = ServerCommunicationConfigClient)]
17pub struct JsServerCommunicationConfigClient {
18 client: ServerCommunicationConfigClient<
19 JsServerCommunicationConfigRepository,
20 JsServerCommunicationConfigPlatformApi,
21 >,
22}
23
24#[wasm_bindgen(js_class = ServerCommunicationConfigClient)]
25impl JsServerCommunicationConfigClient {
26 /// Creates a new ServerCommunicationConfigClient with a JavaScript repository and platform API
27 ///
28 /// The repository should be backed by StateProvider (or equivalent
29 /// storage mechanism) for persistence.
30 ///
31 /// # Arguments
32 ///
33 /// * `repository` - JavaScript implementation of the repository interface
34 /// * `platform_api` - JavaScript implementation of the platform API interface
35 #[wasm_bindgen(constructor)]
36 pub fn new(
37 repository: RawJsServerCommunicationConfigRepository,
38 platform_api: RawJsServerCommunicationConfigPlatformApi,
39 ) -> Self {
40 let js_repository = JsServerCommunicationConfigRepository::new(repository);
41 let js_platform_api = JsServerCommunicationConfigPlatformApi::new(platform_api);
42 Self {
43 client: ServerCommunicationConfigClient::new(js_repository, js_platform_api),
44 }
45 }
46
47 /// Retrieves the server communication configuration for a domain
48 ///
49 /// If no configuration exists, returns a default Direct bootstrap configuration.
50 ///
51 /// # Arguments
52 ///
53 /// * `domain` - The server domain (e.g., "vault.acme.com")
54 ///
55 /// # Errors
56 ///
57 /// Returns an error if the repository fails to retrieve the configuration.
58 #[wasm_bindgen(js_name = getConfig)]
59 pub async fn get_config(&self, domain: String) -> Result<ServerCommunicationConfig, String> {
60 self.client.get_config(domain).await
61 }
62
63 /// Determines if cookie bootstrapping is needed for this domain
64 ///
65 /// # Arguments
66 ///
67 /// * `domain` - The server domain (e.g., "vault.acme.com")
68 #[wasm_bindgen(js_name = needsBootstrap)]
69 pub async fn needs_bootstrap(&self, domain: String) -> bool {
70 self.client.needs_bootstrap(domain).await
71 }
72
73 /// Returns all cookies that should be included in requests to this server
74 ///
75 /// Returns an array of [cookie_name, cookie_value] pairs.
76 ///
77 /// # Arguments
78 ///
79 /// * `domain` - The server domain (e.g., "vault.acme.com")
80 #[wasm_bindgen(js_name = cookies)]
81 #[deprecated(
82 note = "Use get_cookies() instead, which will acquire cookies if not present in the config"
83 )]
84 #[allow(deprecated)]
85 pub async fn cookies(&self, domain: String) -> Result<JsValue, JsError> {
86 #[allow(deprecated)]
87 let cookies = self.client.cookies(domain).await;
88 serde_wasm_bindgen::to_value(&cookies).map_err(|e| JsError::new(&e.to_string()))
89 }
90
91 /// Returns all cookies that should be included in requests to this server
92 /// and triggers cookie acquisition if needed
93 ///
94 /// # Arguments
95 ///
96 /// * `domain` - The server domain (e.g., "vault.acme.com")
97 #[wasm_bindgen(js_name = getCookies)]
98 pub async fn get_cookies(&self, domain: String) -> Result<Vec<AcquiredCookie>, JsError> {
99 let cookies = self.client.get_cookies(domain).await;
100 cookies.map_err(|e| JsError::new(&e.to_string()))
101 }
102
103 /// Sets the server communication configuration for a domain
104 ///
105 /// This method saves the provided communication configuration to the repository.
106 /// Typically called when receiving the `/api/config` response from the server.
107 /// Previously acquired cookies are preserved automatically.
108 ///
109 /// # Arguments
110 ///
111 /// * `domain` - The server domain (e.g., "vault.acme.com")
112 /// * `request` - The server communication configuration to store
113 ///
114 /// # Errors
115 ///
116 /// Returns an error if the repository save operation fails
117 #[deprecated(
118 note = "Use set_communication_type_v2() instead, which extracts the domain from the config"
119 )]
120 #[allow(deprecated)]
121 #[wasm_bindgen(js_name = setCommunicationType)]
122 pub async fn set_communication_type(
123 &self,
124 domain: String,
125 request: SetCommunicationTypeRequest,
126 ) -> Result<(), String> {
127 #[allow(deprecated)]
128 self.client.set_communication_type(domain, request).await
129 }
130
131 /// Sets the server communication configuration using the domain from the config
132 ///
133 /// Extracts the `cookie_domain` from the `SsoCookieVendor` config and uses it as the
134 /// storage key. If the config is `Direct` or `cookie_domain` is not set, the call
135 /// is silently ignored.
136 ///
137 /// # Arguments
138 ///
139 /// * `config` - The server communication configuration to store
140 ///
141 /// # Errors
142 ///
143 /// Returns an error if the repository save operation fails
144 #[wasm_bindgen(js_name = setCommunicationTypeV2)]
145 pub async fn set_communication_type_v2(
146 &self,
147 request: SetCommunicationTypeRequest,
148 ) -> Result<(), String> {
149 self.client.set_communication_type_v2(request).await
150 }
151
152 /// Acquires a cookie from the platform and saves it to the repository
153 ///
154 /// This method calls the platform API to trigger cookie acquisition (e.g., browser
155 /// redirect to IdP), then validates and stores the acquired cookie in the repository.
156 ///
157 /// # Arguments
158 ///
159 /// * `domain` - The server domain (e.g., "vault.acme.com")
160 ///
161 /// # Errors
162 ///
163 /// Returns an error if:
164 /// - Cookie acquisition was cancelled by the user
165 /// - Server configuration doesn't support SSO cookies (Direct bootstrap)
166 /// - Acquired cookie name doesn't match expected name
167 /// - Repository operations fail
168 #[wasm_bindgen(js_name = acquireCookie)]
169 pub async fn acquire_cookie(&self, domain: String) -> Result<Vec<AcquiredCookie>, String> {
170 self.client
171 .acquire_cookie(&domain)
172 .await
173 .map_err(|e| e.to_string())
174 }
175}