mirror of
https://github.com/bitwarden/browser
synced 2026-01-06 02:23:44 +00:00
[PM-4168] Enable encryption for registered passkeys (#7074)
* Added enable encryption * various updates and tests added. * fixing linter errors * updated spec file
This commit is contained in:
@@ -94,7 +94,7 @@ export class CreateCredentialDialogComponent implements OnInit {
|
||||
}
|
||||
|
||||
try {
|
||||
this.credentialOptions = await this.webauthnService.getCredentialCreateOptions(
|
||||
this.credentialOptions = await this.webauthnService.getCredentialAttestationOptions(
|
||||
this.formGroup.value.userVerification.secret,
|
||||
);
|
||||
} catch (error) {
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
<form [formGroup]="formGroup" [bitSubmit]="submit">
|
||||
<bit-dialog dialogSize="large" [loading]="loading$ | async">
|
||||
<span bitDialogTitle
|
||||
>{{ "enablePasskeyEncryption" | i18n }}
|
||||
<span *ngIf="credential" class="tw-text-sm tw-normal-case tw-text-muted">{{
|
||||
credential.name
|
||||
}}</span>
|
||||
</span>
|
||||
<ng-container bitDialogContent>
|
||||
<ng-container *ngIf="!credential">
|
||||
<i class="bwi bwi-spinner bwi-spin tw-ml-1" aria-hidden="true"></i>
|
||||
</ng-container>
|
||||
|
||||
<ng-container *ngIf="credential">
|
||||
<p bitTypography="body1">{{ "useForVaultEncryptionInfo" | i18n }}</p>
|
||||
|
||||
<ng-container formGroupName="userVerification">
|
||||
<app-user-verification
|
||||
formControlName="secret"
|
||||
[(invalidSecret)]="invalidSecret"
|
||||
></app-user-verification>
|
||||
</ng-container>
|
||||
</ng-container>
|
||||
</ng-container>
|
||||
<ng-container bitDialogFooter>
|
||||
<button type="submit" bitButton bitFormButton buttonType="primary">
|
||||
{{ "submit" | i18n }}
|
||||
</button>
|
||||
<button type="button" bitButton bitFormButton buttonType="secondary" bitDialogClose>
|
||||
{{ "cancel" | i18n }}
|
||||
</button>
|
||||
</ng-container>
|
||||
</bit-dialog>
|
||||
</form>
|
||||
@@ -0,0 +1,91 @@
|
||||
import { DIALOG_DATA, DialogConfig, DialogRef } from "@angular/cdk/dialog";
|
||||
import { Component, Inject, OnDestroy, OnInit } from "@angular/core";
|
||||
import { FormBuilder, Validators } from "@angular/forms";
|
||||
import { Subject } from "rxjs";
|
||||
import { takeUntil } from "rxjs/operators";
|
||||
|
||||
import { WebAuthnLoginServiceAbstraction } from "@bitwarden/common/auth/abstractions/webauthn/webauthn-login.service.abstraction";
|
||||
import { WebAuthnLoginCredentialAssertionOptionsView } from "@bitwarden/common/auth/models/view/webauthn-login/webauthn-login-credential-assertion-options.view";
|
||||
import { Verification } from "@bitwarden/common/auth/types/verification";
|
||||
import { ErrorResponse } from "@bitwarden/common/models/response/error.response";
|
||||
import { DialogService } from "@bitwarden/components/src/dialog/dialog.service";
|
||||
|
||||
import { WebauthnLoginAdminService } from "../../../core/services/webauthn-login/webauthn-login-admin.service";
|
||||
import { WebauthnLoginCredentialView } from "../../../core/views/webauthn-login-credential.view";
|
||||
|
||||
export interface EnableEncryptionDialogParams {
|
||||
credentialId: string;
|
||||
}
|
||||
|
||||
@Component({
|
||||
templateUrl: "enable-encryption-dialog.component.html",
|
||||
})
|
||||
export class EnableEncryptionDialogComponent implements OnInit, OnDestroy {
|
||||
private destroy$ = new Subject<void>();
|
||||
|
||||
protected invalidSecret = false;
|
||||
protected formGroup = this.formBuilder.group({
|
||||
userVerification: this.formBuilder.group({
|
||||
secret: [null as Verification | null, Validators.required],
|
||||
}),
|
||||
});
|
||||
|
||||
protected credential?: WebauthnLoginCredentialView;
|
||||
protected credentialOptions?: WebAuthnLoginCredentialAssertionOptionsView;
|
||||
protected loading$ = this.webauthnService.loading$;
|
||||
|
||||
constructor(
|
||||
@Inject(DIALOG_DATA) private params: EnableEncryptionDialogParams,
|
||||
private formBuilder: FormBuilder,
|
||||
private dialogRef: DialogRef,
|
||||
private webauthnService: WebauthnLoginAdminService,
|
||||
private webauthnLoginService: WebAuthnLoginServiceAbstraction,
|
||||
) {}
|
||||
|
||||
ngOnInit(): void {
|
||||
this.webauthnService
|
||||
.getCredential$(this.params.credentialId)
|
||||
.pipe(takeUntil(this.destroy$))
|
||||
.subscribe((credential: any) => (this.credential = credential));
|
||||
}
|
||||
|
||||
submit = async () => {
|
||||
if (this.credential === undefined) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.dialogRef.disableClose = true;
|
||||
try {
|
||||
this.credentialOptions = await this.webauthnService.getCredentialAssertOptions(
|
||||
this.formGroup.value.userVerification.secret,
|
||||
);
|
||||
await this.webauthnService.enableCredentialEncryption(
|
||||
await this.webauthnLoginService.assertCredential(this.credentialOptions),
|
||||
);
|
||||
} catch (error) {
|
||||
if (error instanceof ErrorResponse && error.statusCode === 400) {
|
||||
this.invalidSecret = true;
|
||||
}
|
||||
throw error;
|
||||
}
|
||||
|
||||
this.dialogRef.close();
|
||||
};
|
||||
|
||||
ngOnDestroy(): void {
|
||||
this.destroy$.next();
|
||||
this.destroy$.complete();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Strongly typed helper to open a EnableEncryptionDialogComponent
|
||||
* @param dialogService Instance of the dialog service that will be used to open the dialog
|
||||
* @param config Configuration for the dialog
|
||||
*/
|
||||
export const openEnableCredentialDialogComponent = (
|
||||
dialogService: DialogService,
|
||||
config: DialogConfig<EnableEncryptionDialogParams>,
|
||||
) => {
|
||||
return dialogService.open<unknown>(EnableEncryptionDialogComponent, config);
|
||||
};
|
||||
@@ -39,8 +39,16 @@
|
||||
<span bitTypography="body1" class="tw-text-muted">{{ "usedForEncryption" | i18n }}</span>
|
||||
</ng-container>
|
||||
<ng-container *ngIf="credential.prfStatus === WebauthnLoginCredentialPrfStatus.Supported">
|
||||
<i class="bwi bwi-lock-encrypted"></i>
|
||||
<span bitTypography="body1" class="tw-text-muted">{{ "encryptionNotEnabled" | i18n }}</span>
|
||||
<button
|
||||
type="button"
|
||||
bitLink
|
||||
[disabled]="loading"
|
||||
[attr.aria-label]="('enablePasskeyEncryption' | i18n) + ' ' + credential.name"
|
||||
(click)="enableEncryption(credential.id)"
|
||||
>
|
||||
<i class="bwi bwi-lock-encrypted"></i>
|
||||
{{ "enablePasskeyEncryption" | i18n }}
|
||||
</button>
|
||||
</ng-container>
|
||||
<span
|
||||
*ngIf="credential.prfStatus === WebauthnLoginCredentialPrfStatus.Unsupported"
|
||||
|
||||
@@ -11,6 +11,7 @@ import { WebauthnLoginCredentialView } from "../../core/views/webauthn-login-cre
|
||||
|
||||
import { openCreateCredentialDialog } from "./create-credential-dialog/create-credential-dialog.component";
|
||||
import { openDeleteCredentialDialogComponent } from "./delete-credential-dialog/delete-credential-dialog.component";
|
||||
import { openEnableCredentialDialogComponent } from "./enable-encryption-dialog/enable-encryption-dialog.component";
|
||||
|
||||
@Component({
|
||||
selector: "app-webauthn-login-settings",
|
||||
@@ -83,4 +84,8 @@ export class WebauthnLoginSettingsComponent implements OnInit, OnDestroy {
|
||||
protected deleteCredential(credentialId: string) {
|
||||
openDeleteCredentialDialogComponent(this.dialogService, { data: { credentialId } });
|
||||
}
|
||||
|
||||
protected enableEncryption(credentialId: string) {
|
||||
openEnableCredentialDialogComponent(this.dialogService, { data: { credentialId } });
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@ import { UserVerificationModule } from "../../shared/components/user-verificatio
|
||||
|
||||
import { CreateCredentialDialogComponent } from "./create-credential-dialog/create-credential-dialog.component";
|
||||
import { DeleteCredentialDialogComponent } from "./delete-credential-dialog/delete-credential-dialog.component";
|
||||
import { EnableEncryptionDialogComponent } from "./enable-encryption-dialog/enable-encryption-dialog.component";
|
||||
import { WebauthnLoginSettingsComponent } from "./webauthn-login-settings.component";
|
||||
|
||||
@NgModule({
|
||||
@@ -16,6 +17,7 @@ import { WebauthnLoginSettingsComponent } from "./webauthn-login-settings.compon
|
||||
WebauthnLoginSettingsComponent,
|
||||
CreateCredentialDialogComponent,
|
||||
DeleteCredentialDialogComponent,
|
||||
EnableEncryptionDialogComponent,
|
||||
],
|
||||
exports: [WebauthnLoginSettingsComponent],
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user