[PM-3722] Use `UserVerificationPrompt` in passkey registration dialog (#6422)
* [PM-3722] fix: wrong translation bug * [PM-3722] feat: use user verification component during creation * [PM-3722] feat: use user verification component during deletion * [PM-3722] feat: improve error handling
This commit is contained in:
parent
22a138a46f
commit
317d652088
|
@ -9,12 +9,12 @@
|
|||
<p bitTypography="body1">
|
||||
{{ "passkeyEnterMasterPassword" | i18n }}
|
||||
</p>
|
||||
<bit-form-field disableMargin formGroupName="userVerification">
|
||||
<bit-label>{{ "masterPassword" | i18n }}</bit-label>
|
||||
<input type="password" bitInput formControlName="masterPassword" appAutofocus />
|
||||
<button type="button" bitIconButton bitSuffix bitPasswordInputToggle></button>
|
||||
<bit-hint>{{ "confirmIdentity" | i18n }}</bit-hint>
|
||||
</bit-form-field>
|
||||
<ng-container formGroupName="userVerification">
|
||||
<app-user-verification
|
||||
formControlName="secret"
|
||||
[(invalidSecret)]="invalidSecret"
|
||||
></app-user-verification>
|
||||
</ng-container>
|
||||
</ng-container>
|
||||
|
||||
<div *ngIf="currentStep === 'credentialCreation'" class="tw-flex tw-flex-col tw-items-center">
|
||||
|
|
|
@ -3,11 +3,11 @@ import { Component, OnInit } from "@angular/core";
|
|||
import { FormBuilder, Validators } from "@angular/forms";
|
||||
import { firstValueFrom, map, Observable } from "rxjs";
|
||||
|
||||
import { VerificationType } from "@bitwarden/common/auth/enums/verification-type";
|
||||
import { ErrorResponse } from "@bitwarden/common/models/response/error.response";
|
||||
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
||||
import { LogService } from "@bitwarden/common/platform/abstractions/log.service";
|
||||
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
|
||||
import { Verification } from "@bitwarden/common/types/verification";
|
||||
import { DialogService } from "@bitwarden/components";
|
||||
|
||||
import { WebauthnLoginService } from "../../../core";
|
||||
|
@ -35,9 +35,10 @@ export class CreateCredentialDialogComponent implements OnInit {
|
|||
protected readonly Icons = { CreatePasskeyIcon, CreatePasskeyFailedIcon };
|
||||
|
||||
protected currentStep: Step = "userVerification";
|
||||
protected invalidSecret = false;
|
||||
protected formGroup = this.formBuilder.group({
|
||||
userVerification: this.formBuilder.group({
|
||||
masterPassword: ["", [Validators.required]],
|
||||
secret: [null as Verification | null, Validators.required],
|
||||
}),
|
||||
credentialNaming: this.formBuilder.group({
|
||||
name: ["", Validators.maxLength(50)],
|
||||
|
@ -89,20 +90,19 @@ export class CreateCredentialDialogComponent implements OnInit {
|
|||
}
|
||||
|
||||
try {
|
||||
this.credentialOptions = await this.webauthnService.getCredentialCreateOptions({
|
||||
type: VerificationType.MasterPassword,
|
||||
secret: this.formGroup.value.userVerification.masterPassword,
|
||||
});
|
||||
this.credentialOptions = await this.webauthnService.getCredentialCreateOptions(
|
||||
this.formGroup.value.userVerification.secret
|
||||
);
|
||||
} catch (error) {
|
||||
if (error instanceof ErrorResponse && error.statusCode === 400) {
|
||||
this.platformUtilsService.showToast(
|
||||
"error",
|
||||
this.i18nService.t("error"),
|
||||
this.i18nService.t("invalidMasterPassword")
|
||||
);
|
||||
this.invalidSecret = true;
|
||||
} else {
|
||||
this.logService?.error(error);
|
||||
this.platformUtilsService.showToast("error", null, this.i18nService.t("unexpectedError"));
|
||||
this.platformUtilsService.showToast(
|
||||
"error",
|
||||
this.i18nService.t("unexpectedError"),
|
||||
error.message
|
||||
);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
@ -141,7 +141,11 @@ export class CreateCredentialDialogComponent implements OnInit {
|
|||
);
|
||||
} catch (error) {
|
||||
this.logService?.error(error);
|
||||
this.platformUtilsService.showToast("error", null, this.i18nService.t("unexpectedError"));
|
||||
this.platformUtilsService.showToast(
|
||||
"error",
|
||||
this.i18nService.t("unexpectedError"),
|
||||
error.message
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -14,12 +14,10 @@
|
|||
<ng-container *ngIf="credential">
|
||||
<p bitTypography="body1">{{ "removePasskeyInfo" | i18n }}</p>
|
||||
|
||||
<bit-form-field disableMargin>
|
||||
<bit-label>{{ "masterPassword" | i18n }}</bit-label>
|
||||
<input type="password" bitInput formControlName="masterPassword" />
|
||||
<button type="button" bitIconButton bitSuffix bitPasswordInputToggle></button>
|
||||
<bit-hint>{{ "confirmIdentity" | i18n }}</bit-hint>
|
||||
</bit-form-field>
|
||||
<app-user-verification
|
||||
formControlName="secret"
|
||||
[(invalidSecret)]="invalidSecret"
|
||||
></app-user-verification>
|
||||
</ng-container>
|
||||
</ng-container>
|
||||
<ng-container bitDialogFooter>
|
||||
|
|
|
@ -1,13 +1,13 @@
|
|||
import { DialogConfig, DialogRef, DIALOG_DATA } from "@angular/cdk/dialog";
|
||||
import { Component, Inject, OnDestroy, OnInit } from "@angular/core";
|
||||
import { FormBuilder, Validators } from "@angular/forms";
|
||||
import { FormBuilder } from "@angular/forms";
|
||||
import { Subject, takeUntil } from "rxjs";
|
||||
|
||||
import { VerificationType } from "@bitwarden/common/auth/enums/verification-type";
|
||||
import { ErrorResponse } from "@bitwarden/common/models/response/error.response";
|
||||
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
||||
import { LogService } from "@bitwarden/common/platform/abstractions/log.service";
|
||||
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
|
||||
import { Verification } from "@bitwarden/common/types/verification";
|
||||
import { DialogService } from "@bitwarden/components";
|
||||
|
||||
import { WebauthnLoginService } from "../../../core";
|
||||
|
@ -23,8 +23,9 @@ export interface DeleteCredentialDialogParams {
|
|||
export class DeleteCredentialDialogComponent implements OnInit, OnDestroy {
|
||||
private destroy$ = new Subject<void>();
|
||||
|
||||
protected invalidSecret = false;
|
||||
protected formGroup = this.formBuilder.group({
|
||||
masterPassword: ["", [Validators.required]],
|
||||
secret: null as Verification | null,
|
||||
});
|
||||
protected credential?: WebauthnCredentialView;
|
||||
protected loading$ = this.webauthnService.loading$;
|
||||
|
@ -53,21 +54,18 @@ export class DeleteCredentialDialogComponent implements OnInit, OnDestroy {
|
|||
|
||||
this.dialogRef.disableClose = true;
|
||||
try {
|
||||
await this.webauthnService.deleteCredential(this.credential.id, {
|
||||
type: VerificationType.MasterPassword,
|
||||
secret: this.formGroup.value.masterPassword,
|
||||
});
|
||||
await this.webauthnService.deleteCredential(this.credential.id, this.formGroup.value.secret);
|
||||
this.platformUtilsService.showToast("success", null, this.i18nService.t("passkeyRemoved"));
|
||||
} catch (error) {
|
||||
if (error instanceof ErrorResponse && error.statusCode === 400) {
|
||||
this.invalidSecret = true;
|
||||
} else {
|
||||
this.logService?.error(error);
|
||||
this.platformUtilsService.showToast(
|
||||
"error",
|
||||
this.i18nService.t("error"),
|
||||
this.i18nService.t("invalidMasterPassword")
|
||||
this.i18nService.t("unexpectedError"),
|
||||
error.message
|
||||
);
|
||||
} else {
|
||||
this.logService.error(error);
|
||||
this.platformUtilsService.showToast("error", null, this.i18nService.t("unexpectedError"));
|
||||
}
|
||||
return false;
|
||||
} finally {
|
||||
|
|
|
@ -2,13 +2,14 @@ import { NgModule } from "@angular/core";
|
|||
import { FormsModule, ReactiveFormsModule } from "@angular/forms";
|
||||
|
||||
import { SharedModule } from "../../../shared/shared.module";
|
||||
import { UserVerificationModule } from "../../shared/components/user-verification";
|
||||
|
||||
import { CreateCredentialDialogComponent } from "./create-credential-dialog/create-credential-dialog.component";
|
||||
import { DeleteCredentialDialogComponent } from "./delete-credential-dialog/delete-credential-dialog.component";
|
||||
import { WebauthnLoginSettingsComponent } from "./webauthn-login-settings.component";
|
||||
|
||||
@NgModule({
|
||||
imports: [SharedModule, FormsModule, ReactiveFormsModule],
|
||||
imports: [SharedModule, FormsModule, ReactiveFormsModule, UserVerificationModule],
|
||||
declarations: [
|
||||
WebauthnLoginSettingsComponent,
|
||||
CreateCredentialDialogComponent,
|
||||
|
|
|
@ -51,8 +51,8 @@ export class UserVerificationComponent implements ControlValueAccessor, OnInit,
|
|||
return {
|
||||
invalidSecret: {
|
||||
message: this.hasMasterPassword
|
||||
? this.i18nService.t("incorrectCode")
|
||||
: this.i18nService.t("incorrectPassword"),
|
||||
? this.i18nService.t("incorrectPassword")
|
||||
: this.i18nService.t("incorrectCode"),
|
||||
},
|
||||
};
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue