[PM-9959] Add support for Fido2 credential creation in add-edit-v2

This commit is contained in:
Shane Melton 2024-07-26 13:57:13 -07:00
parent 4ab9fe9214
commit 8827fd7067
No known key found for this signature in database
3 changed files with 79 additions and 5 deletions

View File

@ -10,7 +10,8 @@
*ngIf="!loading"
formId="cipherForm"
[config]="config"
(cipherSaved)="onCipherSaved()"
(cipherSaved)="onCipherSaved($event)"
[beforeSubmit]="checkFido2UserVerification"
[submitBtn]="submitBtn"
>
<app-open-attachments

View File

@ -1,14 +1,15 @@
import { CommonModule, Location } from "@angular/common";
import { Component } from "@angular/core";
import { Component, OnInit } from "@angular/core";
import { takeUntilDestroyed } from "@angular/core/rxjs-interop";
import { FormsModule } from "@angular/forms";
import { ActivatedRoute, Params, Router } from "@angular/router";
import { map, switchMap } from "rxjs";
import { firstValueFrom, map, switchMap } from "rxjs";
import { JslibModule } from "@bitwarden/angular/jslib.module";
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
import { CipherId, CollectionId, OrganizationId } from "@bitwarden/common/types/guid";
import { CipherType } from "@bitwarden/common/vault/enums";
import { CipherView } from "@bitwarden/common/vault/models/view/cipher.view";
import { AsyncActionsModule, ButtonModule, SearchModule } from "@bitwarden/components";
import {
CipherFormConfig,
@ -19,10 +20,18 @@ import {
TotpCaptureService,
} from "@bitwarden/vault";
import BrowserPopupUtils from "../../../../../platform/popup/browser-popup-utils";
import { PopupFooterComponent } from "../../../../../platform/popup/layout/popup-footer.component";
import { PopupHeaderComponent } from "../../../../../platform/popup/layout/popup-header.component";
import { PopupPageComponent } from "../../../../../platform/popup/layout/popup-page.component";
import { PopupCloseWarningService } from "../../../../../popup/services/popup-close-warning.service";
import { BrowserFido2UserInterfaceSession } from "../../../../fido2/browser-fido2-user-interface.service";
import { BrowserTotpCaptureService } from "../../../services/browser-totp-capture.service";
import {
fido2PopoutSessionData$,
Fido2SessionData,
} from "../../../utils/fido2-popout-session-data";
import { VaultPopoutType } from "../../../utils/vault-popout-window";
import { OpenAttachmentsComponent } from "../attachments/open-attachments/open-attachments.component";
/**
@ -99,7 +108,7 @@ export type AddEditQueryParams = Partial<Record<keyof QueryParams, string>>;
AsyncActionsModule,
],
})
export class AddEditV2Component {
export class AddEditV2Component implements OnInit {
headerText: string;
config: CipherFormConfig;
@ -111,16 +120,50 @@ export class AddEditV2Component {
return this.config?.originalCipher?.id as CipherId;
}
private fido2PopoutSessionData$ = fido2PopoutSessionData$();
private fido2PopoutSessionData: Fido2SessionData;
private get inFido2PopoutWindow() {
return BrowserPopupUtils.inPopout(window) && this.fido2PopoutSessionData.isFido2Session;
}
private get inSingleActionPopout() {
return BrowserPopupUtils.inSingleActionPopout(window, VaultPopoutType.addEditVaultItem);
}
constructor(
private route: ActivatedRoute,
private location: Location,
private i18nService: I18nService,
private addEditFormConfigService: CipherFormConfigService,
private router: Router,
private popupCloseWarningService: PopupCloseWarningService,
) {
this.subscribeToParams();
}
async ngOnInit() {
this.fido2PopoutSessionData = await firstValueFrom(this.fido2PopoutSessionData$);
if (BrowserPopupUtils.inPopout(window)) {
this.popupCloseWarningService.enable();
}
}
/**
* Called before the form is submitted, allowing us to handle Fido2 user verification.
*/
protected checkFido2UserVerification: () => Promise<boolean> = async () => {
if (!this.inFido2PopoutWindow) {
// Not in a Fido2 popout window, no need to handle user verification.
return true;
}
// TODO use fido2 user verification service once user verification for passkeys is approved for production.
// We are bypassing user verification pending approval for production.
return true;
};
/**
* Navigates to previous view or view-cipher path
* depending on the history length.
@ -129,6 +172,17 @@ export class AddEditV2Component {
* forced into a popout window.
*/
async handleBackButton() {
if (this.inFido2PopoutWindow) {
this.popupCloseWarningService.disable();
BrowserFido2UserInterfaceSession.abortPopout(this.fido2PopoutSessionData.sessionId);
return;
}
if (this.inSingleActionPopout) {
await BrowserPopupUtils.closeSingleActionPopout(VaultPopoutType.addEditVaultItem);
return;
}
if (history.length === 1) {
await this.router.navigate(["/view-cipher"], {
queryParams: { cipherId: this.originalCipherId },
@ -138,7 +192,25 @@ export class AddEditV2Component {
}
}
onCipherSaved() {
async onCipherSaved(cipher: CipherView) {
if (BrowserPopupUtils.inPopout(window)) {
this.popupCloseWarningService.disable();
}
if (this.inFido2PopoutWindow) {
BrowserFido2UserInterfaceSession.confirmNewCredentialResponse(
this.fido2PopoutSessionData.sessionId,
cipher.id,
this.fido2PopoutSessionData.userVerification,
);
return;
}
if (this.inSingleActionPopout) {
await BrowserPopupUtils.closeSingleActionPopout(VaultPopoutType.addEditVaultItem, 1000);
return;
}
this.location.back();
}

View File

@ -397,6 +397,7 @@ export class AddEditComponent extends BaseAddEditComponent {
}
// TODO: Remove and use fido2 user verification service once user verification for passkeys is approved for production.
// Be sure to make the same changes to add-edit-v2.component.ts if applicable
private async handleFido2UserVerification(
sessionId: string,
userVerification: boolean,