From b18fa68acc4218f4304e775b274f27b6e70e82a1 Mon Sep 17 00:00:00 2001 From: Bernd Schoolmann Date: Fri, 30 Aug 2024 16:16:24 +0200 Subject: [PATCH 1/8] [PM-10395] Add new item type ssh key (#10360) * Implement ssh-key cipher type * Fix linting * Fix edit and view components for ssh-keys on desktop * Fix tests * Remove ssh key type references * Remove add ssh key option * Fix typo * Add tests --- apps/browser/src/_locales/en/messages.json | 27 +++++++ .../add-edit/add-edit-v2.component.ts | 2 + .../item-copy-actions.component.html | 24 ++++++ .../item-copy-actions.component.ts | 8 ++ .../vault-v2/view-v2/view-v2.component.ts | 2 + .../components/vault/add-edit.component.html | 8 ++ .../vault/vault-filter.component.html | 13 +++ .../components/vault/vault-items.component.ts | 3 + .../components/vault/view.component.html | 23 ++++++ .../vault-popup-items.service.spec.ts | 1 + .../services/vault-popup-items.service.ts | 1 + .../vault-popup-list-filters.service.spec.ts | 1 + .../vault-popup-list-filters.service.ts | 5 ++ apps/desktop/src/locales/en/messages.json | 27 +++++++ .../vault/app/vault/add-edit.component.html | 38 +++++++++ .../src/vault/app/vault/add-edit.component.ts | 6 ++ .../filters/type-filter.component.html | 15 ++++ .../src/vault/app/vault/view.component.html | 49 ++++++++++++ .../individual-vault/add-edit.component.html | 55 +++++++++++++ .../components/vault-filter.component.ts | 6 ++ apps/web/src/locales/en/messages.json | 28 ++++++- .../vault/components/add-edit.component.ts | 3 + libs/common/src/vault/enums/cipher-type.ts | 1 + .../src/vault/icon/build-cipher-icon.ts | 3 + .../src/vault/models/api/ssh-key.api.ts | 17 ++++ .../src/vault/models/data/cipher.data.ts | 5 ++ .../src/vault/models/data/ssh-key.data.ts | 17 ++++ libs/common/src/vault/models/domain/cipher.ts | 14 ++++ .../src/vault/models/domain/ssh-key.spec.ts | 67 ++++++++++++++++ .../common/src/vault/models/domain/ssh-key.ts | 70 ++++++++++++++++ .../vault/models/request/cipher.request.ts | 13 +++ .../vault/models/response/cipher.response.ts | 7 ++ .../src/vault/models/view/cipher.view.ts | 7 ++ .../src/vault/models/view/ssh-key.view.ts | 26 ++++++ .../src/vault/services/cipher.service.ts | 14 ++++ .../src/cipher-form/cipher-form-container.ts | 2 + .../components/cipher-form.component.html | 6 ++ .../components/cipher-form.component.ts | 2 + .../sshkey-section.component.html | 18 +++++ .../sshkey-section.component.ts | 80 +++++++++++++++++++ .../cipher-view/cipher-view.component.html | 3 + .../src/cipher-view/cipher-view.component.ts | 6 ++ .../sshkey-view.component.html | 31 +++++++ .../sshkey-sections/sshkey-view.component.ts | 35 ++++++++ .../components/copy-cipher-field.directive.ts | 6 ++ .../src/services/copy-cipher-field.service.ts | 8 +- 46 files changed, 800 insertions(+), 3 deletions(-) create mode 100644 libs/common/src/vault/models/api/ssh-key.api.ts create mode 100644 libs/common/src/vault/models/data/ssh-key.data.ts create mode 100644 libs/common/src/vault/models/domain/ssh-key.spec.ts create mode 100644 libs/common/src/vault/models/domain/ssh-key.ts create mode 100644 libs/common/src/vault/models/view/ssh-key.view.ts create mode 100644 libs/vault/src/cipher-form/components/sshkey-section/sshkey-section.component.html create mode 100644 libs/vault/src/cipher-form/components/sshkey-section/sshkey-section.component.ts create mode 100644 libs/vault/src/cipher-view/sshkey-sections/sshkey-view.component.html create mode 100644 libs/vault/src/cipher-view/sshkey-sections/sshkey-view.component.ts diff --git a/apps/browser/src/_locales/en/messages.json b/apps/browser/src/_locales/en/messages.json index b0df5fadd44..a1061e3d6e9 100644 --- a/apps/browser/src/_locales/en/messages.json +++ b/apps/browser/src/_locales/en/messages.json @@ -1593,6 +1593,9 @@ "typeIdentity": { "message": "Identity" }, + "typeSSHKey": { + "message": "SSH key" + }, "newItemHeader": { "message": "New $TYPE$", "placeholders": { @@ -4210,5 +4213,29 @@ }, "enterprisePolicyRequirementsApplied": { "message": "Enterprise policy requirements have been applied to this setting" + }, + "sshPrivateKey": { + "message": "Private key" + }, + "sshPublicKey": { + "message": "Public key" + }, + "sshFingerprint": { + "message": "Fingerprint" + }, + "sshKeyAlgorithm": { + "message": "Key type" + }, + "sshKeyAlgorithmED25519": { + "message": "ED25519" + }, + "sshKeyAlgorithmRSA2048": { + "message": "RSA 2048-Bit" + }, + "sshKeyAlgorithmRSA3072": { + "message": "RSA 3072-Bit" + }, + "sshKeyAlgorithmRSA4096": { + "message": "RSA 4096-Bit" } } diff --git a/apps/browser/src/vault/popup/components/vault-v2/add-edit/add-edit-v2.component.ts b/apps/browser/src/vault/popup/components/vault-v2/add-edit/add-edit-v2.component.ts index b830ae75048..006c5875ae2 100644 --- a/apps/browser/src/vault/popup/components/vault-v2/add-edit/add-edit-v2.component.ts +++ b/apps/browser/src/vault/popup/components/vault-v2/add-edit/add-edit-v2.component.ts @@ -300,6 +300,8 @@ export class AddEditV2Component implements OnInit { return this.i18nService.t(partOne, this.i18nService.t("typeIdentity")); case CipherType.SecureNote: return this.i18nService.t(partOne, this.i18nService.t("note")); + case CipherType.SSHKey: + return this.i18nService.t(partOne, this.i18nService.t("typeSSHKey")); } } } diff --git a/apps/browser/src/vault/popup/components/vault-v2/item-copy-action/item-copy-actions.component.html b/apps/browser/src/vault/popup/components/vault-v2/item-copy-action/item-copy-actions.component.html index 487168539b9..ca582a71bfb 100644 --- a/apps/browser/src/vault/popup/components/vault-v2/item-copy-action/item-copy-actions.component.html +++ b/apps/browser/src/vault/popup/components/vault-v2/item-copy-action/item-copy-actions.component.html @@ -82,3 +82,27 @@ [cipher]="cipher" > + + + + + + + + + diff --git a/apps/browser/src/vault/popup/components/vault-v2/item-copy-action/item-copy-actions.component.ts b/apps/browser/src/vault/popup/components/vault-v2/item-copy-action/item-copy-actions.component.ts index a53c4a7c355..2df705a7294 100644 --- a/apps/browser/src/vault/popup/components/vault-v2/item-copy-action/item-copy-actions.component.ts +++ b/apps/browser/src/vault/popup/components/vault-v2/item-copy-action/item-copy-actions.component.ts @@ -48,5 +48,13 @@ export class ItemCopyActionsComponent { return !!this.cipher.notes; } + get hasSSHKeyValues() { + return ( + !!this.cipher.sshKey.privateKey || + !!this.cipher.sshKey.publicKey || + !!this.cipher.sshKey.keyFingerprint + ); + } + constructor() {} } diff --git a/apps/browser/src/vault/popup/components/vault-v2/view-v2/view-v2.component.ts b/apps/browser/src/vault/popup/components/vault-v2/view-v2/view-v2.component.ts index 9b8403cd319..1617c8fc9a9 100644 --- a/apps/browser/src/vault/popup/components/vault-v2/view-v2/view-v2.component.ts +++ b/apps/browser/src/vault/popup/components/vault-v2/view-v2/view-v2.component.ts @@ -100,6 +100,8 @@ export class ViewV2Component { ); case CipherType.SecureNote: return this.i18nService.t("viewItemHeader", this.i18nService.t("note").toLowerCase()); + case CipherType.SSHKey: + return this.i18nService.t("viewItemHeader", this.i18nService.t("typeSSHkey").toLowerCase()); } } diff --git a/apps/browser/src/vault/popup/components/vault/add-edit.component.html b/apps/browser/src/vault/popup/components/vault/add-edit.component.html index 9ddae878770..cad3067a3ae 100644 --- a/apps/browser/src/vault/popup/components/vault/add-edit.component.html +++ b/apps/browser/src/vault/popup/components/vault/add-edit.component.html @@ -529,6 +529,14 @@

/> + + +
+
+ {{ "sshPrivateKey" | i18n }} + {{ cipher.sshKey.privateKey }} +
+
diff --git a/apps/browser/src/vault/popup/components/vault/vault-filter.component.html b/apps/browser/src/vault/popup/components/vault/vault-filter.component.html index f9ae340a89b..7f0ef0f569c 100644 --- a/apps/browser/src/vault/popup/components/vault/vault-filter.component.html +++ b/apps/browser/src/vault/popup/components/vault/vault-filter.component.html @@ -114,6 +114,19 @@

{{ typeCounts.get(cipherType.SecureNote) || 0 }} +

diff --git a/apps/browser/src/vault/popup/components/vault/vault-items.component.ts b/apps/browser/src/vault/popup/components/vault/vault-items.component.ts index df78806edf2..e360fb5971c 100644 --- a/apps/browser/src/vault/popup/components/vault/vault-items.component.ts +++ b/apps/browser/src/vault/popup/components/vault/vault-items.component.ts @@ -107,6 +107,9 @@ export class VaultItemsComponent extends BaseVaultItemsComponent implements OnIn case CipherType.SecureNote: this.groupingTitle = this.i18nService.t("secureNotes"); break; + case CipherType.SSHKey: + this.groupingTitle = this.i18nService.t("sshKeys"); + break; default: break; } diff --git a/apps/browser/src/vault/popup/components/vault/view.component.html b/apps/browser/src/vault/popup/components/vault/view.component.html index 606807140ec..640ac0d77e6 100644 --- a/apps/browser/src/vault/popup/components/vault/view.component.html +++ b/apps/browser/src/vault/popup/components/vault/view.component.html @@ -429,6 +429,29 @@

{{ cipher.identity.country }}

+ +
+
+ + {{ "sshPublicKey" | i18n }} + {{ cipher.sshKey.publicKey }} +
+
+ + {{ "sshFingerprint" | i18n }} + {{ cipher.sshKey.keyFingerprint }} +
+
diff --git a/apps/browser/src/vault/popup/services/vault-popup-items.service.spec.ts b/apps/browser/src/vault/popup/services/vault-popup-items.service.spec.ts index 2ead93e5122..322f34aaa49 100644 --- a/apps/browser/src/vault/popup/services/vault-popup-items.service.spec.ts +++ b/apps/browser/src/vault/popup/services/vault-popup-items.service.spec.ts @@ -201,6 +201,7 @@ describe("VaultPopupItemsService", () => { [CipherType.Card]: 2, [CipherType.Identity]: 3, [CipherType.SecureNote]: 4, + [CipherType.SSHKey]: 5, }; // Assume all ciphers are autofill ciphers to test sorting diff --git a/apps/browser/src/vault/popup/services/vault-popup-items.service.ts b/apps/browser/src/vault/popup/services/vault-popup-items.service.ts index e78e289c75a..529de4d488c 100644 --- a/apps/browser/src/vault/popup/services/vault-popup-items.service.ts +++ b/apps/browser/src/vault/popup/services/vault-popup-items.service.ts @@ -257,6 +257,7 @@ export class VaultPopupItemsService { [CipherType.Card]: 2, [CipherType.Identity]: 3, [CipherType.SecureNote]: 4, + [CipherType.SSHKey]: 5, }; // Compare types first diff --git a/apps/browser/src/vault/popup/services/vault-popup-list-filters.service.spec.ts b/apps/browser/src/vault/popup/services/vault-popup-list-filters.service.spec.ts index f6573de1c80..e416486728a 100644 --- a/apps/browser/src/vault/popup/services/vault-popup-list-filters.service.spec.ts +++ b/apps/browser/src/vault/popup/services/vault-popup-list-filters.service.spec.ts @@ -99,6 +99,7 @@ describe("VaultPopupListFiltersService", () => { CipherType.Card, CipherType.Identity, CipherType.SecureNote, + CipherType.SSHKey, ]); }); }); diff --git a/apps/browser/src/vault/popup/services/vault-popup-list-filters.service.ts b/apps/browser/src/vault/popup/services/vault-popup-list-filters.service.ts index 67213163a64..7cd5c6a0af3 100644 --- a/apps/browser/src/vault/popup/services/vault-popup-list-filters.service.ts +++ b/apps/browser/src/vault/popup/services/vault-popup-list-filters.service.ts @@ -165,6 +165,11 @@ export class VaultPopupListFiltersService { label: this.i18nService.t("note"), icon: "bwi-sticky-note", }, + { + value: CipherType.SSHKey, + label: this.i18nService.t("typeSSHKey"), + icon: "bwi-key", + }, ]; /** Resets `filterForm` to the original state */ diff --git a/apps/desktop/src/locales/en/messages.json b/apps/desktop/src/locales/en/messages.json index c0f98f17535..27e6a668ce9 100644 --- a/apps/desktop/src/locales/en/messages.json +++ b/apps/desktop/src/locales/en/messages.json @@ -26,6 +26,9 @@ "typeSecureNote": { "message": "Secure note" }, + "typeSSHKey": { + "message": "SSH key" + }, "folders": { "message": "Folders" }, @@ -174,6 +177,30 @@ "address": { "message": "Address" }, + "sshPrivateKey": { + "message": "Private key" + }, + "sshPublicKey": { + "message": "Public key" + }, + "sshFingerprint": { + "message": "Fingerprint" + }, + "sshKeyAlgorithm": { + "message": "Key type" + }, + "sshKeyAlgorithmED25519": { + "message": "ED25519" + }, + "sshKeyAlgorithmRSA2048": { + "message": "RSA 2048-Bit" + }, + "sshKeyAlgorithmRSA3072": { + "message": "RSA 3072-Bit" + }, + "sshKeyAlgorithmRSA4096": { + "message": "RSA 4096-Bit" + }, "premiumRequired": { "message": "Premium required" }, diff --git a/apps/desktop/src/vault/app/vault/add-edit.component.html b/apps/desktop/src/vault/app/vault/add-edit.component.html index faddd1210eb..cbc5504c28e 100644 --- a/apps/desktop/src/vault/app/vault/add-edit.component.html +++ b/apps/desktop/src/vault/app/vault/add-edit.component.html @@ -471,6 +471,44 @@

/>

+ +
+
+
+ + +
+
+ + +
+
+
diff --git a/apps/desktop/src/vault/app/vault/add-edit.component.ts b/apps/desktop/src/vault/app/vault/add-edit.component.ts index 098316de9ec..060471d5a5f 100644 --- a/apps/desktop/src/vault/app/vault/add-edit.component.ts +++ b/apps/desktop/src/vault/app/vault/add-edit.component.ts @@ -30,6 +30,8 @@ const BroadcasterSubscriptionId = "AddEditComponent"; export class AddEditComponent extends BaseAddEditComponent implements OnInit, OnChanges, OnDestroy { @ViewChild("form") private form: NgForm; + showPrivateKey = false; + constructor( cipherService: CipherService, folderService: FolderService, @@ -137,4 +139,8 @@ export class AddEditComponent extends BaseAddEditComponent implements OnInit, On "https://bitwarden.com/help/managing-items/#protect-individual-items", ); } + + togglePrivateKey() { + this.showPrivateKey = !this.showPrivateKey; + } } diff --git a/apps/desktop/src/vault/app/vault/vault-filter/filters/type-filter.component.html b/apps/desktop/src/vault/app/vault/vault-filter/filters/type-filter.component.html index 381c06e8b67..55ae80eb593 100644 --- a/apps/desktop/src/vault/app/vault/vault-filter/filters/type-filter.component.html +++ b/apps/desktop/src/vault/app/vault/vault-filter/filters/type-filter.component.html @@ -79,4 +79,19 @@

+
  • + + + +
  • diff --git a/apps/desktop/src/vault/app/vault/view.component.html b/apps/desktop/src/vault/app/vault/view.component.html index 1a85e7ef923..4e897c2b53d 100644 --- a/apps/desktop/src/vault/app/vault/view.component.html +++ b/apps/desktop/src/vault/app/vault/view.component.html @@ -399,6 +399,55 @@

    {{ cipher.identity.country }}

    + +
    +
    +
    + + +
    +
    + +
    +
    +
    +
    + + +
    +
    + +
    +
    +
    diff --git a/apps/web/src/app/vault/individual-vault/add-edit.component.html b/apps/web/src/app/vault/individual-vault/add-edit.component.html index 63136890071..82338caa1a6 100644 --- a/apps/web/src/app/vault/individual-vault/add-edit.component.html +++ b/apps/web/src/app/vault/individual-vault/add-edit.component.html @@ -847,6 +847,61 @@

    {{ title }}

    + + +
    +
    + +
    + +
    + +
    +
    +
    +
    + +
    + +
    + +
    +
    +
    +
    +