use super::cipher::{
DecryptedCipher, DecryptedData, DecryptedField, DecryptedHistoryEntry,
DecryptedListCipher, DecryptedSearchCipher, DecryptedUri,
};
use super::field::{Field, ListField};
use crate::bin_error;
pub(super) fn decrypt_field(
name: Field,
field: Option<&str>,
entry_key: Option<&str>,
org_id: Option<&str>,
) -> Option<String> {
let field = field
.as_ref()
.map(|field| crate::actions::decrypt(field, entry_key, org_id))
.transpose();
match field {
Ok(field) => field,
Err(e) => {
log::warn!("failed to decrypt {name}: {e}");
None
}
}
}
pub(super) fn decrypt_list_cipher(
entry: &bwx::db::Entry,
fields: &[ListField],
) -> bin_error::Result<DecryptedListCipher> {
let id = entry.id.clone();
let name = if fields.contains(&ListField::Name) {
Some(crate::actions::decrypt(
&entry.name,
entry.key.as_deref(),
entry.org_id.as_deref(),
)?)
} else {
None
};
let user = if fields.contains(&ListField::User) {
match &entry.data {
bwx::db::EntryData::Login { username, .. } => decrypt_field(
Field::Username,
username.as_deref(),
entry.key.as_deref(),
entry.org_id.as_deref(),
),
_ => None,
}
} else {
None
};
let folder = if fields.contains(&ListField::Folder) {
entry
.folder
.as_ref()
.map(|folder| crate::actions::decrypt(folder, None, None))
.transpose()?
} else {
None
};
let uris = if fields.contains(&ListField::Uri) {
match &entry.data {
bwx::db::EntryData::Login { uris, .. } => Some(
uris.iter()
.filter_map(|s| {
decrypt_field(
Field::Uris,
Some(&s.uri),
entry.key.as_deref(),
entry.org_id.as_deref(),
)
})
.collect(),
),
_ => None,
}
} else {
None
};
let entry_type = fields
.contains(&ListField::EntryType)
.then_some(match &entry.data {
bwx::db::EntryData::Login { .. } => "Login",
bwx::db::EntryData::Identity { .. } => "Identity",
bwx::db::EntryData::SshKey { .. } => "SSH Key",
bwx::db::EntryData::SecureNote => "Note",
bwx::db::EntryData::Card { .. } => "Card",
})
.map(str::to_string);
Ok(DecryptedListCipher {
id,
name,
user,
folder,
uris,
entry_type,
})
}
pub(super) fn decrypt_search_cipher(
entry: &bwx::db::Entry,
) -> bin_error::Result<DecryptedSearchCipher> {
let id = entry.id.clone();
let name = crate::actions::decrypt(
&entry.name,
entry.key.as_deref(),
entry.org_id.as_deref(),
)?;
let user = match &entry.data {
bwx::db::EntryData::Login { username, .. } => decrypt_field(
Field::Username,
username.as_deref(),
entry.key.as_deref(),
entry.org_id.as_deref(),
),
_ => None,
};
let folder = entry
.folder
.as_ref()
.map(|folder| crate::actions::decrypt(folder, None, None))
.transpose()?;
let notes = entry
.notes
.as_ref()
.map(|notes| {
crate::actions::decrypt(
notes,
entry.key.as_deref(),
entry.org_id.as_deref(),
)
})
.transpose();
let uris = if let bwx::db::EntryData::Login { uris, .. } = &entry.data {
uris.iter()
.filter_map(|s| {
decrypt_field(
Field::Uris,
Some(&s.uri),
entry.key.as_deref(),
entry.org_id.as_deref(),
)
.map(|uri| (uri, s.match_type))
})
.collect()
} else {
vec![]
};
let fields = entry
.fields
.iter()
.filter_map(|field| {
if field.ty == Some(bwx::api::FieldType::Hidden) {
None
} else {
field.value.as_ref()
}
})
.map(|value| {
crate::actions::decrypt(
value,
entry.key.as_deref(),
entry.org_id.as_deref(),
)
})
.collect::<bin_error::Result<_>>()?;
let notes = match notes {
Ok(notes) => notes,
Err(e) => {
log::warn!("failed to decrypt notes: {e}");
None
}
};
let entry_type = (match &entry.data {
bwx::db::EntryData::Login { .. } => "Login",
bwx::db::EntryData::Identity { .. } => "Identity",
bwx::db::EntryData::SshKey { .. } => "SSH Key",
bwx::db::EntryData::SecureNote => "Note",
bwx::db::EntryData::Card { .. } => "Card",
})
.to_string();
Ok(DecryptedSearchCipher {
id,
entry_type,
folder,
name,
user,
uris,
fields,
notes,
})
}
pub(super) fn decrypt_cipher(
entry: &bwx::db::Entry,
) -> bin_error::Result<DecryptedCipher> {
let folder = entry
.folder
.as_ref()
.map(|folder| crate::actions::decrypt(folder, None, None))
.transpose();
let folder = match folder {
Ok(folder) => folder,
Err(e) => {
log::warn!("failed to decrypt folder name: {e}");
None
}
};
let fields = entry
.fields
.iter()
.map(|field| {
Ok(DecryptedField {
name: field
.name
.as_ref()
.map(|name| {
crate::actions::decrypt(
name,
entry.key.as_deref(),
entry.org_id.as_deref(),
)
})
.transpose()?,
value: field
.value
.as_ref()
.map(|value| {
crate::actions::decrypt(
value,
entry.key.as_deref(),
entry.org_id.as_deref(),
)
})
.transpose()?,
ty: field.ty,
})
})
.collect::<bin_error::Result<_>>()?;
let notes = entry
.notes
.as_ref()
.map(|notes| {
crate::actions::decrypt(
notes,
entry.key.as_deref(),
entry.org_id.as_deref(),
)
})
.transpose();
let notes = match notes {
Ok(notes) => notes,
Err(e) => {
log::warn!("failed to decrypt notes: {e}");
None
}
};
let history = entry
.history
.iter()
.map(|history_entry| {
Ok(DecryptedHistoryEntry {
last_used_date: history_entry.last_used_date.clone(),
password: crate::actions::decrypt(
&history_entry.password,
entry.key.as_deref(),
entry.org_id.as_deref(),
)?,
})
})
.collect::<bin_error::Result<_>>()?;
let data = match &entry.data {
bwx::db::EntryData::Login {
username,
password,
totp,
uris,
} => DecryptedData::Login {
username: decrypt_field(
Field::Username,
username.as_deref(),
entry.key.as_deref(),
entry.org_id.as_deref(),
),
password: decrypt_field(
Field::Password,
password.as_deref(),
entry.key.as_deref(),
entry.org_id.as_deref(),
),
totp: decrypt_field(
Field::Totp,
totp.as_deref(),
entry.key.as_deref(),
entry.org_id.as_deref(),
),
uris: uris
.iter()
.map(|s| {
decrypt_field(
Field::Uris,
Some(&s.uri),
entry.key.as_deref(),
entry.org_id.as_deref(),
)
.map(|uri| DecryptedUri {
uri,
match_type: s.match_type,
})
})
.collect(),
},
bwx::db::EntryData::Card {
cardholder_name,
number,
brand,
exp_month,
exp_year,
code,
} => DecryptedData::Card {
cardholder_name: decrypt_field(
Field::Cardholder,
cardholder_name.as_deref(),
entry.key.as_deref(),
entry.org_id.as_deref(),
),
number: decrypt_field(
Field::CardNumber,
number.as_deref(),
entry.key.as_deref(),
entry.org_id.as_deref(),
),
brand: decrypt_field(
Field::Brand,
brand.as_deref(),
entry.key.as_deref(),
entry.org_id.as_deref(),
),
exp_month: decrypt_field(
Field::ExpMonth,
exp_month.as_deref(),
entry.key.as_deref(),
entry.org_id.as_deref(),
),
exp_year: decrypt_field(
Field::ExpYear,
exp_year.as_deref(),
entry.key.as_deref(),
entry.org_id.as_deref(),
),
code: decrypt_field(
Field::Cvv,
code.as_deref(),
entry.key.as_deref(),
entry.org_id.as_deref(),
),
},
bwx::db::EntryData::Identity {
title,
first_name,
middle_name,
last_name,
address1,
address2,
address3,
city,
state,
postal_code,
country,
phone,
email,
ssn,
license_number,
passport_number,
username,
} => DecryptedData::Identity {
title: decrypt_field(
Field::Title,
title.as_deref(),
entry.key.as_deref(),
entry.org_id.as_deref(),
),
first_name: decrypt_field(
Field::FirstName,
first_name.as_deref(),
entry.key.as_deref(),
entry.org_id.as_deref(),
),
middle_name: decrypt_field(
Field::MiddleName,
middle_name.as_deref(),
entry.key.as_deref(),
entry.org_id.as_deref(),
),
last_name: decrypt_field(
Field::LastName,
last_name.as_deref(),
entry.key.as_deref(),
entry.org_id.as_deref(),
),
address1: decrypt_field(
Field::Address1,
address1.as_deref(),
entry.key.as_deref(),
entry.org_id.as_deref(),
),
address2: decrypt_field(
Field::Address2,
address2.as_deref(),
entry.key.as_deref(),
entry.org_id.as_deref(),
),
address3: decrypt_field(
Field::Address3,
address3.as_deref(),
entry.key.as_deref(),
entry.org_id.as_deref(),
),
city: decrypt_field(
Field::City,
city.as_deref(),
entry.key.as_deref(),
entry.org_id.as_deref(),
),
state: decrypt_field(
Field::State,
state.as_deref(),
entry.key.as_deref(),
entry.org_id.as_deref(),
),
postal_code: decrypt_field(
Field::PostalCode,
postal_code.as_deref(),
entry.key.as_deref(),
entry.org_id.as_deref(),
),
country: decrypt_field(
Field::Country,
country.as_deref(),
entry.key.as_deref(),
entry.org_id.as_deref(),
),
phone: decrypt_field(
Field::Phone,
phone.as_deref(),
entry.key.as_deref(),
entry.org_id.as_deref(),
),
email: decrypt_field(
Field::Email,
email.as_deref(),
entry.key.as_deref(),
entry.org_id.as_deref(),
),
ssn: decrypt_field(
Field::Ssn,
ssn.as_deref(),
entry.key.as_deref(),
entry.org_id.as_deref(),
),
license_number: decrypt_field(
Field::License,
license_number.as_deref(),
entry.key.as_deref(),
entry.org_id.as_deref(),
),
passport_number: decrypt_field(
Field::Passport,
passport_number.as_deref(),
entry.key.as_deref(),
entry.org_id.as_deref(),
),
username: decrypt_field(
Field::Username,
username.as_deref(),
entry.key.as_deref(),
entry.org_id.as_deref(),
),
},
bwx::db::EntryData::SecureNote => DecryptedData::SecureNote {},
bwx::db::EntryData::SshKey {
public_key,
fingerprint,
private_key,
} => DecryptedData::SshKey {
public_key: decrypt_field(
Field::PublicKey,
public_key.as_deref(),
entry.key.as_deref(),
entry.org_id.as_deref(),
),
fingerprint: decrypt_field(
Field::Fingerprint,
fingerprint.as_deref(),
entry.key.as_deref(),
entry.org_id.as_deref(),
),
private_key: decrypt_field(
Field::PrivateKey,
private_key.as_deref(),
entry.key.as_deref(),
entry.org_id.as_deref(),
),
},
};
Ok(DecryptedCipher {
id: entry.id.clone(),
folder,
name: crate::actions::decrypt(
&entry.name,
entry.key.as_deref(),
entry.org_id.as_deref(),
)?,
data,
fields,
notes,
history,
})
}