Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
63 commits
Select commit Hold shift + click to select a range
d5fb7b2
Added conversions for ciphers
gbubemismith Sep 15, 2025
8144b98
Added create, edit and get
gbubemismith Sep 15, 2025
0734d40
Exposed through cipher client
gbubemismith Sep 15, 2025
0987ba7
Fix missing features (#436)
dani-garcia Sep 11, 2025
0535582
Scaffold workflow for generating api bindings (#441)
Hinton Sep 12, 2025
d008260
[PM-23193] Add ArchivedDate (#422)
Jingo88 Sep 12, 2025
47ea335
[deps]: Update @openapitools/openapi-generator-cli to v2.23.1 (#387)
renovate[bot] Sep 15, 2025
d204e42
Add dylint lints for errors (#430)
Hinton Sep 15, 2025
9a8d482
Migrate more b64 (#411)
Hinton Sep 15, 2025
778c3ac
Remove unused vault locked error (#440)
Hinton Sep 15, 2025
09af3cb
Set default values
gbubemismith Sep 15, 2025
298b336
Added todo's
gbubemismith Sep 15, 2025
841f40a
Added archived date to request and response
gbubemismith Sep 16, 2025
17cecd8
Fixed merge conflicts
gbubemismith Sep 16, 2025
9d27d7f
Removed error
gbubemismith Sep 16, 2025
d219627
Added list with failures
gbubemismith Sep 16, 2025
c1fcadc
fixed lint issues
gbubemismith Sep 16, 2025
2b8491a
removed error
gbubemismith Sep 16, 2025
a0bca6b
restructured cipher client to sub folders
gbubemismith Sep 18, 2025
0c568a0
updated edit
gbubemismith Sep 18, 2025
0f35f92
Reafctored create to use cipher create request and rmoved cipher viewโ€ฆ
gbubemismith Sep 22, 2025
5bffe2a
Added wasm flag
gbubemismith Sep 22, 2025
04269c6
Address PR Feedback - simplify types & logic
nikwithak Sep 25, 2025
4593cd3
Refactor CipherEditRequest to exclude uneditable values.
nikwithak Sep 25, 2025
3f07956
Update CipherEditRequest to use CipherViewType enum instead of indiviโ€ฆ
nikwithak Sep 25, 2025
223cfe1
Update CipherCreateRequest to use CipherViewType enum
nikwithak Sep 25, 2025
bde6dde
Remove encrypted_for from client-facing CreateCipherError
nikwithak Sep 26, 2025
f8dfeea
Handle cipher-key encryption for Create/Edit requests
nikwithak Sep 26, 2025
bd539ac
Merge branch 'main' of https://github.com/bitwarden/sdk-internal intoโ€ฆ
nikwithak Sep 26, 2025
b3bbda7
Add missing field to cipher requests
nikwithak Sep 26, 2025
8c331aa
Export CipherViewType and fix TS export errors
nikwithak Sep 26, 2025
1ea2211
Merge branch 'main' of https://github.com/bitwarden/sdk-internal intoโ€ฆ
nikwithak Sep 26, 2025
cc78556
Consume new ApiClient approach from main
nikwithak Sep 26, 2025
532a6ba
Remove outdated comment from cipher_client/create.rs
nikwithak Sep 26, 2025
7f4033c
Remove `pub` from CipherCreateRequest::generate_cipher_key
nikwithak Sep 26, 2025
69bbc99
Address PR feedback
nikwithak Sep 26, 2025
d06a363
Use slice instead of \&Vec<_> in detect_hidden_field_changes
nikwithak Sep 26, 2025
a331fc6
Remove Default from CipherType
nikwithak Sep 26, 2025
f931e47
Generate login checksums before encrypting
nikwithak Sep 26, 2025
4a0c45c
Remove list operations in favor of list_with_failures
nikwithak Sep 26, 2025
1cf6514
Add docstring for get_cipher_type
nikwithak Sep 26, 2025
86b0b56
Fix clippy errors.
nikwithak Sep 26, 2025
69978d0
Bugfix: Store cipher key when encrypting CipherCreateRequest
nikwithak Sep 27, 2025
ef2f7ca
Remove unnecessary comments
nikwithak Sep 27, 2025
2b57bcf
Remove unused import in create_cipher tests
nikwithak Sep 29, 2025
cc2af00
Merge branch 'main' of https://github.com/bitwarden/sdk-internal intoโ€ฆ
nikwithak Oct 1, 2025
5e13d4c
Remove unneeded fiels from cipher_client edit and create requests
nikwithak Oct 2, 2025
365534e
Remove password_history from CipherEditRequest
nikwithak Oct 2, 2025
a1f39f2
Rename cipher_client::list() to cipher_client::list_ciphers()
nikwithak Oct 2, 2025
1b897a2
Revert formatting changes to Cargo.toml
nikwithak Oct 2, 2025
7c423e9
Add test for preserving password history without edits
nikwithak Oct 2, 2025
c22d519
Add check for last_used_date on new passwords
nikwithak Oct 2, 2025
7332bba
Merge branch 'main' of https://github.com/bitwarden/sdk-internal intoโ€ฆ
nikwithak Oct 3, 2025
c8f96d1
Merge branch 'main' of https://github.com/bitwarden/sdk-internal intoโ€ฆ
nikwithak Oct 7, 2025
8600bd4
Update CipherViewType for CipherCreateRequest
nikwithak Oct 7, 2025
b665cab
Add wasm_bindgen attribute to CiphersClient::edit and ::create
nikwithak Oct 7, 2025
9713beb
Remove CipherViewTypeExt and impl the methods directly
nikwithak Oct 9, 2025
1e0ed6c
Change visibility on PasswordHistoryView creation methods
nikwithak Oct 9, 2025
0ccac3d
Add intermediary CipherEditRequestInternal to prevent accidental misuโ€ฆ
nikwithak Oct 9, 2025
bed6f11
Adjust checks to account for very fast test execution
nikwithak Oct 9, 2025
08dbf06
Fix clippy errors
nikwithak Oct 9, 2025
ea7d98a
Remove unnecessary pub from CipherEditREquestInternal fields
nikwithak Oct 9, 2025
ed2f8e7
Create CipherCreateRequestInternal to abstract key attr from consumer
nikwithak Oct 9, 2025
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
13 changes: 13 additions & 0 deletions crates/bitwarden-vault/src/cipher/card.rs
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,19 @@ impl TryFrom<CipherCardModel> for Card {
}
}

impl From<Card> for bitwarden_api_api::models::CipherCardModel {
fn from(card: Card) -> Self {
Self {
cardholder_name: card.cardholder_name.map(|n| n.to_string()),
brand: card.brand.map(|b| b.to_string()),
number: card.number.map(|n| n.to_string()),
exp_month: card.exp_month.map(|m| m.to_string()),
exp_year: card.exp_year.map(|y| y.to_string()),
code: card.code.map(|c| c.to_string()),
}
}
}

impl CipherKind for Card {
fn decrypt_subtitle(
&self,
Expand Down
95 changes: 84 additions & 11 deletions crates/bitwarden-vault/src/cipher/cipher.rs
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

๐Ÿ‘ Thanks for moving the uri checksum generation and fido2 re-encryption logic to Login!

Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use bitwarden_api_api::models::CipherDetailsResponseModel;
use bitwarden_api_api::models::{CipherDetailsResponseModel, CipherResponseModel};
use bitwarden_collections::collection::CollectionId;
use bitwarden_core::{
MissingFieldError, OrganizationId, UserId,
Expand Down Expand Up @@ -79,11 +79,12 @@ pub enum CipherType {
}

#[allow(missing_docs)]
#[derive(Clone, Copy, Serialize_repr, Deserialize_repr, Debug, PartialEq)]
#[derive(Clone, Copy, Default, Serialize_repr, Deserialize_repr, Debug, PartialEq)]
#[repr(u8)]
#[cfg_attr(feature = "uniffi", derive(uniffi::Enum))]
#[cfg_attr(feature = "wasm", wasm_bindgen)]
pub enum CipherRepromptType {
#[default]
None = 0,
Password = 1,
}
Expand Down Expand Up @@ -472,10 +473,8 @@ impl CipherView {

#[allow(missing_docs)]
pub fn generate_checksums(&mut self) {
if let Some(uris) = self.login.as_mut().and_then(|l| l.uris.as_mut()) {
for uri in uris {
uri.generate_checksum();
}
if let Some(l) = self.login.as_mut() {
l.generate_checksums();
}
}

Expand Down Expand Up @@ -528,11 +527,7 @@ impl CipherView {
new_key: SymmetricKeyId,
) -> Result<(), CryptoError> {
if let Some(login) = self.login.as_mut() {
if let Some(fido2_credentials) = &mut login.fido2_credentials {
let dec_fido2_credentials: Vec<Fido2CredentialFullView> =
fido2_credentials.decrypt(ctx, old_key)?;
*fido2_credentials = dec_fido2_credentials.encrypt_composite(ctx, new_key)?;
}
login.reencrypt_fido2_credentials(ctx, old_key, new_key)?;
}
Ok(())
}
Expand Down Expand Up @@ -695,6 +690,15 @@ impl Decryptable<KeyIds, SymmetricKeyId, CipherListView> for Cipher {
}
}

#[cfg(feature = "wasm")]
impl wasm_bindgen::__rt::VectorIntoJsValue for CipherView {
fn vector_into_jsvalue(
vector: wasm_bindgen::__rt::std::boxed::Box<[Self]>,
) -> wasm_bindgen::JsValue {
wasm_bindgen::__rt::js_value_vector_into_jsvalue(vector)
}
}

Comment on lines +693 to +701
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

question: interesting, haven't seen this before. Did you have issues returning Vec<CipherView without this?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is because tsify isn't adding this derive, which wasm-bindgen expects for types returning lists. Oscar and I had the same problem with folders:
https://github.com/bitwarden/sdk-internal/blob/main/crates/bitwarden-vault/src/folder/folder_models.rs#L44-L51

Reported upstream:
madonoharu/tsify#66

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, nice, thanks!

impl IdentifyKey<SymmetricKeyId> for Cipher {
fn key_identifier(&self) -> SymmetricKeyId {
match self.organization_id {
Expand Down Expand Up @@ -796,6 +800,75 @@ impl From<bitwarden_api_api::models::CipherRepromptType> for CipherRepromptType
}
}

impl From<CipherType> for bitwarden_api_api::models::CipherType {
fn from(t: CipherType) -> Self {
match t {
CipherType::Login => bitwarden_api_api::models::CipherType::Login,
CipherType::SecureNote => bitwarden_api_api::models::CipherType::SecureNote,
CipherType::Card => bitwarden_api_api::models::CipherType::Card,
CipherType::Identity => bitwarden_api_api::models::CipherType::Identity,
CipherType::SshKey => bitwarden_api_api::models::CipherType::SSHKey,
}
}
}

impl From<CipherRepromptType> for bitwarden_api_api::models::CipherRepromptType {
fn from(t: CipherRepromptType) -> Self {
match t {
CipherRepromptType::None => bitwarden_api_api::models::CipherRepromptType::None,
CipherRepromptType::Password => bitwarden_api_api::models::CipherRepromptType::Password,
}
}
}

impl TryFrom<CipherResponseModel> for Cipher {
type Error = VaultParseError;

fn try_from(cipher: CipherResponseModel) -> Result<Self, Self::Error> {
Ok(Self {
id: cipher.id.map(CipherId::new),
organization_id: cipher.organization_id.map(OrganizationId::new),
folder_id: cipher.folder_id.map(FolderId::new),
collection_ids: vec![], // CipherResponseModel doesn't include collection_ids
name: require!(cipher.name).parse()?,
notes: EncString::try_from_optional(cipher.notes)?,
r#type: require!(cipher.r#type).into(),
login: cipher.login.map(|l| (*l).try_into()).transpose()?,
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()?,
ssh_key: cipher.ssh_key.map(|s| (*s).try_into()).transpose()?,
favorite: cipher.favorite.unwrap_or(false),
reprompt: cipher
.reprompt
.map(|r| r.into())
.unwrap_or(CipherRepromptType::None),
organization_use_totp: cipher.organization_use_totp.unwrap_or(false),
edit: cipher.edit.unwrap_or(false),
permissions: cipher.permissions.map(|p| (*p).try_into()).transpose()?,
view_password: cipher.view_password.unwrap_or(true),
local_data: None, // Not sent from server
attachments: cipher
.attachments
.map(|a| a.into_iter().map(|a| a.try_into()).collect())
.transpose()?,
fields: cipher
.fields
.map(|f| f.into_iter().map(|f| f.try_into()).collect())
.transpose()?,
password_history: cipher
.password_history
.map(|p| p.into_iter().map(|p| p.try_into()).collect())
.transpose()?,
creation_date: require!(cipher.creation_date).parse()?,
deleted_date: cipher.deleted_date.map(|d| d.parse()).transpose()?,
revision_date: require!(cipher.revision_date).parse()?,
key: EncString::try_from_optional(cipher.key)?,
archived_date: cipher.archived_date.map(|d| d.parse()).transpose()?,
})
}
}

#[cfg(test)]
mod tests {

Expand Down
Loading