1
0
mirror of https://github.com/bitwarden/browser synced 2025-12-15 15:53:27 +00:00

[PM-12024] Move Lock All To Happen in Background (#11047)

* Move Lock All To Happen in Background

- Make it done serially
- Have the promise only resolve once it's complete

* Unlock Active Account Last

* Add Tests

* Update Comment
This commit is contained in:
Justin Baur
2024-09-16 16:08:03 -04:00
committed by GitHub
parent 112bad03b1
commit 1ebef296b9
8 changed files with 150 additions and 22 deletions

View File

@@ -0,0 +1,49 @@
import { combineLatest, firstValueFrom, map } from "rxjs";
import { VaultTimeoutService } from "@bitwarden/common/abstractions/vault-timeout/vault-timeout.service";
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
import { UserId } from "@bitwarden/common/types/guid";
export abstract class LockService {
/**
* Locks all accounts.
*/
abstract lockAll(): Promise<void>;
}
export class DefaultLockService implements LockService {
constructor(
private readonly accountService: AccountService,
private readonly vaultTimeoutService: VaultTimeoutService,
) {}
async lockAll() {
const accounts = await firstValueFrom(
combineLatest([this.accountService.activeAccount$, this.accountService.accounts$]).pipe(
map(([activeAccount, accounts]) => {
const otherAccounts = Object.keys(accounts) as UserId[];
if (activeAccount == null) {
return { activeAccount: null, otherAccounts: otherAccounts };
}
return {
activeAccount: activeAccount.id,
otherAccounts: otherAccounts.filter((accountId) => accountId !== activeAccount.id),
};
}),
),
);
for (const otherAccount of accounts.otherAccounts) {
await this.vaultTimeoutService.lock(otherAccount);
}
// Do the active account last in case we ever try to route the user on lock
// that way this whole operation will be complete before that routing
// could take place.
if (accounts.activeAccount != null) {
await this.vaultTimeoutService.lock(accounts.activeAccount);
}
}
}

View File

@@ -0,0 +1,43 @@
import { mock } from "jest-mock-extended";
import { VaultTimeoutService } from "@bitwarden/common/abstractions/vault-timeout/vault-timeout.service";
import { mockAccountServiceWith } from "@bitwarden/common/spec";
import { UserId } from "@bitwarden/common/types/guid";
import { DefaultLockService } from "./lock.service";
describe("DefaultLockService", () => {
const mockUser1 = "user1" as UserId;
const mockUser2 = "user2" as UserId;
const mockUser3 = "user3" as UserId;
const accountService = mockAccountServiceWith(mockUser1);
const vaultTimeoutService = mock<VaultTimeoutService>();
const sut = new DefaultLockService(accountService, vaultTimeoutService);
describe("lockAll", () => {
it("locks the active account last", async () => {
await accountService.addAccount(mockUser2, {
name: "name2",
email: "email2@example.com",
emailVerified: false,
});
await accountService.addAccount(mockUser3, {
name: "name3",
email: "email3@example.com",
emailVerified: false,
});
await sut.lockAll();
expect(vaultTimeoutService.lock).toHaveBeenCalledTimes(3);
// Non-Active users should be called first
expect(vaultTimeoutService.lock).toHaveBeenNthCalledWith(1, mockUser2);
expect(vaultTimeoutService.lock).toHaveBeenNthCalledWith(2, mockUser3);
// Active user should be called last
expect(vaultTimeoutService.lock).toHaveBeenNthCalledWith(3, mockUser1);
});
});
});

View File

@@ -4,3 +4,4 @@ export * from "./login-strategies/login-strategy.service";
export * from "./user-decryption-options/user-decryption-options.service";
export * from "./auth-request/auth-request.service";
export * from "./register-route.service";
export * from "./accounts/lock.service";