1#![doc = include_str!("../README.md")]
2
3uniffi::setup_scaffolding!();
4
5use std::sync::{Arc, Once};
6
7use auth::AuthClient;
8use bitwarden_core::{ClientSettings, client::internal::ClientManagedTokens};
9
10#[allow(missing_docs)]
11pub mod auth;
12#[allow(missing_docs)]
13pub mod crypto;
14mod error;
15#[allow(missing_docs)]
16pub mod platform;
17#[allow(missing_docs)]
18pub mod tool;
19mod uniffi_support;
20#[allow(missing_docs)]
21pub mod vault;
22
23#[cfg(target_os = "android")]
24mod android_support;
25
26use crypto::CryptoClient;
27use error::{Error, Result};
28use platform::PlatformClient;
29use tool::{ExporterClient, GeneratorClients, SendClient, SshClient};
30use vault::VaultClient;
31
32#[allow(missing_docs)]
33#[derive(uniffi::Object)]
34pub struct Client(pub(crate) bitwarden_pm::PasswordManagerClient);
35
36#[uniffi::export(async_runtime = "tokio")]
37impl Client {
38 #[uniffi::constructor]
40 pub fn new(
41 token_provider: Arc<dyn ClientManagedTokens>,
42 settings: Option<ClientSettings>,
43 ) -> Self {
44 init_logger();
45 setup_error_converter();
46
47 #[cfg(target_os = "android")]
48 android_support::init();
49
50 Self(bitwarden_pm::PasswordManagerClient::new_with_client_tokens(
51 settings,
52 token_provider,
53 ))
54 }
55
56 pub fn crypto(&self) -> CryptoClient {
58 CryptoClient(self.0.crypto())
59 }
60
61 pub fn vault(&self) -> VaultClient {
63 VaultClient(self.0.vault())
64 }
65
66 #[allow(missing_docs)]
67 pub fn platform(&self) -> PlatformClient {
68 PlatformClient(self.0.0.clone())
69 }
70
71 pub fn generators(&self) -> GeneratorClients {
73 GeneratorClients(self.0.generator())
74 }
75
76 pub fn exporters(&self) -> ExporterClient {
78 ExporterClient(self.0.exporters())
79 }
80
81 pub fn sends(&self) -> SendClient {
83 SendClient(self.0.sends())
84 }
85
86 pub fn ssh(&self) -> SshClient {
88 SshClient()
89 }
90
91 pub fn auth(&self) -> AuthClient {
93 AuthClient(self.0.0.clone())
94 }
95
96 pub fn echo(&self, msg: String) -> String {
98 msg
99 }
100
101 pub async fn http_get(&self, url: String) -> Result<String> {
103 let client = self.0.0.internal.get_http_client();
104 let res = client
105 .get(&url)
106 .send()
107 .await
108 .map_err(|e| Error::Api(e.into()))?;
109
110 res.text().await.map_err(|e| Error::Api(e.into()))
111 }
112}
113
114static INIT: Once = Once::new();
115
116fn init_logger() {
117 use tracing_subscriber::{EnvFilter, layer::SubscriberExt as _, util::SubscriberInitExt as _};
118
119 INIT.call_once(|| {
120 let filter = EnvFilter::builder()
125 .with_default_directive(
126 option_env!("RUST_LOG")
127 .unwrap_or("info")
128 .parse()
129 .expect("should provide valid log level at compile time."),
130 )
131 .from_env_lossy();
132
133 let fmtlayer = tracing_subscriber::fmt::layer()
134 .with_ansi(true)
135 .with_file(true)
136 .with_line_number(true)
137 .with_target(true)
138 .pretty();
139
140 #[cfg(target_os = "ios")]
141 {
142 const TAG: &str = "com.8bit.bitwarden";
143
144 tracing_subscriber::registry()
145 .with(fmtlayer)
146 .with(filter)
147 .with(tracing_oslog::OsLogger::new(TAG, "default"))
148 .init();
149 }
150
151 #[cfg(target_os = "android")]
152 {
153 const TAG: &str = "com.bitwarden.sdk";
154
155 tracing_subscriber::registry()
156 .with(fmtlayer)
157 .with(filter)
158 .with(
159 tracing_android::layer(TAG)
160 .expect("initialization of android logcat tracing layer"),
161 )
162 .init();
163 }
164
165 #[cfg(not(any(target_os = "android", target_os = "ios")))]
166 {
167 tracing_subscriber::registry()
168 .with(fmtlayer)
169 .with(filter)
170 .init();
171 }
172 });
173}
174
175fn setup_error_converter() {
178 bitwarden_uniffi_error::set_error_to_uniffi_error(|e| {
179 crate::error::BitwardenError::Conversion(e.to_string()).into()
180 });
181}