[PM-6797] Prevent account switching race condition on desktop & enable worker decryption (#9312)

* Prevent account switching race condition on desktop

This enables us to allow background thread / multithread bulk decryption on desktop.

* Disable account switcher component during switching
This commit is contained in:
Bernd Schoolmann 2024-07-11 14:11:51 +02:00 committed by GitHub
parent f03dabb6d6
commit e977dacdcf
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 22 additions and 26 deletions

View File

@ -210,7 +210,6 @@ import { AutofillService as AutofillServiceAbstraction } from "../autofill/servi
import AutofillService from "../autofill/services/autofill.service";
import { SafariApp } from "../browser/safariApp";
import { BrowserApi } from "../platform/browser/browser-api";
import { flagEnabled } from "../platform/flags";
import { UpdateBadge } from "../platform/listeners/update-badge";
/* eslint-disable no-restricted-imports */
import { ChromeMessageSender } from "../platform/messaging/chrome-message.sender";
@ -484,14 +483,13 @@ export default class MainBackground {
storageServiceProvider,
);
this.encryptService =
flagEnabled("multithreadDecryption") && BrowserApi.isManifestVersion(2)
? new MultithreadEncryptServiceImplementation(
this.cryptoFunctionService,
this.logService,
true,
)
: new EncryptServiceImplementation(this.cryptoFunctionService, this.logService, true);
this.encryptService = BrowserApi.isManifestVersion(2)
? new MultithreadEncryptServiceImplementation(
this.cryptoFunctionService,
this.logService,
true,
)
: new EncryptServiceImplementation(this.cryptoFunctionService, this.logService, true);
this.singleUserStateProvider = new DefaultSingleUserStateProvider(
storageServiceProvider,

View File

@ -1,7 +1,6 @@
{
"devFlags": {},
"flags": {
"multithreadDecryption": false,
"enableCipherKeyEncryption": true
}
}

View File

@ -422,12 +422,13 @@ export class AppComponent implements OnInit, OnDestroy {
} else {
this.messagingService.send("unlocked");
this.loading = true;
await this.syncService.fullSync(true);
await this.syncService.fullSync(false);
this.loading = false;
// FIXME: Verify that this floating promise is intentional. If it is, add an explanatory comment and ensure there is proper error handling.
// eslint-disable-next-line @typescript-eslint/no-floating-promises
this.router.navigate(["vault"]);
}
this.messagingService.send("finishSwitchAccount");
break;
}
case "systemSuspended":

View File

@ -7,6 +7,7 @@
cdkOverlayOrigin
#trigger="cdkOverlayOrigin"
[hidden]="!view.showSwitcher"
[disabled]="disabled"
aria-haspopup="dialog"
>
<ng-container *ngIf="view.activeAccount; else noActiveAccount">

View File

@ -12,6 +12,7 @@ import { AuthenticationStatus } from "@bitwarden/common/auth/enums/authenticatio
import { EnvironmentService } from "@bitwarden/common/platform/abstractions/environment.service";
import { MessagingService } from "@bitwarden/common/platform/abstractions/messaging.service";
import { StateService } from "@bitwarden/common/platform/abstractions/state.service";
import { CommandDefinition, MessageListener } from "@bitwarden/common/platform/messaging";
import { UserId } from "@bitwarden/common/types/guid";
type ActiveAccount = {
@ -75,12 +76,14 @@ export class AccountSwitcherComponent {
showSwitcher$: Observable<boolean>;
numberOfAccounts$: Observable<number>;
disabled = false;
constructor(
private stateService: StateService,
private authService: AuthService,
private avatarService: AvatarService,
private messagingService: MessagingService,
private messageListener: MessageListener,
private router: Router,
private environmentService: EnvironmentService,
private loginEmailService: LoginEmailServiceAbstraction,
@ -159,7 +162,13 @@ export class AccountSwitcherComponent {
async switch(userId: string) {
this.close();
this.messagingService.send("switchAccount", { userId: userId });
this.disabled = true;
const accountSwitchFinishedPromise = firstValueFrom(
this.messageListener.messages$(new CommandDefinition("finishSwitchAccount")),
);
this.messagingService.send("switchAccount", { userId });
await accountSwitchFinishedPromise;
this.disabled = false;
}
async addAccount() {

View File

@ -154,7 +154,7 @@ import { StateFactory } from "@bitwarden/common/platform/factories/state-factory
import { Message, MessageListener, MessageSender } from "@bitwarden/common/platform/messaging";
// eslint-disable-next-line no-restricted-imports -- Used for dependency injection
import { SubjectMessageSender } from "@bitwarden/common/platform/messaging/internal";
import { devFlagEnabled, flagEnabled } from "@bitwarden/common/platform/misc/flags";
import { devFlagEnabled } from "@bitwarden/common/platform/misc/flags";
import { Account } from "@bitwarden/common/platform/models/domain/account";
import { GlobalState } from "@bitwarden/common/platform/models/domain/global-state";
import { AppIdService } from "@bitwarden/common/platform/services/app-id.service";
@ -162,7 +162,6 @@ import { ConfigApiService } from "@bitwarden/common/platform/services/config/con
import { DefaultConfigService } from "@bitwarden/common/platform/services/config/default-config.service";
import { ConsoleLogService } from "@bitwarden/common/platform/services/console-log.service";
import { CryptoService } from "@bitwarden/common/platform/services/crypto.service";
import { EncryptServiceImplementation } from "@bitwarden/common/platform/services/cryptography/encrypt.service.implementation";
import { MultithreadEncryptServiceImplementation } from "@bitwarden/common/platform/services/cryptography/multithread-encrypt.service.implementation";
import { DefaultBroadcasterService } from "@bitwarden/common/platform/services/default-broadcaster.service";
import { DefaultEnvironmentService } from "@bitwarden/common/platform/services/default-environment.service";
@ -822,7 +821,7 @@ const safeProviders: SafeProvider[] = [
}),
safeProvider({
provide: EncryptService,
useFactory: encryptServiceFactory,
useClass: MultithreadEncryptServiceImplementation,
deps: [CryptoFunctionServiceAbstraction, LogService, LOG_MAC_FAILURES],
}),
safeProvider({
@ -1242,16 +1241,6 @@ const safeProviders: SafeProvider[] = [
}),
];
function encryptServiceFactory(
cryptoFunctionservice: CryptoFunctionServiceAbstraction,
logService: LogService,
logMacFailures: boolean,
): EncryptService {
return flagEnabled("multithreadDecryption")
? new MultithreadEncryptServiceImplementation(cryptoFunctionservice, logService, logMacFailures)
: new EncryptServiceImplementation(cryptoFunctionservice, logService, logMacFailures);
}
@NgModule({
declarations: [],
// Do not register your dependency here! Add it to the typesafeProviders array using the helper function

View File

@ -1,7 +1,6 @@
// required to avoid linting errors when there are no flags
// eslint-disable-next-line @typescript-eslint/ban-types
export type SharedFlags = {
multithreadDecryption: boolean;
showPasswordless?: boolean;
enableCipherKeyEncryption?: boolean;
};