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

[PM-11924] Add ssh-key item type #1037

Merged
merged 20 commits into from
Oct 21, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
37 changes: 31 additions & 6 deletions crates/bitwarden-exporters/src/json.rs
quexten marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@
use thiserror::Error;
use uuid::Uuid;

use crate::{Card, Cipher, CipherType, Field, Folder, Identity, Login, LoginUri, SecureNote};
use crate::{
Card, Cipher, CipherType, Field, Folder, Identity, Login, LoginUri, SecureNote, SshKey,
};

#[derive(Error, Debug)]
pub enum JsonError {
Expand Down Expand Up @@ -69,6 +71,8 @@
card: Option<JsonCard>,
#[serde(skip_serializing_if = "Option::is_none")]
secure_note: Option<JsonSecureNote>,
#[serde(skip_serializing_if = "Option::is_none")]
ssh_key: Option<JsonSshKey>,

favorite: bool,
reprompt: u8,
Expand Down Expand Up @@ -206,6 +210,24 @@
}
}

#[derive(serde::Serialize)]
#[serde(rename_all = "camelCase")]
struct JsonSshKey {
private_key: Option<String>,
public_key: Option<String>,
fingerprint: Option<String>,
}

impl From<SshKey> for JsonSshKey {
fn from(ssh_key: SshKey) -> Self {
JsonSshKey {
private_key: ssh_key.private_key,
public_key: ssh_key.public_key,
fingerprint: ssh_key.fingerprint,
}
}

Check warning on line 228 in crates/bitwarden-exporters/src/json.rs

View check run for this annotation

Codecov / codecov/patch

crates/bitwarden-exporters/src/json.rs#L222-L228

Added lines #L222 - L228 were not covered by tests
}

#[derive(serde::Serialize)]
#[serde(rename_all = "camelCase")]
struct JsonField {
Expand Down Expand Up @@ -233,13 +255,15 @@
CipherType::SecureNote(_) => 2,
CipherType::Card(_) => 3,
CipherType::Identity(_) => 4,
CipherType::SshKey(_) => 5,

Check warning on line 258 in crates/bitwarden-exporters/src/json.rs

View check run for this annotation

Codecov / codecov/patch

crates/bitwarden-exporters/src/json.rs#L258

Added line #L258 was not covered by tests
};

let (login, secure_note, card, identity) = match cipher.r#type {
CipherType::Login(l) => (Some((*l).into()), None, None, None),
CipherType::SecureNote(s) => (None, Some((*s).into()), None, None),
CipherType::Card(c) => (None, None, Some((*c).into()), None),
CipherType::Identity(i) => (None, None, None, Some((*i).into())),
let (login, secure_note, card, identity, ssh_key) = match cipher.r#type {
CipherType::Login(l) => (Some((*l).into()), None, None, None, None),
CipherType::SecureNote(s) => (None, Some((*s).into()), None, None, None),
CipherType::Card(c) => (None, None, Some((*c).into()), None, None),
CipherType::Identity(i) => (None, None, None, Some((*i).into()), None),
CipherType::SshKey(ssh) => (None, None, None, None, Some((*ssh).into())),

Check warning on line 266 in crates/bitwarden-exporters/src/json.rs

View check run for this annotation

Codecov / codecov/patch

crates/bitwarden-exporters/src/json.rs#L266

Added line #L266 was not covered by tests
};

JsonCipher {
Expand All @@ -254,6 +278,7 @@
identity,
card,
secure_note,
ssh_key,
favorite: cipher.favorite,
reprompt: cipher.reprompt,
fields: cipher.fields.into_iter().map(|f| f.into()).collect(),
Expand Down
8 changes: 8 additions & 0 deletions crates/bitwarden-exporters/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@
SecureNote(Box<SecureNote>),
Card(Box<Card>),
Identity(Box<Identity>),
SshKey(Box<SshKey>),
}

impl fmt::Display for CipherType {
Expand All @@ -79,6 +80,7 @@
CipherType::SecureNote(_) => write!(f, "note"),
CipherType::Card(_) => write!(f, "card"),
CipherType::Identity(_) => write!(f, "identity"),
CipherType::SshKey(_) => write!(f, "ssh_key"),

Check warning on line 83 in crates/bitwarden-exporters/src/lib.rs

View check run for this annotation

Codecov / codecov/patch

crates/bitwarden-exporters/src/lib.rs#L83

Added line #L83 was not covered by tests
}
}
}
Expand Down Expand Up @@ -132,3 +134,9 @@
pub passport_number: Option<String>,
pub license_number: Option<String>,
}

pub struct SshKey {
pub private_key: Option<String>,
quexten marked this conversation as resolved.
Show resolved Hide resolved
pub public_key: Option<String>,
pub fingerprint: Option<String>,
}
9 changes: 9 additions & 0 deletions crates/bitwarden-exporters/src/models.rs
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,14 @@
license_number: i.license_number,
}))
}
CipherType::SshKey => {
let s = require!(value.ssh_key);
crate::CipherType::SshKey(Box::new(crate::SshKey {
private_key: s.private_key,
public_key: s.public_key,
fingerprint: s.fingerprint,
}))

Check warning on line 83 in crates/bitwarden-exporters/src/models.rs

View check run for this annotation

Codecov / codecov/patch

crates/bitwarden-exporters/src/models.rs#L78-L83

Added lines #L78 - L83 were not covered by tests
}
};

Ok(Self {
Expand Down Expand Up @@ -172,6 +180,7 @@
identity: None,
card: None,
secure_note: None,
ssh_key: None,
favorite: false,
reprompt: CipherRepromptType::None,
organization_use_totp: true,
Expand Down
3 changes: 3 additions & 0 deletions crates/bitwarden-vault/src/cipher/attachment.rs
Original file line number Diff line number Diff line change
Expand Up @@ -208,6 +208,7 @@ mod tests {
identity: None,
card: None,
secure_note: None,
ssh_key: None,
favorite: false,
reprompt: CipherRepromptType::None,
organization_use_totp: false,
Expand Down Expand Up @@ -258,6 +259,7 @@ mod tests {
identity: None,
card: None,
secure_note: None,
ssh_key: None,
favorite: false,
reprompt: CipherRepromptType::None,
organization_use_totp: false,
Expand Down Expand Up @@ -312,6 +314,7 @@ mod tests {
identity: None,
card: None,
secure_note: None,
ssh_key: None,
favorite: false,
reprompt: CipherRepromptType::None,
organization_use_totp: false,
Expand Down
35 changes: 34 additions & 1 deletion crates/bitwarden-vault/src/cipher/cipher.rs
quexten marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
use super::{
attachment, card, field, identity,
local_data::{LocalData, LocalDataView},
secure_note,
secure_note, ssh_key,
};
use crate::{
password_history, Fido2CredentialFullView, Fido2CredentialView, Login, LoginView,
Expand All @@ -41,6 +41,7 @@
SecureNote = 2,
Card = 3,
Identity = 4,
SshKey = 5,
}

#[derive(Clone, Copy, Serialize_repr, Deserialize_repr, Debug, JsonSchema, PartialEq)]
Expand Down Expand Up @@ -72,6 +73,7 @@
pub identity: Option<identity::Identity>,
pub card: Option<card::Card>,
pub secure_note: Option<secure_note::SecureNote>,
pub ssh_key: Option<ssh_key::SshKey>,

pub favorite: bool,
pub reprompt: CipherRepromptType,
Expand Down Expand Up @@ -109,6 +111,7 @@
pub identity: Option<identity::IdentityView>,
pub card: Option<card::CardView>,
pub secure_note: Option<secure_note::SecureNoteView>,
pub ssh_key: Option<ssh_key::SshKeyView>,

pub favorite: bool,
pub reprompt: CipherRepromptType,
Expand Down Expand Up @@ -137,6 +140,7 @@
SecureNote,
Card,
Identity,
SshKey,
}

#[derive(Serialize, Deserialize, Debug, JsonSchema, PartialEq)]
Expand Down Expand Up @@ -211,6 +215,7 @@
identity: self.identity.encrypt_with_key(key)?,
card: self.card.encrypt_with_key(key)?,
secure_note: self.secure_note.encrypt_with_key(key)?,
ssh_key: self.ssh_key.encrypt_with_key(key)?,
favorite: self.favorite,
reprompt: self.reprompt,
organization_use_totp: self.organization_use_totp,
Expand Down Expand Up @@ -245,6 +250,7 @@
identity: self.identity.decrypt_with_key(key).ok().flatten(),
card: self.card.decrypt_with_key(key).ok().flatten(),
secure_note: self.secure_note.decrypt_with_key(key).ok().flatten(),
ssh_key: self.ssh_key.decrypt_with_key(key).ok().flatten(),
favorite: self.favorite,
reprompt: self.reprompt,
organization_use_totp: self.organization_use_totp,
Expand Down Expand Up @@ -329,6 +335,19 @@
.transpose()?,
)
}
CipherType::SshKey => {
let Some(ssh_key) = &self.ssh_key else {
return Ok(String::new());

Check warning on line 340 in crates/bitwarden-vault/src/cipher/cipher.rs

View check run for this annotation

Codecov / codecov/patch

crates/bitwarden-vault/src/cipher/cipher.rs#L339-L340

Added lines #L339 - L340 were not covered by tests
};

build_subtitle_ssh_key(
ssh_key
.fingerprint
.as_ref()
.map(|c| c.decrypt_with_key(key))
.transpose()?,

Check warning on line 348 in crates/bitwarden-vault/src/cipher/cipher.rs

View check run for this annotation

Codecov / codecov/patch

crates/bitwarden-vault/src/cipher/cipher.rs#L344-L348

Added lines #L344 - L348 were not covered by tests
)
}
})
}
}
Expand Down Expand Up @@ -389,6 +408,14 @@
sub_title
}

fn build_subtitle_ssh_key(fingerprint: Option<String>) -> String {
if let Some(fingerprint) = &fingerprint {
return fingerprint.clone();
}

"".to_string()
}

Check warning on line 417 in crates/bitwarden-vault/src/cipher/cipher.rs

View check run for this annotation

Codecov / codecov/patch

crates/bitwarden-vault/src/cipher/cipher.rs#L411-L417

Added lines #L411 - L417 were not covered by tests

quexten marked this conversation as resolved.
Show resolved Hide resolved
impl CipherView {
pub fn generate_cipher_key(&mut self, key: &SymmetricCryptoKey) -> Result<(), CryptoError> {
let old_ciphers_key = Cipher::get_cipher_key(key, &self.key)?;
Expand Down Expand Up @@ -553,6 +580,7 @@
CipherType::SecureNote => CipherListViewType::SecureNote,
CipherType::Card => CipherListViewType::Card,
CipherType::Identity => CipherListViewType::Identity,
CipherType::SshKey => CipherListViewType::SshKey,

Check warning on line 583 in crates/bitwarden-vault/src/cipher/cipher.rs

View check run for this annotation

Codecov / codecov/patch

crates/bitwarden-vault/src/cipher/cipher.rs#L583

Added line #L583 was not covered by tests
},
favorite: self.favorite,
reprompt: self.reprompt,
Expand Down Expand Up @@ -614,6 +642,8 @@
identity: cipher.identity.map(|i| (*i).try_into()).transpose()?,
card: cipher.card.map(|c| (*c).try_into()).transpose()?,
secure_note: cipher.secure_note.map(|s| (*s).try_into()).transpose()?,
// todo: add ssh_key when api bindings have been updated
quexten marked this conversation as resolved.
Show resolved Hide resolved
ssh_key: None,

Check warning on line 646 in crates/bitwarden-vault/src/cipher/cipher.rs

View check run for this annotation

Codecov / codecov/patch

crates/bitwarden-vault/src/cipher/cipher.rs#L646

Added line #L646 was not covered by tests
favorite: cipher.favorite.unwrap_or(false),
reprompt: cipher
.reprompt
Expand Down Expand Up @@ -650,6 +680,7 @@
bitwarden_api_api::models::CipherType::SecureNote => CipherType::SecureNote,
bitwarden_api_api::models::CipherType::Card => CipherType::Card,
bitwarden_api_api::models::CipherType::Identity => CipherType::Identity,
// todo: add ssh_key when api bindings have been updated
quexten marked this conversation as resolved.
Show resolved Hide resolved
}
}
}
Expand Down Expand Up @@ -695,6 +726,7 @@
identity: None,
card: None,
secure_note: None,
ssh_key: None,
favorite: false,
reprompt: CipherRepromptType::None,
organization_use_totp: true,
Expand Down Expand Up @@ -753,6 +785,7 @@
identity: None,
card: None,
secure_note: None,
ssh_key: None,
favorite: false,
reprompt: CipherRepromptType::None,
organization_use_totp: false,
Expand Down
1 change: 1 addition & 0 deletions crates/bitwarden-vault/src/cipher/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ pub(crate) mod linked_id;
pub(crate) mod local_data;
pub(crate) mod login;
pub(crate) mod secure_note;
pub(crate) mod ssh_key;

pub use attachment::{
Attachment, AttachmentEncryptResult, AttachmentFile, AttachmentFileView, AttachmentView,
Expand Down
43 changes: 43 additions & 0 deletions crates/bitwarden-vault/src/cipher/ssh_key.rs
quexten marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
use bitwarden_crypto::{
CryptoError, EncString, KeyDecryptable, KeyEncryptable, SymmetricCryptoKey,
};
use schemars::JsonSchema;
use serde::{Deserialize, Serialize};

#[derive(Serialize, Deserialize, Debug, JsonSchema, Clone)]

Check warning on line 7 in crates/bitwarden-vault/src/cipher/ssh_key.rs

View check run for this annotation

Codecov / codecov/patch

crates/bitwarden-vault/src/cipher/ssh_key.rs#L7

Added line #L7 was not covered by tests
#[serde(rename_all = "camelCase", deny_unknown_fields)]
#[cfg_attr(feature = "uniffi", derive(uniffi::Record))]
pub struct SshKey {
pub private_key: Option<EncString>,
pub public_key: Option<EncString>,
pub fingerprint: Option<EncString>,
quexten marked this conversation as resolved.
Show resolved Hide resolved
}

#[derive(Serialize, Deserialize, Debug, JsonSchema, Clone)]

Check warning on line 16 in crates/bitwarden-vault/src/cipher/ssh_key.rs

View check run for this annotation

Codecov / codecov/patch

crates/bitwarden-vault/src/cipher/ssh_key.rs#L16

Added line #L16 was not covered by tests
#[serde(rename_all = "camelCase", deny_unknown_fields)]
#[cfg_attr(feature = "uniffi", derive(uniffi::Record))]
pub struct SshKeyView {
pub private_key: Option<String>,
quexten marked this conversation as resolved.
Show resolved Hide resolved
pub public_key: Option<String>,
pub fingerprint: Option<String>,
}

impl KeyEncryptable<SymmetricCryptoKey, SshKey> for SshKeyView {
fn encrypt_with_key(self, key: &SymmetricCryptoKey) -> Result<SshKey, CryptoError> {
Ok(SshKey {
private_key: self.private_key.encrypt_with_key(key)?,
public_key: self.public_key.encrypt_with_key(key)?,
fingerprint: self.fingerprint.encrypt_with_key(key)?,

Check warning on line 30 in crates/bitwarden-vault/src/cipher/ssh_key.rs

View check run for this annotation

Codecov / codecov/patch

crates/bitwarden-vault/src/cipher/ssh_key.rs#L26-L30

Added lines #L26 - L30 were not covered by tests
})
}

Check warning on line 32 in crates/bitwarden-vault/src/cipher/ssh_key.rs

View check run for this annotation

Codecov / codecov/patch

crates/bitwarden-vault/src/cipher/ssh_key.rs#L32

Added line #L32 was not covered by tests
}

impl KeyDecryptable<SymmetricCryptoKey, SshKeyView> for SshKey {
fn decrypt_with_key(&self, key: &SymmetricCryptoKey) -> Result<SshKeyView, CryptoError> {
Ok(SshKeyView {
private_key: self.private_key.decrypt_with_key(key).ok().flatten(),
public_key: self.public_key.decrypt_with_key(key).ok().flatten(),
fingerprint: self.fingerprint.decrypt_with_key(key).ok().flatten(),
})
}

Check warning on line 42 in crates/bitwarden-vault/src/cipher/ssh_key.rs

View check run for this annotation

Codecov / codecov/patch

crates/bitwarden-vault/src/cipher/ssh_key.rs#L36-L42

Added lines #L36 - L42 were not covered by tests
}
2 changes: 2 additions & 0 deletions crates/bitwarden-vault/src/mobile/client_ciphers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,7 @@ mod tests {
identity: None,
card: None,
secure_note: None,
ssh_key: None,
favorite: false,
reprompt: CipherRepromptType::None,
organization_use_totp: true,
Expand Down Expand Up @@ -159,6 +160,7 @@ mod tests {
identity: None,
card: None,
secure_note: None,
ssh_key: None,
favorite: false,
reprompt: CipherRepromptType::None,
organization_use_totp: true,
Expand Down
Loading