diff --git a/Cargo.lock b/Cargo.lock index c1d317d4e..22b65765f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -441,6 +441,7 @@ version = "0.1.0" dependencies = [ "async-lock", "bitwarden", + "chrono", "env_logger", "openssl", "schemars", diff --git a/crates/bitwarden-uniffi/Cargo.toml b/crates/bitwarden-uniffi/Cargo.toml index 4c1ce2101..60228c104 100644 --- a/crates/bitwarden-uniffi/Cargo.toml +++ b/crates/bitwarden-uniffi/Cargo.toml @@ -13,6 +13,10 @@ bench = false [dependencies] async-lock = "2.7.0" +chrono = { version = ">=0.4.26, <0.5", features = [ + "serde", + "std", +], default-features = false } env_logger = "0.10.0" uniffi = "=0.24.1" schemars = { version = ">=0.8, <0.9", optional = true } diff --git a/crates/bitwarden-uniffi/src/docs.rs b/crates/bitwarden-uniffi/src/docs.rs index bd30e974e..bc47a19c3 100644 --- a/crates/bitwarden-uniffi/src/docs.rs +++ b/crates/bitwarden-uniffi/src/docs.rs @@ -3,7 +3,10 @@ use bitwarden::{ client::kdf::Kdf, mobile::crypto::InitCryptoRequest, tool::{ExportFormat, PassphraseGeneratorRequest, PasswordGeneratorRequest}, - vault::{Cipher, CipherView, Collection, Folder, FolderView, Send, SendListView, SendView}, + vault::{ + Cipher, CipherView, Collection, Folder, FolderView, Send, SendListView, SendView, + TotpResponse, + }, }; use schemars::JsonSchema; @@ -35,4 +38,7 @@ pub enum DocRef { // Kdf Kdf(Kdf), + + /// TOTP + TotpResponse(TotpResponse), } diff --git a/crates/bitwarden-uniffi/src/lib.rs b/crates/bitwarden-uniffi/src/lib.rs index 2e2543ab3..6e5415d38 100644 --- a/crates/bitwarden-uniffi/src/lib.rs +++ b/crates/bitwarden-uniffi/src/lib.rs @@ -9,6 +9,7 @@ use bitwarden::{client::client_settings::ClientSettings, mobile::crypto::InitCry pub mod auth; mod error; pub mod tool; +mod uniffi_support; pub mod vault; #[cfg(feature = "docs")] diff --git a/crates/bitwarden-uniffi/src/uniffi_support.rs b/crates/bitwarden-uniffi/src/uniffi_support.rs new file mode 100644 index 000000000..f2a0bfde6 --- /dev/null +++ b/crates/bitwarden-uniffi/src/uniffi_support.rs @@ -0,0 +1,16 @@ +use crate::UniffiCustomTypeConverter; + +type DateTime = chrono::DateTime; +uniffi::custom_type!(DateTime, std::time::SystemTime); + +impl UniffiCustomTypeConverter for chrono::DateTime { + type Builtin = std::time::SystemTime; + + fn into_custom(val: Self::Builtin) -> uniffi::Result { + Ok(Self::from(val)) + } + + fn from_custom(obj: Self) -> Self::Builtin { + obj.into() + } +} diff --git a/crates/bitwarden-uniffi/src/vault/mod.rs b/crates/bitwarden-uniffi/src/vault/mod.rs index 2692632ab..79b3e5835 100644 --- a/crates/bitwarden-uniffi/src/vault/mod.rs +++ b/crates/bitwarden-uniffi/src/vault/mod.rs @@ -1,5 +1,8 @@ use std::sync::Arc; +use bitwarden::vault::TotpResponse; +use chrono::{DateTime, Utc}; + use crate::Client; pub mod ciphers; @@ -37,4 +40,20 @@ impl ClientVault { pub fn sends(self: Arc) -> Arc { Arc::new(sends::ClientSends(self.0.clone())) } + + /// Generate a TOTP code from a provided key. + /// + /// The key can be either: + /// - A base32 encoded string + /// - OTP Auth URI + /// - Steam URI + pub async fn generate_totp(&self, key: String, time: Option>) -> TotpResponse { + self.0 + .0 + .read() + .await + .vault() + .generate_totp(key, time) + .await + } } diff --git a/crates/bitwarden/src/mobile/vault/client_totp.rs b/crates/bitwarden/src/mobile/vault/client_totp.rs new file mode 100644 index 000000000..97eb243af --- /dev/null +++ b/crates/bitwarden/src/mobile/vault/client_totp.rs @@ -0,0 +1,18 @@ +use chrono::{DateTime, Utc}; + +use crate::vault::{generate_totp, TotpResponse}; + +use super::client_vault::ClientVault; + +impl<'a> ClientVault<'a> { + /// Generate a TOTP code from a provided key. + /// + /// Key can be either: + /// - A base32 encoded string + /// - OTP Auth URI + /// - Steam URI + /// + pub async fn generate_totp(&'a self, key: String, time: Option>) -> TotpResponse { + generate_totp(key, time).await + } +} diff --git a/crates/bitwarden/src/mobile/vault/mod.rs b/crates/bitwarden/src/mobile/vault/mod.rs index f0fe4ca76..f22f004ce 100644 --- a/crates/bitwarden/src/mobile/vault/mod.rs +++ b/crates/bitwarden/src/mobile/vault/mod.rs @@ -3,4 +3,5 @@ mod client_collection; mod client_folders; mod client_password_history; mod client_sends; +mod client_totp; mod client_vault; diff --git a/crates/bitwarden/src/vault/mod.rs b/crates/bitwarden/src/vault/mod.rs index 9eecd6620..12910283c 100644 --- a/crates/bitwarden/src/vault/mod.rs +++ b/crates/bitwarden/src/vault/mod.rs @@ -3,9 +3,11 @@ mod collection; mod folder; mod password_history; mod send; +mod totp; pub use cipher::{Cipher, CipherListView, CipherView}; pub use collection::{Collection, CollectionView}; pub use folder::{Folder, FolderView}; pub use password_history::{PasswordHistory, PasswordHistoryView}; pub use send::{Send, SendListView, SendView}; +pub use totp::{generate_totp, TotpResponse}; diff --git a/crates/bitwarden/src/vault/totp.rs b/crates/bitwarden/src/vault/totp.rs new file mode 100644 index 000000000..7e701f92e --- /dev/null +++ b/crates/bitwarden/src/vault/totp.rs @@ -0,0 +1,30 @@ +use chrono::{DateTime, Utc}; +use schemars::JsonSchema; +use serde::{Deserialize, Serialize}; + +#[derive(Serialize, Deserialize, Debug, JsonSchema)] +#[serde(rename_all = "camelCase", deny_unknown_fields)] +#[cfg_attr(feature = "mobile", derive(uniffi::Record))] +pub struct TotpResponse { + /// Generated TOTP code + pub code: String, + /// Time period + pub period: u32, +} + +/// Generate a OATH or RFC 6238 TOTP code from a provided key. +/// +/// +/// +/// Key can be either: +/// - A base32 encoded string +/// - OTP Auth URI +/// - Steam URI +/// +/// Supports providing an optional time, and defaults to current system time if none is provided. +pub async fn generate_totp(_key: String, _time: Option>) -> TotpResponse { + TotpResponse { + code: "000 000".to_string(), + period: 30, + } +} diff --git a/languages/kotlin/doc.md b/languages/kotlin/doc.md index 9e8c19929..6174df750 100644 --- a/languages/kotlin/doc.md +++ b/languages/kotlin/doc.md @@ -441,6 +441,24 @@ Sends operations **Output**: Arc +### `generate_totp` + +Generate a TOTP code from a provided key. + +The key can be either: + +- A base32 encoded string +- OTP Auth URI +- Steam URI + +**Arguments**: + +- self: +- key: String +- time: Option + +**Output**: [TotpResponse](#totpresponse) + # References References are generated from the JSON schemas and should mostly match the kotlin and swift @@ -541,17 +559,17 @@ implementations. attachments - array + array,null fields - array + array,null passwordHistory - array + array,null @@ -606,7 +624,7 @@ implementations. notes - string + string,null @@ -666,17 +684,17 @@ implementations. attachments - array + array,null fields - array + array,null passwordHistory - array + array,null @@ -1253,3 +1271,23 @@ implementations. + +## `TotpResponse` + + + + + + + + + + + + + + + + + +
KeyTypeDescription
codestringGenerated TOTP code
periodintegerTime period