mirror of
https://github.com/bitwarden/browser.git
synced 2024-11-22 11:45:59 +01:00
[PM-4154] Introduce Bulk Encrypt Service for Faster Unlock Times (#6465)
* Implement multi-worker encryption service * Fix feature flag being flipped and check for empty input earlier * Add tests * Small cleanup * Remove restricted import * Rename feature flag * Refactor to BulkEncryptService * Rename feature flag * Fix cipher service spec * Implement browser bulk encryption service * Un-deprecate browserbulkencryptservice * Load browser bulk encrypt service on feature flag asynchronously * Fix bulk encryption service factories * Deprecate BrowserMultithreadEncryptServiceImplementation * Copy tests for browser-bulk-encrypt-service-implementation from browser-multithread-encrypt-service-implementation * Make sure desktop uses non-bulk fallback during feature rollout * Rename FallbackBulkEncryptService and fix service dependency issue * Disable bulk encrypt service on mv3 * Change condition order to avoid expensive api call * Set default hardware concurrency to 1 if not available * Make getdecrypteditemfromworker private * Fix cli build * Add check for key being null
This commit is contained in:
parent
9b50e5c496
commit
84b719d797
@ -112,7 +112,9 @@ 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 { ContainerService } from "@bitwarden/common/platform/services/container.service";
|
||||
import { BulkEncryptServiceImplementation } from "@bitwarden/common/platform/services/cryptography/bulk-encrypt.service.implementation";
|
||||
import { EncryptServiceImplementation } from "@bitwarden/common/platform/services/cryptography/encrypt.service.implementation";
|
||||
import { FallbackBulkEncryptService } from "@bitwarden/common/platform/services/cryptography/fallback-bulk-encrypt.service";
|
||||
import { MultithreadEncryptServiceImplementation } from "@bitwarden/common/platform/services/cryptography/multithread-encrypt.service.implementation";
|
||||
import { Fido2AuthenticatorService } from "@bitwarden/common/platform/services/fido2/fido2-authenticator.service";
|
||||
import { Fido2ClientService } from "@bitwarden/common/platform/services/fido2/fido2-client.service";
|
||||
@ -247,7 +249,6 @@ import CommandsBackground from "./commands.background";
|
||||
import IdleBackground from "./idle.background";
|
||||
import { NativeMessagingBackground } from "./nativeMessaging.background";
|
||||
import RuntimeBackground from "./runtime.background";
|
||||
|
||||
export default class MainBackground {
|
||||
messagingService: MessageSender;
|
||||
storageService: BrowserLocalStorageService;
|
||||
@ -306,6 +307,7 @@ export default class MainBackground {
|
||||
vaultFilterService: VaultFilterService;
|
||||
usernameGenerationService: UsernameGenerationServiceAbstraction;
|
||||
encryptService: EncryptService;
|
||||
bulkEncryptService: FallbackBulkEncryptService;
|
||||
folderApiService: FolderApiServiceAbstraction;
|
||||
policyApiService: PolicyApiServiceAbstraction;
|
||||
sendApiService: SendApiServiceAbstraction;
|
||||
@ -744,6 +746,7 @@ export default class MainBackground {
|
||||
this.stateService,
|
||||
this.autofillSettingsService,
|
||||
this.encryptService,
|
||||
this.bulkEncryptService,
|
||||
this.cipherFileUploadService,
|
||||
this.configService,
|
||||
this.stateProvider,
|
||||
@ -1227,6 +1230,15 @@ export default class MainBackground {
|
||||
this.webRequestBackground?.startListening();
|
||||
this.syncServiceListener?.listener$().subscribe();
|
||||
|
||||
if (
|
||||
BrowserApi.isManifestVersion(2) &&
|
||||
(await this.configService.getFeatureFlag(FeatureFlag.PM4154_BulkEncryptionService))
|
||||
) {
|
||||
await this.bulkEncryptService.setFeatureFlagEncryptService(
|
||||
new BulkEncryptServiceImplementation(this.cryptoFunctionService, this.logService),
|
||||
);
|
||||
}
|
||||
|
||||
return new Promise<void>((resolve) => {
|
||||
setTimeout(async () => {
|
||||
await this.refreshBadge();
|
||||
|
@ -75,6 +75,7 @@ import { DefaultConfigService } from "@bitwarden/common/platform/services/config
|
||||
import { ContainerService } from "@bitwarden/common/platform/services/container.service";
|
||||
import { CryptoService } from "@bitwarden/common/platform/services/crypto.service";
|
||||
import { EncryptServiceImplementation } from "@bitwarden/common/platform/services/cryptography/encrypt.service.implementation";
|
||||
import { FallbackBulkEncryptService } from "@bitwarden/common/platform/services/cryptography/fallback-bulk-encrypt.service";
|
||||
import { DefaultEnvironmentService } from "@bitwarden/common/platform/services/default-environment.service";
|
||||
import { FileUploadService } from "@bitwarden/common/platform/services/file-upload/file-upload.service";
|
||||
import { KeyGenerationService } from "@bitwarden/common/platform/services/key-generation.service";
|
||||
@ -605,6 +606,7 @@ export class ServiceContainer {
|
||||
this.stateService,
|
||||
this.autofillSettingsService,
|
||||
this.encryptService,
|
||||
new FallbackBulkEncryptService(this.encryptService),
|
||||
this.cipherFileUploadService,
|
||||
this.configService,
|
||||
this.stateProvider,
|
||||
|
@ -4,6 +4,8 @@ import mock from "jest-mock-extended/lib/Mock";
|
||||
import { ApiService } from "@bitwarden/common/abstractions/api.service";
|
||||
import { ListResponse } from "@bitwarden/common/models/response/list.response";
|
||||
import { UserKeyResponse } from "@bitwarden/common/models/response/user-key.response";
|
||||
import { BulkEncryptService } from "@bitwarden/common/platform/abstractions/bulk-encrypt.service";
|
||||
import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service";
|
||||
import { CryptoService } from "@bitwarden/common/platform/abstractions/crypto.service";
|
||||
import { EncryptService } from "@bitwarden/common/platform/abstractions/encrypt.service";
|
||||
import { LogService } from "@bitwarden/common/platform/abstractions/log.service";
|
||||
@ -31,15 +33,18 @@ describe("EmergencyAccessService", () => {
|
||||
let apiService: MockProxy<ApiService>;
|
||||
let cryptoService: MockProxy<CryptoService>;
|
||||
let encryptService: MockProxy<EncryptService>;
|
||||
let bulkEncryptService: MockProxy<BulkEncryptService>;
|
||||
let cipherService: MockProxy<CipherService>;
|
||||
let logService: MockProxy<LogService>;
|
||||
let emergencyAccessService: EmergencyAccessService;
|
||||
let configService: ConfigService;
|
||||
|
||||
beforeAll(() => {
|
||||
emergencyAccessApiService = mock<EmergencyAccessApiService>();
|
||||
apiService = mock<ApiService>();
|
||||
cryptoService = mock<CryptoService>();
|
||||
encryptService = mock<EncryptService>();
|
||||
bulkEncryptService = mock<BulkEncryptService>();
|
||||
cipherService = mock<CipherService>();
|
||||
logService = mock<LogService>();
|
||||
|
||||
@ -48,8 +53,10 @@ describe("EmergencyAccessService", () => {
|
||||
apiService,
|
||||
cryptoService,
|
||||
encryptService,
|
||||
bulkEncryptService,
|
||||
cipherService,
|
||||
logService,
|
||||
configService,
|
||||
);
|
||||
});
|
||||
|
||||
|
@ -9,6 +9,9 @@ import {
|
||||
KdfConfig,
|
||||
PBKDF2KdfConfig,
|
||||
} from "@bitwarden/common/auth/models/domain/kdf-config";
|
||||
import { FeatureFlag } from "@bitwarden/common/enums/feature-flag.enum";
|
||||
import { BulkEncryptService } from "@bitwarden/common/platform/abstractions/bulk-encrypt.service";
|
||||
import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service";
|
||||
import { CryptoService } from "@bitwarden/common/platform/abstractions/crypto.service";
|
||||
import { EncryptService } from "@bitwarden/common/platform/abstractions/encrypt.service";
|
||||
import { LogService } from "@bitwarden/common/platform/abstractions/log.service";
|
||||
@ -45,8 +48,10 @@ export class EmergencyAccessService
|
||||
private apiService: ApiService,
|
||||
private cryptoService: CryptoService,
|
||||
private encryptService: EncryptService,
|
||||
private bulkEncryptService: BulkEncryptService,
|
||||
private cipherService: CipherService,
|
||||
private logService: LogService,
|
||||
private configService: ConfigService,
|
||||
) {}
|
||||
|
||||
/**
|
||||
@ -225,10 +230,18 @@ export class EmergencyAccessService
|
||||
);
|
||||
const grantorUserKey = new SymmetricCryptoKey(grantorKeyBuffer) as UserKey;
|
||||
|
||||
const ciphers = await this.encryptService.decryptItems(
|
||||
let ciphers: CipherView[] = [];
|
||||
if (await this.configService.getFeatureFlag(FeatureFlag.PM4154_BulkEncryptionService)) {
|
||||
ciphers = await this.bulkEncryptService.decryptItems(
|
||||
response.ciphers.map((c) => new Cipher(c)),
|
||||
grantorUserKey,
|
||||
);
|
||||
} else {
|
||||
ciphers = await this.encryptService.decryptItems(
|
||||
response.ciphers.map((c) => new Cipher(c)),
|
||||
grantorUserKey,
|
||||
);
|
||||
}
|
||||
return ciphers.sort(this.cipherService.getLocaleSortingFunction());
|
||||
}
|
||||
|
||||
|
@ -131,6 +131,7 @@ import { BraintreeService } from "@bitwarden/common/billing/services/payment-pro
|
||||
import { StripeService } from "@bitwarden/common/billing/services/payment-processors/stripe.service";
|
||||
import { AppIdService as AppIdServiceAbstraction } from "@bitwarden/common/platform/abstractions/app-id.service";
|
||||
import { BroadcasterService } from "@bitwarden/common/platform/abstractions/broadcaster.service";
|
||||
import { BulkEncryptService } from "@bitwarden/common/platform/abstractions/bulk-encrypt.service";
|
||||
import { ConfigApiServiceAbstraction } from "@bitwarden/common/platform/abstractions/config/config-api.service.abstraction";
|
||||
import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service";
|
||||
import { CryptoFunctionService as CryptoFunctionServiceAbstraction } from "@bitwarden/common/platform/abstractions/crypto-function.service";
|
||||
@ -166,6 +167,7 @@ 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 { BulkEncryptServiceImplementation } from "@bitwarden/common/platform/services/cryptography/bulk-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";
|
||||
@ -437,6 +439,7 @@ const safeProviders: SafeProvider[] = [
|
||||
stateService: StateServiceAbstraction,
|
||||
autofillSettingsService: AutofillSettingsServiceAbstraction,
|
||||
encryptService: EncryptService,
|
||||
bulkEncryptService: BulkEncryptService,
|
||||
fileUploadService: CipherFileUploadServiceAbstraction,
|
||||
configService: ConfigService,
|
||||
stateProvider: StateProvider,
|
||||
@ -450,6 +453,7 @@ const safeProviders: SafeProvider[] = [
|
||||
stateService,
|
||||
autofillSettingsService,
|
||||
encryptService,
|
||||
bulkEncryptService,
|
||||
fileUploadService,
|
||||
configService,
|
||||
stateProvider,
|
||||
@ -463,6 +467,7 @@ const safeProviders: SafeProvider[] = [
|
||||
StateServiceAbstraction,
|
||||
AutofillSettingsServiceAbstraction,
|
||||
EncryptService,
|
||||
BulkEncryptService,
|
||||
CipherFileUploadServiceAbstraction,
|
||||
ConfigService,
|
||||
StateProvider,
|
||||
@ -832,6 +837,11 @@ const safeProviders: SafeProvider[] = [
|
||||
useClass: MultithreadEncryptServiceImplementation,
|
||||
deps: [CryptoFunctionServiceAbstraction, LogService, LOG_MAC_FAILURES],
|
||||
}),
|
||||
safeProvider({
|
||||
provide: BulkEncryptService,
|
||||
useClass: BulkEncryptServiceImplementation,
|
||||
deps: [CryptoFunctionServiceAbstraction, LogService],
|
||||
}),
|
||||
safeProvider({
|
||||
provide: EventUploadServiceAbstraction,
|
||||
useClass: EventUploadService,
|
||||
|
@ -14,6 +14,7 @@ export enum FeatureFlag {
|
||||
EnableDeleteProvider = "AC-1218-delete-provider",
|
||||
ExtensionRefresh = "extension-refresh",
|
||||
RestrictProviderAccess = "restrict-provider-access",
|
||||
PM4154_BulkEncryptionService = "PM-4154-bulk-encryption-service",
|
||||
UseTreeWalkerApiForPageDetailsCollection = "use-tree-walker-api-for-page-details-collection",
|
||||
EmailVerification = "email-verification",
|
||||
InlineMenuFieldQualification = "inline-menu-field-qualification",
|
||||
@ -49,6 +50,7 @@ export const DefaultFeatureFlagValue = {
|
||||
[FeatureFlag.EnableDeleteProvider]: FALSE,
|
||||
[FeatureFlag.ExtensionRefresh]: FALSE,
|
||||
[FeatureFlag.RestrictProviderAccess]: FALSE,
|
||||
[FeatureFlag.PM4154_BulkEncryptionService]: FALSE,
|
||||
[FeatureFlag.UseTreeWalkerApiForPageDetailsCollection]: FALSE,
|
||||
[FeatureFlag.EmailVerification]: FALSE,
|
||||
[FeatureFlag.InlineMenuFieldQualification]: FALSE,
|
||||
|
@ -0,0 +1,10 @@
|
||||
import { Decryptable } from "../interfaces/decryptable.interface";
|
||||
import { InitializerMetadata } from "../interfaces/initializer-metadata.interface";
|
||||
import { SymmetricCryptoKey } from "../models/domain/symmetric-crypto-key";
|
||||
|
||||
export abstract class BulkEncryptService {
|
||||
abstract decryptItems<T extends InitializerMetadata>(
|
||||
items: Decryptable<T>[],
|
||||
key: SymmetricCryptoKey,
|
||||
): Promise<T[]>;
|
||||
}
|
@ -13,6 +13,11 @@ export abstract class EncryptService {
|
||||
abstract rsaEncrypt(data: Uint8Array, publicKey: Uint8Array): Promise<EncString>;
|
||||
abstract rsaDecrypt(data: EncString, privateKey: Uint8Array): Promise<Uint8Array>;
|
||||
abstract resolveLegacyKey(key: SymmetricCryptoKey, encThing: Encrypted): SymmetricCryptoKey;
|
||||
/**
|
||||
* @deprecated Replaced by BulkEncryptService, remove once the feature is tested and the featureflag PM-4154-multi-worker-encryption-service is removed
|
||||
* @param items The items to decrypt
|
||||
* @param key The key to decrypt the items with
|
||||
*/
|
||||
abstract decryptItems<T extends InitializerMetadata>(
|
||||
items: Decryptable<T>[],
|
||||
key: SymmetricCryptoKey,
|
||||
|
@ -0,0 +1,164 @@
|
||||
import { firstValueFrom, fromEvent, filter, map, takeUntil, defaultIfEmpty, Subject } from "rxjs";
|
||||
import { Jsonify } from "type-fest";
|
||||
|
||||
import { BulkEncryptService } from "../../abstractions/bulk-encrypt.service";
|
||||
import { CryptoFunctionService } from "../../abstractions/crypto-function.service";
|
||||
import { LogService } from "../../abstractions/log.service";
|
||||
import { Decryptable } from "../../interfaces/decryptable.interface";
|
||||
import { InitializerMetadata } from "../../interfaces/initializer-metadata.interface";
|
||||
import { Utils } from "../../misc/utils";
|
||||
import { SymmetricCryptoKey } from "../../models/domain/symmetric-crypto-key";
|
||||
|
||||
import { getClassInitializer } from "./get-class-initializer";
|
||||
|
||||
// TTL (time to live) is not strictly required but avoids tying up memory resources if inactive
|
||||
const workerTTL = 60000; // 1 minute
|
||||
const maxWorkers = 8;
|
||||
const minNumberOfItemsForMultithreading = 400;
|
||||
|
||||
export class BulkEncryptServiceImplementation implements BulkEncryptService {
|
||||
private workers: Worker[] = [];
|
||||
private timeout: any;
|
||||
|
||||
private clear$ = new Subject<void>();
|
||||
|
||||
constructor(
|
||||
protected cryptoFunctionService: CryptoFunctionService,
|
||||
protected logService: LogService,
|
||||
) {}
|
||||
|
||||
/**
|
||||
* Decrypts items using a web worker if the environment supports it.
|
||||
* Will fall back to the main thread if the window object is not available.
|
||||
*/
|
||||
async decryptItems<T extends InitializerMetadata>(
|
||||
items: Decryptable<T>[],
|
||||
key: SymmetricCryptoKey,
|
||||
): Promise<T[]> {
|
||||
if (key == null) {
|
||||
throw new Error("No encryption key provided.");
|
||||
}
|
||||
|
||||
if (items == null || items.length < 1) {
|
||||
return [];
|
||||
}
|
||||
|
||||
if (typeof window === "undefined") {
|
||||
this.logService.info("Window not available in BulkEncryptService, decrypting sequentially");
|
||||
const results = [];
|
||||
for (let i = 0; i < items.length; i++) {
|
||||
results.push(await items[i].decrypt(key));
|
||||
}
|
||||
return results;
|
||||
}
|
||||
|
||||
const decryptedItems = await this.getDecryptedItemsFromWorkers(items, key);
|
||||
return decryptedItems;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends items to a set of web workers to decrypt them. This utilizes multiple workers to decrypt items
|
||||
* faster without interrupting other operations (e.g. updating UI).
|
||||
*/
|
||||
private async getDecryptedItemsFromWorkers<T extends InitializerMetadata>(
|
||||
items: Decryptable<T>[],
|
||||
key: SymmetricCryptoKey,
|
||||
): Promise<T[]> {
|
||||
if (items == null || items.length < 1) {
|
||||
return [];
|
||||
}
|
||||
|
||||
this.clearTimeout();
|
||||
|
||||
const hardwareConcurrency = navigator.hardwareConcurrency || 1;
|
||||
let numberOfWorkers = Math.min(hardwareConcurrency, maxWorkers);
|
||||
if (items.length < minNumberOfItemsForMultithreading) {
|
||||
numberOfWorkers = 1;
|
||||
}
|
||||
|
||||
this.logService.info(
|
||||
`Starting decryption using multithreading with ${numberOfWorkers} workers for ${items.length} items`,
|
||||
);
|
||||
|
||||
if (this.workers.length == 0) {
|
||||
for (let i = 0; i < numberOfWorkers; i++) {
|
||||
this.workers.push(
|
||||
new Worker(
|
||||
new URL(
|
||||
/* webpackChunkName: 'encrypt-worker' */
|
||||
"@bitwarden/common/platform/services/cryptography/encrypt.worker.ts",
|
||||
import.meta.url,
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const itemsPerWorker = Math.floor(items.length / this.workers.length);
|
||||
const results = [];
|
||||
|
||||
for (const [i, worker] of this.workers.entries()) {
|
||||
const start = i * itemsPerWorker;
|
||||
const end = start + itemsPerWorker;
|
||||
const itemsForWorker = items.slice(start, end);
|
||||
|
||||
// push the remaining items to the last worker
|
||||
if (i == this.workers.length - 1) {
|
||||
itemsForWorker.push(...items.slice(end));
|
||||
}
|
||||
|
||||
const request = {
|
||||
id: Utils.newGuid(),
|
||||
items: itemsForWorker,
|
||||
key: key,
|
||||
};
|
||||
|
||||
worker.postMessage(JSON.stringify(request));
|
||||
results.push(
|
||||
firstValueFrom(
|
||||
fromEvent(worker, "message").pipe(
|
||||
filter((response: MessageEvent) => response.data?.id === request.id),
|
||||
map((response) => JSON.parse(response.data.items)),
|
||||
map((items) =>
|
||||
items.map((jsonItem: Jsonify<T>) => {
|
||||
const initializer = getClassInitializer<T>(jsonItem.initializerKey);
|
||||
return initializer(jsonItem);
|
||||
}),
|
||||
),
|
||||
takeUntil(this.clear$),
|
||||
defaultIfEmpty([]),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
const decryptedItems = (await Promise.all(results)).flat();
|
||||
this.logService.info(
|
||||
`Finished decrypting ${decryptedItems.length} items using ${numberOfWorkers} workers`,
|
||||
);
|
||||
|
||||
this.restartTimeout();
|
||||
|
||||
return decryptedItems;
|
||||
}
|
||||
|
||||
private clear() {
|
||||
this.clear$.next();
|
||||
for (const worker of this.workers) {
|
||||
worker.terminate();
|
||||
}
|
||||
this.workers = [];
|
||||
this.clearTimeout();
|
||||
}
|
||||
|
||||
private restartTimeout() {
|
||||
this.clearTimeout();
|
||||
this.timeout = setTimeout(() => this.clear(), workerTTL);
|
||||
}
|
||||
|
||||
private clearTimeout() {
|
||||
if (this.timeout != null) {
|
||||
clearTimeout(this.timeout);
|
||||
}
|
||||
}
|
||||
}
|
@ -185,6 +185,9 @@ export class EncryptServiceImplementation implements EncryptService {
|
||||
return this.cryptoFunctionService.rsaDecrypt(data.dataBytes, privateKey, algorithm);
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Replaced by BulkEncryptService (PM-4154)
|
||||
*/
|
||||
async decryptItems<T extends InitializerMetadata>(
|
||||
items: Decryptable<T>[],
|
||||
key: SymmetricCryptoKey,
|
||||
|
@ -0,0 +1,33 @@
|
||||
import { BulkEncryptService } from "../../abstractions/bulk-encrypt.service";
|
||||
import { EncryptService } from "../../abstractions/encrypt.service";
|
||||
import { Decryptable } from "../../interfaces/decryptable.interface";
|
||||
import { InitializerMetadata } from "../../interfaces/initializer-metadata.interface";
|
||||
import { SymmetricCryptoKey } from "../../models/domain/symmetric-crypto-key";
|
||||
|
||||
/**
|
||||
* @deprecated For the feature flag from PM-4154, remove once feature is rolled out
|
||||
*/
|
||||
export class FallbackBulkEncryptService implements BulkEncryptService {
|
||||
private featureFlagEncryptService: BulkEncryptService;
|
||||
|
||||
constructor(protected encryptService: EncryptService) {}
|
||||
|
||||
/**
|
||||
* Decrypts items using a web worker if the environment supports it.
|
||||
* Will fall back to the main thread if the window object is not available.
|
||||
*/
|
||||
async decryptItems<T extends InitializerMetadata>(
|
||||
items: Decryptable<T>[],
|
||||
key: SymmetricCryptoKey,
|
||||
): Promise<T[]> {
|
||||
if (this.featureFlagEncryptService != null) {
|
||||
return await this.featureFlagEncryptService.decryptItems(items, key);
|
||||
} else {
|
||||
return await this.encryptService.decryptItems(items, key);
|
||||
}
|
||||
}
|
||||
|
||||
async setFeatureFlagEncryptService(featureFlagEncryptService: BulkEncryptService) {
|
||||
this.featureFlagEncryptService = featureFlagEncryptService;
|
||||
}
|
||||
}
|
@ -12,6 +12,9 @@ import { getClassInitializer } from "./get-class-initializer";
|
||||
// TTL (time to live) is not strictly required but avoids tying up memory resources if inactive
|
||||
const workerTTL = 3 * 60000; // 3 minutes
|
||||
|
||||
/**
|
||||
* @deprecated Replaced by BulkEncryptionService (PM-4154)
|
||||
*/
|
||||
export class MultithreadEncryptServiceImplementation extends EncryptServiceImplementation {
|
||||
private worker: Worker;
|
||||
private timeout: any;
|
||||
|
@ -1,6 +1,8 @@
|
||||
import { mock } from "jest-mock-extended";
|
||||
import { BehaviorSubject, of } from "rxjs";
|
||||
|
||||
import { BulkEncryptService } from "@bitwarden/common/platform/abstractions/bulk-encrypt.service";
|
||||
|
||||
import { FakeAccountService, mockAccountServiceWith } from "../../../spec/fake-account-service";
|
||||
import { FakeStateProvider } from "../../../spec/fake-state-provider";
|
||||
import { makeStaticByteArray } from "../../../spec/utils";
|
||||
@ -114,6 +116,7 @@ describe("Cipher Service", () => {
|
||||
const i18nService = mock<I18nService>();
|
||||
const searchService = mock<SearchService>();
|
||||
const encryptService = mock<EncryptService>();
|
||||
const bulkEncryptService = mock<BulkEncryptService>();
|
||||
const configService = mock<ConfigService>();
|
||||
accountService = mockAccountServiceWith(mockUserId);
|
||||
const stateProvider = new FakeStateProvider(accountService);
|
||||
@ -136,6 +139,7 @@ describe("Cipher Service", () => {
|
||||
stateService,
|
||||
autofillSettingsService,
|
||||
encryptService,
|
||||
bulkEncryptService,
|
||||
cipherFileUploadService,
|
||||
configService,
|
||||
stateProvider,
|
||||
|
@ -1,6 +1,9 @@
|
||||
import { firstValueFrom, map, Observable, skipWhile, switchMap } from "rxjs";
|
||||
import { SemVer } from "semver";
|
||||
|
||||
import { FeatureFlag } from "@bitwarden/common/enums/feature-flag.enum";
|
||||
import { BulkEncryptService } from "@bitwarden/common/platform/abstractions/bulk-encrypt.service";
|
||||
|
||||
import { ApiService } from "../../abstractions/api.service";
|
||||
import { SearchService } from "../../abstractions/search.service";
|
||||
import { AutofillSettingsServiceAbstraction } from "../../autofill/services/autofill-settings.service";
|
||||
@ -102,6 +105,7 @@ export class CipherService implements CipherServiceAbstraction {
|
||||
private stateService: StateService,
|
||||
private autofillSettingsService: AutofillSettingsServiceAbstraction,
|
||||
private encryptService: EncryptService,
|
||||
private bulkEncryptService: BulkEncryptService,
|
||||
private cipherFileUploadService: CipherFileUploadService,
|
||||
private configService: ConfigService,
|
||||
private stateProvider: StateProvider,
|
||||
@ -397,12 +401,19 @@ export class CipherService implements CipherServiceAbstraction {
|
||||
|
||||
const decCiphers = (
|
||||
await Promise.all(
|
||||
Object.entries(grouped).map(([orgId, groupedCiphers]) =>
|
||||
this.encryptService.decryptItems(
|
||||
Object.entries(grouped).map(async ([orgId, groupedCiphers]) => {
|
||||
if (await this.configService.getFeatureFlag(FeatureFlag.PM4154_BulkEncryptionService)) {
|
||||
return await this.bulkEncryptService.decryptItems(
|
||||
groupedCiphers,
|
||||
keys.orgKeys[orgId as OrganizationId] ?? keys.userKey,
|
||||
),
|
||||
),
|
||||
);
|
||||
} else {
|
||||
return await this.encryptService.decryptItems(
|
||||
groupedCiphers,
|
||||
keys.orgKeys[orgId as OrganizationId] ?? keys.userKey,
|
||||
);
|
||||
}
|
||||
}),
|
||||
)
|
||||
)
|
||||
.flat()
|
||||
@ -515,7 +526,12 @@ export class CipherService implements CipherServiceAbstraction {
|
||||
|
||||
const ciphers = response.data.map((cr) => new Cipher(new CipherData(cr)));
|
||||
const key = await this.cryptoService.getOrgKey(organizationId);
|
||||
const decCiphers = await this.encryptService.decryptItems(ciphers, key);
|
||||
let decCiphers: CipherView[] = [];
|
||||
if (await this.configService.getFeatureFlag(FeatureFlag.PM4154_BulkEncryptionService)) {
|
||||
decCiphers = await this.bulkEncryptService.decryptItems(ciphers, key);
|
||||
} else {
|
||||
decCiphers = await this.encryptService.decryptItems(ciphers, key);
|
||||
}
|
||||
|
||||
decCiphers.sort(this.getLocaleSortingFunction());
|
||||
return decCiphers;
|
||||
|
Loading…
Reference in New Issue
Block a user