Skip to main content

bitwarden_pm/
builder.rs

1use std::sync::Arc;
2
3use bitwarden_auth::token_management::PasswordManagerTokenHandler;
4use bitwarden_core::ClientBuilder;
5
6use crate::PasswordManagerClient;
7
8/// Builder for constructing [`PasswordManagerClient`] instances with custom configuration.
9pub struct PasswordManagerClientBuilder {
10    settings: Option<bitwarden_core::ClientSettings>,
11    cookie_provider:
12        Option<std::sync::Arc<dyn bitwarden_server_communication_config::CookieProvider>>,
13}
14
15impl PasswordManagerClientBuilder {
16    /// Creates a new [`PasswordManagerClientBuilder`] with default settings.
17    pub fn new() -> Self {
18        Self {
19            settings: None,
20            cookie_provider: None,
21        }
22    }
23
24    /// Sets the [`ClientSettings`](bitwarden_core::ClientSettings) for the client being built.
25    pub fn with_settings(mut self, settings: bitwarden_core::ClientSettings) -> Self {
26        self.settings = Some(settings);
27        self
28    }
29
30    /// Sets an SSO load balancer cookie provider, enabling cookie middleware for
31    /// self-hosted deployments behind sticky-session load balancers.
32    pub fn with_server_communication_config(
33        mut self,
34        cookie_provider: std::sync::Arc<dyn bitwarden_server_communication_config::CookieProvider>,
35    ) -> Self {
36        self.cookie_provider = Some(cookie_provider);
37        self
38    }
39
40    /// Consumes the builder and constructs a [`PasswordManagerClient`].
41    pub fn build(self) -> PasswordManagerClient {
42        let token_handler = Arc::new(PasswordManagerTokenHandler::default());
43        let mut builder = ClientBuilder::new().with_token_handler(token_handler);
44        if let Some(s) = self.settings {
45            builder = builder.with_settings(s);
46        }
47        if let Some(cookie_provider) = self.cookie_provider {
48            let cookie_middleware: Arc<dyn reqwest_middleware::Middleware> = Arc::new(
49                bitwarden_server_communication_config::ServerCommunicationConfigMiddleware::new(
50                    cookie_provider,
51                ),
52            );
53            builder = builder.with_middleware(vec![cookie_middleware]);
54        }
55        PasswordManagerClient(builder.build())
56    }
57}
58
59impl Default for PasswordManagerClientBuilder {
60    fn default() -> Self {
61        Self::new()
62    }
63}
64
65#[cfg(test)]
66mod tests {
67    use super::*;
68
69    #[test]
70    fn test_pm_builder_default_builds() {
71        let _client = PasswordManagerClientBuilder::new().build();
72    }
73
74    #[test]
75    fn test_pm_builder_with_settings_builds() {
76        let settings = bitwarden_core::ClientSettings::default();
77        let _client = PasswordManagerClientBuilder::new()
78            .with_settings(settings)
79            .build();
80    }
81
82    #[test]
83    fn test_pm_builder_with_server_communication_config_builds() {
84        struct MockCookieProvider;
85
86        #[async_trait::async_trait]
87        impl bitwarden_server_communication_config::CookieProvider for MockCookieProvider {
88            async fn cookies(&self, _hostname: &str) -> Vec<(String, String)> {
89                vec![]
90            }
91
92            async fn acquire_cookie(
93                &self,
94                _hostname: &str,
95            ) -> Result<(), bitwarden_server_communication_config::AcquireCookieError> {
96                Ok(())
97            }
98
99            async fn needs_bootstrap(&self, _hostname: &str) -> bool {
100                false
101            }
102        }
103
104        let _client = PasswordManagerClientBuilder::new()
105            .with_server_communication_config(Arc::new(MockCookieProvider))
106            .build();
107    }
108}