-
Notifications
You must be signed in to change notification settings - Fork 18
[PM-25818] Migrate Basic Cipher Create, Edit, and Get Operations to SDK #455
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
base: main
Are you sure you want to change the base?
Conversation
Great job! No new security vulnerabilities introduced in this pull request |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just a handful of questions from me. I'm following this and the implementation but I would say that my rust experience is a little lack luster on if there are improvements to be made on that thread. I will hold off on approving to hopefully solicit some more impactful feedback, but I can if I'm the gateway between moving this forward.
organization_use_totp: cipher.organization_use_totp.unwrap_or(true), | ||
edit: cipher.edit.unwrap_or(true), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
❓ Probably an edge case, the current CipherView defaults these values to false
rather than true
. Should this logic follow suit or is the deviation intentional?
list_ciphers(key_store, repository.as_ref()).await | ||
} | ||
|
||
/// Get [Cipher] by ID from state and decrypt it to a [CipherView]. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I did not know you could link to other entities in a comment with [...]
, TIL!
## 🎟️ Tracking <!-- Paste the link to the Jira or GitHub issue or otherwise describe / point to where this change is coming from. --> ## 📔 Objective These crates had some missing features, which caused compilation errors when trying to run the tests from VSCode. The reason that CI kept building was that rust unifies all the workspace features, so as long as one crate has them enabled it's fine. On the other hand, when running a test from VSCode, it will only have that crates features in mind. Note that the uniffi feature of core requires internal because of these two types: https://github.com/bitwarden/sdk-internal/blob/main/crates/bitwarden-core/src/uniffi_support.rs#L30-L42 ## ⏰ Reminders before review - Contributor guidelines followed - All formatters and local linters executed and passed - Written new unit and / or integration tests where applicable - Protected functional changes with optionality (feature flags) - Used internationalization (i18n) for all UI strings - CI builds passed - Communicated to DevOps any deployment requirements - Updated any necessary documentation (Confluence, contributing docs) or informed the documentation team ## 🦮 Reviewer guidelines <!-- Suggested interactions but feel free to use (or not) as you desire! --> - 👍 (`:+1:`) or similar for great changes - 📝 (`:memo:`) or ℹ️ (`:information_source:`) for notes or general info - ❓ (`:question:`) for questions - 🤔 (`:thinking:`) or 💭 (`:thought_balloon:`) for more open inquiry that's not quite a confirmed issue and could potentially benefit from discussion - 🎨 (`:art:`) for suggestions / improvements - ❌ (`:x:`) or⚠️ (`:warning:`) for more significant problems or concerns needing attention - 🌱 (`:seedling:`) or ♻️ (`:recycle:`) for future improvements or indications of technical debt - ⛏ (`:pick:`) for minor or nitpick changes
Scaffolds a new workflow for updating API bindings.
Updated SDK to use an `archivedDate` in the ciphers.
This PR contains the following updates: | Package | Change | Age | Confidence | |---|---|---|---| | [@openapitools/openapi-generator-cli](https://redirect.github.com/OpenAPITools/openapi-generator-cli) | [`2.20.2` -> `2.23.1`](https://renovatebot.com/diffs/npm/@openapitools%2fopenapi-generator-cli/2.20.2/2.23.1) | [](https://docs.renovatebot.com/merge-confidence/) | [](https://docs.renovatebot.com/merge-confidence/) | --- ### Release Notes <details> <summary>OpenAPITools/openapi-generator-cli (@​openapitools/openapi-generator-cli)</summary> ### [`v2.23.1`](https://redirect.github.com/OpenAPITools/openapi-generator-cli/releases/tag/v2.23.1) [Compare Source](https://redirect.github.com/OpenAPITools/openapi-generator-cli/compare/v2.23.0...v2.23.1) ##### Bug Fixes - **deps:** update dependency concurrently to v9.2.1 ([#​978](https://redirect.github.com/OpenAPITools/openapi-generator-cli/issues/978)) ([4847fe0](https://redirect.github.com/OpenAPITools/openapi-generator-cli/commit/4847fe0117995db49017c5943e18a6771a88929a)) ### [`v2.23.0`](https://redirect.github.com/OpenAPITools/openapi-generator-cli/releases/tag/v2.23.0) [Compare Source](https://redirect.github.com/OpenAPITools/openapi-generator-cli/compare/v2.22.0...v2.23.0) ##### Features - **release:** v7.15.0 release ([#​973](https://redirect.github.com/OpenAPITools/openapi-generator-cli/issues/973)) ([24443a5](https://redirect.github.com/OpenAPITools/openapi-generator-cli/commit/24443a5ff0b1d201b1ecef2299d82b96ffefd10c)) ### [`v2.22.0`](https://redirect.github.com/OpenAPITools/openapi-generator-cli/releases/tag/v2.22.0) [Compare Source](https://redirect.github.com/OpenAPITools/openapi-generator-cli/compare/v2.21.5...v2.22.0) ##### Features - **release:** trigger a release ([#​963](https://redirect.github.com/OpenAPITools/openapi-generator-cli/issues/963)) ([7ce2ed9](https://redirect.github.com/OpenAPITools/openapi-generator-cli/commit/7ce2ed95eb0bc3fb03bbe7c6f7bdcecd0091794b)) ### [`v2.21.5`](https://redirect.github.com/OpenAPITools/openapi-generator-cli/releases/tag/v2.21.5) [Compare Source](https://redirect.github.com/OpenAPITools/openapi-generator-cli/compare/v2.21.4...v2.21.5) ##### Bug Fixes - **deps:** update dependency fs-extra to v11.3.1 ([#​962](https://redirect.github.com/OpenAPITools/openapi-generator-cli/issues/962)) ([e0ce66f](https://redirect.github.com/OpenAPITools/openapi-generator-cli/commit/e0ce66f36f3dc54539425ff58ddb0d8fd730dc98)) ### [`v2.21.4`](https://redirect.github.com/OpenAPITools/openapi-generator-cli/releases/tag/v2.21.4) [Compare Source](https://redirect.github.com/OpenAPITools/openapi-generator-cli/compare/v2.21.3...v2.21.4) ##### Bug Fixes - **deps:** update dependency axios to v1.11.0 \[security] ([#​956](https://redirect.github.com/OpenAPITools/openapi-generator-cli/issues/956)) ([e517c31](https://redirect.github.com/OpenAPITools/openapi-generator-cli/commit/e517c31ce8697225329e630c03697c147952b660)) ### [`v2.21.3`](https://redirect.github.com/OpenAPITools/openapi-generator-cli/releases/tag/v2.21.3) [Compare Source](https://redirect.github.com/OpenAPITools/openapi-generator-cli/compare/v2.21.2...v2.21.3) ##### Bug Fixes - **deps:** update nest monorepo to v11.1.5 ([#​950](https://redirect.github.com/OpenAPITools/openapi-generator-cli/issues/950)) ([28c5f0d](https://redirect.github.com/OpenAPITools/openapi-generator-cli/commit/28c5f0d8b937bee531a16efb4d6c51017d0ac16c)) ### [`v2.21.2`](https://redirect.github.com/OpenAPITools/openapi-generator-cli/releases/tag/v2.21.2) [Compare Source](https://redirect.github.com/OpenAPITools/openapi-generator-cli/compare/v2.21.1...v2.21.2) ##### Bug Fixes - **deps:** update dependency [@​nestjs/axios](https://redirect.github.com/nestjs/axios) to v4.0.1 ([#​947](https://redirect.github.com/OpenAPITools/openapi-generator-cli/issues/947)) ([9f16faf](https://redirect.github.com/OpenAPITools/openapi-generator-cli/commit/9f16fafa0f757650c423567b2057683b284a88ec)) ### [`v2.21.1`](https://redirect.github.com/OpenAPITools/openapi-generator-cli/releases/tag/v2.21.1) [Compare Source](https://redirect.github.com/OpenAPITools/openapi-generator-cli/compare/v2.21.0...v2.21.1) ##### Bug Fixes - **deps:** update dependency concurrently to v9 ([#​848](https://redirect.github.com/OpenAPITools/openapi-generator-cli/issues/848)) ([5a52eaf](https://redirect.github.com/OpenAPITools/openapi-generator-cli/commit/5a52eaf77db3403b249a1cf30c0eb1bbc1f10671)) ### [`v2.21.0`](https://redirect.github.com/OpenAPITools/openapi-generator-cli/releases/tag/v2.21.0) [Compare Source](https://redirect.github.com/OpenAPITools/openapi-generator-cli/compare/v2.20.6...v2.21.0) ##### Features - **release:** v7.14.0 release ([#​942](https://redirect.github.com/OpenAPITools/openapi-generator-cli/issues/942)) ([cd3c9a4](https://redirect.github.com/OpenAPITools/openapi-generator-cli/commit/cd3c9a4b86de43000ff0f915eb5abb8fc5e86915)) ### [`v2.20.6`](https://redirect.github.com/OpenAPITools/openapi-generator-cli/releases/tag/v2.20.6) [Compare Source](https://redirect.github.com/OpenAPITools/openapi-generator-cli/compare/v2.20.5...v2.20.6) ##### Bug Fixes - **deps:** update dependency axios to v1.10.0 ([#​939](https://redirect.github.com/OpenAPITools/openapi-generator-cli/issues/939)) ([0f623cc](https://redirect.github.com/OpenAPITools/openapi-generator-cli/commit/0f623ccd9de6751b9ae8a7fcdd0bd491807baeac)) ### [`v2.20.5`](https://redirect.github.com/OpenAPITools/openapi-generator-cli/releases/tag/v2.20.5) [Compare Source](https://redirect.github.com/OpenAPITools/openapi-generator-cli/compare/v2.20.4...v2.20.5) ##### Bug Fixes - **deps:** update nest monorepo to v11.1.3 ([#​935](https://redirect.github.com/OpenAPITools/openapi-generator-cli/issues/935)) ([2575f55](https://redirect.github.com/OpenAPITools/openapi-generator-cli/commit/2575f55752012d8442095e76fbea0cfe35a258e8)) ### [`v2.20.4`](https://redirect.github.com/OpenAPITools/openapi-generator-cli/releases/tag/v2.20.4) [Compare Source](https://redirect.github.com/OpenAPITools/openapi-generator-cli/compare/v2.20.3...v2.20.4) ##### Bug Fixes - **deps:** update dependency glob to v11 ([#​904](https://redirect.github.com/OpenAPITools/openapi-generator-cli/issues/904)) ([7b8ac55](https://redirect.github.com/OpenAPITools/openapi-generator-cli/commit/7b8ac55ace0f2d803f80ee125ff301735a0dcb7f)) ### [`v2.20.3`](https://redirect.github.com/OpenAPITools/openapi-generator-cli/releases/tag/v2.20.3) [Compare Source](https://redirect.github.com/OpenAPITools/openapi-generator-cli/compare/v2.20.2...v2.20.3) ##### Bug Fixes - **deps:** update dependency glob to v10 ([#​933](https://redirect.github.com/OpenAPITools/openapi-generator-cli/issues/933)) ([a6b3d6c](https://redirect.github.com/OpenAPITools/openapi-generator-cli/commit/a6b3d6c93be95eb3fedfaa5789b5556a64fb2c5a)) </details> --- ### Configuration 📅 **Schedule**: Branch creation - "every 2nd week starting on the 2 week of the year before 4am on Monday" (UTC), Automerge - At any time (no schedule defined). 🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied. ♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox. 🔕 **Ignore**: Close this PR and you won't be reminded about this update again. --- - [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check this box --- This PR was generated by [Mend Renovate](https://mend.io/renovate/). View the [repository job log](https://developer.mend.io/github/bitwarden/sdk-internal). <!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0MS43MS4xIiwidXBkYXRlZEluVmVyIjoiNDEuOTcuMTAiLCJ0YXJnZXRCcmFuY2giOiJtYWluIiwibGFiZWxzIjpbXX0=--> Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> Co-authored-by: Daniel García <[email protected]>
This adds two custom dylint lint. - `error_suffix`: Requires all types that implements `Error` ends with an `Error` suffix. - `error_enum`: Forbids ending enum error variants with `Error`.
Wraps up the b64 migration.
We removed the ability to throw `VaultLocked` a while back. This removes the actual error struct and any place it's used in.
repository: &dyn Repository<Cipher>, | ||
) -> Result<Vec<CipherView>, GetCipherError> { | ||
let ciphers = repository.list().await?; | ||
let views = store.decrypt_list(&ciphers)?; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would it be better to use decrypt_list_failures
here to avoid blocking when only some of them fail to decrypt?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for adding list_ciphers_with_failures
! Do you think we still need the list_ciphers
for any use cases, or could we remove it altogether?
Codecov Report❌ Patch coverage is Additional details and impacted files@@ Coverage Diff @@
## main #455 +/- ##
=========================================
Coverage 78.48% 78.48%
=========================================
Files 276 280 +4
Lines 27435 28631 +1196
=========================================
+ Hits 21531 22472 +941
- Misses 5904 6159 +255 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
… vault/migrate-ciphers
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Overall good, there are a couple of things we should consider.
login: self | ||
.type_data | ||
.as_login_view() | ||
.as_ref() | ||
.map(|l| l.encrypt_composite(ctx, cipher_key)) | ||
.transpose()? | ||
.map(|l| Box::new(l.into())), | ||
card: self | ||
.type_data | ||
.as_card_view() | ||
.as_ref() | ||
.map(|c| c.encrypt_composite(ctx, cipher_key)) | ||
.transpose()? | ||
.map(|c| Box::new(c.into())), | ||
identity: self | ||
.type_data | ||
.as_identity_view() | ||
.as_ref() | ||
.map(|i| i.encrypt_composite(ctx, cipher_key)) | ||
.transpose()? | ||
.map(|i| Box::new(i.into())), | ||
secure_note: self | ||
.type_data | ||
.as_secure_note_view() | ||
.as_ref() | ||
.map(|s| s.encrypt_composite(ctx, cipher_key)) | ||
.transpose()? | ||
.map(|s| Box::new(s.into())), | ||
ssh_key: self | ||
.type_data | ||
.as_ssh_key_view() | ||
.as_ref() | ||
.map(|s| s.encrypt_composite(ctx, cipher_key)) | ||
.transpose()? | ||
.map(|s| Box::new(s.into())), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Messy, but I suppose we're stuck with it until the cipher is just a blob and we can serialize this manually somehow.
pub reprompt: CipherRepromptType, | ||
pub type_data: Option<CipherViewType>, | ||
pub fields: Vec<FieldView>, | ||
pub key: Option<EncString>, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
question: Should we document this? "INTERNAL, do not set from clients."
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I added a comment - I tried setting it as non-pub, but that doesn't affect the TS types that are generated, and didn't seem to add much benefit in this particular use case.
ctx: &mut KeyStoreContext<KeyIds>, | ||
key: SymmetricKeyId, | ||
) -> Result<(), CryptoError> { | ||
let old_key = Cipher::decrypt_cipher_key(ctx, key, &self.key)?; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
question: Since we're creating a cipher key will never exist right?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It shouldn't, in which case decrypt_cipher_key
will return the existing key. I included this just in case we do get a CipherCreateRequest
that already has a key, which would imply the Fido2 credentials were already encrypted with that key. Happy to remove if we're making the assumption that won't happen.
self.type_data | ||
.as_login_view_mut() | ||
.map(|l| l.reencrypt_fido2_credentials(ctx, old_key, new_key)) | ||
.transpose()?; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
thought: This raises a good question, how would we create a new cipher with a passkey? They are intentionally encrypted but would that even be viable generally?
I think temporarily we can pass in already encrypted data in the web clients, but this might not work on mobile. Long term having a different flow for creating items with passkeys might be required? CC @coroiu since you have more insight into our sdk passkey flows.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
On clients
we don't create ciphers with passkeys. The cipher is created first by the popout, which returns the new cipherId
to background
which then reads out the cipher and attaches a new passkey to it. It's a bad way of doing it but I think it saves us from having to worry about creation with passkeys in this PR.
mobile
on the other hand does create ciphers with passkeys but creation and encryption is encapsulated in the SDK and could use the Repository<Cipher>
instead of going through the CipherClient
pub struct CipherEditRequest { | ||
pub id: CipherId, | ||
|
||
pub r#type: CipherType, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
question: Do we need both type
and type_data
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not anymore - removed type
and now pull this data from CipherViewType
impl TryFrom<CipherView> for CipherEditRequest { | ||
type Error = MissingFieldError; | ||
|
||
fn try_from(value: CipherView) -> Result<Self, Self::Error> { | ||
let type_data = match value.r#type { | ||
CipherType::Login => value.login.map(CipherViewType::Login), | ||
CipherType::SecureNote => value.secure_note.map(CipherViewType::SecureNote), | ||
CipherType::Card => value.card.map(CipherViewType::Card), | ||
CipherType::Identity => value.identity.map(CipherViewType::Identity), | ||
CipherType::SshKey => value.ssh_key.map(CipherViewType::SshKey), | ||
}; | ||
Ok(Self { | ||
id: value.id.ok_or(MissingFieldError("id"))?, | ||
r#type: value.r#type, | ||
organization_id: value.organization_id, | ||
folder_id: value.folder_id, | ||
favorite: value.favorite, | ||
reprompt: value.reprompt, | ||
key: value.key, | ||
name: value.name, | ||
notes: value.notes, | ||
fields: value.fields.unwrap_or_default(), | ||
password_history: value.password_history, | ||
attachments: value.attachments, | ||
type_data, | ||
revision_date: value.revision_date, | ||
archived_date: value.archived_date, | ||
}) | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
question: It seems a bit weird going from CipherView
to CipherEditRequest
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The intent here was that a client will have a CipherView locally, make changes to it, and then go to save those changes by converting it into an Edit request.
Something along the lines of:
// Start with a decrypted cipher
let cipher_view: CipherView = ciphers_client.decrypt(cipher)?;
// Make some local changes to the CipherView
cipher_view.name = "New Cipher Name";
cipher_view.login = Some(LoginView {
username: Some("new_login".to_string()),
password: Some("password".to_string()),
..Default::default(),
});
// Send the changes upstream
ciphers_client.edit(cipher_view.into());
.collect() | ||
} | ||
|
||
fn extract_hidden_fields(fields: &Vec<FieldView>) -> HashMap<String, String> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
suggestion: Use a slice rather than a reference to a vector. It's more generic.
fn extract_hidden_fields(fields: &Vec<FieldView>) -> HashMap<String, String> { | |
fn extract_hidden_fields(fields: &[FieldView]) -> HashMap<String, String> { |
original_cipher: &CipherView, | ||
) -> Vec<PasswordChange> { | ||
if self.r#type != CipherType::Login || original_cipher.r#type != CipherType::Login { | ||
return Default::default(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
suggestion: I think returning vec![]
explicitly improves clarity. (same for the other instances in this function)
|
||
fn detect_hidden_field_changes(&self, original_cipher: &CipherView) -> Vec<PasswordChange> { | ||
let original_fields = | ||
Self::extract_hidden_fields(original_cipher.fields.as_ref().unwrap_or(&vec![])); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
With the change to accept a slice you can update this to use default.
Self::extract_hidden_fields(original_cipher.fields.as_ref().unwrap_or(&vec![])); | |
Self::extract_hidden_fields(original_cipher.fields.as_ref().unwrap_or_default(); |
… vault/migrate-ciphers
Co-authored-by: Oscar Hinton <[email protected]>
Co-authored-by: Oscar Hinton <[email protected]>
|
🎟️ Tracking
https://bitwarden.atlassian.net/browse/PM-25818
📔 Objective
⏰ Reminders before review
team
🦮 Reviewer guidelines
:+1:
) or similar for great changes:memo:
) or ℹ️ (:information_source:
) for notes or general info:question:
) for questions:thinking:
) or 💭 (:thought_balloon:
) for more open inquiry that's not quite a confirmedissue and could potentially benefit from discussion
:art:
) for suggestions / improvements:x:
) or:warning:
) for more significant problems or concerns needing attention:seedling:
) or ♻️ (:recycle:
) for future improvements or indications of technical debt:pick:
) for minor or nitpick changes