bitwarden-estensione-browser/apps/web/src/app/settings/two-factor-webauthn.compone...

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

172 lines
5.5 KiB
TypeScript
Raw Normal View History

2018-06-27 23:50:31 +02:00
import { Component, NgZone } from "@angular/core";
2022-06-14 17:10:53 +02:00
import { ApiService } from "@bitwarden/common/abstractions/api.service";
import { I18nService } from "@bitwarden/common/abstractions/i18n.service";
import { LogService } from "@bitwarden/common/abstractions/log.service";
import { PlatformUtilsService } from "@bitwarden/common/abstractions/platformUtils.service";
import { UserVerificationService } from "@bitwarden/common/abstractions/userVerification.service";
import { TwoFactorProviderType } from "@bitwarden/common/enums/twoFactorProviderType";
import { SecretVerificationRequest } from "@bitwarden/common/models/request/secretVerificationRequest";
import { UpdateTwoFactorWebAuthnDeleteRequest } from "@bitwarden/common/models/request/updateTwoFactorWebAuthnDeleteRequest";
import { UpdateTwoFactorWebAuthnRequest } from "@bitwarden/common/models/request/updateTwoFactorWebAuthnRequest";
2018-07-21 06:26:16 +02:00
import {
ChallengeResponse,
2021-03-16 17:44:31 +01:00
TwoFactorWebAuthnResponse,
2022-06-14 17:10:53 +02:00
} from "@bitwarden/common/models/response/twoFactorWebAuthnResponse";
2018-06-27 23:50:31 +02:00
import { TwoFactorBaseComponent } from "./two-factor-base.component";
2018-06-27 23:50:31 +02:00
@Component({
2021-03-16 17:44:31 +01:00
selector: "app-two-factor-webauthn",
templateUrl: "two-factor-webauthn.component.html",
2018-06-27 23:50:31 +02:00
})
2021-03-16 17:44:31 +01:00
export class TwoFactorWebAuthnComponent extends TwoFactorBaseComponent {
type = TwoFactorProviderType.WebAuthn;
2018-10-08 20:23:30 +02:00
name: string;
keys: any[];
keyIdAvailable: number = null;
keysConfiguredCount = 0;
2021-03-16 17:44:31 +01:00
webAuthnError: boolean;
webAuthnListening: boolean;
webAuthnResponse: PublicKeyCredential;
2018-10-08 20:23:30 +02:00
challengePromise: Promise<ChallengeResponse>;
2018-06-27 23:50:31 +02:00
formPromise: Promise<any>;
2021-12-17 15:57:11 +01:00
constructor(
apiService: ApiService,
i18nService: I18nService,
2021-12-07 20:41:45 +01:00
platformUtilsService: PlatformUtilsService,
private ngZone: NgZone,
logService: LogService,
userVerificationService: UserVerificationService
) {
2021-12-07 20:41:45 +01:00
super(apiService, i18nService, platformUtilsService, logService, userVerificationService);
2021-12-17 15:57:11 +01:00
}
auth(authResponse: any) {
super.auth(authResponse);
this.processResponse(authResponse.response);
2021-12-17 15:57:11 +01:00
}
async submit() {
2021-03-16 17:44:31 +01:00
if (this.webAuthnResponse == null || this.keyIdAvailable == null) {
2018-10-08 20:23:30 +02:00
// Should never happen.
return Promise.reject();
2018-06-27 23:50:31 +02:00
}
const request = await this.buildRequestModel(UpdateTwoFactorWebAuthnRequest);
request.deviceResponse = this.webAuthnResponse;
2018-10-08 20:23:30 +02:00
request.id = this.keyIdAvailable;
request.name = this.name;
2021-12-17 15:57:11 +01:00
return super.enable(async () => {
this.formPromise = this.apiService.putTwoFactorWebAuthn(request);
const response = await this.formPromise;
await this.processResponse(response);
2021-12-17 15:57:11 +01:00
});
}
2018-10-08 20:23:30 +02:00
disable() {
return super.disable(this.formPromise);
2021-12-17 15:57:11 +01:00
}
2018-10-08 20:23:30 +02:00
async remove(key: any) {
if (this.keysConfiguredCount <= 1 || key.removePromise != null) {
2021-12-17 15:57:11 +01:00
return;
2018-06-27 23:50:31 +02:00
}
2021-03-16 17:44:31 +01:00
const name = key.name != null ? key.name : this.i18nService.t("webAuthnkeyX", key.id);
const confirmed = await this.platformUtilsService.showDialog(
2021-03-16 17:44:31 +01:00
this.i18nService.t("removeU2fConfirmation"),
2018-10-08 20:23:30 +02:00
name,
2021-03-16 17:44:31 +01:00
this.i18nService.t("yes"),
this.i18nService.t("no"),
"warning"
);
if (!confirmed) {
return;
}
2018-10-08 20:23:30 +02:00
const request = await this.buildRequestModel(UpdateTwoFactorWebAuthnDeleteRequest);
request.id = key.id;
try {
key.removePromise = this.apiService.deleteTwoFactorWebAuthn(request);
const response = await key.removePromise;
key.removePromise = null;
await this.processResponse(response);
} catch (e) {
this.logService.error(e);
2018-10-08 20:23:30 +02:00
}
2021-12-17 15:57:11 +01:00
}
2018-10-08 20:23:30 +02:00
async readKey() {
if (this.keyIdAvailable == null) {
2018-06-27 23:50:31 +02:00
return;
2018-10-08 20:23:30 +02:00
}
const request = await this.buildRequestModel(SecretVerificationRequest);
2018-10-08 20:23:30 +02:00
try {
2021-03-16 17:44:31 +01:00
this.challengePromise = this.apiService.getTwoFactorWebAuthnChallenge(request);
2018-10-08 20:23:30 +02:00
const challenge = await this.challengePromise;
this.readDevice(challenge);
} catch (e) {
this.logService.error(e);
2018-10-08 20:23:30 +02:00
}
2021-12-17 15:57:11 +01:00
}
2021-03-16 17:44:31 +01:00
private readDevice(webAuthnChallenge: ChallengeResponse) {
2022-02-24 12:10:07 +01:00
// eslint-disable-next-line
2018-06-27 23:50:31 +02:00
console.log("listening for key...");
2021-03-16 17:44:31 +01:00
this.resetWebAuthn(true);
2021-12-17 15:57:11 +01:00
2021-03-16 17:44:31 +01:00
navigator.credentials
.create({
publicKey: webAuthnChallenge,
})
.then((data: PublicKeyCredential) => {
2018-10-08 20:23:30 +02:00
this.ngZone.run(() => {
2021-03-16 17:44:31 +01:00
this.webAuthnListening = false;
this.webAuthnResponse = data;
});
2021-12-17 15:57:11 +01:00
})
2021-03-16 17:44:31 +01:00
.catch((err) => {
2022-02-24 12:10:07 +01:00
// eslint-disable-next-line
2021-03-16 17:44:31 +01:00
console.error(err);
this.resetWebAuthn(false);
// TODO: Should we display the actual error?
this.webAuthnError = true;
2021-12-17 15:57:11 +01:00
});
2018-10-08 20:23:30 +02:00
}
2021-12-17 15:57:11 +01:00
2021-03-16 17:44:31 +01:00
private resetWebAuthn(listening = false) {
this.webAuthnResponse = null;
this.webAuthnError = false;
this.webAuthnListening = listening;
2018-06-27 23:50:31 +02:00
}
2021-12-17 15:57:11 +01:00
2021-03-16 17:44:31 +01:00
private processResponse(response: TwoFactorWebAuthnResponse) {
this.resetWebAuthn();
2018-10-08 20:23:30 +02:00
this.keys = [];
this.keyIdAvailable = null;
this.name = null;
this.keysConfiguredCount = 0;
for (let i = 1; i <= 5; i++) {
if (response.keys != null) {
const key = response.keys.filter((k) => k.id === i);
2018-10-08 20:23:30 +02:00
if (key.length > 0) {
this.keysConfiguredCount++;
this.keys.push({
id: i,
name: key[0].name,
configured: true,
2021-03-16 17:44:31 +01:00
migrated: key[0].migrated,
removePromise: null,
});
continue;
2018-10-08 20:23:30 +02:00
}
2021-12-17 15:57:11 +01:00
}
2018-06-27 23:50:31 +02:00
this.keys.push({ id: i, name: null, configured: false, removePromise: null });
if (this.keyIdAvailable == null) {
this.keyIdAvailable = i;
2021-12-17 15:57:11 +01:00
}
2018-06-27 23:50:31 +02:00
}
this.enabled = response.enabled;
2021-12-17 15:57:11 +01:00
}
2018-06-27 23:50:31 +02:00
}