[PM-8943] Update QRious script initialization in Authenticator two-factor provider (#9926)
* create onload() for qrious as well as error messaging if QR code cannot be displayed * button and message updates and formpromise removal * load QR script async * rename and reorder methods
This commit is contained in:
parent
83a32cd179
commit
9b509cd329
|
@ -72,7 +72,14 @@
|
|||
</ng-container>
|
||||
<hr *ngIf="enabled" />
|
||||
<p class="tw-text-center tw-mb-0">
|
||||
<canvas id="qr"></canvas><br />
|
||||
<ng-container *ngIf="qrScriptError" class="tw-mt-2">
|
||||
<i class="bwi bwi-error tw-text-3xl tw-text-danger" aria-hidden="true"></i>
|
||||
<p>
|
||||
{{ "twoStepAuthenticatorQRCanvasError" | i18n }}
|
||||
</p>
|
||||
</ng-container>
|
||||
<canvas *ngIf="!qrScriptError" id="qr"></canvas>
|
||||
<br />
|
||||
<code appA11yTitle="{{ 'key' | i18n }}">{{ key }}</code>
|
||||
</p>
|
||||
<bit-form-field *ngIf="!enabled" [disableMargin]="true">
|
||||
|
@ -90,7 +97,7 @@
|
|||
>
|
||||
{{ (enabled ? "disable" : "enable") | i18n }}
|
||||
</button>
|
||||
<button bitButton bitFormButton type="button" buttonType="secondary" [bitAction]="close">
|
||||
<button bitButton bitFormButton type="button" buttonType="secondary" bitDialogClose>
|
||||
{{ "close" | i18n }}
|
||||
</button>
|
||||
</ng-container>
|
||||
|
|
|
@ -43,9 +43,9 @@ export class TwoFactorAuthenticatorComponent
|
|||
@Output() onChangeStatus = new EventEmitter<boolean>();
|
||||
type = TwoFactorProviderType.Authenticator;
|
||||
key: string;
|
||||
formPromise: Promise<TwoFactorAuthenticatorResponse>;
|
||||
|
||||
override componentName = "app-two-factor-authenticator";
|
||||
qrScriptError = false;
|
||||
private qrScript: HTMLScriptElement;
|
||||
|
||||
formGroup = this.formBuilder.group({
|
||||
|
@ -90,7 +90,7 @@ export class TwoFactorAuthenticatorComponent
|
|||
this.formGroup.controls.token.markAsTouched();
|
||||
}
|
||||
|
||||
auth(authResponse: AuthResponse<TwoFactorAuthenticatorResponse>) {
|
||||
async auth(authResponse: AuthResponse<TwoFactorAuthenticatorResponse>) {
|
||||
super.auth(authResponse);
|
||||
return this.processResponse(authResponse.response);
|
||||
}
|
||||
|
@ -100,39 +100,57 @@ export class TwoFactorAuthenticatorComponent
|
|||
return;
|
||||
}
|
||||
if (this.enabled) {
|
||||
await this.disableAuthentication(this.formPromise);
|
||||
this.onChangeStatus.emit(this.enabled);
|
||||
this.close();
|
||||
await this.disableMethod();
|
||||
this.dialogRef.close(this.enabled);
|
||||
} else {
|
||||
await this.enable();
|
||||
}
|
||||
this.onChangeStatus.emit(this.enabled);
|
||||
}
|
||||
};
|
||||
|
||||
private async disableAuthentication(promise: Promise<unknown>) {
|
||||
return super.disable(promise);
|
||||
}
|
||||
|
||||
protected async enable() {
|
||||
const request = await this.buildRequestModel(UpdateTwoFactorAuthenticatorRequest);
|
||||
request.token = this.formGroup.value.token;
|
||||
request.key = this.key;
|
||||
|
||||
return super.enable(async () => {
|
||||
this.formPromise = this.apiService.putTwoFactorAuthenticator(request);
|
||||
const response = await this.formPromise;
|
||||
const response = await this.apiService.putTwoFactorAuthenticator(request);
|
||||
await this.processResponse(response);
|
||||
});
|
||||
this.onUpdated.emit(true);
|
||||
}
|
||||
|
||||
private async processResponse(response: TwoFactorAuthenticatorResponse) {
|
||||
this.formGroup.get("token").setValue(null);
|
||||
this.enabled = response.enabled;
|
||||
this.key = response.key;
|
||||
|
||||
await this.waitForQRiousToLoadOrError().catch((error) => {
|
||||
this.logService.error(error);
|
||||
this.qrScriptError = true;
|
||||
});
|
||||
|
||||
await this.createQRCode();
|
||||
}
|
||||
|
||||
private async waitForQRiousToLoadOrError(): Promise<void> {
|
||||
// Check if QRious is already loaded or if there was an error loading it either way don't wait for it to try and load again
|
||||
if (typeof window.QRious !== "undefined" || this.qrScriptError) {
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
this.qrScript.onload = () => resolve();
|
||||
this.qrScript.onerror = () =>
|
||||
reject(new Error(this.i18nService.t("twoStepAuthenticatorQRCanvasError")));
|
||||
});
|
||||
}
|
||||
|
||||
private async createQRCode() {
|
||||
if (this.qrScriptError) {
|
||||
return;
|
||||
}
|
||||
const email = await firstValueFrom(
|
||||
this.accountService.activeAccount$.pipe(map((a) => a?.email)),
|
||||
);
|
||||
window.setTimeout(() => {
|
||||
new window.QRious({
|
||||
element: document.getElementById("qr"),
|
||||
value:
|
||||
|
@ -143,13 +161,8 @@ export class TwoFactorAuthenticatorComponent
|
|||
"&issuer=Bitwarden",
|
||||
size: 160,
|
||||
});
|
||||
}, 100);
|
||||
}
|
||||
|
||||
close = () => {
|
||||
this.dialogRef.close(this.enabled);
|
||||
};
|
||||
|
||||
static open(
|
||||
dialogService: DialogService,
|
||||
config: DialogConfig<AuthResponse<TwoFactorAuthenticatorResponse>>,
|
||||
|
|
|
@ -1691,6 +1691,9 @@
|
|||
"twoStepAuthenticatorScanCodeV2": {
|
||||
"message": "Scan the QR code below with your authenticator app or enter the key."
|
||||
},
|
||||
"twoStepAuthenticatorQRCanvasError": {
|
||||
"message": "Could not load QR code. Try again or use the key below."
|
||||
},
|
||||
"key": {
|
||||
"message": "Key"
|
||||
},
|
||||
|
|
Loading…
Reference in New Issue