bitwarden-estensione-browser/apps/web/src/app/settings/two-factor-setup.component.ts

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

247 lines
8.6 KiB
TypeScript
Raw Normal View History

2018-06-27 04:51:58 +02:00
import { Component, OnInit, Type, ViewChild, ViewContainerRef } from "@angular/core";
2022-06-14 17:10:53 +02:00
import { ModalRef } from "@bitwarden/angular/components/modal/modal.ref";
import { ModalService } from "@bitwarden/angular/services/modal.service";
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 { MessagingService } from "@bitwarden/common/abstractions/messaging.service";
import { PlatformUtilsService } from "@bitwarden/common/abstractions/platformUtils.service";
import { PolicyService } from "@bitwarden/common/abstractions/policy/policy.service.abstraction";
2022-06-14 17:10:53 +02:00
import { StateService } from "@bitwarden/common/abstractions/state.service";
import { PolicyType } from "@bitwarden/common/enums/policyType";
import { TwoFactorProviderType } from "@bitwarden/common/enums/twoFactorProviderType";
import { DeviceVerificationRequest } from "@bitwarden/common/models/request/deviceVerificationRequest";
import { TwoFactorProviders } from "@bitwarden/common/services/twoFactor.service";
2018-06-27 04:51:58 +02:00
2018-06-27 15:20:09 +02:00
import { TwoFactorAuthenticatorComponent } from "./two-factor-authenticator.component";
2018-06-27 21:27:59 +02:00
import { TwoFactorDuoComponent } from "./two-factor-duo.component";
2018-06-27 22:56:11 +02:00
import { TwoFactorEmailComponent } from "./two-factor-email.component";
2018-06-28 15:40:11 +02:00
import { TwoFactorRecoveryComponent } from "./two-factor-recovery.component";
2021-03-16 17:44:31 +01:00
import { TwoFactorWebAuthnComponent } from "./two-factor-webauthn.component";
2018-06-27 19:45:11 +02:00
import { TwoFactorYubiKeyComponent } from "./two-factor-yubikey.component";
2018-06-27 15:20:09 +02:00
2018-06-27 04:51:58 +02:00
@Component({
selector: "app-two-factor-setup",
templateUrl: "two-factor-setup.component.html",
})
// eslint-disable-next-line rxjs-angular/prefer-takeuntil
2018-06-27 04:51:58 +02:00
export class TwoFactorSetupComponent implements OnInit {
@ViewChild("recoveryTemplate", { read: ViewContainerRef, static: true })
recoveryModalRef: ViewContainerRef;
@ViewChild("authenticatorTemplate", { read: ViewContainerRef, static: true })
authenticatorModalRef: ViewContainerRef;
@ViewChild("yubikeyTemplate", { read: ViewContainerRef, static: true })
yubikeyModalRef: ViewContainerRef;
@ViewChild("duoTemplate", { read: ViewContainerRef, static: true }) duoModalRef: ViewContainerRef;
@ViewChild("emailTemplate", { read: ViewContainerRef, static: true })
emailModalRef: ViewContainerRef;
2021-03-16 17:44:31 +01:00
@ViewChild("webAuthnTemplate", { read: ViewContainerRef, static: true })
webAuthnModalRef: ViewContainerRef;
2021-12-17 15:57:11 +01:00
2018-07-18 23:20:35 +02:00
organizationId: string;
2018-06-27 04:51:58 +02:00
providers: any[] = [];
2018-08-29 05:17:58 +02:00
canAccessPremium: boolean;
showPolicyWarning = false;
2018-06-27 04:51:58 +02:00
loading = true;
enableDeviceVerification: boolean;
isDeviceVerificationSectionEnabled: boolean;
modal: ModalRef;
formPromise: Promise<any>;
2021-12-17 15:57:11 +01:00
[Account Switching] [Refactor] Implement new account centric services (#1220) * [chore] updated services.module to use account services * [refactor] sorted services provided by services.module * [chore] removed references to deleted jslib services * [chore] used activeAccount over storageService for account level storage items * [chore] resolved linter warnings * Refactor activeAccountService to stateService * [bug] Remove uneeded calls to state service on logout This was causing console erros on logout. Clearing of data is handled fully in dedicated services, clearing them in state afterwards is essentially a redundant call. * [bug] Add back null locked callback to VaultTimeoutService * Move call to get showUpdateKey * [bug] Ensure HtmlStorageService does not override StateService options and locations * [bug] Adjust theme logic to pull from the new storage locations * [bug] Correct theme not sticking on refresh * [bug] Add enableFullWidth to the account model * [bug] fix theme option empty when light is selected * [bug] init state on application start * [bug] Reinit state when coming back from a lock * [style] Fix lint complaints * [bug] Clean state on logout * [chore] Resolved merge issues * [bug] Correct default for enableGravitars * Bump angular to 12. * Remove angular.json * Bump rxjs * Fix build errors, remove file-loader with asset/resource * Use contenthash * Bump jslib * Bump ngx-toastr * [chore] resolve issues from merge * [chore] resolve issues from merge * [bug] Add missing bracket * Use newer import syntax * [bug] Correct service orge * [style] Fix lint complaints * [chore] update jslib * [review] Address code review * [review] Address code review * [review] Rename providerService to webProviderService Co-authored-by: Robyn MacCallum <robyntmaccallum@gmail.com> Co-authored-by: Hinton <oscar@oscarhinton.com>
2021-12-14 17:10:26 +01:00
constructor(
protected apiService: ApiService,
protected modalService: ModalService,
protected messagingService: MessagingService,
protected policyService: PolicyService,
private stateService: StateService,
private platformUtilsService: PlatformUtilsService,
private i18nService: I18nService,
private logService: LogService
[Account Switching] [Refactor] Implement new account centric services (#1220) * [chore] updated services.module to use account services * [refactor] sorted services provided by services.module * [chore] removed references to deleted jslib services * [chore] used activeAccount over storageService for account level storage items * [chore] resolved linter warnings * Refactor activeAccountService to stateService * [bug] Remove uneeded calls to state service on logout This was causing console erros on logout. Clearing of data is handled fully in dedicated services, clearing them in state afterwards is essentially a redundant call. * [bug] Add back null locked callback to VaultTimeoutService * Move call to get showUpdateKey * [bug] Ensure HtmlStorageService does not override StateService options and locations * [bug] Adjust theme logic to pull from the new storage locations * [bug] Correct theme not sticking on refresh * [bug] Add enableFullWidth to the account model * [bug] fix theme option empty when light is selected * [bug] init state on application start * [bug] Reinit state when coming back from a lock * [style] Fix lint complaints * [bug] Clean state on logout * [chore] Resolved merge issues * [bug] Correct default for enableGravitars * Bump angular to 12. * Remove angular.json * Bump rxjs * Fix build errors, remove file-loader with asset/resource * Use contenthash * Bump jslib * Bump ngx-toastr * [chore] resolve issues from merge * [chore] resolve issues from merge * [bug] Add missing bracket * Use newer import syntax * [bug] Correct service orge * [style] Fix lint complaints * [chore] update jslib * [review] Address code review * [review] Address code review * [review] Rename providerService to webProviderService Co-authored-by: Robyn MacCallum <robyntmaccallum@gmail.com> Co-authored-by: Hinton <oscar@oscarhinton.com>
2021-12-14 17:10:26 +01:00
) {}
2021-12-17 15:57:11 +01:00
2018-06-27 04:51:58 +02:00
async ngOnInit() {
[Account Switching] [Refactor] Implement new account centric services (#1220) * [chore] updated services.module to use account services * [refactor] sorted services provided by services.module * [chore] removed references to deleted jslib services * [chore] used activeAccount over storageService for account level storage items * [chore] resolved linter warnings * Refactor activeAccountService to stateService * [bug] Remove uneeded calls to state service on logout This was causing console erros on logout. Clearing of data is handled fully in dedicated services, clearing them in state afterwards is essentially a redundant call. * [bug] Add back null locked callback to VaultTimeoutService * Move call to get showUpdateKey * [bug] Ensure HtmlStorageService does not override StateService options and locations * [bug] Adjust theme logic to pull from the new storage locations * [bug] Correct theme not sticking on refresh * [bug] Add enableFullWidth to the account model * [bug] fix theme option empty when light is selected * [bug] init state on application start * [bug] Reinit state when coming back from a lock * [style] Fix lint complaints * [bug] Clean state on logout * [chore] Resolved merge issues * [bug] Correct default for enableGravitars * Bump angular to 12. * Remove angular.json * Bump rxjs * Fix build errors, remove file-loader with asset/resource * Use contenthash * Bump jslib * Bump ngx-toastr * [chore] resolve issues from merge * [chore] resolve issues from merge * [bug] Add missing bracket * Use newer import syntax * [bug] Correct service orge * [style] Fix lint complaints * [chore] update jslib * [review] Address code review * [review] Address code review * [review] Rename providerService to webProviderService Co-authored-by: Robyn MacCallum <robyntmaccallum@gmail.com> Co-authored-by: Hinton <oscar@oscarhinton.com>
2021-12-14 17:10:26 +01:00
this.canAccessPremium = await this.stateService.getCanAccessPremium();
try {
const deviceVerificationSettings = await this.apiService.getDeviceVerificationSettings();
this.isDeviceVerificationSectionEnabled =
deviceVerificationSettings.isDeviceVerificationSectionEnabled;
this.enableDeviceVerification = deviceVerificationSettings.unknownDeviceVerificationEnabled;
} catch (e) {
this.logService.error(e);
}
2021-12-17 15:57:11 +01:00
2018-06-27 04:51:58 +02:00
for (const key in TwoFactorProviders) {
2022-02-24 12:10:07 +01:00
// eslint-disable-next-line
2018-06-27 04:51:58 +02:00
if (!TwoFactorProviders.hasOwnProperty(key)) {
continue;
}
2021-12-17 15:57:11 +01:00
2018-06-27 04:51:58 +02:00
const p = (TwoFactorProviders as any)[key];
2018-07-18 23:10:26 +02:00
if (this.filterProvider(p.type)) {
2018-06-27 04:51:58 +02:00
continue;
}
2021-12-17 15:57:11 +01:00
2018-06-27 04:51:58 +02:00
this.providers.push({
type: p.type,
name: p.name,
description: p.description,
enabled: false,
premium: p.premium,
sort: p.sort,
});
}
this.providers.sort((a: any, b: any) => a.sort - b.sort);
await this.load();
2021-12-17 15:57:11 +01:00
}
2018-06-27 04:51:58 +02:00
async load() {
this.loading = true;
2018-07-18 23:10:26 +02:00
const providerList = await this.getTwoFactorProviders();
providerList.data.forEach((p) => {
this.providers.forEach((p2) => {
2018-06-27 04:51:58 +02:00
if (p.type === p2.type) {
p2.enabled = p.enabled;
2021-12-17 15:57:11 +01:00
}
});
});
this.evaluatePolicies();
2018-06-27 04:51:58 +02:00
this.loading = false;
}
2021-12-17 15:57:11 +01:00
async manage(type: TwoFactorProviderType) {
2018-06-27 15:20:09 +02:00
switch (type) {
2022-02-24 12:10:07 +01:00
case TwoFactorProviderType.Authenticator: {
const authComp = await this.openModal(
this.authenticatorModalRef,
TwoFactorAuthenticatorComponent
2021-12-17 15:57:11 +01:00
);
// eslint-disable-next-line rxjs-angular/prefer-takeuntil
2018-06-27 19:45:11 +02:00
authComp.onUpdated.subscribe((enabled: boolean) => {
2018-06-27 21:27:59 +02:00
this.updateStatus(enabled, TwoFactorProviderType.Authenticator);
2021-12-17 15:57:11 +01:00
});
break;
2022-02-24 12:10:07 +01:00
}
case TwoFactorProviderType.Yubikey: {
const yubiComp = await this.openModal(this.yubikeyModalRef, TwoFactorYubiKeyComponent);
// eslint-disable-next-line rxjs-angular/prefer-takeuntil
2018-06-27 19:45:11 +02:00
yubiComp.onUpdated.subscribe((enabled: boolean) => {
2018-06-27 21:27:59 +02:00
this.updateStatus(enabled, TwoFactorProviderType.Yubikey);
2018-06-27 04:51:58 +02:00
});
2021-12-17 15:57:11 +01:00
break;
2022-02-24 12:10:07 +01:00
}
case TwoFactorProviderType.Duo: {
const duoComp = await this.openModal(this.duoModalRef, TwoFactorDuoComponent);
// eslint-disable-next-line rxjs-angular/prefer-takeuntil
2018-06-27 21:27:59 +02:00
duoComp.onUpdated.subscribe((enabled: boolean) => {
this.updateStatus(enabled, TwoFactorProviderType.Duo);
2018-06-27 04:51:58 +02:00
});
2021-12-17 15:57:11 +01:00
break;
2022-02-24 12:10:07 +01:00
}
case TwoFactorProviderType.Email: {
const emailComp = await this.openModal(this.emailModalRef, TwoFactorEmailComponent);
// eslint-disable-next-line rxjs-angular/prefer-takeuntil
emailComp.onUpdated.subscribe((enabled: boolean) => {
this.updateStatus(enabled, TwoFactorProviderType.Email);
2018-06-27 04:51:58 +02:00
});
2021-12-17 15:57:11 +01:00
break;
2022-02-24 12:10:07 +01:00
}
case TwoFactorProviderType.WebAuthn: {
2018-06-27 04:51:58 +02:00
const webAuthnComp = await this.openModal(
this.webAuthnModalRef,
TwoFactorWebAuthnComponent
2021-12-17 15:57:11 +01:00
);
// eslint-disable-next-line rxjs-angular/prefer-takeuntil
2021-03-16 17:44:31 +01:00
webAuthnComp.onUpdated.subscribe((enabled: boolean) => {
this.updateStatus(enabled, TwoFactorProviderType.WebAuthn);
2021-12-17 15:57:11 +01:00
});
break;
2022-02-24 12:10:07 +01:00
}
2021-12-17 15:57:11 +01:00
default:
break;
2018-06-27 04:51:58 +02:00
}
2021-12-17 15:57:11 +01:00
}
2018-06-27 15:20:09 +02:00
recoveryCode() {
this.openModal(this.recoveryModalRef, TwoFactorRecoveryComponent);
2018-06-27 15:20:09 +02:00
}
2018-06-28 15:40:11 +02:00
async premiumRequired() {
if (!this.canAccessPremium) {
this.messagingService.send("premiumRequired");
2021-12-17 15:57:11 +01:00
return;
2018-06-28 15:40:11 +02:00
}
2021-12-17 15:57:11 +01:00
}
2018-06-28 15:40:11 +02:00
2018-07-18 15:21:23 +02:00
protected getTwoFactorProviders() {
return this.apiService.getTwoFactorProviders();
}
2018-07-18 23:10:26 +02:00
protected filterProvider(type: TwoFactorProviderType) {
return type === TwoFactorProviderType.OrganizationDuo;
}
protected async openModal<T>(ref: ViewContainerRef, type: Type<T>): Promise<T> {
const [modal, childComponent] = await this.modalService.openViewRef(type, ref);
this.modal = modal;
return childComponent;
2021-12-17 15:57:11 +01:00
}
2018-06-27 15:20:09 +02:00
protected updateStatus(enabled: boolean, type: TwoFactorProviderType) {
if (!enabled && this.modal != null) {
this.modal.close();
}
this.providers.forEach((p) => {
2018-06-27 15:20:09 +02:00
if (p.type === type) {
p.enabled = enabled;
}
});
this.evaluatePolicies();
}
2021-12-17 15:57:11 +01:00
private async evaluatePolicies() {
if (this.organizationId == null && this.providers.filter((p) => p.enabled).length === 1) {
this.showPolicyWarning = await this.policyService.policyAppliesToUser(
PolicyType.TwoFactorAuthentication
);
} else {
this.showPolicyWarning = false;
2018-06-27 15:20:09 +02:00
}
2021-12-17 15:57:11 +01:00
}
async submit() {
try {
if (this.enableDeviceVerification) {
const email = await this.stateService.getEmail();
const confirmed = await this.platformUtilsService.showDialog(
this.i18nService.t(
"areYouSureYouWantToEnableDeviceVerificationTheVerificationCodeEmailsWillArriveAtX",
email
),
this.i18nService.t("deviceVerification"),
this.i18nService.t("yes"),
this.i18nService.t("no"),
"warning"
);
if (!confirmed) {
return;
}
}
this.formPromise = this.apiService.putDeviceVerificationSettings(
new DeviceVerificationRequest(this.enableDeviceVerification)
);
await this.formPromise;
this.platformUtilsService.showToast(
"success",
null,
this.i18nService.t("updatedDeviceVerification")
);
} catch (e) {
this.logService.error(e);
}
}
2018-06-27 04:51:58 +02:00
}