mirror of
https://github.com/bitwarden/browser.git
synced 2024-11-22 11:45:59 +01:00
[EC-272] Web workers using EncryptionService (#3532)
* Add item decryption to encryptService * Create multithreadEncryptService subclass to handle web workers * Create encryption web worker * Refactor cipherService to use new interface * Update dependencies
This commit is contained in:
parent
e972e905c8
commit
da47992a22
1
.github/whitelist-capital-letters.txt
vendored
1
.github/whitelist-capital-letters.txt
vendored
@ -235,7 +235,6 @@
|
|||||||
./libs/common/src/abstractions/fileDownload/fileDownloadBuilder.ts
|
./libs/common/src/abstractions/fileDownload/fileDownloadBuilder.ts
|
||||||
./libs/common/src/abstractions/fileDownload/fileDownload.service.ts
|
./libs/common/src/abstractions/fileDownload/fileDownload.service.ts
|
||||||
./libs/common/src/abstractions/fileDownload/fileDownloadRequest.ts
|
./libs/common/src/abstractions/fileDownload/fileDownloadRequest.ts
|
||||||
./libs/common/src/abstractions/abstractEncrypt.service.ts
|
|
||||||
./libs/common/src/abstractions/passwordGeneration.service.ts
|
./libs/common/src/abstractions/passwordGeneration.service.ts
|
||||||
./libs/common/src/abstractions/passwordReprompt.service.ts
|
./libs/common/src/abstractions/passwordReprompt.service.ts
|
||||||
./libs/common/src/abstractions/formValidationErrors.service.ts
|
./libs/common/src/abstractions/formValidationErrors.service.ts
|
||||||
|
@ -6,6 +6,7 @@ import { CipherService as CipherServiceAbstraction } from "@bitwarden/common/abs
|
|||||||
import { CollectionService as CollectionServiceAbstraction } from "@bitwarden/common/abstractions/collection.service";
|
import { CollectionService as CollectionServiceAbstraction } from "@bitwarden/common/abstractions/collection.service";
|
||||||
import { CryptoService as CryptoServiceAbstraction } from "@bitwarden/common/abstractions/crypto.service";
|
import { CryptoService as CryptoServiceAbstraction } from "@bitwarden/common/abstractions/crypto.service";
|
||||||
import { CryptoFunctionService as CryptoFunctionServiceAbstraction } from "@bitwarden/common/abstractions/cryptoFunction.service";
|
import { CryptoFunctionService as CryptoFunctionServiceAbstraction } from "@bitwarden/common/abstractions/cryptoFunction.service";
|
||||||
|
import { EncryptService } from "@bitwarden/common/abstractions/encrypt.service";
|
||||||
import { EventService as EventServiceAbstraction } from "@bitwarden/common/abstractions/event.service";
|
import { EventService as EventServiceAbstraction } from "@bitwarden/common/abstractions/event.service";
|
||||||
import { ExportService as ExportServiceAbstraction } from "@bitwarden/common/abstractions/export.service";
|
import { ExportService as ExportServiceAbstraction } from "@bitwarden/common/abstractions/export.service";
|
||||||
import { FileUploadService as FileUploadServiceAbstraction } from "@bitwarden/common/abstractions/fileUpload.service";
|
import { FileUploadService as FileUploadServiceAbstraction } from "@bitwarden/common/abstractions/fileUpload.service";
|
||||||
@ -51,7 +52,8 @@ import { CipherService } from "@bitwarden/common/services/cipher.service";
|
|||||||
import { CollectionService } from "@bitwarden/common/services/collection.service";
|
import { CollectionService } from "@bitwarden/common/services/collection.service";
|
||||||
import { ConsoleLogService } from "@bitwarden/common/services/consoleLog.service";
|
import { ConsoleLogService } from "@bitwarden/common/services/consoleLog.service";
|
||||||
import { ContainerService } from "@bitwarden/common/services/container.service";
|
import { ContainerService } from "@bitwarden/common/services/container.service";
|
||||||
import { EncryptService } from "@bitwarden/common/services/encrypt.service";
|
import { EncryptServiceImplementation } from "@bitwarden/common/services/cryptography/encrypt.service.implementation";
|
||||||
|
import { MultithreadEncryptServiceImplementation } from "@bitwarden/common/services/cryptography/multithread-encrypt.service.implementation";
|
||||||
import { EventService } from "@bitwarden/common/services/event.service";
|
import { EventService } from "@bitwarden/common/services/event.service";
|
||||||
import { ExportService } from "@bitwarden/common/services/export.service";
|
import { ExportService } from "@bitwarden/common/services/export.service";
|
||||||
import { FileUploadService } from "@bitwarden/common/services/fileUpload.service";
|
import { FileUploadService } from "@bitwarden/common/services/fileUpload.service";
|
||||||
@ -82,6 +84,7 @@ import { WebCryptoFunctionService } from "@bitwarden/common/services/webCryptoFu
|
|||||||
|
|
||||||
import { BrowserApi } from "../browser/browserApi";
|
import { BrowserApi } from "../browser/browserApi";
|
||||||
import { SafariApp } from "../browser/safariApp";
|
import { SafariApp } from "../browser/safariApp";
|
||||||
|
import { flagEnabled } from "../flags";
|
||||||
import { UpdateBadge } from "../listeners/update-badge";
|
import { UpdateBadge } from "../listeners/update-badge";
|
||||||
import { Account } from "../models/account";
|
import { Account } from "../models/account";
|
||||||
import { PopupUtilsService } from "../popup/services/popup-utils.service";
|
import { PopupUtilsService } from "../popup/services/popup-utils.service";
|
||||||
@ -215,7 +218,7 @@ export default class MainBackground {
|
|||||||
this.memoryStorageService =
|
this.memoryStorageService =
|
||||||
BrowserApi.manifestVersion === 3
|
BrowserApi.manifestVersion === 3
|
||||||
? new LocalBackedSessionStorageService(
|
? new LocalBackedSessionStorageService(
|
||||||
new EncryptService(this.cryptoFunctionService, this.logService, false),
|
new EncryptServiceImplementation(this.cryptoFunctionService, this.logService, false),
|
||||||
new KeyGenerationService(this.cryptoFunctionService)
|
new KeyGenerationService(this.cryptoFunctionService)
|
||||||
)
|
)
|
||||||
: new MemoryStorageService();
|
: new MemoryStorageService();
|
||||||
@ -255,7 +258,13 @@ export default class MainBackground {
|
|||||||
window
|
window
|
||||||
);
|
);
|
||||||
this.i18nService = new I18nService(BrowserApi.getUILanguage(window));
|
this.i18nService = new I18nService(BrowserApi.getUILanguage(window));
|
||||||
this.encryptService = new EncryptService(this.cryptoFunctionService, this.logService, true);
|
this.encryptService = flagEnabled("multithreadDecryption")
|
||||||
|
? new MultithreadEncryptServiceImplementation(
|
||||||
|
this.cryptoFunctionService,
|
||||||
|
this.logService,
|
||||||
|
true
|
||||||
|
)
|
||||||
|
: new EncryptServiceImplementation(this.cryptoFunctionService, this.logService, true);
|
||||||
this.cryptoService = new BrowserCryptoService(
|
this.cryptoService = new BrowserCryptoService(
|
||||||
this.cryptoFunctionService,
|
this.cryptoFunctionService,
|
||||||
this.encryptService,
|
this.encryptService,
|
||||||
@ -283,7 +292,8 @@ export default class MainBackground {
|
|||||||
this.i18nService,
|
this.i18nService,
|
||||||
() => this.searchService,
|
() => this.searchService,
|
||||||
this.logService,
|
this.logService,
|
||||||
this.stateService
|
this.stateService,
|
||||||
|
this.encryptService
|
||||||
);
|
);
|
||||||
this.folderService = new FolderService(
|
this.folderService = new FolderService(
|
||||||
this.cryptoService,
|
this.cryptoService,
|
||||||
|
@ -4,6 +4,7 @@ import { CipherService } from "@bitwarden/common/services/cipher.service";
|
|||||||
|
|
||||||
import { apiServiceFactory, ApiServiceInitOptions } from "./api-service.factory";
|
import { apiServiceFactory, ApiServiceInitOptions } from "./api-service.factory";
|
||||||
import { cryptoServiceFactory, CryptoServiceInitOptions } from "./crypto-service.factory";
|
import { cryptoServiceFactory, CryptoServiceInitOptions } from "./crypto-service.factory";
|
||||||
|
import { encryptServiceFactory, EncryptServiceInitOptions } from "./encrypt-service.factory";
|
||||||
import { CachedServices, factory, FactoryOptions } from "./factory-options";
|
import { CachedServices, factory, FactoryOptions } from "./factory-options";
|
||||||
import {
|
import {
|
||||||
FileUploadServiceInitOptions,
|
FileUploadServiceInitOptions,
|
||||||
@ -27,7 +28,8 @@ export type CipherServiceInitOptions = CipherServiceFactoryOptions &
|
|||||||
FileUploadServiceInitOptions &
|
FileUploadServiceInitOptions &
|
||||||
I18nServiceInitOptions &
|
I18nServiceInitOptions &
|
||||||
LogServiceInitOptions &
|
LogServiceInitOptions &
|
||||||
StateServiceInitOptions;
|
StateServiceInitOptions &
|
||||||
|
EncryptServiceInitOptions;
|
||||||
|
|
||||||
export function cipherServiceFactory(
|
export function cipherServiceFactory(
|
||||||
cache: { cipherService?: AbstractCipherService } & CachedServices,
|
cache: { cipherService?: AbstractCipherService } & CachedServices,
|
||||||
@ -48,7 +50,8 @@ export function cipherServiceFactory(
|
|||||||
? () => cache.searchService
|
? () => cache.searchService
|
||||||
: opts.cipherServiceOptions.searchServiceFactory,
|
: opts.cipherServiceOptions.searchServiceFactory,
|
||||||
await logServiceFactory(cache, opts),
|
await logServiceFactory(cache, opts),
|
||||||
await stateServiceFactory(cache, opts)
|
await stateServiceFactory(cache, opts),
|
||||||
|
await encryptServiceFactory(cache, opts)
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,7 @@
|
|||||||
import { EncryptService } from "@bitwarden/common/services/encrypt.service";
|
import { EncryptServiceImplementation } from "@bitwarden/common/services/cryptography/encrypt.service.implementation";
|
||||||
|
import { MultithreadEncryptServiceImplementation } from "@bitwarden/common/services/cryptography/multithread-encrypt.service.implementation";
|
||||||
|
|
||||||
|
import { flagEnabled } from "../../flags";
|
||||||
|
|
||||||
import {
|
import {
|
||||||
cryptoFunctionServiceFactory,
|
cryptoFunctionServiceFactory,
|
||||||
@ -18,18 +21,20 @@ export type EncryptServiceInitOptions = EncryptServiceFactoryOptions &
|
|||||||
LogServiceInitOptions;
|
LogServiceInitOptions;
|
||||||
|
|
||||||
export function encryptServiceFactory(
|
export function encryptServiceFactory(
|
||||||
cache: { encryptService?: EncryptService } & CachedServices,
|
cache: { encryptService?: EncryptServiceImplementation } & CachedServices,
|
||||||
opts: EncryptServiceInitOptions
|
opts: EncryptServiceInitOptions
|
||||||
): Promise<EncryptService> {
|
): Promise<EncryptServiceImplementation> {
|
||||||
return factory(
|
return factory(cache, "encryptService", opts, async () =>
|
||||||
cache,
|
flagEnabled("multithreadDecryption")
|
||||||
"encryptService",
|
? new MultithreadEncryptServiceImplementation(
|
||||||
opts,
|
await cryptoFunctionServiceFactory(cache, opts),
|
||||||
async () =>
|
await logServiceFactory(cache, opts),
|
||||||
new EncryptService(
|
opts.encryptServiceOptions.logMacFailures
|
||||||
await cryptoFunctionServiceFactory(cache, opts),
|
)
|
||||||
await logServiceFactory(cache, opts),
|
: new EncryptServiceImplementation(
|
||||||
opts.encryptServiceOptions.logMacFailures
|
await cryptoFunctionServiceFactory(cache, opts),
|
||||||
)
|
await logServiceFactory(cache, opts),
|
||||||
|
opts.encryptServiceOptions.logMacFailures
|
||||||
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import { AbstractEncryptService } from "@bitwarden/common/abstractions/abstractEncrypt.service";
|
|
||||||
import { AuthService } from "@bitwarden/common/abstractions/auth.service";
|
import { AuthService } from "@bitwarden/common/abstractions/auth.service";
|
||||||
import { CipherService } from "@bitwarden/common/abstractions/cipher.service";
|
import { CipherService } from "@bitwarden/common/abstractions/cipher.service";
|
||||||
import { CryptoService } from "@bitwarden/common/abstractions/crypto.service";
|
import { CryptoService } from "@bitwarden/common/abstractions/crypto.service";
|
||||||
|
import { EncryptService } from "@bitwarden/common/abstractions/encrypt.service";
|
||||||
import { AuthenticationStatus } from "@bitwarden/common/enums/authenticationStatus";
|
import { AuthenticationStatus } from "@bitwarden/common/enums/authenticationStatus";
|
||||||
import { StateFactory } from "@bitwarden/common/factories/stateFactory";
|
import { StateFactory } from "@bitwarden/common/factories/stateFactory";
|
||||||
import { Utils } from "@bitwarden/common/misc/utils";
|
import { Utils } from "@bitwarden/common/misc/utils";
|
||||||
@ -259,7 +259,7 @@ export class UpdateBadge {
|
|||||||
if (!self.bitwardenContainerService) {
|
if (!self.bitwardenContainerService) {
|
||||||
new ContainerService(
|
new ContainerService(
|
||||||
serviceCache.cryptoService as CryptoService,
|
serviceCache.cryptoService as CryptoService,
|
||||||
serviceCache.encryptService as AbstractEncryptService
|
serviceCache.encryptService as EncryptService
|
||||||
).attachToGlobal(self);
|
).attachToGlobal(self);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4,7 +4,7 @@ import { Arg, Substitute, SubstituteOf } from "@fluffy-spoon/substitute";
|
|||||||
import { Utils } from "@bitwarden/common/misc/utils";
|
import { Utils } from "@bitwarden/common/misc/utils";
|
||||||
import { EncString } from "@bitwarden/common/models/domain/enc-string";
|
import { EncString } from "@bitwarden/common/models/domain/enc-string";
|
||||||
import { SymmetricCryptoKey } from "@bitwarden/common/models/domain/symmetric-crypto-key";
|
import { SymmetricCryptoKey } from "@bitwarden/common/models/domain/symmetric-crypto-key";
|
||||||
import { EncryptService } from "@bitwarden/common/src/services/encrypt.service";
|
import { EncryptServiceImplementation } from "@bitwarden/common/services/cryptography/encrypt.service.implementation";
|
||||||
|
|
||||||
import BrowserLocalStorageService from "./browserLocalStorage.service";
|
import BrowserLocalStorageService from "./browserLocalStorage.service";
|
||||||
import BrowserMemoryStorageService from "./browserMemoryStorage.service";
|
import BrowserMemoryStorageService from "./browserMemoryStorage.service";
|
||||||
@ -12,7 +12,7 @@ import { KeyGenerationService } from "./keyGeneration.service";
|
|||||||
import { LocalBackedSessionStorageService } from "./localBackedSessionStorage.service";
|
import { LocalBackedSessionStorageService } from "./localBackedSessionStorage.service";
|
||||||
|
|
||||||
describe("Browser Session Storage Service", () => {
|
describe("Browser Session Storage Service", () => {
|
||||||
let encryptService: SubstituteOf<EncryptService>;
|
let encryptService: SubstituteOf<EncryptServiceImplementation>;
|
||||||
let keyGenerationService: SubstituteOf<KeyGenerationService>;
|
let keyGenerationService: SubstituteOf<KeyGenerationService>;
|
||||||
|
|
||||||
let cache: Map<string, any>;
|
let cache: Map<string, any>;
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import { Jsonify } from "type-fest";
|
import { Jsonify } from "type-fest";
|
||||||
|
|
||||||
import { AbstractEncryptService } from "@bitwarden/common/abstractions/abstractEncrypt.service";
|
import { EncryptService } from "@bitwarden/common/abstractions/encrypt.service";
|
||||||
import {
|
import {
|
||||||
AbstractCachedStorageService,
|
AbstractCachedStorageService,
|
||||||
MemoryStorageServiceInterface,
|
MemoryStorageServiceInterface,
|
||||||
@ -30,7 +30,7 @@ export class LocalBackedSessionStorageService
|
|||||||
private sessionStorage = new BrowserMemoryStorageService();
|
private sessionStorage = new BrowserMemoryStorageService();
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private encryptService: AbstractEncryptService,
|
private encryptService: EncryptService,
|
||||||
private keyGenerationService: AbstractKeyGenerationService
|
private keyGenerationService: AbstractKeyGenerationService
|
||||||
) {
|
) {
|
||||||
super();
|
super();
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
"noImplicitAny": true,
|
"noImplicitAny": true,
|
||||||
"emitDecoratorMetadata": true,
|
"emitDecoratorMetadata": true,
|
||||||
"experimentalDecorators": true,
|
"experimentalDecorators": true,
|
||||||
"module": "es6",
|
"module": "ES2020",
|
||||||
"target": "ES2016",
|
"target": "ES2016",
|
||||||
"allowJs": true,
|
"allowJs": true,
|
||||||
"sourceMap": true,
|
"sourceMap": true,
|
||||||
@ -17,5 +17,5 @@
|
|||||||
"angularCompilerOptions": {
|
"angularCompilerOptions": {
|
||||||
"preserveWhitespaces": true
|
"preserveWhitespaces": true
|
||||||
},
|
},
|
||||||
"include": ["src"]
|
"include": ["src", "../../libs/common/src/services/**/*.worker.ts"]
|
||||||
}
|
}
|
||||||
|
@ -20,7 +20,7 @@ import { CipherService } from "@bitwarden/common/services/cipher.service";
|
|||||||
import { CollectionService } from "@bitwarden/common/services/collection.service";
|
import { CollectionService } from "@bitwarden/common/services/collection.service";
|
||||||
import { ContainerService } from "@bitwarden/common/services/container.service";
|
import { ContainerService } from "@bitwarden/common/services/container.service";
|
||||||
import { CryptoService } from "@bitwarden/common/services/crypto.service";
|
import { CryptoService } from "@bitwarden/common/services/crypto.service";
|
||||||
import { EncryptService } from "@bitwarden/common/services/encrypt.service";
|
import { EncryptServiceImplementation } from "@bitwarden/common/services/cryptography/encrypt.service.implementation";
|
||||||
import { EnvironmentService } from "@bitwarden/common/services/environment.service";
|
import { EnvironmentService } from "@bitwarden/common/services/environment.service";
|
||||||
import { ExportService } from "@bitwarden/common/services/export.service";
|
import { ExportService } from "@bitwarden/common/services/export.service";
|
||||||
import { FileUploadService } from "@bitwarden/common/services/fileUpload.service";
|
import { FileUploadService } from "@bitwarden/common/services/fileUpload.service";
|
||||||
@ -94,7 +94,7 @@ export class Main {
|
|||||||
exportService: ExportService;
|
exportService: ExportService;
|
||||||
searchService: SearchService;
|
searchService: SearchService;
|
||||||
cryptoFunctionService: NodeCryptoFunctionService;
|
cryptoFunctionService: NodeCryptoFunctionService;
|
||||||
encryptService: EncryptService;
|
encryptService: EncryptServiceImplementation;
|
||||||
authService: AuthService;
|
authService: AuthService;
|
||||||
policyService: PolicyService;
|
policyService: PolicyService;
|
||||||
program: Program;
|
program: Program;
|
||||||
@ -140,7 +140,11 @@ export class Main {
|
|||||||
(level) => process.env.BITWARDENCLI_DEBUG !== "true" && level <= LogLevelType.Info
|
(level) => process.env.BITWARDENCLI_DEBUG !== "true" && level <= LogLevelType.Info
|
||||||
);
|
);
|
||||||
this.cryptoFunctionService = new NodeCryptoFunctionService();
|
this.cryptoFunctionService = new NodeCryptoFunctionService();
|
||||||
this.encryptService = new EncryptService(this.cryptoFunctionService, this.logService, true);
|
this.encryptService = new EncryptServiceImplementation(
|
||||||
|
this.cryptoFunctionService,
|
||||||
|
this.logService,
|
||||||
|
true
|
||||||
|
);
|
||||||
this.storageService = new LowdbStorageService(this.logService, null, p, false, true);
|
this.storageService = new LowdbStorageService(this.logService, null, p, false, true);
|
||||||
this.secureStorageService = new NodeEnvSecureStorageService(
|
this.secureStorageService = new NodeEnvSecureStorageService(
|
||||||
this.storageService,
|
this.storageService,
|
||||||
@ -211,7 +215,8 @@ export class Main {
|
|||||||
this.i18nService,
|
this.i18nService,
|
||||||
null,
|
null,
|
||||||
this.logService,
|
this.logService,
|
||||||
this.stateService
|
this.stateService,
|
||||||
|
this.encryptService
|
||||||
);
|
);
|
||||||
|
|
||||||
this.broadcasterService = new BroadcasterService();
|
this.broadcasterService = new BroadcasterService();
|
||||||
|
@ -1,4 +1,6 @@
|
|||||||
{
|
{
|
||||||
"dev_flags": {},
|
"dev_flags": {},
|
||||||
"flags": {}
|
"flags": {
|
||||||
|
"multithreadDecryption": false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,7 +6,7 @@ import { Utils } from "@bitwarden/common/misc/utils";
|
|||||||
import { EncString } from "@bitwarden/common/models/domain/enc-string";
|
import { EncString } from "@bitwarden/common/models/domain/enc-string";
|
||||||
import { SymmetricCryptoKey } from "@bitwarden/common/models/domain/symmetric-crypto-key";
|
import { SymmetricCryptoKey } from "@bitwarden/common/models/domain/symmetric-crypto-key";
|
||||||
import { ConsoleLogService } from "@bitwarden/common/services/consoleLog.service";
|
import { ConsoleLogService } from "@bitwarden/common/services/consoleLog.service";
|
||||||
import { EncryptService } from "@bitwarden/common/services/encrypt.service";
|
import { EncryptServiceImplementation } from "@bitwarden/common/services/cryptography/encrypt.service.implementation";
|
||||||
import { NodeCryptoFunctionService } from "@bitwarden/node/services/nodeCryptoFunction.service";
|
import { NodeCryptoFunctionService } from "@bitwarden/node/services/nodeCryptoFunction.service";
|
||||||
|
|
||||||
import { DecryptedCommandData } from "../../src/models/nativeMessaging/decryptedCommandData";
|
import { DecryptedCommandData } from "../../src/models/nativeMessaging/decryptedCommandData";
|
||||||
@ -32,7 +32,7 @@ const CONFIRMATION_MESSAGE_TIMEOUT = 100 * 1000; // 100 seconds
|
|||||||
export default class NativeMessageService {
|
export default class NativeMessageService {
|
||||||
private ipcService: IPCService;
|
private ipcService: IPCService;
|
||||||
private nodeCryptoFunctionService: NodeCryptoFunctionService;
|
private nodeCryptoFunctionService: NodeCryptoFunctionService;
|
||||||
private encryptService: EncryptService;
|
private encryptService: EncryptServiceImplementation;
|
||||||
|
|
||||||
constructor(private apiVersion: number) {
|
constructor(private apiVersion: number) {
|
||||||
console.log("Starting native messaging service");
|
console.log("Starting native messaging service");
|
||||||
@ -41,7 +41,7 @@ export default class NativeMessageService {
|
|||||||
});
|
});
|
||||||
|
|
||||||
this.nodeCryptoFunctionService = new NodeCryptoFunctionService();
|
this.nodeCryptoFunctionService = new NodeCryptoFunctionService();
|
||||||
this.encryptService = new EncryptService(
|
this.encryptService = new EncryptServiceImplementation(
|
||||||
this.nodeCryptoFunctionService,
|
this.nodeCryptoFunctionService,
|
||||||
new ConsoleLogService(false),
|
new ConsoleLogService(false),
|
||||||
false
|
false
|
||||||
|
@ -2,8 +2,8 @@ import { Inject, Injectable } from "@angular/core";
|
|||||||
|
|
||||||
import { WINDOW } from "@bitwarden/angular/services/injection-tokens";
|
import { WINDOW } from "@bitwarden/angular/services/injection-tokens";
|
||||||
import { AbstractThemingService } from "@bitwarden/angular/services/theming/theming.service.abstraction";
|
import { AbstractThemingService } from "@bitwarden/angular/services/theming/theming.service.abstraction";
|
||||||
import { AbstractEncryptService } from "@bitwarden/common/abstractions/abstractEncrypt.service";
|
|
||||||
import { CryptoService as CryptoServiceAbstraction } from "@bitwarden/common/abstractions/crypto.service";
|
import { CryptoService as CryptoServiceAbstraction } from "@bitwarden/common/abstractions/crypto.service";
|
||||||
|
import { EncryptService } from "@bitwarden/common/abstractions/encrypt.service";
|
||||||
import { EnvironmentService as EnvironmentServiceAbstraction } from "@bitwarden/common/abstractions/environment.service";
|
import { EnvironmentService as EnvironmentServiceAbstraction } from "@bitwarden/common/abstractions/environment.service";
|
||||||
import { EventService as EventServiceAbstraction } from "@bitwarden/common/abstractions/event.service";
|
import { EventService as EventServiceAbstraction } from "@bitwarden/common/abstractions/event.service";
|
||||||
import { I18nService as I18nServiceAbstraction } from "@bitwarden/common/abstractions/i18n.service";
|
import { I18nService as I18nServiceAbstraction } from "@bitwarden/common/abstractions/i18n.service";
|
||||||
@ -36,7 +36,7 @@ export class InitService {
|
|||||||
private cryptoService: CryptoServiceAbstraction,
|
private cryptoService: CryptoServiceAbstraction,
|
||||||
private nativeMessagingService: NativeMessagingService,
|
private nativeMessagingService: NativeMessagingService,
|
||||||
private themingService: AbstractThemingService,
|
private themingService: AbstractThemingService,
|
||||||
private encryptService: AbstractEncryptService
|
private encryptService: EncryptService
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
init() {
|
init() {
|
||||||
|
@ -11,12 +11,12 @@ import {
|
|||||||
} from "@bitwarden/angular/services/injection-tokens";
|
} from "@bitwarden/angular/services/injection-tokens";
|
||||||
import { JslibServicesModule } from "@bitwarden/angular/services/jslib-services.module";
|
import { JslibServicesModule } from "@bitwarden/angular/services/jslib-services.module";
|
||||||
import { AbstractThemingService } from "@bitwarden/angular/services/theming/theming.service.abstraction";
|
import { AbstractThemingService } from "@bitwarden/angular/services/theming/theming.service.abstraction";
|
||||||
import { AbstractEncryptService } from "@bitwarden/common/abstractions/abstractEncrypt.service";
|
|
||||||
import { AuthService as AuthServiceAbstraction } from "@bitwarden/common/abstractions/auth.service";
|
import { AuthService as AuthServiceAbstraction } from "@bitwarden/common/abstractions/auth.service";
|
||||||
import { BroadcasterService as BroadcasterServiceAbstraction } from "@bitwarden/common/abstractions/broadcaster.service";
|
import { BroadcasterService as BroadcasterServiceAbstraction } from "@bitwarden/common/abstractions/broadcaster.service";
|
||||||
import { CipherService as CipherServiceAbstraction } from "@bitwarden/common/abstractions/cipher.service";
|
import { CipherService as CipherServiceAbstraction } from "@bitwarden/common/abstractions/cipher.service";
|
||||||
import { CryptoService as CryptoServiceAbstraction } from "@bitwarden/common/abstractions/crypto.service";
|
import { CryptoService as CryptoServiceAbstraction } from "@bitwarden/common/abstractions/crypto.service";
|
||||||
import { CryptoFunctionService as CryptoFunctionServiceAbstraction } from "@bitwarden/common/abstractions/cryptoFunction.service";
|
import { CryptoFunctionService as CryptoFunctionServiceAbstraction } from "@bitwarden/common/abstractions/cryptoFunction.service";
|
||||||
|
import { EncryptService } from "@bitwarden/common/abstractions/encrypt.service";
|
||||||
import { FileDownloadService } from "@bitwarden/common/abstractions/fileDownload/fileDownload.service";
|
import { FileDownloadService } from "@bitwarden/common/abstractions/fileDownload/fileDownload.service";
|
||||||
import { I18nService as I18nServiceAbstraction } from "@bitwarden/common/abstractions/i18n.service";
|
import { I18nService as I18nServiceAbstraction } from "@bitwarden/common/abstractions/i18n.service";
|
||||||
import {
|
import {
|
||||||
@ -115,7 +115,7 @@ const RELOAD_CALLBACK = new InjectionToken<() => any>("RELOAD_CALLBACK");
|
|||||||
useClass: ElectronCryptoService,
|
useClass: ElectronCryptoService,
|
||||||
deps: [
|
deps: [
|
||||||
CryptoFunctionServiceAbstraction,
|
CryptoFunctionServiceAbstraction,
|
||||||
AbstractEncryptService,
|
EncryptService,
|
||||||
PlatformUtilsServiceAbstraction,
|
PlatformUtilsServiceAbstraction,
|
||||||
LogServiceAbstraction,
|
LogServiceAbstraction,
|
||||||
StateServiceAbstraction,
|
StateServiceAbstraction,
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
"noImplicitAny": true,
|
"noImplicitAny": true,
|
||||||
"emitDecoratorMetadata": true,
|
"emitDecoratorMetadata": true,
|
||||||
"experimentalDecorators": true,
|
"experimentalDecorators": true,
|
||||||
"module": "es6",
|
"module": "ES2020",
|
||||||
"target": "ES2016",
|
"target": "ES2016",
|
||||||
"sourceMap": true,
|
"sourceMap": true,
|
||||||
"types": [],
|
"types": [],
|
||||||
@ -18,5 +18,5 @@
|
|||||||
"angularCompilerOptions": {
|
"angularCompilerOptions": {
|
||||||
"preserveWhitespaces": true
|
"preserveWhitespaces": true
|
||||||
},
|
},
|
||||||
"include": ["src"]
|
"include": ["src", "../../libs/common/src/services/**/*.worker.ts"]
|
||||||
}
|
}
|
||||||
|
@ -6,7 +6,7 @@ import { BrowserAnimationsModule } from "@angular/platform-browser/animations";
|
|||||||
import { InfiniteScrollModule } from "ngx-infinite-scroll";
|
import { InfiniteScrollModule } from "ngx-infinite-scroll";
|
||||||
|
|
||||||
import { AppComponent } from "./app.component";
|
import { AppComponent } from "./app.component";
|
||||||
import { CoreModule } from "./core";
|
import { CoreModule } from "./core/core.module";
|
||||||
import { OssRoutingModule } from "./oss-routing.module";
|
import { OssRoutingModule } from "./oss-routing.module";
|
||||||
import { OssModule } from "./oss.module";
|
import { OssModule } from "./oss.module";
|
||||||
import { WildcardRoutingModule } from "./wildcard-routing.module";
|
import { WildcardRoutingModule } from "./wildcard-routing.module";
|
||||||
|
@ -1,4 +1,7 @@
|
|||||||
export * from "./core.module";
|
// Do not export this here or it will import MultithreadEncryptService (via JslibServicesModule) into test code.
|
||||||
|
// MultithreadEncryptService contains ES2020 features (import.meta) which are not supported in Node and Jest.
|
||||||
|
// Revisit this when Node & Jest get stable support for ESM.
|
||||||
|
// export * from "./core.module";
|
||||||
export * from "./event.service";
|
export * from "./event.service";
|
||||||
export * from "./policy-list.service";
|
export * from "./policy-list.service";
|
||||||
export * from "./router.service";
|
export * from "./router.service";
|
||||||
|
@ -2,8 +2,8 @@ import { Inject, Injectable } from "@angular/core";
|
|||||||
|
|
||||||
import { WINDOW } from "@bitwarden/angular/services/injection-tokens";
|
import { WINDOW } from "@bitwarden/angular/services/injection-tokens";
|
||||||
import { AbstractThemingService } from "@bitwarden/angular/services/theming/theming.service.abstraction";
|
import { AbstractThemingService } from "@bitwarden/angular/services/theming/theming.service.abstraction";
|
||||||
import { AbstractEncryptService } from "@bitwarden/common/abstractions/abstractEncrypt.service";
|
|
||||||
import { CryptoService as CryptoServiceAbstraction } from "@bitwarden/common/abstractions/crypto.service";
|
import { CryptoService as CryptoServiceAbstraction } from "@bitwarden/common/abstractions/crypto.service";
|
||||||
|
import { EncryptService } from "@bitwarden/common/abstractions/encrypt.service";
|
||||||
import {
|
import {
|
||||||
EnvironmentService as EnvironmentServiceAbstraction,
|
EnvironmentService as EnvironmentServiceAbstraction,
|
||||||
Urls,
|
Urls,
|
||||||
@ -33,7 +33,7 @@ export class InitService {
|
|||||||
private stateService: StateServiceAbstraction,
|
private stateService: StateServiceAbstraction,
|
||||||
private cryptoService: CryptoServiceAbstraction,
|
private cryptoService: CryptoServiceAbstraction,
|
||||||
private themingService: AbstractThemingService,
|
private themingService: AbstractThemingService,
|
||||||
private encryptService: AbstractEncryptService
|
private encryptService: EncryptService
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
init() {
|
init() {
|
||||||
|
@ -3,7 +3,7 @@ import { APP_INITIALIZER, NgModule } from "@angular/core";
|
|||||||
import { I18nService } from "@bitwarden/common/abstractions/i18n.service";
|
import { I18nService } from "@bitwarden/common/abstractions/i18n.service";
|
||||||
import { I18nService as BaseI18nService } from "@bitwarden/common/services/i18n.service";
|
import { I18nService as BaseI18nService } from "@bitwarden/common/services/i18n.service";
|
||||||
|
|
||||||
import * as eng from "../../locales/en/messages.json";
|
import eng from "../../locales/en/messages.json";
|
||||||
|
|
||||||
class PreloadedEnglishI18nService extends BaseI18nService {
|
class PreloadedEnglishI18nService extends BaseI18nService {
|
||||||
constructor() {
|
constructor() {
|
||||||
|
@ -15,5 +15,10 @@
|
|||||||
"preserveWhitespaces": true
|
"preserveWhitespaces": true
|
||||||
},
|
},
|
||||||
"files": ["src/polyfills.ts", "src/main.ts", "../../bitwarden_license/bit-web/src/main.ts"],
|
"files": ["src/polyfills.ts", "src/main.ts", "../../bitwarden_license/bit-web/src/main.ts"],
|
||||||
"include": ["src/connectors/*.ts", "src/**/*.stories.ts", "src/**/*.spec.ts"]
|
"include": [
|
||||||
|
"src/connectors/*.ts",
|
||||||
|
"src/**/*.stories.ts",
|
||||||
|
"src/**/*.spec.ts",
|
||||||
|
"../../libs/common/src/services/**/*.worker.ts"
|
||||||
|
]
|
||||||
}
|
}
|
||||||
|
@ -7,7 +7,7 @@ import { RouterModule } from "@angular/router";
|
|||||||
import { InfiniteScrollModule } from "ngx-infinite-scroll";
|
import { InfiniteScrollModule } from "ngx-infinite-scroll";
|
||||||
|
|
||||||
import { JslibModule } from "@bitwarden/angular/jslib.module";
|
import { JslibModule } from "@bitwarden/angular/jslib.module";
|
||||||
import { CoreModule } from "@bitwarden/web-vault/app/core";
|
import { CoreModule } from "@bitwarden/web-vault/app/core/core.module";
|
||||||
import { OssRoutingModule } from "@bitwarden/web-vault/app/oss-routing.module";
|
import { OssRoutingModule } from "@bitwarden/web-vault/app/oss-routing.module";
|
||||||
import { OssModule } from "@bitwarden/web-vault/app/oss.module";
|
import { OssModule } from "@bitwarden/web-vault/app/oss.module";
|
||||||
import { WildcardRoutingModule } from "@bitwarden/web-vault/app/wildcard-routing.module";
|
import { WildcardRoutingModule } from "@bitwarden/web-vault/app/wildcard-routing.module";
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
import { Injector, LOCALE_ID, NgModule } from "@angular/core";
|
import { Injector, LOCALE_ID, NgModule } from "@angular/core";
|
||||||
|
|
||||||
import { AbstractEncryptService } from "@bitwarden/common/abstractions/abstractEncrypt.service";
|
|
||||||
import { AccountApiService as AccountApiServiceAbstraction } from "@bitwarden/common/abstractions/account/account-api.service";
|
import { AccountApiService as AccountApiServiceAbstraction } from "@bitwarden/common/abstractions/account/account-api.service";
|
||||||
import {
|
import {
|
||||||
InternalAccountService,
|
InternalAccountService,
|
||||||
@ -18,6 +17,7 @@ import { ConfigApiServiceAbstraction } from "@bitwarden/common/abstractions/conf
|
|||||||
import { ConfigServiceAbstraction } from "@bitwarden/common/abstractions/config/config.service.abstraction";
|
import { ConfigServiceAbstraction } from "@bitwarden/common/abstractions/config/config.service.abstraction";
|
||||||
import { CryptoService as CryptoServiceAbstraction } from "@bitwarden/common/abstractions/crypto.service";
|
import { CryptoService as CryptoServiceAbstraction } from "@bitwarden/common/abstractions/crypto.service";
|
||||||
import { CryptoFunctionService as CryptoFunctionServiceAbstraction } from "@bitwarden/common/abstractions/cryptoFunction.service";
|
import { CryptoFunctionService as CryptoFunctionServiceAbstraction } from "@bitwarden/common/abstractions/cryptoFunction.service";
|
||||||
|
import { EncryptService } from "@bitwarden/common/abstractions/encrypt.service";
|
||||||
import { EnvironmentService as EnvironmentServiceAbstraction } from "@bitwarden/common/abstractions/environment.service";
|
import { EnvironmentService as EnvironmentServiceAbstraction } from "@bitwarden/common/abstractions/environment.service";
|
||||||
import { EventService as EventServiceAbstraction } from "@bitwarden/common/abstractions/event.service";
|
import { EventService as EventServiceAbstraction } from "@bitwarden/common/abstractions/event.service";
|
||||||
import { ExportService as ExportServiceAbstraction } from "@bitwarden/common/abstractions/export.service";
|
import { ExportService as ExportServiceAbstraction } from "@bitwarden/common/abstractions/export.service";
|
||||||
@ -62,6 +62,7 @@ import { ValidationService as ValidationServiceAbstraction } from "@bitwarden/co
|
|||||||
import { VaultTimeoutService as VaultTimeoutServiceAbstraction } from "@bitwarden/common/abstractions/vaultTimeout/vaultTimeout.service";
|
import { VaultTimeoutService as VaultTimeoutServiceAbstraction } from "@bitwarden/common/abstractions/vaultTimeout/vaultTimeout.service";
|
||||||
import { VaultTimeoutSettingsService as VaultTimeoutSettingsServiceAbstraction } from "@bitwarden/common/abstractions/vaultTimeout/vaultTimeoutSettings.service";
|
import { VaultTimeoutSettingsService as VaultTimeoutSettingsServiceAbstraction } from "@bitwarden/common/abstractions/vaultTimeout/vaultTimeoutSettings.service";
|
||||||
import { StateFactory } from "@bitwarden/common/factories/stateFactory";
|
import { StateFactory } from "@bitwarden/common/factories/stateFactory";
|
||||||
|
import { flagEnabled } from "@bitwarden/common/misc/flags";
|
||||||
import { Account } from "@bitwarden/common/models/domain/account";
|
import { Account } from "@bitwarden/common/models/domain/account";
|
||||||
import { GlobalState } from "@bitwarden/common/models/domain/global-state";
|
import { GlobalState } from "@bitwarden/common/models/domain/global-state";
|
||||||
import { AccountApiServiceImplementation } from "@bitwarden/common/services/account/account-api.service";
|
import { AccountApiServiceImplementation } from "@bitwarden/common/services/account/account-api.service";
|
||||||
@ -77,7 +78,8 @@ import { ConfigApiService } from "@bitwarden/common/services/config/config-api.s
|
|||||||
import { ConfigService } from "@bitwarden/common/services/config/config.service";
|
import { ConfigService } from "@bitwarden/common/services/config/config.service";
|
||||||
import { ConsoleLogService } from "@bitwarden/common/services/consoleLog.service";
|
import { ConsoleLogService } from "@bitwarden/common/services/consoleLog.service";
|
||||||
import { CryptoService } from "@bitwarden/common/services/crypto.service";
|
import { CryptoService } from "@bitwarden/common/services/crypto.service";
|
||||||
import { EncryptService } from "@bitwarden/common/services/encrypt.service";
|
import { EncryptServiceImplementation } from "@bitwarden/common/services/cryptography/encrypt.service.implementation";
|
||||||
|
import { MultithreadEncryptServiceImplementation } from "@bitwarden/common/services/cryptography/multithread-encrypt.service.implementation";
|
||||||
import { EnvironmentService } from "@bitwarden/common/services/environment.service";
|
import { EnvironmentService } from "@bitwarden/common/services/environment.service";
|
||||||
import { EventService } from "@bitwarden/common/services/event.service";
|
import { EventService } from "@bitwarden/common/services/event.service";
|
||||||
import { ExportService } from "@bitwarden/common/services/export.service";
|
import { ExportService } from "@bitwarden/common/services/export.service";
|
||||||
@ -216,7 +218,8 @@ import { AbstractThemingService } from "./theming/theming.service.abstraction";
|
|||||||
i18nService: I18nServiceAbstraction,
|
i18nService: I18nServiceAbstraction,
|
||||||
injector: Injector,
|
injector: Injector,
|
||||||
logService: LogService,
|
logService: LogService,
|
||||||
stateService: StateServiceAbstraction
|
stateService: StateServiceAbstraction,
|
||||||
|
encryptService: EncryptService
|
||||||
) =>
|
) =>
|
||||||
new CipherService(
|
new CipherService(
|
||||||
cryptoService,
|
cryptoService,
|
||||||
@ -226,7 +229,8 @@ import { AbstractThemingService } from "./theming/theming.service.abstraction";
|
|||||||
i18nService,
|
i18nService,
|
||||||
() => injector.get(SearchServiceAbstraction),
|
() => injector.get(SearchServiceAbstraction),
|
||||||
logService,
|
logService,
|
||||||
stateService
|
stateService,
|
||||||
|
encryptService
|
||||||
),
|
),
|
||||||
deps: [
|
deps: [
|
||||||
CryptoServiceAbstraction,
|
CryptoServiceAbstraction,
|
||||||
@ -237,6 +241,7 @@ import { AbstractThemingService } from "./theming/theming.service.abstraction";
|
|||||||
Injector, // TODO: Get rid of this circular dependency!
|
Injector, // TODO: Get rid of this circular dependency!
|
||||||
LogService,
|
LogService,
|
||||||
StateServiceAbstraction,
|
StateServiceAbstraction,
|
||||||
|
EncryptService,
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -299,7 +304,7 @@ import { AbstractThemingService } from "./theming/theming.service.abstraction";
|
|||||||
useClass: CryptoService,
|
useClass: CryptoService,
|
||||||
deps: [
|
deps: [
|
||||||
CryptoFunctionServiceAbstraction,
|
CryptoFunctionServiceAbstraction,
|
||||||
AbstractEncryptService,
|
EncryptService,
|
||||||
PlatformUtilsServiceAbstraction,
|
PlatformUtilsServiceAbstraction,
|
||||||
LogService,
|
LogService,
|
||||||
StateServiceAbstraction,
|
StateServiceAbstraction,
|
||||||
@ -442,8 +447,8 @@ import { AbstractThemingService } from "./theming/theming.service.abstraction";
|
|||||||
deps: [WINDOW],
|
deps: [WINDOW],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
provide: AbstractEncryptService,
|
provide: EncryptService,
|
||||||
useClass: EncryptService,
|
useFactory: encryptServiceFactory,
|
||||||
deps: [CryptoFunctionServiceAbstraction, LogService, LOG_MAC_FAILURES],
|
deps: [CryptoFunctionServiceAbstraction, LogService, LOG_MAC_FAILURES],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -576,3 +581,13 @@ import { AbstractThemingService } from "./theming/theming.service.abstraction";
|
|||||||
],
|
],
|
||||||
})
|
})
|
||||||
export class JslibServicesModule {}
|
export class JslibServicesModule {}
|
||||||
|
|
||||||
|
function encryptServiceFactory(
|
||||||
|
cryptoFunctionservice: CryptoFunctionServiceAbstraction,
|
||||||
|
logService: LogService,
|
||||||
|
logMacFailures: boolean
|
||||||
|
): EncryptService {
|
||||||
|
return flagEnabled("multithreadDecryption")
|
||||||
|
? new MultithreadEncryptServiceImplementation(cryptoFunctionservice, logService, logMacFailures)
|
||||||
|
: new EncryptServiceImplementation(cryptoFunctionservice, logService, logMacFailures);
|
||||||
|
}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import { mock, MockProxy } from "jest-mock-extended";
|
import { mock, MockProxy } from "jest-mock-extended";
|
||||||
|
|
||||||
import { AbstractEncryptService } from "@bitwarden/common/abstractions/abstractEncrypt.service";
|
|
||||||
import { CryptoService } from "@bitwarden/common/abstractions/crypto.service";
|
import { CryptoService } from "@bitwarden/common/abstractions/crypto.service";
|
||||||
|
import { EncryptService } from "@bitwarden/common/abstractions/encrypt.service";
|
||||||
import { AttachmentData } from "@bitwarden/common/models/data/attachment.data";
|
import { AttachmentData } from "@bitwarden/common/models/data/attachment.data";
|
||||||
import { Attachment } from "@bitwarden/common/models/domain/attachment";
|
import { Attachment } from "@bitwarden/common/models/domain/attachment";
|
||||||
import { EncString } from "@bitwarden/common/models/domain/enc-string";
|
import { EncString } from "@bitwarden/common/models/domain/enc-string";
|
||||||
@ -58,11 +58,11 @@ describe("Attachment", () => {
|
|||||||
|
|
||||||
describe("decrypt", () => {
|
describe("decrypt", () => {
|
||||||
let cryptoService: MockProxy<CryptoService>;
|
let cryptoService: MockProxy<CryptoService>;
|
||||||
let encryptService: MockProxy<AbstractEncryptService>;
|
let encryptService: MockProxy<EncryptService>;
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
cryptoService = mock<CryptoService>();
|
cryptoService = mock<CryptoService>();
|
||||||
encryptService = mock<AbstractEncryptService>();
|
encryptService = mock<EncryptService>();
|
||||||
|
|
||||||
(window as any).bitwardenContainerService = new ContainerService(
|
(window as any).bitwardenContainerService = new ContainerService(
|
||||||
cryptoService,
|
cryptoService,
|
||||||
|
@ -20,6 +20,7 @@ import { SecureNote } from "@bitwarden/common/models/domain/secure-note";
|
|||||||
import { CardView } from "@bitwarden/common/models/view/card.view";
|
import { CardView } from "@bitwarden/common/models/view/card.view";
|
||||||
import { IdentityView } from "@bitwarden/common/models/view/identity.view";
|
import { IdentityView } from "@bitwarden/common/models/view/identity.view";
|
||||||
import { LoginView } from "@bitwarden/common/models/view/login.view";
|
import { LoginView } from "@bitwarden/common/models/view/login.view";
|
||||||
|
import { InitializerKey } from "@bitwarden/common/services/cryptography/initializer-key";
|
||||||
|
|
||||||
import { mockEnc, mockFromJson } from "../../utils";
|
import { mockEnc, mockFromJson } from "../../utils";
|
||||||
|
|
||||||
@ -29,6 +30,7 @@ describe("Cipher DTO", () => {
|
|||||||
const cipher = new Cipher(data);
|
const cipher = new Cipher(data);
|
||||||
|
|
||||||
expect(cipher).toEqual({
|
expect(cipher).toEqual({
|
||||||
|
initializerKey: InitializerKey.Cipher,
|
||||||
id: null,
|
id: null,
|
||||||
organizationId: null,
|
organizationId: null,
|
||||||
folderId: null,
|
folderId: null,
|
||||||
@ -120,6 +122,7 @@ describe("Cipher DTO", () => {
|
|||||||
const cipher = new Cipher(cipherData);
|
const cipher = new Cipher(cipherData);
|
||||||
|
|
||||||
expect(cipher).toEqual({
|
expect(cipher).toEqual({
|
||||||
|
initializerKey: InitializerKey.Cipher,
|
||||||
id: "id",
|
id: "id",
|
||||||
organizationId: "orgId",
|
organizationId: "orgId",
|
||||||
folderId: "folderId",
|
folderId: "folderId",
|
||||||
@ -271,6 +274,7 @@ describe("Cipher DTO", () => {
|
|||||||
const cipher = new Cipher(cipherData);
|
const cipher = new Cipher(cipherData);
|
||||||
|
|
||||||
expect(cipher).toEqual({
|
expect(cipher).toEqual({
|
||||||
|
initializerKey: InitializerKey.Cipher,
|
||||||
id: "id",
|
id: "id",
|
||||||
organizationId: "orgId",
|
organizationId: "orgId",
|
||||||
folderId: "folderId",
|
folderId: "folderId",
|
||||||
@ -379,6 +383,7 @@ describe("Cipher DTO", () => {
|
|||||||
const cipher = new Cipher(cipherData);
|
const cipher = new Cipher(cipherData);
|
||||||
|
|
||||||
expect(cipher).toEqual({
|
expect(cipher).toEqual({
|
||||||
|
initializerKey: InitializerKey.Cipher,
|
||||||
id: "id",
|
id: "id",
|
||||||
organizationId: "orgId",
|
organizationId: "orgId",
|
||||||
folderId: "folderId",
|
folderId: "folderId",
|
||||||
@ -512,6 +517,7 @@ describe("Cipher DTO", () => {
|
|||||||
const cipher = new Cipher(cipherData);
|
const cipher = new Cipher(cipherData);
|
||||||
|
|
||||||
expect(cipher).toEqual({
|
expect(cipher).toEqual({
|
||||||
|
initializerKey: InitializerKey.Cipher,
|
||||||
id: "id",
|
id: "id",
|
||||||
organizationId: "orgId",
|
organizationId: "orgId",
|
||||||
folderId: "folderId",
|
folderId: "folderId",
|
||||||
|
@ -2,8 +2,8 @@
|
|||||||
import { Substitute, Arg } from "@fluffy-spoon/substitute";
|
import { Substitute, Arg } from "@fluffy-spoon/substitute";
|
||||||
import { mock, MockProxy } from "jest-mock-extended";
|
import { mock, MockProxy } from "jest-mock-extended";
|
||||||
|
|
||||||
import { AbstractEncryptService } from "@bitwarden/common/abstractions/abstractEncrypt.service";
|
|
||||||
import { CryptoService } from "@bitwarden/common/abstractions/crypto.service";
|
import { CryptoService } from "@bitwarden/common/abstractions/crypto.service";
|
||||||
|
import { EncryptService } from "@bitwarden/common/abstractions/encrypt.service";
|
||||||
import { EncryptionType } from "@bitwarden/common/enums/encryptionType";
|
import { EncryptionType } from "@bitwarden/common/enums/encryptionType";
|
||||||
import { EncString } from "@bitwarden/common/models/domain/enc-string";
|
import { EncString } from "@bitwarden/common/models/domain/enc-string";
|
||||||
import { SymmetricCryptoKey } from "@bitwarden/common/models/domain/symmetric-crypto-key";
|
import { SymmetricCryptoKey } from "@bitwarden/common/models/domain/symmetric-crypto-key";
|
||||||
@ -52,7 +52,7 @@ describe("EncString", () => {
|
|||||||
const cryptoService = Substitute.for<CryptoService>();
|
const cryptoService = Substitute.for<CryptoService>();
|
||||||
cryptoService.getOrgKey(null).resolves(null);
|
cryptoService.getOrgKey(null).resolves(null);
|
||||||
|
|
||||||
const encryptService = Substitute.for<AbstractEncryptService>();
|
const encryptService = Substitute.for<EncryptService>();
|
||||||
encryptService.decryptToUtf8(encString, Arg.any()).resolves("decrypted");
|
encryptService.decryptToUtf8(encString, Arg.any()).resolves("decrypted");
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
@ -157,12 +157,12 @@ describe("EncString", () => {
|
|||||||
|
|
||||||
describe("decrypt", () => {
|
describe("decrypt", () => {
|
||||||
let cryptoService: MockProxy<CryptoService>;
|
let cryptoService: MockProxy<CryptoService>;
|
||||||
let encryptService: MockProxy<AbstractEncryptService>;
|
let encryptService: MockProxy<EncryptService>;
|
||||||
let encString: EncString;
|
let encString: EncString;
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
cryptoService = mock<CryptoService>();
|
cryptoService = mock<CryptoService>();
|
||||||
encryptService = mock<AbstractEncryptService>();
|
encryptService = mock<EncryptService>();
|
||||||
encString = new EncString(null);
|
encString = new EncString(null);
|
||||||
|
|
||||||
(window as any).bitwardenContainerService = new ContainerService(
|
(window as any).bitwardenContainerService = new ContainerService(
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
// eslint-disable-next-line no-restricted-imports
|
// eslint-disable-next-line no-restricted-imports
|
||||||
import { Substitute, Arg, SubstituteOf } from "@fluffy-spoon/substitute";
|
import { Substitute, Arg, SubstituteOf } from "@fluffy-spoon/substitute";
|
||||||
|
|
||||||
import { AbstractEncryptService } from "@bitwarden/common/abstractions/abstractEncrypt.service";
|
|
||||||
import { CryptoService } from "@bitwarden/common/abstractions/crypto.service";
|
import { CryptoService } from "@bitwarden/common/abstractions/crypto.service";
|
||||||
|
import { EncryptService } from "@bitwarden/common/abstractions/encrypt.service";
|
||||||
import { SendType } from "@bitwarden/common/enums/sendType";
|
import { SendType } from "@bitwarden/common/enums/sendType";
|
||||||
import { SendData } from "@bitwarden/common/models/data/send.data";
|
import { SendData } from "@bitwarden/common/models/data/send.data";
|
||||||
import { EncString } from "@bitwarden/common/models/domain/enc-string";
|
import { EncString } from "@bitwarden/common/models/domain/enc-string";
|
||||||
@ -112,7 +112,7 @@ describe("Send", () => {
|
|||||||
cryptoService.decryptToBytes(send.key, null).resolves(makeStaticByteArray(32));
|
cryptoService.decryptToBytes(send.key, null).resolves(makeStaticByteArray(32));
|
||||||
cryptoService.makeSendKey(Arg.any()).resolves("cryptoKey" as any);
|
cryptoService.makeSendKey(Arg.any()).resolves("cryptoKey" as any);
|
||||||
|
|
||||||
const encryptService = Substitute.for<AbstractEncryptService>();
|
const encryptService = Substitute.for<EncryptService>();
|
||||||
|
|
||||||
(window as any).bitwardenContainerService = new ContainerService(cryptoService, encryptService);
|
(window as any).bitwardenContainerService = new ContainerService(cryptoService, encryptService);
|
||||||
|
|
||||||
|
@ -3,6 +3,7 @@ import { Arg, Substitute, SubstituteOf } from "@fluffy-spoon/substitute";
|
|||||||
|
|
||||||
import { ApiService } from "@bitwarden/common/abstractions/api.service";
|
import { ApiService } from "@bitwarden/common/abstractions/api.service";
|
||||||
import { CryptoService } from "@bitwarden/common/abstractions/crypto.service";
|
import { CryptoService } from "@bitwarden/common/abstractions/crypto.service";
|
||||||
|
import { EncryptService } from "@bitwarden/common/abstractions/encrypt.service";
|
||||||
import { FileUploadService } from "@bitwarden/common/abstractions/fileUpload.service";
|
import { FileUploadService } from "@bitwarden/common/abstractions/fileUpload.service";
|
||||||
import { I18nService } from "@bitwarden/common/abstractions/i18n.service";
|
import { I18nService } from "@bitwarden/common/abstractions/i18n.service";
|
||||||
import { LogService } from "@bitwarden/common/abstractions/log.service";
|
import { LogService } from "@bitwarden/common/abstractions/log.service";
|
||||||
@ -27,6 +28,7 @@ describe("Cipher Service", () => {
|
|||||||
let i18nService: SubstituteOf<I18nService>;
|
let i18nService: SubstituteOf<I18nService>;
|
||||||
let searchService: SubstituteOf<SearchService>;
|
let searchService: SubstituteOf<SearchService>;
|
||||||
let logService: SubstituteOf<LogService>;
|
let logService: SubstituteOf<LogService>;
|
||||||
|
let encryptService: SubstituteOf<EncryptService>;
|
||||||
|
|
||||||
let cipherService: CipherService;
|
let cipherService: CipherService;
|
||||||
|
|
||||||
@ -39,6 +41,7 @@ describe("Cipher Service", () => {
|
|||||||
i18nService = Substitute.for<I18nService>();
|
i18nService = Substitute.for<I18nService>();
|
||||||
searchService = Substitute.for<SearchService>();
|
searchService = Substitute.for<SearchService>();
|
||||||
logService = Substitute.for<LogService>();
|
logService = Substitute.for<LogService>();
|
||||||
|
encryptService = Substitute.for<EncryptService>();
|
||||||
|
|
||||||
cryptoService.encryptToBytes(Arg.any(), Arg.any()).resolves(ENCRYPTED_BYTES);
|
cryptoService.encryptToBytes(Arg.any(), Arg.any()).resolves(ENCRYPTED_BYTES);
|
||||||
cryptoService.encrypt(Arg.any(), Arg.any()).resolves(new EncString(ENCRYPTED_TEXT));
|
cryptoService.encrypt(Arg.any(), Arg.any()).resolves(new EncString(ENCRYPTED_TEXT));
|
||||||
@ -51,7 +54,8 @@ describe("Cipher Service", () => {
|
|||||||
i18nService,
|
i18nService,
|
||||||
() => searchService,
|
() => searchService,
|
||||||
logService,
|
logService,
|
||||||
stateService
|
stateService,
|
||||||
|
encryptService
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import { mock, mockReset } from "jest-mock-extended";
|
import { mock, mockReset } from "jest-mock-extended";
|
||||||
|
|
||||||
import { AbstractEncryptService } from "@bitwarden/common/abstractions/abstractEncrypt.service";
|
|
||||||
import { CryptoFunctionService } from "@bitwarden/common/abstractions/cryptoFunction.service";
|
import { CryptoFunctionService } from "@bitwarden/common/abstractions/cryptoFunction.service";
|
||||||
|
import { EncryptService } from "@bitwarden/common/abstractions/encrypt.service";
|
||||||
import { LogService } from "@bitwarden/common/abstractions/log.service";
|
import { LogService } from "@bitwarden/common/abstractions/log.service";
|
||||||
import { PlatformUtilsService } from "@bitwarden/common/abstractions/platformUtils.service";
|
import { PlatformUtilsService } from "@bitwarden/common/abstractions/platformUtils.service";
|
||||||
import { StateService } from "@bitwarden/common/abstractions/state.service";
|
import { StateService } from "@bitwarden/common/abstractions/state.service";
|
||||||
@ -11,7 +11,7 @@ describe("cryptoService", () => {
|
|||||||
let cryptoService: CryptoService;
|
let cryptoService: CryptoService;
|
||||||
|
|
||||||
const cryptoFunctionService = mock<CryptoFunctionService>();
|
const cryptoFunctionService = mock<CryptoFunctionService>();
|
||||||
const encryptService = mock<AbstractEncryptService>();
|
const encryptService = mock<EncryptService>();
|
||||||
const platformUtilService = mock<PlatformUtilsService>();
|
const platformUtilService = mock<PlatformUtilsService>();
|
||||||
const logService = mock<LogService>();
|
const logService = mock<LogService>();
|
||||||
const stateService = mock<StateService>();
|
const stateService = mock<StateService>();
|
||||||
|
@ -6,7 +6,7 @@ import { EncryptionType } from "@bitwarden/common/enums/encryptionType";
|
|||||||
import { EncArrayBuffer } from "@bitwarden/common/models/domain/enc-array-buffer";
|
import { EncArrayBuffer } from "@bitwarden/common/models/domain/enc-array-buffer";
|
||||||
import { EncString } from "@bitwarden/common/models/domain/enc-string";
|
import { EncString } from "@bitwarden/common/models/domain/enc-string";
|
||||||
import { SymmetricCryptoKey } from "@bitwarden/common/models/domain/symmetric-crypto-key";
|
import { SymmetricCryptoKey } from "@bitwarden/common/models/domain/symmetric-crypto-key";
|
||||||
import { EncryptService } from "@bitwarden/common/services/encrypt.service";
|
import { EncryptServiceImplementation } from "@bitwarden/common/services/cryptography/encrypt.service.implementation";
|
||||||
|
|
||||||
import { makeStaticByteArray } from "../utils";
|
import { makeStaticByteArray } from "../utils";
|
||||||
|
|
||||||
@ -14,13 +14,13 @@ describe("EncryptService", () => {
|
|||||||
const cryptoFunctionService = mock<CryptoFunctionService>();
|
const cryptoFunctionService = mock<CryptoFunctionService>();
|
||||||
const logService = mock<LogService>();
|
const logService = mock<LogService>();
|
||||||
|
|
||||||
let encryptService: EncryptService;
|
let encryptService: EncryptServiceImplementation;
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
mockReset(cryptoFunctionService);
|
mockReset(cryptoFunctionService);
|
||||||
mockReset(logService);
|
mockReset(logService);
|
||||||
|
|
||||||
encryptService = new EncryptService(cryptoFunctionService, logService, true);
|
encryptService = new EncryptServiceImplementation(cryptoFunctionService, logService, true);
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("encryptToBytes", () => {
|
describe("encryptToBytes", () => {
|
||||||
|
@ -2,9 +2,9 @@
|
|||||||
import { Arg, Substitute, SubstituteOf } from "@fluffy-spoon/substitute";
|
import { Arg, Substitute, SubstituteOf } from "@fluffy-spoon/substitute";
|
||||||
import { BehaviorSubject, firstValueFrom } from "rxjs";
|
import { BehaviorSubject, firstValueFrom } from "rxjs";
|
||||||
|
|
||||||
import { AbstractEncryptService } from "@bitwarden/common/abstractions/abstractEncrypt.service";
|
|
||||||
import { CipherService } from "@bitwarden/common/abstractions/cipher.service";
|
import { CipherService } from "@bitwarden/common/abstractions/cipher.service";
|
||||||
import { CryptoService } from "@bitwarden/common/abstractions/crypto.service";
|
import { CryptoService } from "@bitwarden/common/abstractions/crypto.service";
|
||||||
|
import { EncryptService } from "@bitwarden/common/abstractions/encrypt.service";
|
||||||
import { I18nService } from "@bitwarden/common/abstractions/i18n.service";
|
import { I18nService } from "@bitwarden/common/abstractions/i18n.service";
|
||||||
import { FolderData } from "@bitwarden/common/models/data/folder.data";
|
import { FolderData } from "@bitwarden/common/models/data/folder.data";
|
||||||
import { EncString } from "@bitwarden/common/models/domain/enc-string";
|
import { EncString } from "@bitwarden/common/models/domain/enc-string";
|
||||||
@ -17,7 +17,7 @@ describe("Folder Service", () => {
|
|||||||
let folderService: FolderService;
|
let folderService: FolderService;
|
||||||
|
|
||||||
let cryptoService: SubstituteOf<CryptoService>;
|
let cryptoService: SubstituteOf<CryptoService>;
|
||||||
let encryptService: SubstituteOf<AbstractEncryptService>;
|
let encryptService: SubstituteOf<EncryptService>;
|
||||||
let i18nService: SubstituteOf<I18nService>;
|
let i18nService: SubstituteOf<I18nService>;
|
||||||
let cipherService: SubstituteOf<CipherService>;
|
let cipherService: SubstituteOf<CipherService>;
|
||||||
let stateService: SubstituteOf<StateService>;
|
let stateService: SubstituteOf<StateService>;
|
||||||
|
@ -3,6 +3,7 @@ import { Arg, Substitute, SubstituteOf } from "@fluffy-spoon/substitute";
|
|||||||
import { BehaviorSubject, firstValueFrom } from "rxjs";
|
import { BehaviorSubject, firstValueFrom } from "rxjs";
|
||||||
|
|
||||||
import { CryptoService } from "@bitwarden/common/abstractions/crypto.service";
|
import { CryptoService } from "@bitwarden/common/abstractions/crypto.service";
|
||||||
|
import { EncryptService } from "@bitwarden/common/abstractions/encrypt.service";
|
||||||
import { OrganizationService } from "@bitwarden/common/abstractions/organization/organization.service.abstraction";
|
import { OrganizationService } from "@bitwarden/common/abstractions/organization/organization.service.abstraction";
|
||||||
import { OrganizationUserStatusType } from "@bitwarden/common/enums/organizationUserStatusType";
|
import { OrganizationUserStatusType } from "@bitwarden/common/enums/organizationUserStatusType";
|
||||||
import { PolicyType } from "@bitwarden/common/enums/policyType";
|
import { PolicyType } from "@bitwarden/common/enums/policyType";
|
||||||
@ -16,7 +17,6 @@ import { ResetPasswordPolicyOptions } from "@bitwarden/common/models/domain/rese
|
|||||||
import { ListResponse } from "@bitwarden/common/models/response/list.response";
|
import { ListResponse } from "@bitwarden/common/models/response/list.response";
|
||||||
import { PolicyResponse } from "@bitwarden/common/models/response/policy.response";
|
import { PolicyResponse } from "@bitwarden/common/models/response/policy.response";
|
||||||
import { ContainerService } from "@bitwarden/common/services/container.service";
|
import { ContainerService } from "@bitwarden/common/services/container.service";
|
||||||
import { EncryptService } from "@bitwarden/common/services/encrypt.service";
|
|
||||||
import { PolicyService } from "@bitwarden/common/services/policy/policy.service";
|
import { PolicyService } from "@bitwarden/common/services/policy/policy.service";
|
||||||
import { StateService } from "@bitwarden/common/services/state.service";
|
import { StateService } from "@bitwarden/common/services/state.service";
|
||||||
|
|
||||||
|
@ -2,8 +2,8 @@
|
|||||||
import { Arg, Substitute, SubstituteOf } from "@fluffy-spoon/substitute";
|
import { Arg, Substitute, SubstituteOf } from "@fluffy-spoon/substitute";
|
||||||
import { BehaviorSubject, firstValueFrom } from "rxjs";
|
import { BehaviorSubject, firstValueFrom } from "rxjs";
|
||||||
|
|
||||||
import { AbstractEncryptService } from "@bitwarden/common/abstractions/abstractEncrypt.service";
|
|
||||||
import { CryptoService } from "@bitwarden/common/abstractions/crypto.service";
|
import { CryptoService } from "@bitwarden/common/abstractions/crypto.service";
|
||||||
|
import { EncryptService } from "@bitwarden/common/abstractions/encrypt.service";
|
||||||
import { ContainerService } from "@bitwarden/common/services/container.service";
|
import { ContainerService } from "@bitwarden/common/services/container.service";
|
||||||
import { SettingsService } from "@bitwarden/common/services/settings.service";
|
import { SettingsService } from "@bitwarden/common/services/settings.service";
|
||||||
import { StateService } from "@bitwarden/common/services/state.service";
|
import { StateService } from "@bitwarden/common/services/state.service";
|
||||||
@ -12,7 +12,7 @@ describe("SettingsService", () => {
|
|||||||
let settingsService: SettingsService;
|
let settingsService: SettingsService;
|
||||||
|
|
||||||
let cryptoService: SubstituteOf<CryptoService>;
|
let cryptoService: SubstituteOf<CryptoService>;
|
||||||
let encryptService: SubstituteOf<AbstractEncryptService>;
|
let encryptService: SubstituteOf<EncryptService>;
|
||||||
let stateService: SubstituteOf<StateService>;
|
let stateService: SubstituteOf<StateService>;
|
||||||
let activeAccount: BehaviorSubject<string>;
|
let activeAccount: BehaviorSubject<string>;
|
||||||
let activeAccountUnlocked: BehaviorSubject<boolean>;
|
let activeAccountUnlocked: BehaviorSubject<boolean>;
|
||||||
|
@ -1,9 +1,11 @@
|
|||||||
import { IEncrypted } from "../interfaces/IEncrypted";
|
import { IEncrypted } from "../interfaces/IEncrypted";
|
||||||
|
import { Decryptable } from "../interfaces/decryptable.interface";
|
||||||
|
import { InitializerMetadata } from "../interfaces/initializer-metadata.interface";
|
||||||
import { EncArrayBuffer } from "../models/domain/enc-array-buffer";
|
import { EncArrayBuffer } from "../models/domain/enc-array-buffer";
|
||||||
import { EncString } from "../models/domain/enc-string";
|
import { EncString } from "../models/domain/enc-string";
|
||||||
import { SymmetricCryptoKey } from "../models/domain/symmetric-crypto-key";
|
import { SymmetricCryptoKey } from "../models/domain/symmetric-crypto-key";
|
||||||
|
|
||||||
export abstract class AbstractEncryptService {
|
export abstract class EncryptService {
|
||||||
abstract encrypt(plainValue: string | ArrayBuffer, key: SymmetricCryptoKey): Promise<EncString>;
|
abstract encrypt(plainValue: string | ArrayBuffer, key: SymmetricCryptoKey): Promise<EncString>;
|
||||||
abstract encryptToBytes: (
|
abstract encryptToBytes: (
|
||||||
plainValue: ArrayBuffer,
|
plainValue: ArrayBuffer,
|
||||||
@ -12,4 +14,8 @@ export abstract class AbstractEncryptService {
|
|||||||
abstract decryptToUtf8: (encString: EncString, key: SymmetricCryptoKey) => Promise<string>;
|
abstract decryptToUtf8: (encString: EncString, key: SymmetricCryptoKey) => Promise<string>;
|
||||||
abstract decryptToBytes: (encThing: IEncrypted, key: SymmetricCryptoKey) => Promise<ArrayBuffer>;
|
abstract decryptToBytes: (encThing: IEncrypted, key: SymmetricCryptoKey) => Promise<ArrayBuffer>;
|
||||||
abstract resolveLegacyKey: (key: SymmetricCryptoKey, encThing: IEncrypted) => SymmetricCryptoKey;
|
abstract resolveLegacyKey: (key: SymmetricCryptoKey, encThing: IEncrypted) => SymmetricCryptoKey;
|
||||||
|
abstract decryptItems: <T extends InitializerMetadata>(
|
||||||
|
items: Decryptable<T>[],
|
||||||
|
key: SymmetricCryptoKey
|
||||||
|
) => Promise<T[]>;
|
||||||
}
|
}
|
12
libs/common/src/interfaces/decryptable.interface.ts
Normal file
12
libs/common/src/interfaces/decryptable.interface.ts
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
import { SymmetricCryptoKey } from "../models/domain/symmetric-crypto-key";
|
||||||
|
|
||||||
|
import { InitializerMetadata } from "./initializer-metadata.interface";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An object that contains EncStrings and knows how to decrypt them. This is usually a domain object with the
|
||||||
|
* corresponding view object as the type argument.
|
||||||
|
* @example Cipher implements Decryptable<CipherView>
|
||||||
|
*/
|
||||||
|
export interface Decryptable<TDecrypted extends InitializerMetadata> extends InitializerMetadata {
|
||||||
|
decrypt: (key?: SymmetricCryptoKey) => Promise<TDecrypted>;
|
||||||
|
}
|
11
libs/common/src/interfaces/initializer-metadata.interface.ts
Normal file
11
libs/common/src/interfaces/initializer-metadata.interface.ts
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
import { InitializerKey } from "../services/cryptography/initializer-key";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This interface enables deserialization of arbitrary objects by recording their class name as an enum, which
|
||||||
|
* will survive serialization. The enum can then be matched to a constructor or factory method for deserialization.
|
||||||
|
* See get-class-initializer.ts for the initializer map.
|
||||||
|
*/
|
||||||
|
export interface InitializerMetadata {
|
||||||
|
initializerKey: InitializerKey;
|
||||||
|
toJSON?: () => { initializerKey: InitializerKey };
|
||||||
|
}
|
@ -1,6 +1,8 @@
|
|||||||
// required to avoid linting errors when there are no flags
|
// required to avoid linting errors when there are no flags
|
||||||
/* eslint-disable @typescript-eslint/ban-types */
|
/* eslint-disable @typescript-eslint/ban-types */
|
||||||
export type SharedFlags = {};
|
export type SharedFlags = {
|
||||||
|
multithreadDecryption: boolean;
|
||||||
|
};
|
||||||
|
|
||||||
// required to avoid linting errors when there are no flags
|
// required to avoid linting errors when there are no flags
|
||||||
/* eslint-disable @typescript-eslint/ban-types */
|
/* eslint-disable @typescript-eslint/ban-types */
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
/* eslint-disable no-useless-escape */
|
/* eslint-disable no-useless-escape */
|
||||||
import { getHostname, parse } from "tldts";
|
import { getHostname, parse } from "tldts";
|
||||||
|
|
||||||
import { AbstractEncryptService } from "../abstractions/abstractEncrypt.service";
|
|
||||||
import { CryptoService } from "../abstractions/crypto.service";
|
import { CryptoService } from "../abstractions/crypto.service";
|
||||||
|
import { EncryptService } from "../abstractions/encrypt.service";
|
||||||
import { I18nService } from "../abstractions/i18n.service";
|
import { I18nService } from "../abstractions/i18n.service";
|
||||||
|
|
||||||
const nodeURL = typeof window === "undefined" ? require("url") : null;
|
const nodeURL = typeof window === "undefined" ? require("url") : null;
|
||||||
@ -14,7 +14,7 @@ declare global {
|
|||||||
|
|
||||||
interface BitwardenContainerService {
|
interface BitwardenContainerService {
|
||||||
getCryptoService: () => CryptoService;
|
getCryptoService: () => CryptoService;
|
||||||
getEncryptService: () => AbstractEncryptService;
|
getEncryptService: () => EncryptService;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class Utils {
|
export class Utils {
|
||||||
|
@ -2,6 +2,8 @@ import { Jsonify } from "type-fest";
|
|||||||
|
|
||||||
import { CipherRepromptType } from "../../enums/cipherRepromptType";
|
import { CipherRepromptType } from "../../enums/cipherRepromptType";
|
||||||
import { CipherType } from "../../enums/cipherType";
|
import { CipherType } from "../../enums/cipherType";
|
||||||
|
import { Decryptable } from "../../interfaces/decryptable.interface";
|
||||||
|
import { InitializerKey } from "../../services/cryptography/initializer-key";
|
||||||
import { CipherData } from "../data/cipher.data";
|
import { CipherData } from "../data/cipher.data";
|
||||||
import { LocalData } from "../data/local.data";
|
import { LocalData } from "../data/local.data";
|
||||||
import { CipherView } from "../view/cipher.view";
|
import { CipherView } from "../view/cipher.view";
|
||||||
@ -17,7 +19,9 @@ import { Password } from "./password";
|
|||||||
import { SecureNote } from "./secure-note";
|
import { SecureNote } from "./secure-note";
|
||||||
import { SymmetricCryptoKey } from "./symmetric-crypto-key";
|
import { SymmetricCryptoKey } from "./symmetric-crypto-key";
|
||||||
|
|
||||||
export class Cipher extends Domain {
|
export class Cipher extends Domain implements Decryptable<CipherView> {
|
||||||
|
readonly initializerKey = InitializerKey.Cipher;
|
||||||
|
|
||||||
id: string;
|
id: string;
|
||||||
organizationId: string;
|
organizationId: string;
|
||||||
folderId: string;
|
folderId: string;
|
||||||
|
@ -3,6 +3,8 @@ import { Jsonify } from "type-fest";
|
|||||||
import { CipherRepromptType } from "../../enums/cipherRepromptType";
|
import { CipherRepromptType } from "../../enums/cipherRepromptType";
|
||||||
import { CipherType } from "../../enums/cipherType";
|
import { CipherType } from "../../enums/cipherType";
|
||||||
import { LinkedIdType } from "../../enums/linkedIdType";
|
import { LinkedIdType } from "../../enums/linkedIdType";
|
||||||
|
import { InitializerMetadata } from "../../interfaces/initializer-metadata.interface";
|
||||||
|
import { InitializerKey } from "../../services/cryptography/initializer-key";
|
||||||
import { LocalData } from "../data/local.data";
|
import { LocalData } from "../data/local.data";
|
||||||
import { Cipher } from "../domain/cipher";
|
import { Cipher } from "../domain/cipher";
|
||||||
|
|
||||||
@ -15,7 +17,9 @@ import { PasswordHistoryView } from "./password-history.view";
|
|||||||
import { SecureNoteView } from "./secure-note.view";
|
import { SecureNoteView } from "./secure-note.view";
|
||||||
import { View } from "./view";
|
import { View } from "./view";
|
||||||
|
|
||||||
export class CipherView implements View {
|
export class CipherView implements View, InitializerMetadata {
|
||||||
|
readonly initializerKey = InitializerKey.CipherView;
|
||||||
|
|
||||||
id: string = null;
|
id: string = null;
|
||||||
organizationId: string = null;
|
organizationId: string = null;
|
||||||
folderId: string = null;
|
folderId: string = null;
|
||||||
|
@ -3,6 +3,7 @@ import { firstValueFrom } from "rxjs";
|
|||||||
import { ApiService } from "../abstractions/api.service";
|
import { ApiService } from "../abstractions/api.service";
|
||||||
import { CipherService as CipherServiceAbstraction } from "../abstractions/cipher.service";
|
import { CipherService as CipherServiceAbstraction } from "../abstractions/cipher.service";
|
||||||
import { CryptoService } from "../abstractions/crypto.service";
|
import { CryptoService } from "../abstractions/crypto.service";
|
||||||
|
import { EncryptService } from "../abstractions/encrypt.service";
|
||||||
import { FileUploadService } from "../abstractions/fileUpload.service";
|
import { FileUploadService } from "../abstractions/fileUpload.service";
|
||||||
import { I18nService } from "../abstractions/i18n.service";
|
import { I18nService } from "../abstractions/i18n.service";
|
||||||
import { LogService } from "../abstractions/log.service";
|
import { LogService } from "../abstractions/log.service";
|
||||||
@ -65,7 +66,8 @@ export class CipherService implements CipherServiceAbstraction {
|
|||||||
private i18nService: I18nService,
|
private i18nService: I18nService,
|
||||||
private searchService: () => SearchService,
|
private searchService: () => SearchService,
|
||||||
private logService: LogService,
|
private logService: LogService,
|
||||||
private stateService: StateService
|
private stateService: StateService,
|
||||||
|
private encryptService: EncryptService
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
async getDecryptedCipherCache(): Promise<CipherView[]> {
|
async getDecryptedCipherCache(): Promise<CipherView[]> {
|
||||||
@ -329,35 +331,50 @@ export class CipherService implements CipherServiceAbstraction {
|
|||||||
|
|
||||||
@sequentialize(() => "getAllDecrypted")
|
@sequentialize(() => "getAllDecrypted")
|
||||||
async getAllDecrypted(): Promise<CipherView[]> {
|
async getAllDecrypted(): Promise<CipherView[]> {
|
||||||
const userId = await this.stateService.getUserId();
|
|
||||||
if ((await this.getDecryptedCipherCache()) != null) {
|
if ((await this.getDecryptedCipherCache()) != null) {
|
||||||
if (
|
await this.reindexCiphers();
|
||||||
this.searchService != null &&
|
|
||||||
(this.searchService().indexedEntityId ?? userId) !== userId
|
|
||||||
) {
|
|
||||||
await this.searchService().indexCiphers(userId, await this.getDecryptedCipherCache());
|
|
||||||
}
|
|
||||||
return await this.getDecryptedCipherCache();
|
return await this.getDecryptedCipherCache();
|
||||||
}
|
}
|
||||||
|
|
||||||
const decCiphers: CipherView[] = [];
|
|
||||||
const hasKey = await this.cryptoService.hasKey();
|
const hasKey = await this.cryptoService.hasKey();
|
||||||
if (!hasKey) {
|
if (!hasKey) {
|
||||||
throw new Error("No key.");
|
throw new Error("No key.");
|
||||||
}
|
}
|
||||||
|
|
||||||
const promises: Promise<number>[] = [];
|
|
||||||
const ciphers = await this.getAll();
|
const ciphers = await this.getAll();
|
||||||
ciphers.forEach(async (cipher) => {
|
const orgKeys = await this.cryptoService.getOrgKeys();
|
||||||
promises.push(cipher.decrypt().then((c) => decCiphers.push(c)));
|
const userKey = await this.cryptoService.getKeyForUserEncryption();
|
||||||
});
|
|
||||||
|
// Group ciphers by orgId or under 'null' for the user's ciphers
|
||||||
|
const grouped = ciphers.reduce((agg, c) => {
|
||||||
|
agg[c.organizationId] ??= [];
|
||||||
|
agg[c.organizationId].push(c);
|
||||||
|
return agg;
|
||||||
|
}, {} as Record<string, Cipher[]>);
|
||||||
|
|
||||||
|
const decCiphers = (
|
||||||
|
await Promise.all(
|
||||||
|
Object.entries(grouped).map(([orgId, groupedCiphers]) =>
|
||||||
|
this.encryptService.decryptItems(groupedCiphers, orgKeys.get(orgId) ?? userKey)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
.flat()
|
||||||
|
.sort(this.getLocaleSortingFunction());
|
||||||
|
|
||||||
await Promise.all(promises);
|
|
||||||
decCiphers.sort(this.getLocaleSortingFunction());
|
|
||||||
await this.setDecryptedCipherCache(decCiphers);
|
await this.setDecryptedCipherCache(decCiphers);
|
||||||
return decCiphers;
|
return decCiphers;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async reindexCiphers() {
|
||||||
|
const userId = await this.stateService.getUserId();
|
||||||
|
const reindexRequired =
|
||||||
|
this.searchService != null && (this.searchService().indexedEntityId ?? userId) !== userId;
|
||||||
|
if (reindexRequired) {
|
||||||
|
await this.searchService().indexCiphers(userId, await this.getDecryptedCipherCache());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
async getAllDecryptedForGrouping(groupingId: string, folder = true): Promise<CipherView[]> {
|
async getAllDecryptedForGrouping(groupingId: string, folder = true): Promise<CipherView[]> {
|
||||||
const ciphers = await this.getAllDecrypted();
|
const ciphers = await this.getAllDecrypted();
|
||||||
|
|
||||||
@ -488,21 +505,17 @@ export class CipherService implements CipherServiceAbstraction {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async getAllFromApiForOrganization(organizationId: string): Promise<CipherView[]> {
|
async getAllFromApiForOrganization(organizationId: string): Promise<CipherView[]> {
|
||||||
const ciphers = await this.apiService.getCiphersOrganization(organizationId);
|
const response = await this.apiService.getCiphersOrganization(organizationId);
|
||||||
if (ciphers != null && ciphers.data != null && ciphers.data.length) {
|
if (response?.data == null || response.data.length < 1) {
|
||||||
const decCiphers: CipherView[] = [];
|
|
||||||
const promises: any[] = [];
|
|
||||||
ciphers.data.forEach((r) => {
|
|
||||||
const data = new CipherData(r);
|
|
||||||
const cipher = new Cipher(data);
|
|
||||||
promises.push(cipher.decrypt().then((c) => decCiphers.push(c)));
|
|
||||||
});
|
|
||||||
await Promise.all(promises);
|
|
||||||
decCiphers.sort(this.getLocaleSortingFunction());
|
|
||||||
return decCiphers;
|
|
||||||
} else {
|
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
decCiphers.sort(this.getLocaleSortingFunction());
|
||||||
|
return decCiphers;
|
||||||
}
|
}
|
||||||
|
|
||||||
async getLastUsedForUrl(url: string, autofillOnPageLoad = false): Promise<CipherView> {
|
async getLastUsedForUrl(url: string, autofillOnPageLoad = false): Promise<CipherView> {
|
||||||
|
@ -1,11 +1,8 @@
|
|||||||
import { AbstractEncryptService } from "../abstractions/abstractEncrypt.service";
|
|
||||||
import { CryptoService } from "../abstractions/crypto.service";
|
import { CryptoService } from "../abstractions/crypto.service";
|
||||||
|
import { EncryptService } from "../abstractions/encrypt.service";
|
||||||
|
|
||||||
export class ContainerService {
|
export class ContainerService {
|
||||||
constructor(
|
constructor(private cryptoService: CryptoService, private encryptService: EncryptService) {}
|
||||||
private cryptoService: CryptoService,
|
|
||||||
private encryptService: AbstractEncryptService
|
|
||||||
) {}
|
|
||||||
|
|
||||||
attachToGlobal(global: any) {
|
attachToGlobal(global: any) {
|
||||||
if (!global.bitwardenContainerService) {
|
if (!global.bitwardenContainerService) {
|
||||||
@ -26,7 +23,7 @@ export class ContainerService {
|
|||||||
/**
|
/**
|
||||||
* @throws Will throw if EncryptService was not instantiated and provided to the ContainerService constructor
|
* @throws Will throw if EncryptService was not instantiated and provided to the ContainerService constructor
|
||||||
*/
|
*/
|
||||||
getEncryptService(): AbstractEncryptService {
|
getEncryptService(): EncryptService {
|
||||||
if (this.encryptService == null) {
|
if (this.encryptService == null) {
|
||||||
throw new Error("ContainerService.encryptService not initialized.");
|
throw new Error("ContainerService.encryptService not initialized.");
|
||||||
}
|
}
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
import * as bigInt from "big-integer";
|
import * as bigInt from "big-integer";
|
||||||
|
|
||||||
import { AbstractEncryptService } from "../abstractions/abstractEncrypt.service";
|
|
||||||
import { CryptoService as CryptoServiceAbstraction } from "../abstractions/crypto.service";
|
import { CryptoService as CryptoServiceAbstraction } from "../abstractions/crypto.service";
|
||||||
import { CryptoFunctionService } from "../abstractions/cryptoFunction.service";
|
import { CryptoFunctionService } from "../abstractions/cryptoFunction.service";
|
||||||
|
import { EncryptService } from "../abstractions/encrypt.service";
|
||||||
import { LogService } from "../abstractions/log.service";
|
import { LogService } from "../abstractions/log.service";
|
||||||
import { PlatformUtilsService } from "../abstractions/platformUtils.service";
|
import { PlatformUtilsService } from "../abstractions/platformUtils.service";
|
||||||
import { StateService } from "../abstractions/state.service";
|
import { StateService } from "../abstractions/state.service";
|
||||||
@ -25,7 +25,7 @@ import { ProfileProviderResponse } from "../models/response/profile-provider.res
|
|||||||
export class CryptoService implements CryptoServiceAbstraction {
|
export class CryptoService implements CryptoServiceAbstraction {
|
||||||
constructor(
|
constructor(
|
||||||
private cryptoFunctionService: CryptoFunctionService,
|
private cryptoFunctionService: CryptoFunctionService,
|
||||||
private encryptService: AbstractEncryptService,
|
private encryptService: EncryptService,
|
||||||
protected platformUtilService: PlatformUtilsService,
|
protected platformUtilService: PlatformUtilsService,
|
||||||
protected logService: LogService,
|
protected logService: LogService,
|
||||||
protected stateService: StateService
|
protected stateService: StateService
|
||||||
|
@ -1,19 +1,21 @@
|
|||||||
import { AbstractEncryptService } from "../abstractions/abstractEncrypt.service";
|
import { CryptoFunctionService } from "../../abstractions/cryptoFunction.service";
|
||||||
import { CryptoFunctionService } from "../abstractions/cryptoFunction.service";
|
import { EncryptService } from "../../abstractions/encrypt.service";
|
||||||
import { LogService } from "../abstractions/log.service";
|
import { LogService } from "../../abstractions/log.service";
|
||||||
import { EncryptionType } from "../enums/encryptionType";
|
import { EncryptionType } from "../../enums/encryptionType";
|
||||||
import { IEncrypted } from "../interfaces/IEncrypted";
|
import { IEncrypted } from "../../interfaces/IEncrypted";
|
||||||
import { Utils } from "../misc/utils";
|
import { Decryptable } from "../../interfaces/decryptable.interface";
|
||||||
import { EncArrayBuffer } from "../models/domain/enc-array-buffer";
|
import { InitializerMetadata } from "../../interfaces/initializer-metadata.interface";
|
||||||
import { EncString } from "../models/domain/enc-string";
|
import { Utils } from "../../misc/utils";
|
||||||
import { EncryptedObject } from "../models/domain/encrypted-object";
|
import { EncArrayBuffer } from "../../models/domain/enc-array-buffer";
|
||||||
import { SymmetricCryptoKey } from "../models/domain/symmetric-crypto-key";
|
import { EncString } from "../../models/domain/enc-string";
|
||||||
|
import { EncryptedObject } from "../../models/domain/encrypted-object";
|
||||||
|
import { SymmetricCryptoKey } from "../../models/domain/symmetric-crypto-key";
|
||||||
|
|
||||||
export class EncryptService implements AbstractEncryptService {
|
export class EncryptServiceImplementation implements EncryptService {
|
||||||
constructor(
|
constructor(
|
||||||
private cryptoFunctionService: CryptoFunctionService,
|
protected cryptoFunctionService: CryptoFunctionService,
|
||||||
private logService: LogService,
|
protected logService: LogService,
|
||||||
private logMacFailures: boolean
|
protected logMacFailures: boolean
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
async encrypt(plainValue: string | ArrayBuffer, key: SymmetricCryptoKey): Promise<EncString> {
|
async encrypt(plainValue: string | ArrayBuffer, key: SymmetricCryptoKey): Promise<EncString> {
|
||||||
@ -148,6 +150,17 @@ export class EncryptService implements AbstractEncryptService {
|
|||||||
return result ?? null;
|
return result ?? null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async decryptItems<T extends InitializerMetadata>(
|
||||||
|
items: Decryptable<T>[],
|
||||||
|
key: SymmetricCryptoKey
|
||||||
|
): Promise<T[]> {
|
||||||
|
if (items == null || items.length < 1) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
return await Promise.all(items.map((item) => item.decrypt(key)));
|
||||||
|
}
|
||||||
|
|
||||||
private async aesEncrypt(data: ArrayBuffer, key: SymmetricCryptoKey): Promise<EncryptedObject> {
|
private async aesEncrypt(data: ArrayBuffer, key: SymmetricCryptoKey): Promise<EncryptedObject> {
|
||||||
const obj = new EncryptedObject();
|
const obj = new EncryptedObject();
|
||||||
obj.key = key;
|
obj.key = key;
|
56
libs/common/src/services/cryptography/encrypt.worker.ts
Normal file
56
libs/common/src/services/cryptography/encrypt.worker.ts
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
import { Jsonify } from "type-fest";
|
||||||
|
|
||||||
|
import { Decryptable } from "../../interfaces/decryptable.interface";
|
||||||
|
import { SymmetricCryptoKey } from "../../models/domain/symmetric-crypto-key";
|
||||||
|
import { ConsoleLogService } from "../../services/consoleLog.service";
|
||||||
|
import { ContainerService } from "../../services/container.service";
|
||||||
|
import { WebCryptoFunctionService } from "../../services/webCryptoFunction.service";
|
||||||
|
|
||||||
|
import { EncryptServiceImplementation } from "./encrypt.service.implementation";
|
||||||
|
import { getClassInitializer } from "./get-class-initializer";
|
||||||
|
|
||||||
|
const workerApi: Worker = self as any;
|
||||||
|
|
||||||
|
let inited = false;
|
||||||
|
let encryptService: EncryptServiceImplementation;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Bootstrap the worker environment with services required for decryption
|
||||||
|
*/
|
||||||
|
export function init() {
|
||||||
|
const cryptoFunctionService = new WebCryptoFunctionService(self);
|
||||||
|
const logService = new ConsoleLogService(false);
|
||||||
|
encryptService = new EncryptServiceImplementation(cryptoFunctionService, logService, true);
|
||||||
|
|
||||||
|
const bitwardenContainerService = new ContainerService(null, encryptService);
|
||||||
|
bitwardenContainerService.attachToGlobal(self);
|
||||||
|
|
||||||
|
inited = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Listen for messages and decrypt their contents
|
||||||
|
*/
|
||||||
|
workerApi.addEventListener("message", async (event: { data: string }) => {
|
||||||
|
if (!inited) {
|
||||||
|
init();
|
||||||
|
}
|
||||||
|
|
||||||
|
const request: {
|
||||||
|
id: string;
|
||||||
|
items: Jsonify<Decryptable<any>>[];
|
||||||
|
key: Jsonify<SymmetricCryptoKey>;
|
||||||
|
} = JSON.parse(event.data);
|
||||||
|
|
||||||
|
const key = SymmetricCryptoKey.fromJSON(request.key);
|
||||||
|
const items = request.items.map((jsonItem) => {
|
||||||
|
const initializer = getClassInitializer<Decryptable<any>>(jsonItem.initializerKey);
|
||||||
|
return initializer(jsonItem);
|
||||||
|
});
|
||||||
|
const result = await encryptService.decryptItems(items, key);
|
||||||
|
|
||||||
|
workerApi.postMessage({
|
||||||
|
id: request.id,
|
||||||
|
items: JSON.stringify(result),
|
||||||
|
});
|
||||||
|
});
|
@ -0,0 +1,22 @@
|
|||||||
|
import { Jsonify } from "type-fest";
|
||||||
|
|
||||||
|
import { InitializerMetadata } from "../../interfaces/initializer-metadata.interface";
|
||||||
|
import { Cipher } from "../../models/domain/cipher";
|
||||||
|
import { CipherView } from "../../models/view/cipher.view";
|
||||||
|
|
||||||
|
import { InitializerKey } from "./initializer-key";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Internal reference of classes so we can reconstruct objects properly.
|
||||||
|
* Each entry should be keyed using the Decryptable.initializerKey property
|
||||||
|
*/
|
||||||
|
const classInitializers: Record<InitializerKey, (obj: any) => any> = {
|
||||||
|
[InitializerKey.Cipher]: Cipher.fromJSON,
|
||||||
|
[InitializerKey.CipherView]: CipherView.fromJSON,
|
||||||
|
};
|
||||||
|
|
||||||
|
export function getClassInitializer<T extends InitializerMetadata>(
|
||||||
|
className: InitializerKey
|
||||||
|
): (obj: Jsonify<T>) => T {
|
||||||
|
return classInitializers[className];
|
||||||
|
}
|
4
libs/common/src/services/cryptography/initializer-key.ts
Normal file
4
libs/common/src/services/cryptography/initializer-key.ts
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
export enum InitializerKey {
|
||||||
|
Cipher = 0,
|
||||||
|
CipherView = 1,
|
||||||
|
}
|
@ -0,0 +1,82 @@
|
|||||||
|
import { defaultIfEmpty, filter, firstValueFrom, fromEvent, map, Subject, takeUntil } from "rxjs";
|
||||||
|
import { Jsonify } from "type-fest";
|
||||||
|
|
||||||
|
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 { EncryptServiceImplementation } from "./encrypt.service.implementation";
|
||||||
|
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
|
||||||
|
|
||||||
|
export class MultithreadEncryptServiceImplementation extends EncryptServiceImplementation {
|
||||||
|
private worker: Worker;
|
||||||
|
private timeout: any;
|
||||||
|
|
||||||
|
private clear$ = new Subject<void>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sends items to a web worker to decrypt them.
|
||||||
|
* This utilises multithreading to decrypt items faster without interrupting other operations (e.g. updating UI).
|
||||||
|
*/
|
||||||
|
async decryptItems<T extends InitializerMetadata>(
|
||||||
|
items: Decryptable<T>[],
|
||||||
|
key: SymmetricCryptoKey
|
||||||
|
): Promise<T[]> {
|
||||||
|
if (items == null || items.length < 1) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
this.logService.info("Starting decryption using multithreading");
|
||||||
|
|
||||||
|
this.worker ??= new Worker(
|
||||||
|
new URL("@bitwarden/common/services/cryptography/encrypt.worker.ts", import.meta.url)
|
||||||
|
);
|
||||||
|
|
||||||
|
this.restartTimeout();
|
||||||
|
|
||||||
|
const request = {
|
||||||
|
id: Utils.newGuid(),
|
||||||
|
items: items,
|
||||||
|
key: key,
|
||||||
|
};
|
||||||
|
|
||||||
|
this.worker.postMessage(JSON.stringify(request));
|
||||||
|
|
||||||
|
return await firstValueFrom(
|
||||||
|
fromEvent(this.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([])
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private clear() {
|
||||||
|
this.clear$.next();
|
||||||
|
this.worker?.terminate();
|
||||||
|
this.worker = null;
|
||||||
|
this.clearTimeout();
|
||||||
|
}
|
||||||
|
|
||||||
|
private restartTimeout() {
|
||||||
|
this.clearTimeout();
|
||||||
|
this.timeout = setTimeout(() => this.clear(), workerTTL);
|
||||||
|
}
|
||||||
|
|
||||||
|
private clearTimeout() {
|
||||||
|
if (this.timeout != null) {
|
||||||
|
clearTimeout(this.timeout);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,5 +1,5 @@
|
|||||||
import { AbstractEncryptService } from "@bitwarden/common/abstractions/abstractEncrypt.service";
|
|
||||||
import { CryptoFunctionService } from "@bitwarden/common/abstractions/cryptoFunction.service";
|
import { CryptoFunctionService } from "@bitwarden/common/abstractions/cryptoFunction.service";
|
||||||
|
import { EncryptService } from "@bitwarden/common/abstractions/encrypt.service";
|
||||||
import { LogService } from "@bitwarden/common/abstractions/log.service";
|
import { LogService } from "@bitwarden/common/abstractions/log.service";
|
||||||
import { PlatformUtilsService } from "@bitwarden/common/abstractions/platformUtils.service";
|
import { PlatformUtilsService } from "@bitwarden/common/abstractions/platformUtils.service";
|
||||||
import { StateService } from "@bitwarden/common/abstractions/state.service";
|
import { StateService } from "@bitwarden/common/abstractions/state.service";
|
||||||
@ -10,7 +10,7 @@ import { CryptoService } from "@bitwarden/common/services/crypto.service";
|
|||||||
export class ElectronCryptoService extends CryptoService {
|
export class ElectronCryptoService extends CryptoService {
|
||||||
constructor(
|
constructor(
|
||||||
cryptoFunctionService: CryptoFunctionService,
|
cryptoFunctionService: CryptoFunctionService,
|
||||||
encryptService: AbstractEncryptService,
|
encryptService: EncryptService,
|
||||||
platformUtilService: PlatformUtilsService,
|
platformUtilService: PlatformUtilsService,
|
||||||
logService: LogService,
|
logService: LogService,
|
||||||
stateService: StateService
|
stateService: StateService
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
"moduleResolution": "node",
|
"moduleResolution": "node",
|
||||||
"noImplicitAny": true,
|
"noImplicitAny": true,
|
||||||
"target": "ES6",
|
"target": "ES6",
|
||||||
"module": "commonjs",
|
"module": "es2020",
|
||||||
"lib": ["es5", "es6", "es7", "dom"],
|
"lib": ["es5", "es6", "es7", "dom"],
|
||||||
"sourceMap": true,
|
"sourceMap": true,
|
||||||
"allowSyntheticDefaultImports": true,
|
"allowSyntheticDefaultImports": true,
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
"moduleResolution": "node",
|
"moduleResolution": "node",
|
||||||
"noImplicitAny": true,
|
"noImplicitAny": true,
|
||||||
"target": "ES6",
|
"target": "ES6",
|
||||||
"module": "commonjs",
|
"module": "ES2020",
|
||||||
"lib": ["es5", "es6", "es7", "dom"],
|
"lib": ["es5", "es6", "es7", "dom"],
|
||||||
"sourceMap": true,
|
"sourceMap": true,
|
||||||
"allowSyntheticDefaultImports": true,
|
"allowSyntheticDefaultImports": true,
|
||||||
|
Loading…
Reference in New Issue
Block a user