From e2aa10212270ff21a8c99937d4a55b0d65080bb6 Mon Sep 17 00:00:00 2001 From: Opeyemi Date: Mon, 21 Oct 2024 13:11:03 +0100 Subject: [PATCH 1/5] [BRE-372] - Clean up document start (#1147) --- .github/workflows/build-android.yml | 1 - .github/workflows/build-cli-docker.yml | 1 - .github/workflows/build-cli.yml | 1 - .github/workflows/build-java.yml | 1 - .github/workflows/build-napi.yml | 1 - .github/workflows/build-python-wheels.yml | 1 - .github/workflows/build-ruby.yml | 1 - .github/workflows/build-rust-crates.yml | 1 - .github/workflows/build-swift.yml | 1 - .github/workflows/build-wasm-internal.yml | 1 - .github/workflows/build-wasm.yml | 1 - .github/workflows/delete-old-packages.yml | 1 - .github/workflows/direct-minimal-versions.yml | 1 - .github/workflows/enforce-labels.yml | 1 - .github/workflows/memory-testing.yml | 1 - .github/workflows/minimum-rust-version.yml | 1 - .github/workflows/publish-bws.yml | 1 - .github/workflows/publish-internal.yml | 1 - .github/workflows/publish-java.yml | 1 - .github/workflows/publish-napi.yml | 1 - .github/workflows/publish-php.yml | 1 - .github/workflows/publish-python.yml | 1 - .github/workflows/publish-rust-crates.yml | 1 - .github/workflows/publish-wasm.yml | 1 - .github/workflows/release-bws.yml | 1 - .github/workflows/release-napi.yml | 1 - .github/workflows/release-python.yml | 1 - .github/workflows/release-swift.yml | 1 - .github/workflows/release-wasm.yml | 1 - .github/workflows/version-bump.yml | 1 - .github/workflows/workflow-linter.yml | 12 ------- languages/java/example/bin/main/.classpath | 12 +++++++ languages/java/example/bin/main/.project | 34 +++++++++++++++++++ .../org.eclipse.buildship.core.prefs | 2 ++ .../main/.settings/org.eclipse.jdt.core.prefs | 4 +++ languages/java/example/bin/main/build.gradle | 23 +++++++++++++ 36 files changed, 75 insertions(+), 42 deletions(-) delete mode 100644 .github/workflows/workflow-linter.yml create mode 100644 languages/java/example/bin/main/.classpath create mode 100644 languages/java/example/bin/main/.project create mode 100644 languages/java/example/bin/main/.settings/org.eclipse.buildship.core.prefs create mode 100644 languages/java/example/bin/main/.settings/org.eclipse.jdt.core.prefs create mode 100644 languages/java/example/bin/main/build.gradle diff --git a/.github/workflows/build-android.yml b/.github/workflows/build-android.yml index e49fc0d6b..49ee20849 100644 --- a/.github/workflows/build-android.yml +++ b/.github/workflows/build-android.yml @@ -1,4 +1,3 @@ ---- name: Build Android on: diff --git a/.github/workflows/build-cli-docker.yml b/.github/workflows/build-cli-docker.yml index 65e164807..abf1c3a8e 100644 --- a/.github/workflows/build-cli-docker.yml +++ b/.github/workflows/build-cli-docker.yml @@ -1,4 +1,3 @@ ---- name: Build bws Docker image on: diff --git a/.github/workflows/build-cli.yml b/.github/workflows/build-cli.yml index 648291eb2..05f4cd230 100644 --- a/.github/workflows/build-cli.yml +++ b/.github/workflows/build-cli.yml @@ -1,4 +1,3 @@ ---- name: Build CLI on: diff --git a/.github/workflows/build-java.yml b/.github/workflows/build-java.yml index 761ba5cee..abeabe9db 100644 --- a/.github/workflows/build-java.yml +++ b/.github/workflows/build-java.yml @@ -1,4 +1,3 @@ ---- name: Build Java SDK on: diff --git a/.github/workflows/build-napi.yml b/.github/workflows/build-napi.yml index f9ebbc7ae..cae88a1b7 100644 --- a/.github/workflows/build-napi.yml +++ b/.github/workflows/build-napi.yml @@ -1,4 +1,3 @@ ---- name: Build @bitwarden/sdk-napi on: diff --git a/.github/workflows/build-python-wheels.yml b/.github/workflows/build-python-wheels.yml index 60c6e4b2c..da3305e79 100644 --- a/.github/workflows/build-python-wheels.yml +++ b/.github/workflows/build-python-wheels.yml @@ -1,4 +1,3 @@ ---- name: Build Python Wheels on: diff --git a/.github/workflows/build-ruby.yml b/.github/workflows/build-ruby.yml index 559c161cd..3ac79de78 100644 --- a/.github/workflows/build-ruby.yml +++ b/.github/workflows/build-ruby.yml @@ -1,4 +1,3 @@ ---- name: Build Ruby on: diff --git a/.github/workflows/build-rust-crates.yml b/.github/workflows/build-rust-crates.yml index 115be589f..bc00dd973 100644 --- a/.github/workflows/build-rust-crates.yml +++ b/.github/workflows/build-rust-crates.yml @@ -1,4 +1,3 @@ ---- name: Build Rust crates on: diff --git a/.github/workflows/build-swift.yml b/.github/workflows/build-swift.yml index 94b730e86..93cb314c4 100644 --- a/.github/workflows/build-swift.yml +++ b/.github/workflows/build-swift.yml @@ -1,4 +1,3 @@ ---- name: Build Swift Package on: diff --git a/.github/workflows/build-wasm-internal.yml b/.github/workflows/build-wasm-internal.yml index 6e0e28b98..e45bcc264 100644 --- a/.github/workflows/build-wasm-internal.yml +++ b/.github/workflows/build-wasm-internal.yml @@ -1,4 +1,3 @@ ---- name: Build @bitwarden/sdk-internal on: diff --git a/.github/workflows/build-wasm.yml b/.github/workflows/build-wasm.yml index f3a57f062..7e01e10e4 100644 --- a/.github/workflows/build-wasm.yml +++ b/.github/workflows/build-wasm.yml @@ -1,4 +1,3 @@ ---- name: Build @bitwarden/sdk-wasm on: diff --git a/.github/workflows/delete-old-packages.yml b/.github/workflows/delete-old-packages.yml index b3be807a6..f690e8011 100644 --- a/.github/workflows/delete-old-packages.yml +++ b/.github/workflows/delete-old-packages.yml @@ -1,4 +1,3 @@ ---- name: Delete old packages on: diff --git a/.github/workflows/direct-minimal-versions.yml b/.github/workflows/direct-minimal-versions.yml index 7b3820c70..66623ed6e 100644 --- a/.github/workflows/direct-minimal-versions.yml +++ b/.github/workflows/direct-minimal-versions.yml @@ -1,4 +1,3 @@ ---- name: Direct Minimum Version on: diff --git a/.github/workflows/enforce-labels.yml b/.github/workflows/enforce-labels.yml index a98c4ae1b..40ddfe773 100644 --- a/.github/workflows/enforce-labels.yml +++ b/.github/workflows/enforce-labels.yml @@ -1,4 +1,3 @@ ---- name: Enforce PR labels on: diff --git a/.github/workflows/memory-testing.yml b/.github/workflows/memory-testing.yml index 527121baf..619fbb469 100644 --- a/.github/workflows/memory-testing.yml +++ b/.github/workflows/memory-testing.yml @@ -1,4 +1,3 @@ ---- name: Test for memory leaks on: diff --git a/.github/workflows/minimum-rust-version.yml b/.github/workflows/minimum-rust-version.yml index deaca3c10..812822c6e 100644 --- a/.github/workflows/minimum-rust-version.yml +++ b/.github/workflows/minimum-rust-version.yml @@ -1,4 +1,3 @@ ---- name: Minimum Rust Version on: diff --git a/.github/workflows/publish-bws.yml b/.github/workflows/publish-bws.yml index d4dc445cf..3f4245b9f 100644 --- a/.github/workflows/publish-bws.yml +++ b/.github/workflows/publish-bws.yml @@ -1,4 +1,3 @@ ---- name: Publish bws CLI run-name: Publish bws CLI ${{ inputs.release_type }} diff --git a/.github/workflows/publish-internal.yml b/.github/workflows/publish-internal.yml index 62ffc9e45..eef5b4d09 100644 --- a/.github/workflows/publish-internal.yml +++ b/.github/workflows/publish-internal.yml @@ -1,4 +1,3 @@ ---- name: Publish @bitwarden/sdk-internal run-name: Publish @bitwarden/sdk-internal ${{ inputs.release_type }} diff --git a/.github/workflows/publish-java.yml b/.github/workflows/publish-java.yml index 7f461c198..84ce0a955 100644 --- a/.github/workflows/publish-java.yml +++ b/.github/workflows/publish-java.yml @@ -1,4 +1,3 @@ ---- name: Publish Java SDK run-name: Publish Java SDK ${{ inputs.release_type }} diff --git a/.github/workflows/publish-napi.yml b/.github/workflows/publish-napi.yml index 0caec4009..5c7aca190 100644 --- a/.github/workflows/publish-napi.yml +++ b/.github/workflows/publish-napi.yml @@ -1,4 +1,3 @@ ---- name: Publish @bitwarden/sdk-napi run-name: Publish @bitwarden/sdk-napi ${{ inputs.release_type }} diff --git a/.github/workflows/publish-php.yml b/.github/workflows/publish-php.yml index fc82c6bcb..d3965f701 100644 --- a/.github/workflows/publish-php.yml +++ b/.github/workflows/publish-php.yml @@ -1,4 +1,3 @@ ---- name: Publish PHP SDK run-name: Publish PHP SDK ${{ inputs.release_type }} diff --git a/.github/workflows/publish-python.yml b/.github/workflows/publish-python.yml index 76b06a433..bfc6b7a03 100644 --- a/.github/workflows/publish-python.yml +++ b/.github/workflows/publish-python.yml @@ -1,4 +1,3 @@ ---- name: Publish Python SDK run-name: Publish Python SDK ${{ inputs.release_type }} diff --git a/.github/workflows/publish-rust-crates.yml b/.github/workflows/publish-rust-crates.yml index 156aedb0c..30921f6b3 100644 --- a/.github/workflows/publish-rust-crates.yml +++ b/.github/workflows/publish-rust-crates.yml @@ -1,4 +1,3 @@ ---- name: Publish Rust crates run-name: Publish Rust crates ${{ inputs.release_type }} diff --git a/.github/workflows/publish-wasm.yml b/.github/workflows/publish-wasm.yml index b8bd637f1..95779b780 100644 --- a/.github/workflows/publish-wasm.yml +++ b/.github/workflows/publish-wasm.yml @@ -1,4 +1,3 @@ ---- name: Publish @bitwarden/sdk-wasm run-name: Publish @bitwarden/sdk-wasm ${{ inputs.release_type }} diff --git a/.github/workflows/release-bws.yml b/.github/workflows/release-bws.yml index aec837411..9063ca6a0 100644 --- a/.github/workflows/release-bws.yml +++ b/.github/workflows/release-bws.yml @@ -1,4 +1,3 @@ ---- name: Release bws CLI run-name: Release bws CLI ${{ inputs.release_type }} diff --git a/.github/workflows/release-napi.yml b/.github/workflows/release-napi.yml index b47f51f50..65534e8e3 100644 --- a/.github/workflows/release-napi.yml +++ b/.github/workflows/release-napi.yml @@ -1,4 +1,3 @@ ---- name: Release @bitwarden/sdk-napi run-name: Release @bitwarden/sdk-napi ${{ inputs.release_type }} diff --git a/.github/workflows/release-python.yml b/.github/workflows/release-python.yml index 6d246270b..a634a2d17 100644 --- a/.github/workflows/release-python.yml +++ b/.github/workflows/release-python.yml @@ -1,4 +1,3 @@ ---- name: Release Python SDK run-name: Release Python SDK ${{ inputs.release_type }} diff --git a/.github/workflows/release-swift.yml b/.github/workflows/release-swift.yml index 38f247cce..c5c25d65b 100644 --- a/.github/workflows/release-swift.yml +++ b/.github/workflows/release-swift.yml @@ -1,4 +1,3 @@ ---- name: Release Swift Package on: diff --git a/.github/workflows/release-wasm.yml b/.github/workflows/release-wasm.yml index c53d30813..982a31ec8 100644 --- a/.github/workflows/release-wasm.yml +++ b/.github/workflows/release-wasm.yml @@ -1,4 +1,3 @@ ---- name: Release @bitwarden/sdk-wasm run-name: Release @bitwarden/sdk-wasm ${{ inputs.release_type }} diff --git a/.github/workflows/version-bump.yml b/.github/workflows/version-bump.yml index 9cd716eb7..47642e198 100644 --- a/.github/workflows/version-bump.yml +++ b/.github/workflows/version-bump.yml @@ -1,4 +1,3 @@ ---- name: Version Bump run-name: Version Bump - ${{ inputs.project }} - v${{ inputs.version_number }} diff --git a/.github/workflows/workflow-linter.yml b/.github/workflows/workflow-linter.yml deleted file mode 100644 index 24f10f1e4..000000000 --- a/.github/workflows/workflow-linter.yml +++ /dev/null @@ -1,12 +0,0 @@ ---- -name: Workflow linter - -on: - pull_request: - paths: - - .github/workflows/** - -jobs: - call-workflow: - name: Lint - uses: bitwarden/gh-actions/.github/workflows/workflow-linter.yml@main diff --git a/languages/java/example/bin/main/.classpath b/languages/java/example/bin/main/.classpath new file mode 100644 index 000000000..18f7d2381 --- /dev/null +++ b/languages/java/example/bin/main/.classpath @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/languages/java/example/bin/main/.project b/languages/java/example/bin/main/.project new file mode 100644 index 000000000..050f3113a --- /dev/null +++ b/languages/java/example/bin/main/.project @@ -0,0 +1,34 @@ + + + example + Project example created by Buildship. + + + + + org.eclipse.jdt.core.javabuilder + + + + + org.eclipse.buildship.core.gradleprojectbuilder + + + + + + org.eclipse.jdt.core.javanature + org.eclipse.buildship.core.gradleprojectnature + + + + 1729179122477 + + 30 + + org.eclipse.core.resources.regexFilterMatcher + node_modules|\.git|__CREATED_BY_JAVA_LANGUAGE_SERVER__ + + + + diff --git a/languages/java/example/bin/main/.settings/org.eclipse.buildship.core.prefs b/languages/java/example/bin/main/.settings/org.eclipse.buildship.core.prefs new file mode 100644 index 000000000..b1886adb4 --- /dev/null +++ b/languages/java/example/bin/main/.settings/org.eclipse.buildship.core.prefs @@ -0,0 +1,2 @@ +connection.project.dir=.. +eclipse.preferences.version=1 diff --git a/languages/java/example/bin/main/.settings/org.eclipse.jdt.core.prefs b/languages/java/example/bin/main/.settings/org.eclipse.jdt.core.prefs new file mode 100644 index 000000000..55e9d5ff0 --- /dev/null +++ b/languages/java/example/bin/main/.settings/org.eclipse.jdt.core.prefs @@ -0,0 +1,4 @@ +eclipse.preferences.version=1 +org.eclipse.jdt.core.compiler.codegen.targetPlatform=19 +org.eclipse.jdt.core.compiler.compliance=19 +org.eclipse.jdt.core.compiler.source=19 diff --git a/languages/java/example/bin/main/build.gradle b/languages/java/example/bin/main/build.gradle new file mode 100644 index 000000000..73025e50d --- /dev/null +++ b/languages/java/example/bin/main/build.gradle @@ -0,0 +1,23 @@ +plugins { + id 'application' +} + +repositories { + mavenLocal() + mavenCentral() +} + +dependencies { + implementation rootProject +} + +application { + mainClass = 'Example' +} + +sourceSets { + main { + java.srcDirs += '.' + } +} + From c5a74193dbe8fa6d2b7c45412c678d7dcdb2a239 Mon Sep 17 00:00:00 2001 From: Andreas Coroiu Date: Mon, 21 Oct 2024 14:53:38 +0200 Subject: [PATCH 2/5] fix: downgrade rust to 1.81.0 in WASM builds (#1149) This is a temporary fix for WASM no longer building due to wasm2js breaking when using 1.82.0 --- .github/workflows/build-wasm-internal.yml | 2 +- .github/workflows/build-wasm.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build-wasm-internal.yml b/.github/workflows/build-wasm-internal.yml index e45bcc264..2262babcd 100644 --- a/.github/workflows/build-wasm-internal.yml +++ b/.github/workflows/build-wasm-internal.yml @@ -36,7 +36,7 @@ jobs: - name: Install rust uses: dtolnay/rust-toolchain@7b1c307e0dcbda6122208f10795a713336a9b35a # stable with: - toolchain: stable + toolchain: 1.81.0 targets: wasm32-unknown-unknown - name: Cache cargo registry diff --git a/.github/workflows/build-wasm.yml b/.github/workflows/build-wasm.yml index 7e01e10e4..e1924ca21 100644 --- a/.github/workflows/build-wasm.yml +++ b/.github/workflows/build-wasm.yml @@ -36,7 +36,7 @@ jobs: - name: Install rust uses: dtolnay/rust-toolchain@7b1c307e0dcbda6122208f10795a713336a9b35a # stable with: - toolchain: stable + toolchain: 1.81.0 targets: wasm32-unknown-unknown - name: Cache cargo registry From 39358acc891590b5c90fa0734cd50a04cf80bb1c Mon Sep 17 00:00:00 2001 From: Opeyemi Date: Mon, 21 Oct 2024 15:07:22 +0100 Subject: [PATCH 3/5] [BRE-372] - Clean up Eclipse added files (#1150) --- languages/java/example/bin/main/.classpath | 12 ------- languages/java/example/bin/main/.project | 34 ------------------- .../org.eclipse.buildship.core.prefs | 2 -- .../main/.settings/org.eclipse.jdt.core.prefs | 4 --- languages/java/example/bin/main/build.gradle | 23 ------------- 5 files changed, 75 deletions(-) delete mode 100644 languages/java/example/bin/main/.classpath delete mode 100644 languages/java/example/bin/main/.project delete mode 100644 languages/java/example/bin/main/.settings/org.eclipse.buildship.core.prefs delete mode 100644 languages/java/example/bin/main/.settings/org.eclipse.jdt.core.prefs delete mode 100644 languages/java/example/bin/main/build.gradle diff --git a/languages/java/example/bin/main/.classpath b/languages/java/example/bin/main/.classpath deleted file mode 100644 index 18f7d2381..000000000 --- a/languages/java/example/bin/main/.classpath +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - - - - - - - diff --git a/languages/java/example/bin/main/.project b/languages/java/example/bin/main/.project deleted file mode 100644 index 050f3113a..000000000 --- a/languages/java/example/bin/main/.project +++ /dev/null @@ -1,34 +0,0 @@ - - - example - Project example created by Buildship. - - - - - org.eclipse.jdt.core.javabuilder - - - - - org.eclipse.buildship.core.gradleprojectbuilder - - - - - - org.eclipse.jdt.core.javanature - org.eclipse.buildship.core.gradleprojectnature - - - - 1729179122477 - - 30 - - org.eclipse.core.resources.regexFilterMatcher - node_modules|\.git|__CREATED_BY_JAVA_LANGUAGE_SERVER__ - - - - diff --git a/languages/java/example/bin/main/.settings/org.eclipse.buildship.core.prefs b/languages/java/example/bin/main/.settings/org.eclipse.buildship.core.prefs deleted file mode 100644 index b1886adb4..000000000 --- a/languages/java/example/bin/main/.settings/org.eclipse.buildship.core.prefs +++ /dev/null @@ -1,2 +0,0 @@ -connection.project.dir=.. -eclipse.preferences.version=1 diff --git a/languages/java/example/bin/main/.settings/org.eclipse.jdt.core.prefs b/languages/java/example/bin/main/.settings/org.eclipse.jdt.core.prefs deleted file mode 100644 index 55e9d5ff0..000000000 --- a/languages/java/example/bin/main/.settings/org.eclipse.jdt.core.prefs +++ /dev/null @@ -1,4 +0,0 @@ -eclipse.preferences.version=1 -org.eclipse.jdt.core.compiler.codegen.targetPlatform=19 -org.eclipse.jdt.core.compiler.compliance=19 -org.eclipse.jdt.core.compiler.source=19 diff --git a/languages/java/example/bin/main/build.gradle b/languages/java/example/bin/main/build.gradle deleted file mode 100644 index 73025e50d..000000000 --- a/languages/java/example/bin/main/build.gradle +++ /dev/null @@ -1,23 +0,0 @@ -plugins { - id 'application' -} - -repositories { - mavenLocal() - mavenCentral() -} - -dependencies { - implementation rootProject -} - -application { - mainClass = 'Example' -} - -sourceSets { - main { - java.srcDirs += '.' - } -} - From be75311e92309109147c4b6d742e23a192b253c6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Garc=C3=ADa?= Date: Mon, 21 Oct 2024 17:37:04 +0200 Subject: [PATCH 4/5] [PM-13420] Support case-insensitive TOTP generation (#1144) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## 🎟ī¸ Tracking https://bitwarden.atlassian.net/browse/PM-13420 ## 📔 Objective Update TOTP parsing to be case insensitive by lowercasing the input initially. `decode_b32` is already converting the input to uppercase so secret decoding will still work the same. I've also removed the `to_uppercase` from algorithm now that we know the string is lowercase. ## ⏰ 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 - 👍 (`:+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 --- crates/bitwarden-vault/src/totp.rs | 44 ++++++++++++++++++++++++++---- 1 file changed, 38 insertions(+), 6 deletions(-) diff --git a/crates/bitwarden-vault/src/totp.rs b/crates/bitwarden-vault/src/totp.rs index 8aee3e694..d6167a1ab 100644 --- a/crates/bitwarden-vault/src/totp.rs +++ b/crates/bitwarden-vault/src/totp.rs @@ -157,17 +157,19 @@ impl FromStr for Totp { /// - OTP Auth URI /// - Steam URI fn from_str(key: &str) -> Result { + let key = key.to_lowercase(); + let params = if key.starts_with("otpauth://") { - let url = Url::parse(key).map_err(|_| TotpError::InvalidOtpauth)?; + let url = Url::parse(&key).map_err(|_| TotpError::InvalidOtpauth)?; let parts: HashMap<_, _> = url.query_pairs().collect(); Totp { algorithm: parts .get("algorithm") - .and_then(|v| match v.to_uppercase().as_ref() { - "SHA1" => Some(Algorithm::Sha1), - "SHA256" => Some(Algorithm::Sha256), - "SHA512" => Some(Algorithm::Sha512), + .and_then(|v| match v.as_ref() { + "sha1" => Some(Algorithm::Sha1), + "sha256" => Some(Algorithm::Sha256), + "sha512" => Some(Algorithm::Sha512), _ => None, }) .unwrap_or(DEFAULT_ALGORITHM), @@ -200,7 +202,7 @@ impl FromStr for Totp { algorithm: DEFAULT_ALGORITHM, digits: DEFAULT_DIGITS, period: DEFAULT_PERIOD, - secret: decode_b32(key), + secret: decode_b32(&key), } }; @@ -285,6 +287,7 @@ mod tests { ("PIUD1IS!EQYA=", "829846"), // sanitized // Steam ("steam://HXDMVJECJJWSRB3HWIZR4IFUGFTMXBOZ", "7W6CJ"), + ("StEam://HXDMVJECJJWSRB3HWIZR4IFUGFTMXBOZ", "7W6CJ"), ("steam://ABCD123", "N26DF"), // Various weird lengths ("ddfdf", "932653"), @@ -321,6 +324,20 @@ mod tests { assert_eq!(response.period, 30); } + #[test] + fn test_generate_otpauth_uppercase() { + let key = "OTPauth://totp/test-account?secret=WQIQ25BRKZYCJVYP".to_string(); + let time = Some( + DateTime::parse_from_rfc3339("2023-01-01T00:00:00.000Z") + .unwrap() + .with_timezone(&Utc), + ); + let response = generate_totp(key, time).unwrap(); + + assert_eq!(response.code, "194506".to_string()); + assert_eq!(response.period, 30); + } + #[test] fn test_generate_otpauth_period() { let key = "otpauth://totp/test-account?secret=WQIQ25BRKZYCJVYP&period=60".to_string(); @@ -335,6 +352,21 @@ mod tests { assert_eq!(response.period, 60); } + #[test] + fn test_generate_otpauth_algorithm_sha256() { + let key = + "otpauth://totp/test-account?secret=WQIQ25BRKZYCJVYP&algorithm=SHA256".to_string(); + let time = Some( + DateTime::parse_from_rfc3339("2023-01-01T00:00:00.000Z") + .unwrap() + .with_timezone(&Utc), + ); + let response = generate_totp(key, time).unwrap(); + + assert_eq!(response.code, "842615".to_string()); + assert_eq!(response.period, 30); + } + #[test] fn test_generate_totp_cipher_view() { let view = CipherListView { From 38ecf133f86940f9c8f6a9627012938e7569b44d Mon Sep 17 00:00:00 2001 From: Bernd Schoolmann Date: Mon, 21 Oct 2024 18:05:18 +0200 Subject: [PATCH 5/5] [PM-11924] Add ssh-key item type (#1037) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## 🎟ī¸ Tracking https://bitwarden.atlassian.net/browse/PM-11924 Server PR: https://bitwarden.atlassian.net/browse/PM-10394 ## 📔 Objective Add a new item type for ssh-keys. ## ⏰ 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 - 👍 (`:+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 --------- Co-authored-by: Oscar Hinton --- .../resources/json_export.json | 20 ++++ crates/bitwarden-exporters/src/json.rs | 113 +++++++++++++++++- crates/bitwarden-exporters/src/lib.rs | 11 ++ crates/bitwarden-exporters/src/models.rs | 9 ++ .../bitwarden-vault/src/cipher/attachment.rs | 3 + crates/bitwarden-vault/src/cipher/cipher.rs | 71 ++++++++++- crates/bitwarden-vault/src/cipher/mod.rs | 1 + crates/bitwarden-vault/src/cipher/ssh_key.rs | 49 ++++++++ .../src/mobile/client_ciphers.rs | 2 + 9 files changed, 272 insertions(+), 7 deletions(-) create mode 100644 crates/bitwarden-vault/src/cipher/ssh_key.rs diff --git a/crates/bitwarden-exporters/resources/json_export.json b/crates/bitwarden-exporters/resources/json_export.json index ad5380550..27a0921d9 100644 --- a/crates/bitwarden-exporters/resources/json_export.json +++ b/crates/bitwarden-exporters/resources/json_export.json @@ -141,6 +141,26 @@ "revisionDate": "2024-01-30T17:54:50.706Z", "creationDate": "2024-01-30T17:54:50.706Z", "deletedDate": null + }, + { + "id": "646594a9-a9cb-4082-9d57-0024c3fbcaa9", + "folderId": null, + "organizationId": null, + "collectionIds": null, + "name": "My ssh key", + "notes": null, + "type": 5, + "sshKey": { + "privateKey": "-----BEGIN OPENSSH PRIVATE KEY-----\nb3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtzc2gtZW\nQyNTUxOQAAACBinNE5chMtCHh3BV0H1+CpPlEQBwR5cD+Xb9i8MaHGiwAAAKAy48fwMuPH\n8AAAAAtzc2gtZWQyNTUxOQAAACBinNE5chMtCHh3BV0H1+CpPlEQBwR5cD+Xb9i8MaHGiw\nAAAEAYUCIdfLI14K3XIy9V0FDZLQoZ9gcjOnvFjb4uA335HmKc0TlyEy0IeHcFXQfX4Kk+\nURAHBHlwP5dv2LwxocaLAAAAHHF1ZXh0ZW5ATWFjQm9vay1Qcm8tMTYubG9jYWwB\n-----END OPENSSH PRIVATE KEY-----", + "publicKey": "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIGKc0TlyEy0IeHcFXQfX4Kk+URAHBHlwP5dv2LwxocaL", + "fingerprint": "SHA256:1JjFjvPRkj1Gbf2qRP1dgHiIzEuNAEvp+92x99jw3K0" + }, + "favorite": false, + "reprompt": 0, + "passwordHistory": null, + "revisionDate": "2024-01-30T11:25:25.466Z", + "creationDate": "2024-01-30T11:25:25.466Z", + "deletedDate": null } ] } \ No newline at end of file diff --git a/crates/bitwarden-exporters/src/json.rs b/crates/bitwarden-exporters/src/json.rs index 3f6c72c1f..7ed85d451 100644 --- a/crates/bitwarden-exporters/src/json.rs +++ b/crates/bitwarden-exporters/src/json.rs @@ -2,7 +2,9 @@ use chrono::{DateTime, Utc}; 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 { @@ -69,6 +71,8 @@ struct JsonCipher { card: Option, #[serde(skip_serializing_if = "Option::is_none")] secure_note: Option, + #[serde(skip_serializing_if = "Option::is_none")] + ssh_key: Option, favorite: bool, reprompt: u8, @@ -206,6 +210,24 @@ impl From for JsonIdentity { } } +#[derive(serde::Serialize)] +#[serde(rename_all = "camelCase")] +struct JsonSshKey { + private_key: Option, + public_key: Option, + fingerprint: Option, +} + +impl From 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, + } + } +} + #[derive(serde::Serialize)] #[serde(rename_all = "camelCase")] struct JsonField { @@ -233,13 +255,15 @@ impl From for JsonCipher { CipherType::SecureNote(_) => 2, CipherType::Card(_) => 3, CipherType::Identity(_) => 4, + CipherType::SshKey(_) => 5, }; - 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())), }; JsonCipher { @@ -254,6 +278,7 @@ impl From for JsonCipher { identity, card, secure_note, + ssh_key, favorite: cipher.favorite, reprompt: cipher.reprompt, fields: cipher.fields.into_iter().map(|f| f.into()).collect(), @@ -594,6 +619,60 @@ mod tests { ) } + #[test] + fn test_convert_ssh_key() { + let cipher = Cipher { + id: "23f0f877-42b1-4820-a850-b10700bc41eb".parse().unwrap(), + folder_id: None, + + name: "My ssh key".to_string(), + notes: None, + + r#type: CipherType::SshKey(Box::new(SshKey { + private_key: Some("private".to_string()), + public_key: Some("public".to_string()), + fingerprint: Some("fingerprint".to_string()), + })), + + favorite: false, + reprompt: 0, + + fields: vec![], + + revision_date: "2024-01-30T11:25:25.466Z".parse().unwrap(), + creation_date: "2024-01-30T11:25:25.466Z".parse().unwrap(), + deleted_date: None, + }; + + let json = serde_json::to_string(&JsonCipher::from(cipher)).unwrap(); + + let expected = r#"{ + "passwordHistory": null, + "revisionDate": "2024-01-30T11:25:25.466Z", + "creationDate": "2024-01-30T11:25:25.466Z", + "deletedDate": null, + "id": "23f0f877-42b1-4820-a850-b10700bc41eb", + "organizationId": null, + "folderId": null, + "type": 5, + "reprompt": 0, + "name": "My ssh key", + "notes": null, + "sshKey": { + "privateKey": "private", + "publicKey": "public", + "fingerprint": "fingerprint" + }, + "favorite": false, + "collectionIds": null + }"#; + + assert_eq!( + json.parse::().unwrap(), + expected.parse::().unwrap() + ) + } + #[test] pub fn test_export() { let mut d = PathBuf::from(env!("CARGO_MANIFEST_DIR")); @@ -750,6 +829,28 @@ mod tests { creation_date: "2024-01-30T17:54:50.706Z".parse().unwrap(), deleted_date: None, }, + Cipher { + id: "646594a9-a9cb-4082-9d57-0024c3fbcaa9".parse().unwrap(), + folder_id: None, + + name: "My ssh key".to_string(), + notes: None, + + r#type: CipherType::SshKey(Box::new(SshKey { + private_key: Some("-----BEGIN OPENSSH PRIVATE KEY-----\nb3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtzc2gtZW\nQyNTUxOQAAACBinNE5chMtCHh3BV0H1+CpPlEQBwR5cD+Xb9i8MaHGiwAAAKAy48fwMuPH\n8AAAAAtzc2gtZWQyNTUxOQAAACBinNE5chMtCHh3BV0H1+CpPlEQBwR5cD+Xb9i8MaHGiw\nAAAEAYUCIdfLI14K3XIy9V0FDZLQoZ9gcjOnvFjb4uA335HmKc0TlyEy0IeHcFXQfX4Kk+\nURAHBHlwP5dv2LwxocaLAAAAHHF1ZXh0ZW5ATWFjQm9vay1Qcm8tMTYubG9jYWwB\n-----END OPENSSH PRIVATE KEY-----".to_string()), + public_key: Some("ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIGKc0TlyEy0IeHcFXQfX4Kk+URAHBHlwP5dv2LwxocaL".to_string()), + fingerprint: Some("SHA256:1JjFjvPRkj1Gbf2qRP1dgHiIzEuNAEvp+92x99jw3K0".to_string()), + })), + + favorite: false, + reprompt: 0, + + fields: vec![], + + revision_date: "2024-01-30T11:25:25.466Z".parse().unwrap(), + creation_date: "2024-01-30T11:25:25.466Z".parse().unwrap(), + deleted_date: None, + } ], ) .unwrap(); diff --git a/crates/bitwarden-exporters/src/lib.rs b/crates/bitwarden-exporters/src/lib.rs index 75b0503e2..f6bb8dbf7 100644 --- a/crates/bitwarden-exporters/src/lib.rs +++ b/crates/bitwarden-exporters/src/lib.rs @@ -70,6 +70,7 @@ pub enum CipherType { SecureNote(Box), Card(Box), Identity(Box), + SshKey(Box), } impl fmt::Display for CipherType { @@ -79,6 +80,7 @@ impl fmt::Display for CipherType { CipherType::SecureNote(_) => write!(f, "note"), CipherType::Card(_) => write!(f, "card"), CipherType::Identity(_) => write!(f, "identity"), + CipherType::SshKey(_) => write!(f, "ssh_key"), } } } @@ -132,3 +134,12 @@ pub struct Identity { pub passport_number: Option, pub license_number: Option, } + +pub struct SshKey { + /// [OpenSSH private key](https://github.com/openssh/openssh-portable/blob/master/PROTOCOL.key), in PEM encoding. + pub private_key: Option, + /// Ssh public key (ed25519/rsa) according to [RFC4253](https://datatracker.ietf.org/doc/html/rfc4253#section-6.6) + pub public_key: Option, + /// SSH fingerprint using SHA256 in the format: `SHA256:BASE64_ENCODED_FINGERPRINT` + pub fingerprint: Option, +} diff --git a/crates/bitwarden-exporters/src/models.rs b/crates/bitwarden-exporters/src/models.rs index 1d56e7233..1d2e80d93 100644 --- a/crates/bitwarden-exporters/src/models.rs +++ b/crates/bitwarden-exporters/src/models.rs @@ -74,6 +74,14 @@ impl TryFrom for crate::Cipher { 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, + })) + } }; Ok(Self { @@ -172,6 +180,7 @@ mod tests { identity: None, card: None, secure_note: None, + ssh_key: None, favorite: false, reprompt: CipherRepromptType::None, organization_use_totp: true, diff --git a/crates/bitwarden-vault/src/cipher/attachment.rs b/crates/bitwarden-vault/src/cipher/attachment.rs index d1a058c01..bf589879c 100644 --- a/crates/bitwarden-vault/src/cipher/attachment.rs +++ b/crates/bitwarden-vault/src/cipher/attachment.rs @@ -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, @@ -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, @@ -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, diff --git a/crates/bitwarden-vault/src/cipher/cipher.rs b/crates/bitwarden-vault/src/cipher/cipher.rs index 8ac4bfe79..846d332cd 100644 --- a/crates/bitwarden-vault/src/cipher/cipher.rs +++ b/crates/bitwarden-vault/src/cipher/cipher.rs @@ -14,7 +14,7 @@ use uuid::Uuid; use super::{ attachment, card, field, identity, local_data::{LocalData, LocalDataView}, - secure_note, + secure_note, ssh_key, }; use crate::{ password_history, Fido2CredentialFullView, Fido2CredentialView, Login, LoginView, @@ -41,6 +41,7 @@ pub enum CipherType { SecureNote = 2, Card = 3, Identity = 4, + SshKey = 5, } #[derive(Clone, Copy, Serialize_repr, Deserialize_repr, Debug, JsonSchema, PartialEq)] @@ -72,6 +73,7 @@ pub struct Cipher { pub identity: Option, pub card: Option, pub secure_note: Option, + pub ssh_key: Option, pub favorite: bool, pub reprompt: CipherRepromptType, @@ -109,6 +111,7 @@ pub struct CipherView { pub identity: Option, pub card: Option, pub secure_note: Option, + pub ssh_key: Option, pub favorite: bool, pub reprompt: CipherRepromptType, @@ -137,6 +140,7 @@ pub enum CipherListViewType { SecureNote, Card, Identity, + SshKey, } #[derive(Serialize, Deserialize, Debug, JsonSchema, PartialEq)] @@ -211,6 +215,7 @@ impl KeyEncryptable for CipherView { 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, @@ -245,6 +250,7 @@ impl KeyDecryptable for Cipher { 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, @@ -329,6 +335,18 @@ impl Cipher { .transpose()?, ) } + CipherType::SshKey => { + let Some(ssh_key) = &self.ssh_key else { + return Ok(String::new()); + }; + + ssh_key + .fingerprint + .as_ref() + .map(|c| c.decrypt_with_key(key)) + .transpose()? + .unwrap_or_default() + } }) } } @@ -553,6 +571,7 @@ impl KeyDecryptable for Cipher { CipherType::SecureNote => CipherListViewType::SecureNote, CipherType::Card => CipherListViewType::Card, CipherType::Identity => CipherListViewType::Identity, + CipherType::SshKey => CipherListViewType::SshKey, }, favorite: self.favorite, reprompt: self.reprompt, @@ -614,6 +633,8 @@ impl TryFrom for Cipher { 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 + ssh_key: None, favorite: cipher.favorite.unwrap_or(false), reprompt: cipher .reprompt @@ -650,6 +671,7 @@ impl From for CipherType { 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 } } } @@ -669,6 +691,7 @@ mod tests { use std::collections::HashMap; use attachment::AttachmentView; + use ssh_key::SshKey; use super::*; use crate::Fido2Credential; @@ -695,6 +718,7 @@ mod tests { identity: None, card: None, secure_note: None, + ssh_key: None, favorite: false, reprompt: CipherRepromptType::None, organization_use_totp: true, @@ -753,6 +777,7 @@ mod tests { identity: None, card: None, secure_note: None, + ssh_key: None, favorite: false, reprompt: CipherRepromptType::None, organization_use_totp: false, @@ -1159,4 +1184,48 @@ mod tests { let subtitle = build_subtitle_identity(first_name, last_name); assert_eq!(subtitle, ""); } + + #[test] + fn test_subtitle_ssh_key() { + let key = "hvBMMb1t79YssFZkpetYsM3deyVuQv4r88Uj9gvYe0+G8EwxvW3v1iywVmSl61iwzd17JW5C/ivzxSP2C9h7Tw==".to_string(); + let key = SymmetricCryptoKey::try_from(key).unwrap(); + let original_subtitle = "SHA256:1JjFjvPRkj1Gbf2qRP1dgHiIzEuNAEvp+92x99jw3K0".to_string(); + let fingerprint_encrypted = original_subtitle.to_owned().encrypt_with_key(&key).unwrap(); + let ssh_key_cipher = Cipher { + id: Some("090c19ea-a61a-4df6-8963-262b97bc6266".parse().unwrap()), + organization_id: None, + folder_id: None, + collection_ids: vec![], + r#type: CipherType::SshKey, + key: None, + name: "My test ssh key" + .to_string() + .encrypt_with_key(&key) + .unwrap(), + notes: None, + login: None, + identity: None, + card: None, + secure_note: None, + ssh_key: Some(SshKey { + private_key: None, + public_key: None, + fingerprint: Some(fingerprint_encrypted), + }), + favorite: false, + reprompt: CipherRepromptType::None, + organization_use_totp: false, + edit: true, + view_password: true, + local_data: None, + attachments: None, + fields: None, + password_history: None, + creation_date: "2024-01-01T00:00:00.000Z".parse().unwrap(), + deleted_date: None, + revision_date: "2024-01-01T00:00:00.000Z".parse().unwrap(), + }; + let subtitle = ssh_key_cipher.get_decrypted_subtitle(&key).unwrap(); + assert_eq!(subtitle, original_subtitle); + } } diff --git a/crates/bitwarden-vault/src/cipher/mod.rs b/crates/bitwarden-vault/src/cipher/mod.rs index 67513d524..a4a6088dc 100644 --- a/crates/bitwarden-vault/src/cipher/mod.rs +++ b/crates/bitwarden-vault/src/cipher/mod.rs @@ -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, diff --git a/crates/bitwarden-vault/src/cipher/ssh_key.rs b/crates/bitwarden-vault/src/cipher/ssh_key.rs new file mode 100644 index 000000000..6d4977c85 --- /dev/null +++ b/crates/bitwarden-vault/src/cipher/ssh_key.rs @@ -0,0 +1,49 @@ +use bitwarden_crypto::{ + CryptoError, EncString, KeyDecryptable, KeyEncryptable, SymmetricCryptoKey, +}; +use schemars::JsonSchema; +use serde::{Deserialize, Serialize}; + +#[derive(Serialize, Deserialize, Debug, JsonSchema, Clone)] +#[serde(rename_all = "camelCase", deny_unknown_fields)] +#[cfg_attr(feature = "uniffi", derive(uniffi::Record))] +pub struct SshKey { + /// SSH private key (ed25519/rsa) in unencrypted openssh private key format [OpenSSH private key](https://github.com/openssh/openssh-portable/blob/master/PROTOCOL.key) + pub private_key: Option, + /// SSH public key (ed25519/rsa) according to [RFC4253](https://datatracker.ietf.org/doc/html/rfc4253#section-6.6) + pub public_key: Option, + /// SSH fingerprint using SHA256 in the format: `SHA256:BASE64_ENCODED_FINGERPRINT` + pub fingerprint: Option, +} + +#[derive(Serialize, Deserialize, Debug, JsonSchema, Clone)] +#[serde(rename_all = "camelCase", deny_unknown_fields)] +#[cfg_attr(feature = "uniffi", derive(uniffi::Record))] +pub struct SshKeyView { + /// SSH private key (ed25519/rsa) in unencrypted openssh private key format [OpenSSH private key](https://github.com/openssh/openssh-portable/blob/master/PROTOCOL.key) + pub private_key: Option, + /// SSH public key (ed25519/rsa) according to [RFC4253](https://datatracker.ietf.org/doc/html/rfc4253#section-6.6) + pub public_key: Option, + /// SSH fingerprint using SHA256 in the format: `SHA256:BASE64_ENCODED_FINGERPRINT` + pub fingerprint: Option, +} + +impl KeyEncryptable for SshKeyView { + fn encrypt_with_key(self, key: &SymmetricCryptoKey) -> Result { + 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)?, + }) + } +} + +impl KeyDecryptable for SshKey { + fn decrypt_with_key(&self, key: &SymmetricCryptoKey) -> Result { + 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(), + }) + } +} diff --git a/crates/bitwarden-vault/src/mobile/client_ciphers.rs b/crates/bitwarden-vault/src/mobile/client_ciphers.rs index 345f04df1..063fb4bc6 100644 --- a/crates/bitwarden-vault/src/mobile/client_ciphers.rs +++ b/crates/bitwarden-vault/src/mobile/client_ciphers.rs @@ -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, @@ -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,