Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for generating the users fingerprint #474

Merged
merged 7 commits into from
Jan 5, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion crates/bitwarden-json/src/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@
#[cfg(feature = "internal")]
Command::Sync(req) => self.0.sync(&req).await.into_string(),
#[cfg(feature = "internal")]
Command::Fingerprint(req) => self.0.fingerprint(&req).into_string(),
Command::Fingerprint(req) => self.0.platform().fingerprint(&req).into_string(),

Check warning on line 61 in crates/bitwarden-json/src/client.rs

View check run for this annotation

Codecov / codecov/patch

crates/bitwarden-json/src/client.rs#L61

Added line #L61 was not covered by tests

#[cfg(feature = "secrets")]
Command::Secrets(cmd) => match cmd {
Expand Down
22 changes: 20 additions & 2 deletions crates/bitwarden-uniffi/src/platform/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,26 @@

#[uniffi::export(async_runtime = "tokio")]
impl ClientPlatform {
/// Fingerprint
/// Fingerprint (public key)
pub async fn fingerprint(&self, req: FingerprintRequest) -> Result<String> {
Ok(self.0 .0.read().await.fingerprint(&req)?.fingerprint)
Ok(self
.0
.0
.write()
.await
.platform()
.fingerprint(&req)?

Check warning on line 20 in crates/bitwarden-uniffi/src/platform/mod.rs

View check run for this annotation

Codecov / codecov/patch

crates/bitwarden-uniffi/src/platform/mod.rs#L14-L20

Added lines #L14 - L20 were not covered by tests
.fingerprint)
}

Check warning on line 22 in crates/bitwarden-uniffi/src/platform/mod.rs

View check run for this annotation

Codecov / codecov/patch

crates/bitwarden-uniffi/src/platform/mod.rs#L22

Added line #L22 was not covered by tests

/// Fingerprint using logged in user's public key
pub async fn user_fingerprint(&self, fingerprint_material: String) -> Result<String> {
Ok(self
.0
.0
.write()
.await
.platform()
.user_fingerprint(fingerprint_material)?)

Check warning on line 32 in crates/bitwarden-uniffi/src/platform/mod.rs

View check run for this annotation

Codecov / codecov/patch

crates/bitwarden-uniffi/src/platform/mod.rs#L25-L32

Added lines #L25 - L32 were not covered by tests
}
}
3 changes: 3 additions & 0 deletions crates/bitwarden-uniffi/src/uniffi_support.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
use bitwarden::crypto::EncString;

// Forward the type definitions to the main bitwarden crate
type DateTime = chrono::DateTime<chrono::Utc>;
uniffi::ffi_converter_forward!(DateTime, bitwarden::UniFfiTag, crate::UniFfiTag);
uniffi::ffi_converter_forward!(EncString, bitwarden::UniFfiTag, crate::UniFfiTag);
12 changes: 3 additions & 9 deletions crates/bitwarden/src/client/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,16 @@ use chrono::Utc;
use reqwest::header::{self};
use uuid::Uuid;

use super::AccessToken;
#[cfg(feature = "secrets")]
use crate::auth::login::{AccessTokenLoginRequest, AccessTokenLoginResponse};
#[cfg(feature = "internal")]
use crate::{
client::kdf::Kdf,
crypto::{AsymmEncString, EncString},
platform::{
generate_fingerprint, get_user_api_key, sync, FingerprintRequest, FingerprintResponse,
SecretVerificationRequest, SyncRequest, SyncResponse, UserApiKeyResponse,
get_user_api_key, sync, SecretVerificationRequest, SyncRequest, SyncResponse,
UserApiKeyResponse,
},
};
use crate::{
Expand All @@ -24,8 +25,6 @@ use crate::{
error::{Error, Result},
};

use super::AccessToken;

#[derive(Debug)]
pub(crate) struct ApiConfigurations {
pub identity: bitwarden_api_identity::apis::configuration::Configuration,
Expand Down Expand Up @@ -285,9 +284,4 @@ impl Client {
enc.set_org_keys(org_keys)?;
Ok(self.encryption_settings.as_ref().unwrap())
}

#[cfg(feature = "internal")]
pub fn fingerprint(&self, input: &FingerprintRequest) -> Result<FingerprintResponse> {
generate_fingerprint(input)
}
}
2 changes: 1 addition & 1 deletion crates/bitwarden/src/client/encryption_settings.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ use crate::crypto::SymmetricCryptoKey;

pub struct EncryptionSettings {
user_key: SymmetricCryptoKey,
private_key: Option<RsaPrivateKey>,
pub(crate) private_key: Option<RsaPrivateKey>,
org_keys: HashMap<Uuid, SymmetricCryptoKey>,
}

Expand Down
25 changes: 25 additions & 0 deletions crates/bitwarden/src/platform/client_platform.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
use super::{
generate_fingerprint::{generate_fingerprint, generate_user_fingerprint},
FingerprintRequest, FingerprintResponse,
};
use crate::{error::Result, Client};

pub struct ClientPlatform<'a> {
pub(crate) client: &'a mut Client,
}

impl<'a> ClientPlatform<'a> {
pub fn fingerprint(&self, input: &FingerprintRequest) -> Result<FingerprintResponse> {
generate_fingerprint(input)
}

Check warning on line 14 in crates/bitwarden/src/platform/client_platform.rs

View check run for this annotation

Codecov / codecov/patch

crates/bitwarden/src/platform/client_platform.rs#L12-L14

Added lines #L12 - L14 were not covered by tests

pub fn user_fingerprint(self, fingerprint_material: String) -> Result<String> {
generate_user_fingerprint(self.client, fingerprint_material)
}

Check warning on line 18 in crates/bitwarden/src/platform/client_platform.rs

View check run for this annotation

Codecov / codecov/patch

crates/bitwarden/src/platform/client_platform.rs#L16-L18

Added lines #L16 - L18 were not covered by tests
}

impl<'a> Client {
pub fn platform(&'a mut self) -> ClientPlatform<'a> {
ClientPlatform { client: self }
}

Check warning on line 24 in crates/bitwarden/src/platform/client_platform.rs

View check run for this annotation

Codecov / codecov/patch

crates/bitwarden/src/platform/client_platform.rs#L22-L24

Added lines #L22 - L24 were not covered by tests
}
66 changes: 64 additions & 2 deletions crates/bitwarden/src/platform/generate_fingerprint.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use base64::Engine;
use log::{debug, info};
use log::info;
use rsa::pkcs8::EncodePublicKey;
use schemars::JsonSchema;
use serde::{Deserialize, Serialize};

Expand All @@ -23,11 +24,72 @@ pub struct FingerprintResponse {

pub(crate) fn generate_fingerprint(input: &FingerprintRequest) -> Result<FingerprintResponse> {
info!("Generating fingerprint");
debug!("{:?}", input);

let key = BASE64_ENGINE.decode(&input.public_key)?;

Ok(FingerprintResponse {
fingerprint: fingerprint(&input.fingerprint_material, &key)?,
})
}

pub(crate) fn generate_user_fingerprint(
client: &mut crate::Client,
fingerprint_material: String,
) -> Result<String> {
info!("Generating fingerprint");

let enc_settings = client.get_encryption_settings()?;
let private_key = enc_settings
.private_key
.as_ref()
.ok_or("Missing private key")?;

let public_key = private_key
.to_public_key()
.to_public_key_der()
.map_err(|_| "Invalid key")?;

let fingerprint = fingerprint(&fingerprint_material, public_key.as_bytes())?;

Ok(fingerprint)
}

#[cfg(test)]
mod tests {
use std::num::NonZeroU32;

use crate::{
client::{kdf::Kdf, LoginMethod, UserLoginMethod},
Client,
};

use super::*;

#[test]
fn test_generate_user_fingerprint() {
let user_key = "2.oZg5RYpU2HjUAKI1DUQCkg==|PyRzI9kZpt66P2OedH8CHOeU0/lgKLkhIJiKDijdyFqIemBSIBoslhfQh/P1TK9xgZp0smgD6+5+yNbZfOpBaCVrsT3WWAO78xOWizduRe4=|xfDLDZSJ+yZAdh388flVg7SMDBJuMs0+CHTjutKs4uQ=";
let private_key = "2.tY6WsWKUbBwNU8wROuipiQ==|DNFL1d19xVojUKTTy2gxT+9J1VXbMQLcbMnx1HSeA6U3yZhsLR6DPaGibb3Bp8doIHtrsxzL/JeLb4gLDZ8RnDhFfE4iLRaPakX14kbBXrKH9/uW/zc7TqIVciWhI1PaeFlu8wnVuGt3e5Ysx6Y7Uw7RS8pRT5aE3sX3aDPGZTAdTutLn1VUfkShS5OK5HJl9CdiwV2wOcrf4w/WqtaNUUqGdsJ8C4ELlpBzHxqs+lEm+8pGPYmuGQIjVc0eOR9Tza9GTk3ih1XGc1znOCoKUZbtA29RfbwfmJy/yGi/3RLWZFQGCCij4cLC5OpldiX4JWL5Dhox44p/5IVF3rfxTVz3GCyDOoHevRG/06sUBq6nhbdCQf3lJvxwcQJhoQg4rsapM3rgol+u+TbXRiwWPbfswuLkRlvGFKtKUWMa4S57gj0CFYgSBPdTyhZTB44D7JQ2bd901Ur1dYWcDe4Kn3ZawpxL0cX2ZPlE3v8FXFJf2s8DJytL8yu73GasDzVmaGHxueWWVz7EHjh+pmB4oaAHARcY8d3LActAyl/+bcFRPYQJ68ae6DJhYYJGHIBWMImf2BifGgUX8vUFfUAYjne3D82lRyZQHs3xbl+ZxEPgWiPYRWUtxGXLLP4f9mbl+LeJdehtHNjC8kOduBL0CsP4gmugzNNUXI+Izc/9svno6kFr6SU0LA3MGrOU8ao7UCQbf/Pj/RKnG1gRmBDQqf7IMm6jOyTwdde9NpfQb32iH11PkuAKBvEtUuq9BeAKWjoZku+ycsN2jZH0hzd/QrU2c+E4+yHwX3wSxxorNOXt5EZkJbEDBlpRyE1zWoyy0wIYfcChYLvFN8QFHchlw5wmHxL+OOgdgndAtV/2DCx+NB6caY31qLictME+1GPPlQ7QvicMLgmpSWq83rs4ex/My6p3hCRSrJJiLvjEDZLYWKHHLd5tsPRAjX8ADNWB1VeIeiJrj1wpOCc1PbWpbljbbTsBmVPo6iKm/UDGAHBdQ//0j3FQg8f5w/j+McsoaMpDNHNTiLvjWERR+RBmsEA0lEL00wZz/DHlzOAYHLYYqFMT7GBCQD+Wk/l1TL+X2agUy7Irlk7QbZ4ivfdNIpSW8Ct9MGE6o4wV+nIpXURojgBBTcP85RTBLXXGrIprnK1G/VE8ONag3+nkqIyChjYyk5QMsxqOqSHsbiOxhCdXypbCbY4g9yKJtBJ/ADjxmELj0X7pqsTFqC0eRT7rk9qTBcYBBu6rwlAfq8AKjDB7WjNjzLaMi6lBoe4petBn1xcLkXD5hHra0TULxcYrq8MIb+Vk4CBZZdwwyVm/28SwSjHBIBpRysPAonDDsp3KlahwXEFvRDQR/oFww172GI7cx8SoPn93Qh0JfpTAAowsO3meR8bzUSyd7v3rmtaBPsWHE9zUXye/6nloMU5joEcD6uJaxd0kdaWWIoKLH++zHW1R776wJrS6u+TIWZgHqiIJoCd9fV25BnQcbZRKd6mnfNQkchJ6c6ozXKrFaa8DLdERdfh84+isw5mzW2zMJwHEwtKt6LUTyieC2exzPAwPxJT1+IMjuzuwiLnvGKOq+kwE/LWBSB0ZfGuCP/3jMM8OCfe7Hbpt1TfXcUxUzj6sSjkjQB6qBt+TINRdOFA=|fppguME86utsAOKrBYn6XU95q7daVbZ+3dD9OVkQlAw=";
let fingerprint_material = "a09726a0-9590-49d1-a5f5-afe300b6a515";

let mut client = Client::new(None);
client.set_login_method(LoginMethod::User(UserLoginMethod::Username {
client_id: "a09726a0-9590-49d1-a5f5-afe300b6a515".to_owned(),
email: "[email protected]".to_owned(),
kdf: Kdf::PBKDF2 {
iterations: NonZeroU32::new(600_000).unwrap(),
},
}));
client
.initialize_user_crypto(
"asdfasdfasdf",
user_key.parse().unwrap(),
private_key.parse().unwrap(),
)
.unwrap();

let fingerprint =
generate_user_fingerprint(&mut client, fingerprint_material.to_string()).unwrap();

assert_eq!(fingerprint, "turban-deftly-anime-chatroom-unselfish");
}
}
2 changes: 1 addition & 1 deletion crates/bitwarden/src/platform/mod.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
pub mod client_platform;
mod domain;
mod generate_fingerprint;
mod get_user_api_key;
mod secret_verification_request;
mod sync;

pub(crate) use generate_fingerprint::generate_fingerprint;
pub use generate_fingerprint::{FingerprintRequest, FingerprintResponse};
pub(crate) use get_user_api_key::get_user_api_key;
pub use get_user_api_key::UserApiKeyResponse;
Expand Down
40 changes: 31 additions & 9 deletions languages/kotlin/doc.md
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ Test method, echoes back the input

### `satisfies_policy`

**API Draft:** Evaluate if the provided password satisfies the provided policy
Evaluate if the provided password satisfies the provided policy

**Arguments**:

Expand Down Expand Up @@ -333,6 +333,17 @@ Decrypt folder list

**Output**: std::result::Result<String,BitwardenError>

### `username`

**API Draft:** Generate Username

**Arguments**:

- self:
- settings: UsernameGeneratorRequest

**Output**: std::result::Result<String,BitwardenError>

## ClientPasswordHistory

### `encrypt`
Expand Down Expand Up @@ -361,7 +372,7 @@ Decrypt password history

### `fingerprint`

Fingerprint
Fingerprint (public key)

**Arguments**:

Expand All @@ -370,6 +381,17 @@ Fingerprint

**Output**: std::result::Result<String,BitwardenError>

### `user_fingerprint`

Fingerprint using logged in user&#x27;s public key

**Arguments**:

- self:
- fingerprint_material: String

**Output**: std::result::Result<String,BitwardenError>

## ClientSends

### `encrypt`
Expand Down Expand Up @@ -800,7 +822,7 @@ implementations.
</tr>
<tr>
<th>id</th>
<th>string</th>
<th>string,null</th>
<th></th>
</tr>
<tr>
Expand Down Expand Up @@ -891,7 +913,7 @@ implementations.
</tr>
<tr>
<th>id</th>
<th>string</th>
<th>string,null</th>
<th></th>
</tr>
<tr>
Expand All @@ -916,7 +938,7 @@ implementations.
</tr>
<tr>
<th>id</th>
<th>string</th>
<th>string,null</th>
<th></th>
</tr>
<tr>
Expand Down Expand Up @@ -1296,12 +1318,12 @@ implementations.
</tr>
<tr>
<th>id</th>
<th>string</th>
<th>string,null</th>
<th></th>
</tr>
<tr>
<th>accessId</th>
<th>string</th>
<th>string,null</th>
<th></th>
</tr>
<tr>
Expand Down Expand Up @@ -1386,12 +1408,12 @@ implementations.
</tr>
<tr>
<th>id</th>
<th>string</th>
<th>string,null</th>
<th></th>
</tr>
<tr>
<th>accessId</th>
<th>string</th>
<th>string,null</th>
<th></th>
</tr>
<tr>
Expand Down