2022-06-14 17:10:53 +02:00
|
|
|
import { DOCUMENT } from "@angular/common";
|
2022-06-06 19:08:06 +02:00
|
|
|
import { Component, Inject, NgZone, OnDestroy, OnInit, SecurityContext } from "@angular/core";
|
2018-10-03 16:33:04 +02:00
|
|
|
import { DomSanitizer } from "@angular/platform-browser";
|
2018-06-09 19:59:09 +02:00
|
|
|
import { NavigationEnd, Router } from "@angular/router";
|
2021-12-07 20:41:45 +01:00
|
|
|
import * as jq from "jquery";
|
|
|
|
import { IndividualConfig, ToastrService } from "ngx-toastr";
|
2022-07-12 15:02:19 +02:00
|
|
|
import { Subject, takeUntil } from "rxjs";
|
2021-12-07 20:41:45 +01:00
|
|
|
import Swal from "sweetalert2";
|
2018-06-05 05:10:41 +02:00
|
|
|
|
2022-06-14 17:10:53 +02:00
|
|
|
import { AuthService } from "@bitwarden/common/abstractions/auth.service";
|
|
|
|
import { BroadcasterService } from "@bitwarden/common/abstractions/broadcaster.service";
|
|
|
|
import { CipherService } from "@bitwarden/common/abstractions/cipher.service";
|
|
|
|
import { CollectionService } from "@bitwarden/common/abstractions/collection.service";
|
|
|
|
import { CryptoService } from "@bitwarden/common/abstractions/crypto.service";
|
|
|
|
import { EventService } from "@bitwarden/common/abstractions/event.service";
|
2022-07-08 15:40:31 +02:00
|
|
|
import { InternalFolderService } from "@bitwarden/common/abstractions/folder/folder.service.abstraction";
|
2022-06-14 17:10:53 +02:00
|
|
|
import { I18nService } from "@bitwarden/common/abstractions/i18n.service";
|
|
|
|
import { KeyConnectorService } from "@bitwarden/common/abstractions/keyConnector.service";
|
|
|
|
import { NotificationsService } from "@bitwarden/common/abstractions/notifications.service";
|
|
|
|
import { PasswordGenerationService } from "@bitwarden/common/abstractions/passwordGeneration.service";
|
|
|
|
import { PlatformUtilsService } from "@bitwarden/common/abstractions/platformUtils.service";
|
|
|
|
import { PolicyService } from "@bitwarden/common/abstractions/policy.service";
|
|
|
|
import { SearchService } from "@bitwarden/common/abstractions/search.service";
|
|
|
|
import { SettingsService } from "@bitwarden/common/abstractions/settings.service";
|
|
|
|
import { StateService } from "@bitwarden/common/abstractions/state.service";
|
|
|
|
import { SyncService } from "@bitwarden/common/abstractions/sync.service";
|
|
|
|
import { VaultTimeoutService } from "@bitwarden/common/abstractions/vaultTimeout.service";
|
2021-06-07 20:13:58 +02:00
|
|
|
|
2022-07-26 19:34:45 +02:00
|
|
|
import { PolicyListService, RouterService } from "./core";
|
2021-08-25 16:10:17 +02:00
|
|
|
import { DisableSendPolicy } from "./organizations/policies/disable-send.component";
|
|
|
|
import { MasterPasswordPolicy } from "./organizations/policies/master-password.component";
|
|
|
|
import { PasswordGeneratorPolicy } from "./organizations/policies/password-generator.component";
|
|
|
|
import { PersonalOwnershipPolicy } from "./organizations/policies/personal-ownership.component";
|
|
|
|
import { RequireSsoPolicy } from "./organizations/policies/require-sso.component";
|
|
|
|
import { ResetPasswordPolicy } from "./organizations/policies/reset-password.component";
|
|
|
|
import { SendOptionsPolicy } from "./organizations/policies/send-options.component";
|
|
|
|
import { SingleOrgPolicy } from "./organizations/policies/single-org.component";
|
|
|
|
import { TwoFactorAuthenticationPolicy } from "./organizations/policies/two-factor-authentication.component";
|
|
|
|
|
2018-06-08 23:08:19 +02:00
|
|
|
const BroadcasterSubscriptionId = "AppComponent";
|
2018-08-23 04:56:00 +02:00
|
|
|
const IdleTimeout = 60000 * 10; // 10 minutes
|
2018-06-08 23:08:19 +02:00
|
|
|
|
2018-06-05 05:10:41 +02:00
|
|
|
@Component({
|
|
|
|
selector: "app-root",
|
2018-06-06 15:43:28 +02:00
|
|
|
templateUrl: "app.component.html",
|
2018-06-05 05:10:41 +02:00
|
|
|
})
|
2018-06-08 23:08:19 +02:00
|
|
|
export class AppComponent implements OnDestroy, OnInit {
|
|
|
|
private lastActivity: number = null;
|
2018-08-23 04:37:55 +02:00
|
|
|
private idleTimer: number = null;
|
|
|
|
private isIdle = false;
|
2022-07-12 15:02:19 +02:00
|
|
|
private destroy$ = new Subject<void>();
|
2021-08-25 16:10:17 +02:00
|
|
|
|
2018-06-08 23:08:19 +02:00
|
|
|
constructor(
|
2022-06-06 19:08:06 +02:00
|
|
|
@Inject(DOCUMENT) private document: Document,
|
2018-06-08 23:08:19 +02:00
|
|
|
private broadcasterService: BroadcasterService,
|
2022-07-08 15:40:31 +02:00
|
|
|
private folderService: InternalFolderService,
|
2021-12-14 17:10:26 +01:00
|
|
|
private settingsService: SettingsService,
|
|
|
|
private syncService: SyncService,
|
|
|
|
private passwordGenerationService: PasswordGenerationService,
|
|
|
|
private cipherService: CipherService,
|
|
|
|
private authService: AuthService,
|
|
|
|
private router: Router,
|
|
|
|
private toastrService: ToastrService,
|
|
|
|
private i18nService: I18nService,
|
2018-06-08 23:08:19 +02:00
|
|
|
private platformUtilsService: PlatformUtilsService,
|
2018-08-23 04:37:55 +02:00
|
|
|
private ngZone: NgZone,
|
|
|
|
private vaultTimeoutService: VaultTimeoutService,
|
2021-12-14 17:10:26 +01:00
|
|
|
private cryptoService: CryptoService,
|
2018-08-23 04:37:55 +02:00
|
|
|
private collectionService: CollectionService,
|
|
|
|
private sanitizer: DomSanitizer,
|
2021-12-14 17:10:26 +01:00
|
|
|
private searchService: SearchService,
|
|
|
|
private notificationsService: NotificationsService,
|
|
|
|
private routerService: RouterService,
|
|
|
|
private stateService: StateService,
|
|
|
|
private eventService: EventService,
|
|
|
|
private policyService: PolicyService,
|
2018-08-23 04:37:55 +02:00
|
|
|
protected policyListService: PolicyListService,
|
|
|
|
private keyConnectorService: KeyConnectorService
|
2021-12-17 15:57:11 +01:00
|
|
|
) {}
|
2018-06-08 23:08:19 +02:00
|
|
|
|
|
|
|
ngOnInit() {
|
2022-07-12 15:02:19 +02:00
|
|
|
this.i18nService.locale$.pipe(takeUntil(this.destroy$)).subscribe((locale) => {
|
|
|
|
this.document.documentElement.lang = locale;
|
|
|
|
});
|
2022-06-06 19:08:06 +02:00
|
|
|
|
2021-04-14 23:43:40 +02:00
|
|
|
this.ngZone.runOutsideAngular(() => {
|
2021-12-14 17:10:26 +01:00
|
|
|
window.onmousemove = () => this.recordActivity();
|
|
|
|
window.onmousedown = () => this.recordActivity();
|
|
|
|
window.ontouchstart = () => this.recordActivity();
|
|
|
|
window.onclick = () => this.recordActivity();
|
|
|
|
window.onscroll = () => this.recordActivity();
|
|
|
|
window.onkeypress = () => this.recordActivity();
|
|
|
|
});
|
2018-06-08 23:08:19 +02:00
|
|
|
|
|
|
|
this.broadcasterService.subscribe(BroadcasterSubscriptionId, async (message: any) => {
|
|
|
|
this.ngZone.run(async () => {
|
|
|
|
switch (message.command) {
|
|
|
|
case "loggedIn":
|
2022-04-25 15:41:44 +02:00
|
|
|
this.notificationsService.updateConnection(false);
|
|
|
|
break;
|
2018-06-08 23:08:19 +02:00
|
|
|
case "loggedOut":
|
2022-04-25 15:41:44 +02:00
|
|
|
this.routerService.setPreviousUrl(null);
|
|
|
|
this.notificationsService.updateConnection(false);
|
|
|
|
break;
|
2018-08-21 04:21:13 +02:00
|
|
|
case "unlocked":
|
2018-06-08 23:08:19 +02:00
|
|
|
this.notificationsService.updateConnection(false);
|
2021-12-17 15:57:11 +01:00
|
|
|
break;
|
2019-04-18 16:11:04 +02:00
|
|
|
case "authBlocked":
|
2022-04-25 15:41:44 +02:00
|
|
|
this.routerService.setPreviousUrl(message.url);
|
2019-04-18 16:11:04 +02:00
|
|
|
this.router.navigate(["/"]);
|
2018-06-08 23:08:19 +02:00
|
|
|
break;
|
|
|
|
case "logout":
|
|
|
|
this.logOut(!!message.expired);
|
2021-12-17 15:57:11 +01:00
|
|
|
break;
|
2018-06-08 23:08:19 +02:00
|
|
|
case "lockVault":
|
|
|
|
await this.vaultTimeoutService.lock();
|
2021-12-17 15:57:11 +01:00
|
|
|
break;
|
2018-06-08 23:08:19 +02:00
|
|
|
case "locked":
|
|
|
|
this.notificationsService.updateConnection(false);
|
2018-06-09 20:55:34 +02:00
|
|
|
this.router.navigate(["lock"]);
|
2021-12-17 15:57:11 +01:00
|
|
|
break;
|
2019-02-22 19:17:10 +01:00
|
|
|
case "lockedUrl":
|
2022-04-25 15:41:44 +02:00
|
|
|
this.routerService.setPreviousUrl(message.url);
|
2018-06-08 23:08:19 +02:00
|
|
|
break;
|
|
|
|
case "syncStarted":
|
2021-12-17 15:57:11 +01:00
|
|
|
break;
|
2018-06-08 23:08:19 +02:00
|
|
|
case "syncCompleted":
|
2021-12-17 15:57:11 +01:00
|
|
|
break;
|
2022-02-24 12:10:07 +01:00
|
|
|
case "upgradeOrganization": {
|
2018-06-08 23:08:19 +02:00
|
|
|
const upgradeConfirmed = await this.platformUtilsService.showDialog(
|
|
|
|
this.i18nService.t("upgradeOrganizationDesc"),
|
2018-07-18 15:21:23 +02:00
|
|
|
this.i18nService.t("upgradeOrganization"),
|
|
|
|
this.i18nService.t("upgradeOrganization"),
|
|
|
|
this.i18nService.t("cancel")
|
2018-06-08 23:08:19 +02:00
|
|
|
);
|
|
|
|
if (upgradeConfirmed) {
|
|
|
|
this.router.navigate([
|
2018-07-18 15:21:23 +02:00
|
|
|
"organizations",
|
2018-06-08 23:08:19 +02:00
|
|
|
message.organizationId,
|
|
|
|
"settings",
|
2021-12-17 15:57:11 +01:00
|
|
|
"billing",
|
|
|
|
]);
|
|
|
|
}
|
|
|
|
break;
|
2022-02-24 12:10:07 +01:00
|
|
|
}
|
|
|
|
case "premiumRequired": {
|
2018-06-08 23:08:19 +02:00
|
|
|
const premiumConfirmed = await this.platformUtilsService.showDialog(
|
2018-07-18 15:21:23 +02:00
|
|
|
this.i18nService.t("premiumRequiredDesc"),
|
|
|
|
this.i18nService.t("premiumRequired"),
|
2018-06-08 23:08:19 +02:00
|
|
|
this.i18nService.t("learnMore"),
|
2018-07-18 15:21:23 +02:00
|
|
|
this.i18nService.t("cancel")
|
2021-12-17 15:57:11 +01:00
|
|
|
);
|
2018-06-08 23:08:19 +02:00
|
|
|
if (premiumConfirmed) {
|
|
|
|
this.router.navigate(["settings/premium"]);
|
2021-12-17 15:57:11 +01:00
|
|
|
}
|
|
|
|
break;
|
2022-02-24 12:10:07 +01:00
|
|
|
}
|
|
|
|
case "emailVerificationRequired": {
|
2018-06-08 23:08:19 +02:00
|
|
|
const emailVerificationConfirmed = await this.platformUtilsService.showDialog(
|
2021-04-09 18:19:16 +02:00
|
|
|
this.i18nService.t("emailVerificationRequiredDesc"),
|
|
|
|
this.i18nService.t("emailVerificationRequired"),
|
|
|
|
this.i18nService.t("learnMore"),
|
|
|
|
this.i18nService.t("cancel")
|
2021-12-17 15:57:11 +01:00
|
|
|
);
|
2021-04-09 18:19:16 +02:00
|
|
|
if (emailVerificationConfirmed) {
|
2018-06-08 23:08:19 +02:00
|
|
|
this.platformUtilsService.launchUri(
|
2022-01-31 20:11:27 +01:00
|
|
|
"https://bitwarden.com/help/create-bitwarden-account/"
|
2021-12-17 15:57:11 +01:00
|
|
|
);
|
|
|
|
}
|
|
|
|
break;
|
2022-02-24 12:10:07 +01:00
|
|
|
}
|
2018-10-03 16:33:04 +02:00
|
|
|
case "showToast":
|
|
|
|
this.showToast(message);
|
2021-12-17 15:57:11 +01:00
|
|
|
break;
|
2020-05-30 10:30:35 +02:00
|
|
|
case "setFullWidth":
|
2018-06-08 23:08:19 +02:00
|
|
|
this.setFullWidth();
|
2021-12-17 15:57:11 +01:00
|
|
|
break;
|
2021-11-09 19:24:26 +01:00
|
|
|
case "convertAccountToKeyConnector":
|
2018-06-08 23:08:19 +02:00
|
|
|
this.router.navigate(["/remove-password"]);
|
|
|
|
break;
|
2021-12-17 15:57:11 +01:00
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
2018-06-08 23:08:19 +02:00
|
|
|
});
|
2021-12-17 15:57:11 +01:00
|
|
|
});
|
2018-06-08 23:08:19 +02:00
|
|
|
|
2022-07-12 15:02:19 +02:00
|
|
|
this.router.events.pipe(takeUntil(this.destroy$)).subscribe((event) => {
|
2018-08-23 14:56:45 +02:00
|
|
|
if (event instanceof NavigationEnd) {
|
2018-07-18 15:21:23 +02:00
|
|
|
const modals = Array.from(document.querySelectorAll(".modal"));
|
|
|
|
for (const modal of modals) {
|
2021-04-09 18:19:16 +02:00
|
|
|
(jq(modal) as any).modal("hide");
|
2018-06-08 23:08:19 +02:00
|
|
|
}
|
2018-06-09 19:59:09 +02:00
|
|
|
|
|
|
|
if (document.querySelector(".swal-modal") != null) {
|
|
|
|
Swal.close(undefined);
|
2021-12-17 15:57:11 +01:00
|
|
|
}
|
2018-06-09 19:59:09 +02:00
|
|
|
}
|
2021-12-17 15:57:11 +01:00
|
|
|
});
|
2018-06-09 19:59:09 +02:00
|
|
|
|
|
|
|
this.policyListService.addPolicies([
|
|
|
|
new TwoFactorAuthenticationPolicy(),
|
|
|
|
new MasterPasswordPolicy(),
|
2022-07-11 12:24:02 +02:00
|
|
|
new ResetPasswordPolicy(),
|
2021-08-25 16:10:17 +02:00
|
|
|
new PasswordGeneratorPolicy(),
|
2018-06-09 19:59:09 +02:00
|
|
|
new SingleOrgPolicy(),
|
|
|
|
new RequireSsoPolicy(),
|
2020-03-02 19:52:09 +01:00
|
|
|
new PersonalOwnershipPolicy(),
|
2021-08-25 16:10:17 +02:00
|
|
|
new DisableSendPolicy(),
|
2020-03-02 19:52:09 +01:00
|
|
|
new SendOptionsPolicy(),
|
2018-06-09 19:59:09 +02:00
|
|
|
]);
|
2022-03-09 17:16:53 +01:00
|
|
|
|
|
|
|
this.setFullWidth();
|
2021-12-17 15:57:11 +01:00
|
|
|
}
|
2021-08-25 16:10:17 +02:00
|
|
|
|
2020-05-31 14:02:41 +02:00
|
|
|
ngOnDestroy() {
|
|
|
|
this.broadcasterService.unsubscribe(BroadcasterSubscriptionId);
|
2022-07-12 15:02:19 +02:00
|
|
|
this.destroy$.next();
|
|
|
|
this.destroy$.unsubscribe();
|
2018-06-08 23:08:19 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
private async logOut(expired: boolean) {
|
|
|
|
await this.eventService.uploadEvents();
|
|
|
|
const userId = await this.stateService.getUserId();
|
|
|
|
await Promise.all([
|
2019-07-12 04:03:12 +02:00
|
|
|
this.eventService.clearEvents(),
|
2018-06-08 23:08:19 +02:00
|
|
|
this.syncService.setLastSync(new Date(0)),
|
|
|
|
this.cryptoService.clearKeys(),
|
|
|
|
this.settingsService.clear(userId),
|
|
|
|
this.cipherService.clear(userId),
|
|
|
|
this.folderService.clear(userId),
|
|
|
|
this.collectionService.clear(userId),
|
2020-01-29 04:42:20 +01:00
|
|
|
this.policyService.clear(userId),
|
2018-06-08 23:08:19 +02:00
|
|
|
this.passwordGenerationService.clear(),
|
2021-11-09 19:24:26 +01:00
|
|
|
this.keyConnectorService.clear(),
|
2021-12-17 15:57:11 +01:00
|
|
|
]);
|
2018-06-08 23:08:19 +02:00
|
|
|
|
|
|
|
this.searchService.clearIndex();
|
|
|
|
this.authService.logOut(async () => {
|
|
|
|
if (expired) {
|
|
|
|
this.platformUtilsService.showToast(
|
|
|
|
"warning",
|
|
|
|
this.i18nService.t("loggedOut"),
|
2021-11-09 19:24:26 +01:00
|
|
|
this.i18nService.t("loginExpired")
|
2018-06-08 23:08:19 +02:00
|
|
|
);
|
2021-12-17 15:57:11 +01:00
|
|
|
}
|
2018-06-08 23:08:19 +02:00
|
|
|
|
2018-08-13 22:27:17 +02:00
|
|
|
await this.stateService.clean({ userId: userId });
|
2018-06-08 23:08:19 +02:00
|
|
|
Swal.close();
|
2021-12-07 20:41:45 +01:00
|
|
|
this.router.navigate(["/"]);
|
2018-06-08 23:08:19 +02:00
|
|
|
});
|
|
|
|
}
|
2020-07-09 22:11:28 +02:00
|
|
|
|
2021-12-14 17:10:26 +01:00
|
|
|
private async recordActivity() {
|
|
|
|
const now = new Date().getTime();
|
|
|
|
if (this.lastActivity != null && now - this.lastActivity < 250) {
|
2018-06-08 23:08:19 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
this.lastActivity = now;
|
2021-12-14 17:10:26 +01:00
|
|
|
this.stateService.setLastActive(now);
|
2018-08-23 04:37:55 +02:00
|
|
|
// Idle states
|
|
|
|
if (this.isIdle) {
|
|
|
|
this.isIdle = false;
|
|
|
|
this.idleStateChanged();
|
|
|
|
}
|
|
|
|
if (this.idleTimer != null) {
|
|
|
|
window.clearTimeout(this.idleTimer);
|
|
|
|
this.idleTimer = null;
|
2021-12-17 15:57:11 +01:00
|
|
|
}
|
2018-08-23 04:37:55 +02:00
|
|
|
this.idleTimer = window.setTimeout(() => {
|
|
|
|
if (!this.isIdle) {
|
|
|
|
this.isIdle = true;
|
|
|
|
this.idleStateChanged();
|
2021-12-17 15:57:11 +01:00
|
|
|
}
|
2018-08-23 04:37:55 +02:00
|
|
|
}, IdleTimeout);
|
2021-12-17 15:57:11 +01:00
|
|
|
}
|
2018-08-23 04:37:55 +02:00
|
|
|
|
2018-10-03 16:33:04 +02:00
|
|
|
private showToast(msg: any) {
|
2021-12-07 20:41:45 +01:00
|
|
|
let message = "";
|
|
|
|
|
|
|
|
const options: Partial<IndividualConfig> = {};
|
|
|
|
|
|
|
|
if (typeof msg.text === "string") {
|
|
|
|
message = msg.text;
|
|
|
|
} else if (msg.text.length === 1) {
|
|
|
|
message = msg.text[0];
|
2021-12-17 15:57:11 +01:00
|
|
|
} else {
|
2018-10-03 16:33:04 +02:00
|
|
|
msg.text.forEach(
|
2021-12-07 20:41:45 +01:00
|
|
|
(t: string) =>
|
|
|
|
(message += "<p>" + this.sanitizer.sanitize(SecurityContext.HTML, t) + "</p>")
|
|
|
|
);
|
|
|
|
options.enableHtml = true;
|
2021-12-17 15:57:11 +01:00
|
|
|
}
|
2018-10-03 16:33:04 +02:00
|
|
|
if (msg.options != null) {
|
2021-12-07 20:41:45 +01:00
|
|
|
if (msg.options.trustedHtml === true) {
|
|
|
|
options.enableHtml = true;
|
2021-12-17 15:57:11 +01:00
|
|
|
}
|
2018-10-03 16:33:04 +02:00
|
|
|
if (msg.options.timeout != null && msg.options.timeout > 0) {
|
|
|
|
options.timeOut = msg.options.timeout;
|
2021-12-17 15:57:11 +01:00
|
|
|
}
|
2018-10-03 16:33:04 +02:00
|
|
|
}
|
|
|
|
|
2021-12-07 20:41:45 +01:00
|
|
|
this.toastrService.show(message, msg.title, options, "toast-" + msg.type);
|
2021-12-17 15:57:11 +01:00
|
|
|
}
|
|
|
|
|
2018-08-23 04:37:55 +02:00
|
|
|
private idleStateChanged() {
|
|
|
|
if (this.isIdle) {
|
|
|
|
this.notificationsService.disconnectFromInactivity();
|
|
|
|
} else {
|
|
|
|
this.notificationsService.reconnectFromActivity();
|
2018-06-05 05:10:41 +02:00
|
|
|
}
|
2021-12-17 15:57:11 +01:00
|
|
|
}
|
2020-05-30 10:30:35 +02:00
|
|
|
|
|
|
|
private async setFullWidth() {
|
2021-12-14 17:10:26 +01:00
|
|
|
const enableFullWidth = await this.stateService.getEnableFullWidth();
|
2020-06-02 15:56:16 +02:00
|
|
|
if (enableFullWidth) {
|
2020-05-30 10:30:35 +02:00
|
|
|
document.body.classList.add("full-width");
|
|
|
|
} else {
|
|
|
|
document.body.classList.remove("full-width");
|
|
|
|
}
|
2021-12-17 15:57:11 +01:00
|
|
|
}
|
2018-06-05 05:10:41 +02:00
|
|
|
}
|