1#![warn(rust_2018_idioms, missing_debug_implementations)]
2
3use derive_setters::Setters;
4use serde::{Deserialize, Serialize};
5use serde_repr::Serialize_repr as SerializeRepr;
6use std::{result::Result as StdResult, time::SystemTime};
7use url::Url;
8use uuid::Uuid;
9
10pub use client::{AnonymousClient, Client, ClientBuilder};
11pub use error::{Error, RequestResponseError};
12pub use rwarden_crypto as crypto;
13
14#[macro_use]
15mod util;
16
17mod client;
18mod error;
19
20pub mod account;
21pub mod cache;
22pub mod cipher;
23pub mod collection;
24pub mod folder;
25pub mod response;
26pub mod settings;
27pub mod sync;
28
29pub type Result<TOk, TCacheError> = StdResult<TOk, Error<TCacheError>>;
31
32pub trait Request<'request, 'client, TCache> {
33 type Output;
34 fn send(&'request self, client: &'client mut Client<TCache>) -> Self::Output;
35}
36
37#[derive(Debug, Clone, PartialEq, Eq, Hash, Deserialize, Serialize)]
39pub struct Urls {
40 pub base: Url,
41 pub auth: Url,
42 }
46
47impl Urls {
48 pub fn official() -> Self {
58 Self {
59 base: Url::parse("https://api.bitwarden.com").unwrap(),
60 auth: Url::parse("https://identity.bitwarden.com/connect/token").unwrap(),
61 }
62 }
63
64 pub fn custom<S: AsRef<str>>(url: S) -> StdResult<Self, url::ParseError> {
87 let url = Url::parse(url.as_ref())?;
88 Ok(Self {
89 base: url.join("api")?,
90 auth: url.join("identity/connect/token")?,
91 })
92 }
93}
94
95#[derive(Debug, Clone, PartialEq, Eq, Hash)]
97pub struct AccessTokenData {
98 pub access_token: String,
99 pub expiry_time: SystemTime,
100}
101
102impl AccessTokenData {
103 fn token_has_expired(&self) -> bool {
104 self.expiry_time < SystemTime::now()
105 }
106}
107
108#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, SerializeRepr)]
110#[repr(u8)]
111pub enum DeviceType {
112 Android = 0,
113 Ios = 1,
114 ChromeExtension = 2,
115 FirefoxExtension = 3,
116 OperaExtension = 4,
117 EdgeExtension = 5,
118 WindowsDesktop = 6,
119 MacOsDesktop = 7,
120 LinuxDesktop = 8,
121 ChromeBrowser = 9,
122 FirefoxBrowser = 10,
123 OperaBrowser = 11,
124 EdgeBrowser = 12,
125 IeBrowser = 13,
126 UnknownBrowser = 14,
127 AndroidAmazon = 15,
128 Uwp = 16,
129 SafariBrowser = 17,
130 VivaldiBrowser = 18,
131 VivaldiExtension = 19,
132 SafariExtension = 20,
133}
134
135#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, SerializeRepr)]
137#[repr(u8)]
138pub enum TwoFactorProvider {
139 Authenticator = 0,
140 Email = 1,
141 Duo = 2,
142 YubiKey = 3,
143 U2f = 4,
144 Remember = 5,
145 OrganizationDuo = 6,
146 WebAuthn = 7,
147}
148
149#[derive(Debug, Clone, PartialEq, Eq, Hash, Setters)]
151#[setters(strip_option, prefix = "with_")]
152pub struct LoginData {
153 #[setters(skip)]
155 pub email: String,
156 #[setters(skip)]
158 pub password: String,
159 #[setters(skip)]
160 pub client_id: String,
161 #[setters(into)]
162 pub device_name: Option<String>,
163 pub device_type: Option<DeviceType>,
164 #[setters(into)]
165 pub device_push_token: Option<String>,
166 pub two_factor_provider: Option<TwoFactorProvider>,
167 #[setters(into)]
168 pub two_factor_token: Option<String>,
169 pub two_factor_remember: bool,
170}
171
172impl LoginData {
173 pub fn new<E, P, C>(email: E, password: P, client_id: C) -> Self
175 where
176 E: Into<String>,
177 P: Into<String>,
178 C: Into<String>,
179 {
180 Self {
181 client_id: client_id.into(),
182 email: email.into(),
183 password: password.into(),
184 device_name: None,
185 device_type: None,
186 device_push_token: None,
187 two_factor_provider: None,
188 two_factor_token: None,
189 two_factor_remember: false,
190 }
191 }
192}
193
194#[derive(Debug, Clone, PartialEq, Eq, Hash, Setters)]
196#[setters(strip_option, prefix = "with_")]
197pub struct RegisterData {
198 #[setters(skip)]
200 pub email: String,
201 #[setters(skip)]
203 pub password: String,
204 #[setters(into)]
206 pub password_hint: Option<String>,
207 #[setters(into)]
209 pub name: Option<String>,
210 pub organization_user_id: Option<Uuid>,
212 pub kdf_type: Option<crypto::KdfType>,
216 pub kdf_iterations: Option<u32>,
218}
219
220impl RegisterData {
221 pub fn new<E, P>(email: E, password: P) -> Self
223 where
224 E: Into<String>,
225 P: Into<String>,
226 {
227 Self {
228 email: email.into(),
229 password: password.into(),
230 password_hint: None,
231 name: None,
232 organization_user_id: None,
233 kdf_type: None,
234 kdf_iterations: None,
235 }
236 }
237}