1
0
mirror of https://github.com/bitwarden/browser synced 2025-12-14 07:13:32 +00:00

[PM-7838] [PM-7864] Ensure AuthStatus Changes Before Exiting (#9018)

* Ensure AuthStatus Changes Before Exiting

* Do Not Display Account Without Name Or Email

* Fix Environment Selectors

* Add AccountService.clean to Web
This commit is contained in:
Justin Baur
2024-05-03 16:43:42 -04:00
committed by GitHub
parent b46766affd
commit e4ef7d362e
6 changed files with 182 additions and 85 deletions

View File

@@ -1,4 +1,4 @@
import { combineLatest, firstValueFrom, switchMap } from "rxjs";
import { combineLatest, filter, firstValueFrom, map, switchMap, timeout } from "rxjs";
import { SearchService } from "../../abstractions/search.service";
import { VaultTimeoutSettingsService } from "../../abstractions/vault-timeout/vault-timeout-settings.service";
@@ -80,7 +80,7 @@ export class VaultTimeoutService implements VaultTimeoutServiceAbstraction {
);
}
async lock(userId?: string): Promise<void> {
async lock(userId?: UserId): Promise<void> {
const authed = await this.stateService.getIsAuthenticated({ userId: userId });
if (!authed) {
return;
@@ -94,7 +94,27 @@ export class VaultTimeoutService implements VaultTimeoutServiceAbstraction {
await this.logOut(userId);
}
const currentUserId = (await firstValueFrom(this.accountService.activeAccount$)).id;
const currentUserId = await firstValueFrom(
this.accountService.activeAccount$.pipe(map((a) => a?.id)),
);
const lockingUserId = userId ?? currentUserId;
// HACK: Start listening for the transition of the locking user from something to the locked state.
// This is very much a hack to ensure that the authentication status to retrievable right after
// it does its work. Particularly the `lockedCallback` and `"locked"` message. Instead
// lockedCallback should be deprecated and people should subscribe and react to `authStatusFor$` themselves.
const lockPromise = firstValueFrom(
this.authService.authStatusFor$(lockingUserId).pipe(
filter((authStatus) => authStatus === AuthenticationStatus.Locked),
timeout({
first: 5_000,
with: () => {
throw new Error("The lock process did not complete in a reasonable amount of time.");
},
}),
),
);
if (userId == null || userId === currentUserId) {
await this.searchService.clearIndex();
@@ -102,19 +122,21 @@ export class VaultTimeoutService implements VaultTimeoutServiceAbstraction {
await this.collectionService.clearActiveUserCache();
}
await this.masterPasswordService.clearMasterKey((userId ?? currentUserId) as UserId);
await this.masterPasswordService.clearMasterKey(lockingUserId);
await this.stateService.setUserKeyAutoUnlock(null, { userId: userId });
await this.stateService.setCryptoMasterKeyAuto(null, { userId: userId });
await this.stateService.setUserKeyAutoUnlock(null, { userId: lockingUserId });
await this.stateService.setCryptoMasterKeyAuto(null, { userId: lockingUserId });
await this.cipherService.clearCache(userId);
await this.cipherService.clearCache(lockingUserId);
await this.stateEventRunnerService.handleEvent("lock", (userId ?? currentUserId) as UserId);
await this.stateEventRunnerService.handleEvent("lock", lockingUserId);
// FIXME: We should send the userId of the user that was locked, in the case of this method being passed
// undefined then it should give back the currentUserId. Better yet, this method shouldn't take
// an undefined userId at all. All receivers need to be checked for how they handle getting undefined.
this.messagingService.send("locked", { userId: userId });
// HACK: Sit here and wait for the the auth status to transition to `Locked`
// to ensure the message and lockedCallback will get the correct status
// if/when they call it.
await lockPromise;
this.messagingService.send("locked", { userId: lockingUserId });
if (this.lockedCallback != null) {
await this.lockedCallback(userId);
@@ -162,7 +184,7 @@ export class VaultTimeoutService implements VaultTimeoutServiceAbstraction {
return diffSeconds >= vaultTimeoutSeconds;
}
private async executeTimeoutAction(userId: string): Promise<void> {
private async executeTimeoutAction(userId: UserId): Promise<void> {
const timeoutAction = await firstValueFrom(
this.vaultTimeoutSettingsService.vaultTimeoutAction$(userId),
);