From 31276a92f8dfd2198c14a0e3b7c08557e8b45d3a Mon Sep 17 00:00:00 2001 From: SmithThe4th Date: Mon, 24 Jul 2023 09:34:10 -0400 Subject: [PATCH] [PM-1976] Display passkeys properly on the browser (#5616) * Removed passkeys from the vault types filter and added fucntion to get the count of Fido2keys and Login types * Updated build filter to take Fido2key type as a Login type * Updated icon font files * Updated vault items and view to handle changes with fido2keys * Updated add edit view for fido2keys * Prevent moving passkeys to an organization where it exists * Prevent moving passkeys to an organization where it exists * Added view for non-discoverable passkeys * Added diaglog to inform user that passkey won't be copied when cloning a non discoverable key * Muted text that shows cipher item is available for 2fa * Changed conditional to check if an organization already has the same passkey item * Muted text to align with figma designs and used rpId for the application input value * Modified checkFido2KeyExistsInOrg function to workk with discoverable and non discoverable keys * Differentiate between non-discoverable and discoverable keys when moving to an organization * Added suggested changes from PR review * Updated font files css changes * Fixed bug preventing launch bitton from working for Login types (#5639) * [PM-1574] Display passkeys on web (#5651) * Allowed discoverable Fido2key type to be displayed alongside Login type * Added view during edit for discoverable and non-discoverable passkeys * Fixed PR comments, added relvant tests to domain changes * Fixed imports and updated the launch function to use the Launchable interface * Added launch on vault filter for fido2key types * Added missing passkey text field in edit view (#5800) * [PM-1977] Display passkeys properly on the desktop (#5763) * Allowed discoverable Fido2key type to be displayed alongside Login type * Added view during edit for discoverable and non-discoverable passkeys * Fixed PR comments, added relvant tests to domain changes * Fixed imports and updated the launch function to use the Launchable interface * Added fido2key to login filter and added view display for fido2key * Added passkeys view for non discoverable passkeys and edit view for passkeys * Fixed PR comments * switched date format to short * [PM-3046] [PM-3047] Defects for discoverable and non-discoverable passkeys on desktop and web (#5847) * Added missing passkey text field in edit view (#5800) * Added dialog to clone no discoverable passkeys on web and desktop.Also, removed clone on the desktop for discoverable passkeys and added passkey view to non- discoverable passkeys on desktop during edit * Prevent cloning dialog on non fido2key ciphers * Made fido2key use website favicon if avaialble instead of the passkey icon * Do not display passkey view on clone edit for dekstop * Do not display passkey view on clone edit for browser * Prevented movement of passkeys ND or D to an organization once one exists and also made it possible for org memebers with user roles to move passkeys to an organization. (#5868) * two step passkey view was outside the conditional (#5872) --- apps/browser/src/_locales/en/messages.json | 21 ++++ .../components/action-buttons.component.html | 38 +++++++ .../components/vault/add-edit.component.html | 47 ++++++++ .../vault/vault-filter.component.html | 17 +-- .../vault/vault-filter.component.ts | 15 ++- .../components/vault/vault-items.component.ts | 20 +++- .../components/vault/view.component.html | 69 +++++++++--- .../popup/components/vault/view.component.ts | 2 - apps/desktop/src/locales/en/messages.json | 21 ++++ .../vault/app/vault/add-edit.component.html | 46 ++++++++ .../src/vault/app/vault/vault.component.ts | 10 +- .../src/vault/app/vault/view.component.html | 57 +++++++++- .../vault-cipher-row.component.html | 14 +++ .../vault-items/vault-items.component.html | 5 +- .../vault-items/vault-items.component.ts | 8 ++ .../individual-vault/add-edit.component.html | 102 ++++++++++++++++++ .../individual-vault/add-edit.component.ts | 4 +- .../shared/models/filter-function.spec.ts | 11 ++ .../shared/models/filter-function.ts | 7 +- .../shared/models/vault-filter.model.spec.ts | 22 ++++ .../shared/models/vault-filter.model.ts | 8 +- .../vault/individual-vault/vault.component.ts | 12 +++ apps/web/src/locales/en/messages.json | 21 ++++ .../angular/src/components/share.component.ts | 32 ++++++ .../src/scss/bwicons/fonts/bwi-font.svg | 10 +- .../src/scss/bwicons/fonts/bwi-font.ttf | Bin 75260 -> 76108 bytes .../src/scss/bwicons/fonts/bwi-font.woff | Bin 75336 -> 76184 bytes .../src/scss/bwicons/fonts/bwi-font.woff2 | Bin 33048 -> 33420 bytes .../src/scss/bwicons/styles/style.scss | 10 +- .../vault/components/add-edit.component.ts | 6 +- .../src/vault/components/icon.component.ts | 35 +++--- .../src/vault/components/view.component.ts | 17 ++- .../models/vault-filter.model.spec.ts | 13 +++ .../vault-filter/models/vault-filter.model.ts | 8 +- .../common/src/vault/interfaces/launchable.ts | 4 + .../src/vault/models/view/fido2-key.view.ts | 8 ++ 36 files changed, 644 insertions(+), 76 deletions(-) create mode 100644 libs/common/src/vault/interfaces/launchable.ts diff --git a/apps/browser/src/_locales/en/messages.json b/apps/browser/src/_locales/en/messages.json index b0593ac2b20..97a8d3cc4ee 100644 --- a/apps/browser/src/_locales/en/messages.json +++ b/apps/browser/src/_locales/en/messages.json @@ -2249,5 +2249,26 @@ }, "accessDenied": { "message": "Access denied. You do not have permission to view this page." + }, + "loginPasskey": { + "message": "This login uses a passkey" + }, + "application": { + "message": "Application" + }, + "passkeyEditInformation": { + "message": "You cannot edit passkey application because it would invalidate the passkey." + }, + "duplicatePasskey": { + "message": "A passkey with this ID already exists in this organization." + }, + "passkeyTwoStepLogin": { + "message": "Available for two-step login" + }, + "passkeyNotCopied": { + "message": "Passkey will not be copied" + }, + "passkeyNotCopiedAlert": { + "message": "The passkey will not be copied to the cloned item. Do you want to continue cloning this item?" } } diff --git a/apps/browser/src/vault/popup/components/action-buttons.component.html b/apps/browser/src/vault/popup/components/action-buttons.component.html index f63c1f1ac32..97e41f2f5a0 100644 --- a/apps/browser/src/vault/popup/components/action-buttons.component.html +++ b/apps/browser/src/vault/popup/components/action-buttons.component.html @@ -100,3 +100,41 @@ + + + + + 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 1373669ca17..4033437e59f 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 @@ -21,6 +21,9 @@

{{ "itemInformation" | i18n }}

+
@@ -129,6 +132,17 @@
+ + +
+
+
+ {{ "typePasskey" | i18n }} + {{ "passkeyTwoStepLogin" | i18n }} +
+
+
+
+ +
+
+ + +
+
+ {{ "typePasskey" | i18n }} + {{ "dateCreated" | i18n }} {{ cipher.creationDate | date : "short" }} +
+ +
+
+
+ + +
+
+
+
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 2008001aabc..2065181ba25 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 @@ -70,7 +70,9 @@
{{ "typeLogin" | i18n }}
- {{ typeCounts.get(cipherType.Login) || 0 }} + {{ + getTypeCountsSum(typeCounts, cipherType.Login, cipherType.Fido2Key) + }} -
diff --git a/apps/browser/src/vault/popup/components/vault/vault-filter.component.ts b/apps/browser/src/vault/popup/components/vault/vault-filter.component.ts index 4be0fe89fe1..519e7715ef3 100644 --- a/apps/browser/src/vault/popup/components/vault/vault-filter.component.ts +++ b/apps/browser/src/vault/popup/components/vault/vault-filter.component.ts @@ -255,7 +255,14 @@ export class VaultFilterComponent implements OnInit, OnDestroy { } async launchCipher(cipher: CipherView) { - if (cipher.type !== CipherType.Login || !cipher.login.canLaunch) { + let launchUri: string; + if (cipher.type === CipherType.Login && cipher.login.canLaunch) { + launchUri = cipher.login.launchUri; + } else if (cipher.type === CipherType.Fido2Key && cipher.fido2Key.canLaunch) { + launchUri = cipher.fido2Key.launchUri; + } + + if (!launchUri) { return; } @@ -264,7 +271,7 @@ export class VaultFilterComponent implements OnInit, OnDestroy { } this.preventSelected = true; await this.cipherService.updateLastLaunchedDate(cipher.id); - BrowserApi.createNewTab(cipher.login.launchUri); + BrowserApi.createNewTab(launchUri); if (this.popupUtils.inPopup(window)) { BrowserApi.closePopup(window); } @@ -355,6 +362,10 @@ export class VaultFilterComponent implements OnInit, OnDestroy { this.collectionCounts = collectionCounts; } + getTypeCountsSum(typeCounts: Map, ...types: CipherType[]): number { + return types.reduce((sum, type) => sum + (typeCounts.get(type) || 0), 0); + } + showSearching() { return ( this.hasSearched || (!this.searchPending && this.searchService.isSearchable(this.searchText)) 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 59d7ae92c28..62f0aa14c69 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 @@ -99,6 +99,7 @@ export class VaultItemsComponent extends BaseVaultItemsComponent implements OnIn this.type = parseInt(params.type, null); switch (this.type) { case CipherType.Login: + case CipherType.Fido2Key: this.groupingTitle = this.i18nService.t("logins"); break; case CipherType.Card: @@ -209,7 +210,15 @@ export class VaultItemsComponent extends BaseVaultItemsComponent implements OnIn } async launchCipher(cipher: CipherView) { - if (cipher.type !== CipherType.Login || !cipher.login.canLaunch) { + let launchUri: string; + + if (cipher.type === CipherType.Login && cipher.login.canLaunch) { + launchUri = cipher.login.launchUri; + } else if (cipher.type === CipherType.Fido2Key && cipher.fido2Key.canLaunch) { + launchUri = cipher.fido2Key.launchUri; + } + + if (!launchUri) { return; } @@ -218,7 +227,7 @@ export class VaultItemsComponent extends BaseVaultItemsComponent implements OnIn } this.preventSelected = true; await this.cipherService.updateLastLaunchedDate(cipher.id); - BrowserApi.createNewTab(cipher.login.launchUri); + BrowserApi.createNewTab(launchUri); if (this.popupUtils.inPopup(window)) { BrowserApi.closePopup(window); } @@ -264,7 +273,12 @@ export class VaultItemsComponent extends BaseVaultItemsComponent implements OnIn cipherPassesFilter = cipher.isDeleted; } if (this.type != null && cipherPassesFilter) { - cipherPassesFilter = cipher.type === this.type; + //Fido2Key's should also be included in the Login type + if (this.type === CipherType.Login) { + cipherPassesFilter = cipher.type === this.type || cipher.type === CipherType.Fido2Key; + } else { + cipherPassesFilter = cipher.type === this.type; + } } if (this.folderId != null && this.folderId != "none" && cipherPassesFilter) { cipherPassesFilter = cipher.folderId === this.folderId; 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 99adef3b7c6..f290becfe48 100644 --- a/apps/browser/src/vault/popup/components/vault/view.component.html +++ b/apps/browser/src/vault/popup/components/vault/view.component.html @@ -201,6 +201,16 @@
+ + +
+
+
+ {{ "typePasskey" | i18n }} + {{ "passkeyTwoStepLogin" | i18n }} +
+
+
@@ -416,25 +426,54 @@
-
- {{ "keyType" | i18n }} - {{ cipher.fido2Key.keyType }} -
- -
- {{ "keyCurve" | i18n }} - {{ cipher.fido2Key.keyCurve }} -
- -
- {{ "rpName" | i18n }} - {{ cipher.fido2Key.rpName }} -
-
{{ "username" | i18n }} {{ cipher.fido2Key.userName }}
+
+ {{ "typePasskey" | i18n }} + {{ "dateCreated" | i18n }} {{ cipher.creationDate | date : "short" }} +
+ +
+
+
+
+ + + + +
+
+ + +
+
+
+
diff --git a/apps/browser/src/vault/popup/components/vault/view.component.ts b/apps/browser/src/vault/popup/components/vault/view.component.ts index efdb48b95cd..d769f48f820 100644 --- a/apps/browser/src/vault/popup/components/vault/view.component.ts +++ b/apps/browser/src/vault/popup/components/vault/view.component.ts @@ -21,7 +21,6 @@ import { StateService } from "@bitwarden/common/platform/abstractions/state.serv import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service"; import { FolderService } from "@bitwarden/common/vault/abstractions/folder/folder.service.abstraction"; import { PasswordRepromptService } from "@bitwarden/common/vault/abstractions/password-reprompt.service"; -import { CipherType } from "@bitwarden/common/vault/enums/cipher-type"; import { Cipher } from "@bitwarden/common/vault/models/domain/cipher"; import { LoginUriView } from "@bitwarden/common/vault/models/view/login-uri.view"; @@ -41,7 +40,6 @@ export class ViewComponent extends BaseViewComponent { tab: any; loadPageDetailsTimeout: number; inPopout = false; - cipherType = CipherType; constructor( cipherService: CipherService, diff --git a/apps/desktop/src/locales/en/messages.json b/apps/desktop/src/locales/en/messages.json index 9debdbc13fe..b8cf1f7fbc6 100644 --- a/apps/desktop/src/locales/en/messages.json +++ b/apps/desktop/src/locales/en/messages.json @@ -2268,5 +2268,26 @@ }, "accessDenied": { "message": "Access denied. You do not have permission to view this page." + }, + "typePasskey": { + "message": "Passkey" + }, + "application": { + "message": "Application" + }, + "passkeyEditInformation": { + "message": "You cannot edit passkey application because it would invalidate the passkey." + }, + "duplicatePasskey": { + "message": "A passkey with this ID already exists in this organization." + }, + "passkeyTwoStepLogin": { + "message": "Available for two-step login" + }, + "passkeyNotCopied": { + "message": "Passkey will not be copied" + }, + "passkeyNotCopiedAlert": { + "message": "The passkey will not be copied to the cloned item. Do you want to continue cloning this item?" } } 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 c26078394ad..4b6d1ed5794 100644 --- a/apps/desktop/src/vault/app/vault/add-edit.component.html +++ b/apps/desktop/src/vault/app/vault/add-edit.component.html @@ -114,6 +114,16 @@ + +
+ {{ "typePasskey" | i18n }} + {{ "passkeyTwoStepLogin" | i18n }} +
+
+ +
+
+ + +
+
+ {{ "typePasskey" | i18n }} + {{ "dateCreated" | i18n }} {{ cipher.creationDate | date : "short" }} +
+
@@ -528,6 +556,24 @@
+ +
+
+
+ + +
+
+ +
diff --git a/apps/desktop/src/vault/app/vault/vault.component.ts b/apps/desktop/src/vault/app/vault/vault.component.ts index 5405a913a75..f6c3780412b 100644 --- a/apps/desktop/src/vault/app/vault/vault.component.ts +++ b/apps/desktop/src/vault/app/vault/vault.component.ts @@ -288,7 +288,7 @@ export class VaultComponent implements OnInit, OnDestroy { this.editCipher(cipher); }), }); - if (!cipher.organizationId) { + if (!cipher.organizationId && !cipher.fido2Key?.rpId) { menu.push({ label: this.i18nService.t("clone"), click: () => @@ -359,6 +359,14 @@ export class VaultComponent implements OnInit, OnDestroy { }); } break; + case CipherType.Fido2Key: + if (cipher.fido2Key.canLaunch) { + menu.push({ + label: this.i18nService.t("launch"), + click: () => this.platformUtilsService.launchUri(cipher.fido2Key.launchUri), + }); + } + break; default: break; } diff --git a/apps/desktop/src/vault/app/vault/view.component.html b/apps/desktop/src/vault/app/vault/view.component.html index ac23264c8d6..11327e14ca1 100644 --- a/apps/desktop/src/vault/app/vault/view.component.html +++ b/apps/desktop/src/vault/app/vault/view.component.html @@ -118,6 +118,11 @@
+ +
+ {{ "typePasskey" | i18n }} + {{ "passkeyTwoStepLogin" | i18n }} +
{{ cipher.identity.country }}
+ +
+
+
+ {{ "username" | i18n }} + {{ cipher.fido2Key.userName }} +
+
+
+ {{ "typePasskey" | i18n }} + {{ "dateCreated" | i18n }} {{ cipher.creationDate | date : "short" }} +
+
@@ -465,6 +483,43 @@
{{ cipher.notes }}
+
+
+
+
+ + + + +
+
+ + +
+
+
+
diff --git a/apps/web/src/app/vault/components/vault-items/vault-cipher-row.component.html b/apps/web/src/app/vault/components/vault-items/vault-cipher-row.component.html index 664b3bbc380..15440024153 100644 --- a/apps/web/src/app/vault/components/vault-items/vault-cipher-row.component.html +++ b/apps/web/src/app/vault/components/vault-items/vault-cipher-row.component.html @@ -103,6 +103,20 @@ {{ "launch" | i18n }} + + + + + {{ "launch" | i18n }} + + + + +
+
+ +
+ +
+
+
+
@@ -813,6 +832,89 @@
+ + +
+
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+ +
+
+ +
+ +
+ + +
+
+ {{ "passkeyEditInformation" | i18n }} +
+
+