mirror of
https://github.com/bitwarden/browser
synced 2025-12-10 13:23:34 +00:00
Move process reload ownership to key-management (#10853)
This commit is contained in:
@@ -0,0 +1,6 @@
|
||||
import { AuthService } from "../../auth/abstractions/auth.service";
|
||||
|
||||
export abstract class ProcessReloadServiceAbstraction {
|
||||
abstract startProcessReload(authService: AuthService): Promise<void>;
|
||||
abstract cancelProcessReload(): void;
|
||||
}
|
||||
@@ -0,0 +1,106 @@
|
||||
import { firstValueFrom, map, timeout } from "rxjs";
|
||||
|
||||
import { MessagingService } from "@bitwarden/common/platform/abstractions/messaging.service";
|
||||
import { BiometricStateService } from "@bitwarden/key-management";
|
||||
|
||||
import { PinServiceAbstraction } from "../../../../auth/src/common/abstractions";
|
||||
import { VaultTimeoutSettingsService } from "../../abstractions/vault-timeout/vault-timeout-settings.service";
|
||||
import { AccountService } from "../../auth/abstractions/account.service";
|
||||
import { AuthService } from "../../auth/abstractions/auth.service";
|
||||
import { AuthenticationStatus } from "../../auth/enums/authentication-status";
|
||||
import { VaultTimeoutAction } from "../../enums/vault-timeout-action.enum";
|
||||
import { UserId } from "../../types/guid";
|
||||
import { ProcessReloadServiceAbstraction } from "../abstractions/process-reload.service";
|
||||
|
||||
export class ProcessReloadService implements ProcessReloadServiceAbstraction {
|
||||
private reloadInterval: any = null;
|
||||
|
||||
constructor(
|
||||
private pinService: PinServiceAbstraction,
|
||||
private messagingService: MessagingService,
|
||||
private reloadCallback: () => Promise<void> = null,
|
||||
private vaultTimeoutSettingsService: VaultTimeoutSettingsService,
|
||||
private biometricStateService: BiometricStateService,
|
||||
private accountService: AccountService,
|
||||
) {}
|
||||
|
||||
async startProcessReload(authService: AuthService): Promise<void> {
|
||||
const accounts = await firstValueFrom(this.accountService.accounts$);
|
||||
if (accounts != null) {
|
||||
const keys = Object.keys(accounts);
|
||||
if (keys.length > 0) {
|
||||
for (const userId of keys) {
|
||||
let status = await firstValueFrom(authService.authStatusFor$(userId as UserId));
|
||||
status = await authService.getAuthStatus(userId);
|
||||
if (status === AuthenticationStatus.Unlocked) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// A reloadInterval has already been set and is executing
|
||||
if (this.reloadInterval != null) {
|
||||
return;
|
||||
}
|
||||
|
||||
// If there is an active user, check if they have a pinKeyEncryptedUserKeyEphemeral. If so, prevent process reload upon lock.
|
||||
const userId = (await firstValueFrom(this.accountService.activeAccount$))?.id;
|
||||
if (userId != null) {
|
||||
const ephemeralPin = await this.pinService.getPinKeyEncryptedUserKeyEphemeral(userId);
|
||||
if (ephemeralPin != null) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
this.cancelProcessReload();
|
||||
await this.executeProcessReload();
|
||||
}
|
||||
|
||||
private async executeProcessReload() {
|
||||
const biometricLockedFingerprintValidated = await firstValueFrom(
|
||||
this.biometricStateService.fingerprintValidated$,
|
||||
);
|
||||
if (!biometricLockedFingerprintValidated) {
|
||||
clearInterval(this.reloadInterval);
|
||||
this.reloadInterval = null;
|
||||
|
||||
const activeUserId = await firstValueFrom(
|
||||
this.accountService.activeAccount$.pipe(
|
||||
map((a) => a?.id),
|
||||
timeout(500),
|
||||
),
|
||||
);
|
||||
// Replace current active user if they will be logged out on reload
|
||||
if (activeUserId != null) {
|
||||
const timeoutAction = await firstValueFrom(
|
||||
this.vaultTimeoutSettingsService
|
||||
.getVaultTimeoutActionByUserId$(activeUserId)
|
||||
.pipe(timeout(500)), // safety feature to avoid this call hanging and stopping process reload from clearing memory
|
||||
);
|
||||
if (timeoutAction === VaultTimeoutAction.LogOut) {
|
||||
const nextUser = await firstValueFrom(
|
||||
this.accountService.nextUpAccount$.pipe(map((account) => account?.id ?? null)),
|
||||
);
|
||||
await this.accountService.switchAccount(nextUser);
|
||||
}
|
||||
}
|
||||
|
||||
this.messagingService.send("reloadProcess");
|
||||
if (this.reloadCallback != null) {
|
||||
await this.reloadCallback();
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (this.reloadInterval == null) {
|
||||
this.reloadInterval = setInterval(async () => await this.executeProcessReload(), 1000);
|
||||
}
|
||||
}
|
||||
|
||||
cancelProcessReload(): void {
|
||||
if (this.reloadInterval != null) {
|
||||
clearInterval(this.reloadInterval);
|
||||
this.reloadInterval = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,8 +1,4 @@
|
||||
import { AuthService } from "../../auth/abstractions/auth.service";
|
||||
|
||||
export abstract class SystemService {
|
||||
abstract startProcessReload(authService: AuthService): Promise<void>;
|
||||
abstract cancelProcessReload(): void;
|
||||
abstract clearClipboard(clipboardValue: string, timeoutMs?: number): Promise<void>;
|
||||
abstract clearPendingClipboard(): Promise<any>;
|
||||
}
|
||||
|
||||
@@ -1,16 +1,6 @@
|
||||
import { firstValueFrom, map, Subscription, timeout } from "rxjs";
|
||||
import { firstValueFrom, Subscription } from "rxjs";
|
||||
|
||||
import { BiometricStateService } from "@bitwarden/key-management";
|
||||
|
||||
import { PinServiceAbstraction } from "../../../../auth/src/common/abstractions";
|
||||
import { VaultTimeoutSettingsService } from "../../abstractions/vault-timeout/vault-timeout-settings.service";
|
||||
import { AccountService } from "../../auth/abstractions/account.service";
|
||||
import { AuthService } from "../../auth/abstractions/auth.service";
|
||||
import { AuthenticationStatus } from "../../auth/enums/authentication-status";
|
||||
import { AutofillSettingsServiceAbstraction } from "../../autofill/services/autofill-settings.service";
|
||||
import { VaultTimeoutAction } from "../../enums/vault-timeout-action.enum";
|
||||
import { UserId } from "../../types/guid";
|
||||
import { MessagingService } from "../abstractions/messaging.service";
|
||||
import { PlatformUtilsService } from "../abstractions/platform-utils.service";
|
||||
import { SystemService as SystemServiceAbstraction } from "../abstractions/system.service";
|
||||
import { Utils } from "../misc/utils";
|
||||
@@ -18,19 +8,12 @@ import { ScheduledTaskNames } from "../scheduling/scheduled-task-name.enum";
|
||||
import { TaskSchedulerService } from "../scheduling/task-scheduler.service";
|
||||
|
||||
export class SystemService implements SystemServiceAbstraction {
|
||||
private reloadInterval: any = null;
|
||||
private clearClipboardTimeoutSubscription: Subscription;
|
||||
private clearClipboardTimeoutFunction: () => Promise<any> = null;
|
||||
|
||||
constructor(
|
||||
private pinService: PinServiceAbstraction,
|
||||
private messagingService: MessagingService,
|
||||
private platformUtilsService: PlatformUtilsService,
|
||||
private reloadCallback: () => Promise<void> = null,
|
||||
private autofillSettingsService: AutofillSettingsServiceAbstraction,
|
||||
private vaultTimeoutSettingsService: VaultTimeoutSettingsService,
|
||||
private biometricStateService: BiometricStateService,
|
||||
private accountService: AccountService,
|
||||
private taskSchedulerService: TaskSchedulerService,
|
||||
) {
|
||||
this.taskSchedulerService.registerTaskHandler(
|
||||
@@ -39,86 +22,6 @@ export class SystemService implements SystemServiceAbstraction {
|
||||
);
|
||||
}
|
||||
|
||||
async startProcessReload(authService: AuthService): Promise<void> {
|
||||
const accounts = await firstValueFrom(this.accountService.accounts$);
|
||||
if (accounts != null) {
|
||||
const keys = Object.keys(accounts);
|
||||
if (keys.length > 0) {
|
||||
for (const userId of keys) {
|
||||
let status = await firstValueFrom(authService.authStatusFor$(userId as UserId));
|
||||
status = await authService.getAuthStatus(userId);
|
||||
if (status === AuthenticationStatus.Unlocked) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// A reloadInterval has already been set and is executing
|
||||
if (this.reloadInterval != null) {
|
||||
return;
|
||||
}
|
||||
|
||||
// If there is an active user, check if they have a pinKeyEncryptedUserKeyEphemeral. If so, prevent process reload upon lock.
|
||||
const userId = (await firstValueFrom(this.accountService.activeAccount$))?.id;
|
||||
if (userId != null) {
|
||||
const ephemeralPin = await this.pinService.getPinKeyEncryptedUserKeyEphemeral(userId);
|
||||
if (ephemeralPin != null) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
this.cancelProcessReload();
|
||||
await this.executeProcessReload();
|
||||
}
|
||||
|
||||
private async executeProcessReload() {
|
||||
const biometricLockedFingerprintValidated = await firstValueFrom(
|
||||
this.biometricStateService.fingerprintValidated$,
|
||||
);
|
||||
if (!biometricLockedFingerprintValidated) {
|
||||
clearInterval(this.reloadInterval);
|
||||
this.reloadInterval = null;
|
||||
|
||||
const activeUserId = await firstValueFrom(
|
||||
this.accountService.activeAccount$.pipe(
|
||||
map((a) => a?.id),
|
||||
timeout(500),
|
||||
),
|
||||
);
|
||||
// Replace current active user if they will be logged out on reload
|
||||
if (activeUserId != null) {
|
||||
const timeoutAction = await firstValueFrom(
|
||||
this.vaultTimeoutSettingsService
|
||||
.getVaultTimeoutActionByUserId$(activeUserId)
|
||||
.pipe(timeout(500)), // safety feature to avoid this call hanging and stopping process reload from clearing memory
|
||||
);
|
||||
if (timeoutAction === VaultTimeoutAction.LogOut) {
|
||||
const nextUser = await firstValueFrom(
|
||||
this.accountService.nextUpAccount$.pipe(map((account) => account?.id ?? null)),
|
||||
);
|
||||
await this.accountService.switchAccount(nextUser);
|
||||
}
|
||||
}
|
||||
|
||||
this.messagingService.send("reloadProcess");
|
||||
if (this.reloadCallback != null) {
|
||||
await this.reloadCallback();
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (this.reloadInterval == null) {
|
||||
this.reloadInterval = setInterval(async () => await this.executeProcessReload(), 1000);
|
||||
}
|
||||
}
|
||||
|
||||
cancelProcessReload(): void {
|
||||
if (this.reloadInterval != null) {
|
||||
clearInterval(this.reloadInterval);
|
||||
this.reloadInterval = null;
|
||||
}
|
||||
}
|
||||
|
||||
async clearClipboard(clipboardValue: string, timeoutMs: number = null): Promise<void> {
|
||||
this.clearClipboardTimeoutSubscription?.unsubscribe();
|
||||
|
||||
|
||||
Reference in New Issue
Block a user