Skip to main content

bitwarden_uniffi/platform/
server_communication_config.rs

1use std::sync::Arc;
2
3use bitwarden_server_communication_config::{
4    AcquiredCookie, ServerCommunicationConfig, ServerCommunicationConfigPlatformApi,
5    SetCommunicationTypeRequest,
6};
7
8use crate::error::Result;
9
10type UniffiRepository = UniffiRepositoryBridge<Arc<dyn ServerCommunicationConfigRepository>>;
11type UniffiPlatformApi = UniffiPlatformApiBridge<Arc<dyn ServerCommunicationConfigPlatformApi>>;
12
13/// UniFFI wrapper for ServerCommunicationConfigClient
14#[derive(uniffi::Object)]
15pub struct ServerCommunicationConfigClient {
16    client: bitwarden_server_communication_config::ServerCommunicationConfigClient<
17        UniffiRepository,
18        UniffiPlatformApi,
19    >,
20}
21
22impl ServerCommunicationConfigClient {
23    /// Creates a new server communication configuration client
24    pub fn new(
25        repository: Arc<dyn ServerCommunicationConfigRepository>,
26        platform_api: Arc<dyn ServerCommunicationConfigPlatformApi>,
27    ) -> Arc<Self> {
28        Arc::new(Self {
29            client: bitwarden_server_communication_config::ServerCommunicationConfigClient::new(
30                UniffiRepositoryBridge(repository),
31                UniffiPlatformApiBridge(platform_api),
32            ),
33        })
34    }
35}
36
37#[uniffi::export]
38impl ServerCommunicationConfigClient {
39    /// Retrieves the server communication configuration for a hostname
40    pub async fn get_config(&self, hostname: String) -> Result<ServerCommunicationConfig> {
41        self.client.get_config(hostname).await
42    }
43
44    /// Determines if cookie bootstrapping is needed for this hostname
45    pub async fn needs_bootstrap(&self, hostname: String) -> bool {
46        self.client.needs_bootstrap(hostname).await
47    }
48
49    /// Returns all cookies that should be included in requests to this server
50    pub async fn cookies(&self, hostname: String) -> Vec<AcquiredCookie> {
51        self.client
52            .cookies(hostname)
53            .await
54            .into_iter()
55            .map(|(name, value)| AcquiredCookie { name, value })
56            .collect()
57    }
58
59    /// Sets the server communication configuration for a hostname
60    ///
61    /// This method saves the provided communication configuration to the repository.
62    /// Typically called when receiving the `/api/config` response from the server.
63    /// Previously acquired cookies are preserved automatically.
64    pub async fn set_communication_type(
65        &self,
66        hostname: String,
67        request: SetCommunicationTypeRequest,
68    ) -> Result<()> {
69        self.client
70            .set_communication_type(hostname, request)
71            .await?;
72        Ok(())
73    }
74
75    /// Acquires a cookie from the platform and saves it to the repository
76    pub async fn acquire_cookie(&self, hostname: String) -> Result<()> {
77        self.client.acquire_cookie(&hostname).await?;
78        Ok(())
79    }
80}
81
82/// UniFFI repository trait for server communication configuration
83#[uniffi::export(with_foreign)]
84#[async_trait::async_trait]
85pub trait ServerCommunicationConfigRepository: Send + Sync {
86    /// Get configuration for a hostname
87    async fn get(&self, hostname: String) -> Result<Option<ServerCommunicationConfig>>;
88
89    /// Save configuration for a hostname
90    async fn save(&self, hostname: String, config: ServerCommunicationConfig) -> Result<()>;
91}
92
93/// Bridge from UniFFI trait to internal repository trait
94pub struct UniffiRepositoryBridge<T>(pub T);
95
96impl<T: ?Sized> UniffiRepositoryBridge<Arc<T>> {
97    #[allow(dead_code)]
98    pub fn new(repo: Arc<T>) -> Arc<Self> {
99        Arc::new(UniffiRepositoryBridge(repo))
100    }
101}
102
103impl<T: std::fmt::Debug> std::fmt::Debug for UniffiRepositoryBridge<T> {
104    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
105        self.0.fmt(f)
106    }
107}
108
109impl<'a> bitwarden_server_communication_config::ServerCommunicationConfigRepository
110    for UniffiRepositoryBridge<Arc<dyn ServerCommunicationConfigRepository + 'a>>
111{
112    type GetError = crate::error::Error;
113    type SaveError = crate::error::Error;
114
115    async fn get(
116        &self,
117        hostname: String,
118    ) -> std::result::Result<Option<ServerCommunicationConfig>, Self::GetError> {
119        self.0.get(hostname).await
120    }
121
122    async fn save(
123        &self,
124        hostname: String,
125        config: ServerCommunicationConfig,
126    ) -> std::result::Result<(), Self::SaveError> {
127        self.0.save(hostname, config).await
128    }
129}
130
131/// Bridge for platform API trait
132pub struct UniffiPlatformApiBridge<T>(pub T);
133
134impl<T: std::fmt::Debug> std::fmt::Debug for UniffiPlatformApiBridge<T> {
135    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
136        self.0.fmt(f)
137    }
138}
139
140#[async_trait::async_trait]
141impl<'a> ServerCommunicationConfigPlatformApi
142    for UniffiPlatformApiBridge<Arc<dyn ServerCommunicationConfigPlatformApi + 'a>>
143{
144    async fn acquire_cookies(&self, vault_url: String) -> Option<Vec<AcquiredCookie>> {
145        self.0.acquire_cookies(vault_url).await
146    }
147}