This commit is contained in:
Bernd Schoolmann 2024-05-17 23:13:56 +02:00 committed by GitHub
commit 9139cddde8
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
15 changed files with 335 additions and 10 deletions

View File

@ -72,7 +72,9 @@ import {
import { BillingAccountProfileStateService } from "@bitwarden/common/billing/abstractions/account/billing-account-profile-state.service";
import { DefaultBillingAccountProfileStateService } from "@bitwarden/common/billing/services/account/billing-account-profile-state.service";
import { ClientType } from "@bitwarden/common/enums";
import { FeatureFlag } from "@bitwarden/common/enums/feature-flag.enum";
import { AppIdService as AppIdServiceAbstraction } from "@bitwarden/common/platform/abstractions/app-id.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";
@ -108,7 +110,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 { FallbackBulkEncryptServiceImplementation } from "@bitwarden/common/platform/services/cryptography/fallback-bulk-encrypt.service.implementation";
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";
@ -244,7 +248,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;
@ -303,6 +306,7 @@ export default class MainBackground {
vaultFilterService: VaultFilterService;
usernameGenerationService: UsernameGenerationServiceAbstraction;
encryptService: EncryptService;
bulkEncryptService: BulkEncryptService;
folderApiService: FolderApiServiceAbstraction;
policyApiService: PolicyApiServiceAbstraction;
sendApiService: SendApiServiceAbstraction;
@ -487,6 +491,7 @@ export default class MainBackground {
true,
)
: new EncryptServiceImplementation(this.cryptoFunctionService, this.logService, true);
this.bulkEncryptService = new FallbackBulkEncryptServiceImplementation(this.encryptService);
this.singleUserStateProvider = new DefaultSingleUserStateProvider(
storageServiceProvider,
@ -721,6 +726,7 @@ export default class MainBackground {
this.stateService,
this.autofillSettingsService,
this.encryptService,
this.bulkEncryptService,
this.cipherFileUploadService,
this.configService,
this.stateProvider,
@ -1167,6 +1173,13 @@ export default class MainBackground {
this.webRequestBackground?.startListening();
this.syncServiceListener?.startListening();
if (await this.configService.getFeatureFlag(FeatureFlag.PM4154_BulkEncryptionService)) {
this.bulkEncryptService = new BulkEncryptServiceImplementation(
this.cryptoFunctionService,
this.logService,
);
}
return new Promise<void>((resolve) => {
setTimeout(async () => {
await this.refreshBadge();

View File

@ -0,0 +1,31 @@
import { BulkEncryptServiceImplementation } from "@bitwarden/common/platform/services/cryptography/bulk-encrypt.service.implementation";
import {
CryptoFunctionServiceInitOptions,
cryptoFunctionServiceFactory,
} from "./crypto-function-service.factory";
import { EncryptServiceInitOptions } from "./encrypt-service.factory";
import { FactoryOptions, CachedServices, factory } from "./factory-options";
import { LogServiceInitOptions, logServiceFactory } from "./log-service.factory";
type BulkEncryptServiceFactoryOptions = FactoryOptions;
export type BulkEncryptServiceInitOptions = BulkEncryptServiceFactoryOptions &
CryptoFunctionServiceInitOptions &
LogServiceInitOptions;
export function bulkEncryptServiceFactory(
cache: { bulkEncryptService?: BulkEncryptServiceImplementation } & CachedServices,
opts: EncryptServiceInitOptions,
): Promise<BulkEncryptServiceImplementation> {
return factory(
cache,
"bulkEncryptService",
opts,
async () =>
new BulkEncryptServiceImplementation(
await cryptoFunctionServiceFactory(cache, opts),
await logServiceFactory(cache, opts),
),
);
}

View File

@ -21,6 +21,10 @@ import {
apiServiceFactory,
ApiServiceInitOptions,
} from "../../../platform/background/service-factories/api-service.factory";
import {
BulkEncryptServiceInitOptions,
bulkEncryptServiceFactory,
} from "../../../platform/background/service-factories/bulk-encrypt-service.factory";
import {
configServiceFactory,
ConfigServiceInitOptions,
@ -44,8 +48,8 @@ import {
} from "../../../platform/background/service-factories/i18n-service.factory";
import { stateProviderFactory } from "../../../platform/background/service-factories/state-provider.factory";
import {
stateServiceFactory,
StateServiceInitOptions,
stateServiceFactory,
} from "../../../platform/background/service-factories/state-service.factory";
type CipherServiceFactoryOptions = FactoryOptions;
@ -60,6 +64,7 @@ export type CipherServiceInitOptions = CipherServiceFactoryOptions &
AutofillSettingsServiceInitOptions &
DomainSettingsServiceInitOptions &
EncryptServiceInitOptions &
BulkEncryptServiceInitOptions &
ConfigServiceInitOptions;
export function cipherServiceFactory(
@ -80,6 +85,7 @@ export function cipherServiceFactory(
await stateServiceFactory(cache, opts),
await autofillSettingsServiceFactory(cache, opts),
await encryptServiceFactory(cache, opts),
await bulkEncryptServiceFactory(cache, opts),
await cipherFileUploadServiceFactory(cache, opts),
await configServiceFactory(cache, opts),
await stateProviderFactory(cache, opts),

View File

@ -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";
@ -30,15 +32,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>();
@ -47,8 +52,10 @@ describe("EmergencyAccessService", () => {
apiService,
cryptoService,
encryptService,
bulkEncryptService,
cipherService,
logService,
configService,
);
});

View File

@ -8,6 +8,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";
@ -41,8 +44,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,
) {}
/**
@ -221,10 +226,18 @@ export class EmergencyAccessService {
);
const grantorUserKey = new SymmetricCryptoKey(grantorKeyBuffer) as UserKey;
const ciphers = await this.encryptService.decryptItems(
response.ciphers.map((c) => new Cipher(c)),
grantorUserKey,
);
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());
}

View File

@ -119,6 +119,7 @@ import { OrganizationBillingService } from "@bitwarden/common/billing/services/o
import { PaymentMethodWarningsService } from "@bitwarden/common/billing/services/payment-method-warnings.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";
@ -150,7 +151,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 { CryptoService } from "@bitwarden/common/platform/services/crypto.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 { FallbackBulkEncryptServiceImplementation } from "@bitwarden/common/platform/services/cryptography/fallback-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";
@ -418,6 +421,7 @@ const safeProviders: SafeProvider[] = [
stateService: StateServiceAbstraction,
autofillSettingsService: AutofillSettingsServiceAbstraction,
encryptService: EncryptService,
bulkEncryptService: BulkEncryptService,
fileUploadService: CipherFileUploadServiceAbstraction,
configService: ConfigService,
stateProvider: StateProvider,
@ -431,6 +435,7 @@ const safeProviders: SafeProvider[] = [
stateService,
autofillSettingsService,
encryptService,
bulkEncryptService,
fileUploadService,
configService,
stateProvider,
@ -444,6 +449,7 @@ const safeProviders: SafeProvider[] = [
StateServiceAbstraction,
AutofillSettingsServiceAbstraction,
EncryptService,
BulkEncryptService,
CipherFileUploadServiceAbstraction,
ConfigService,
StateProvider,
@ -778,6 +784,11 @@ const safeProviders: SafeProvider[] = [
useFactory: encryptServiceFactory,
deps: [CryptoFunctionServiceAbstraction, LogService, LOG_MAC_FAILURES],
}),
safeProvider({
provide: BulkEncryptService,
useFactory: bulkEncryptServiceFactory,
deps: [CryptoFunctionServiceAbstraction, EncryptService, LogService],
}),
safeProvider({
provide: EventUploadServiceAbstraction,
useClass: EventUploadService,
@ -1178,6 +1189,9 @@ const safeProviders: SafeProvider[] = [
}),
];
/**
* @deprecated
*/
function encryptServiceFactory(
cryptoFunctionservice: CryptoFunctionServiceAbstraction,
logService: LogService,
@ -1188,6 +1202,19 @@ function encryptServiceFactory(
: new EncryptServiceImplementation(cryptoFunctionservice, logService, logMacFailures);
}
/**
* @deprecated
*/
function bulkEncryptServiceFactory(
cryptoFunctionservice: CryptoFunctionServiceAbstraction,
encryptService: EncryptService,
logService: LogService,
): BulkEncryptService {
return flagEnabled("multithreadDecryption")
? new BulkEncryptServiceImplementation(cryptoFunctionservice, logService)
: new FallbackBulkEncryptServiceImplementation(encryptService);
}
@NgModule({
declarations: [],
// Do not register your dependency here! Add it to the typesafeProviders array using the helper function

View File

@ -17,6 +17,7 @@ export enum FeatureFlag {
EnableDeleteProvider = "AC-1218-delete-provider",
ExtensionRefresh = "extension-refresh",
RestrictProviderAccess = "restrict-provider-access",
PM4154_BulkEncryptionService = "PM-4154-bulk-encryption-service",
}
export type AllowedFeatureFlagTypes = boolean | number | string;
@ -44,6 +45,7 @@ export const DefaultFeatureFlagValue = {
[FeatureFlag.EnableDeleteProvider]: FALSE,
[FeatureFlag.ExtensionRefresh]: FALSE,
[FeatureFlag.RestrictProviderAccess]: FALSE,
[FeatureFlag.PM4154_BulkEncryptionService]: FALSE,
} satisfies Record<FeatureFlag, AllowedFeatureFlagTypes>;
export type DefaultFeatureFlagValueType = typeof DefaultFeatureFlagValue;

View File

@ -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[]>;
}

View File

@ -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,

View File

@ -0,0 +1,159 @@
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 (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).
*/
async getDecryptedItemsFromWorkers<T extends InitializerMetadata>(
items: Decryptable<T>[],
key: SymmetricCryptoKey,
): Promise<T[]> {
if (items == null || items.length < 1) {
return [];
}
this.clearTimeout();
let numberOfWorkers = Math.min(navigator.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);
}
}
}

View File

@ -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,

View File

@ -0,0 +1,23 @@
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 FallbackBulkEncryptServiceImplementation implements 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[]> {
return await this.encryptService.decryptItems(items, key);
}
}

View File

@ -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;

View File

@ -1,6 +1,8 @@
import { mock } from "jest-mock-extended";
import { 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,

View File

@ -1,6 +1,9 @@
import { Observable, firstValueFrom, map, share, 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";
@ -101,6 +104,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,9 +401,19 @@ export class CipherService implements CipherServiceAbstraction {
const decCiphers = (
await Promise.all(
Object.entries(grouped).map(([orgId, groupedCiphers]) =>
this.encryptService.decryptItems(groupedCiphers, orgKeys[orgId] ?? userKey),
),
Object.entries(grouped).map(async ([orgId, groupedCiphers]) => {
if (await this.configService.getFeatureFlag(FeatureFlag.PM4154_BulkEncryptionService)) {
return await this.bulkEncryptService.decryptItems(
groupedCiphers,
orgKeys[orgId] ?? userKey,
);
} else {
return await this.encryptService.decryptItems(
groupedCiphers,
orgKeys[orgId] ?? userKey,
);
}
}),
)
)
.flat()
@ -503,7 +517,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;