Browse Source
* Add new encrypt service functions * Undo changes * Cleanup * Fix build * Fix comments * Switch encrypt service to use SDK functions * Move remaining functions to PureCrypto * Tests * Increase test coverage * Enforce sdk.ready and drop unused codepaths * Delete unused code * Delete unused code * Delete more code * Add forgotten sdk init logic * Fix build * Fix cli * Fix tests * Fix build * Fix browser build * Remove compare and add more comments / warnings * Run prettier * Remove unused feature flags * Add hazmat warning to aesDecrypt * Fix build * Fix comment * Fix testpull/15844/head
39 changed files with 77 additions and 706 deletions
@ -1,8 +1,5 @@
@@ -1,8 +1,5 @@
|
||||
{ |
||||
"extends": "./tsconfig.json", |
||||
"files": ["src/polyfills.ts", "src/main.ts", "src/theme.ts"], |
||||
"include": [ |
||||
"src/connectors/*.ts", |
||||
"../../libs/common/src/key-management/crypto/services/encrypt.worker.ts" |
||||
] |
||||
"include": ["src/connectors/*.ts"] |
||||
} |
||||
|
||||
@ -1,13 +0,0 @@
@@ -1,13 +0,0 @@
|
||||
import { ServerConfig } from "../../../platform/abstractions/config/server-config"; |
||||
import { Decryptable } from "../../../platform/interfaces/decryptable.interface"; |
||||
import { InitializerMetadata } from "../../../platform/interfaces/initializer-metadata.interface"; |
||||
import { SymmetricCryptoKey } from "../../../platform/models/domain/symmetric-crypto-key"; |
||||
|
||||
export abstract class BulkEncryptService { |
||||
abstract decryptItems<T extends InitializerMetadata>( |
||||
items: Decryptable<T>[], |
||||
key: SymmetricCryptoKey, |
||||
): Promise<T[]>; |
||||
|
||||
abstract onServerConfigChange(newConfig: ServerConfig): void; |
||||
} |
||||
@ -1,46 +0,0 @@
@@ -1,46 +0,0 @@
|
||||
import { BulkEncryptService } from "@bitwarden/common/key-management/crypto/abstractions/bulk-encrypt.service"; |
||||
import { CryptoFunctionService } from "@bitwarden/common/key-management/crypto/abstractions/crypto-function.service"; |
||||
import { LogService } from "@bitwarden/common/platform/abstractions/log.service"; |
||||
import { Decryptable } from "@bitwarden/common/platform/interfaces/decryptable.interface"; |
||||
import { InitializerMetadata } from "@bitwarden/common/platform/interfaces/initializer-metadata.interface"; |
||||
import { SymmetricCryptoKey } from "@bitwarden/common/platform/models/domain/symmetric-crypto-key"; |
||||
|
||||
import { DefaultFeatureFlagValue, FeatureFlag } from "../../../enums/feature-flag.enum"; |
||||
import { ServerConfig } from "../../../platform/abstractions/config/server-config"; |
||||
|
||||
/** |
||||
* @deprecated Will be deleted in an immediate subsequent PR |
||||
*/ |
||||
export class BulkEncryptServiceImplementation implements BulkEncryptService { |
||||
protected useSDKForDecryption: boolean = DefaultFeatureFlagValue[FeatureFlag.UseSDKForDecryption]; |
||||
|
||||
constructor( |
||||
protected cryptoFunctionService: CryptoFunctionService, |
||||
protected logService: LogService, |
||||
) {} |
||||
|
||||
/** |
||||
* Decrypts items using a web worker if the environment supports it. |
||||
* Will fall back to the main thread if the window object is not available. |
||||
*/ |
||||
async decryptItems<T extends InitializerMetadata>( |
||||
items: Decryptable<T>[], |
||||
key: SymmetricCryptoKey, |
||||
): Promise<T[]> { |
||||
if (key == null) { |
||||
throw new Error("No encryption key provided."); |
||||
} |
||||
|
||||
if (items == null || items.length < 1) { |
||||
return []; |
||||
} |
||||
|
||||
const results = []; |
||||
for (let i = 0; i < items.length; i++) { |
||||
results.push(await items[i].decrypt(key)); |
||||
} |
||||
return results; |
||||
} |
||||
|
||||
onServerConfigChange(newConfig: ServerConfig): void {} |
||||
} |
||||
@ -1,81 +0,0 @@
@@ -1,81 +0,0 @@
|
||||
// FIXME: Update this file to be type safe and remove this and next line
|
||||
// @ts-strict-ignore
|
||||
import { Jsonify } from "type-fest"; |
||||
|
||||
import { ServerConfig } from "../../../platform/abstractions/config/server-config"; |
||||
import { LogService } from "../../../platform/abstractions/log.service"; |
||||
import { Decryptable } from "../../../platform/interfaces/decryptable.interface"; |
||||
import { SymmetricCryptoKey } from "../../../platform/models/domain/symmetric-crypto-key"; |
||||
import { ConsoleLogService } from "../../../platform/services/console-log.service"; |
||||
import { ContainerService } from "../../../platform/services/container.service"; |
||||
import { getClassInitializer } from "../../../platform/services/cryptography/get-class-initializer"; |
||||
import { |
||||
DECRYPT_COMMAND, |
||||
SET_CONFIG_COMMAND, |
||||
ParsedDecryptCommandData, |
||||
} from "../types/worker-command.type"; |
||||
|
||||
import { EncryptServiceImplementation } from "./encrypt.service.implementation"; |
||||
import { WebCryptoFunctionService } from "./web-crypto-function.service"; |
||||
|
||||
const workerApi: Worker = self as any; |
||||
|
||||
let inited = false; |
||||
let encryptService: EncryptServiceImplementation; |
||||
let logService: LogService; |
||||
|
||||
/** |
||||
* Bootstrap the worker environment with services required for decryption |
||||
*/ |
||||
export function init() { |
||||
const cryptoFunctionService = new WebCryptoFunctionService(self); |
||||
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: { |
||||
command: string; |
||||
} = JSON.parse(event.data); |
||||
|
||||
switch (request.command) { |
||||
case DECRYPT_COMMAND: |
||||
return await handleDecrypt(request as unknown as ParsedDecryptCommandData); |
||||
case SET_CONFIG_COMMAND: { |
||||
const newConfig = (request as unknown as { newConfig: Jsonify<ServerConfig> }).newConfig; |
||||
return await handleSetConfig(newConfig); |
||||
} |
||||
default: |
||||
logService.error(`[EncryptWorker] unknown worker command`, request.command, request); |
||||
} |
||||
}); |
||||
|
||||
async function handleDecrypt(request: ParsedDecryptCommandData) { |
||||
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), |
||||
}); |
||||
} |
||||
|
||||
async function handleSetConfig(newConfig: Jsonify<ServerConfig>) { |
||||
encryptService.onServerConfigChange(ServerConfig.fromJSON(newConfig)); |
||||
} |
||||
@ -1,34 +0,0 @@
@@ -1,34 +0,0 @@
|
||||
// FIXME: Update this file to be type safe and remove this and next line
|
||||
// @ts-strict-ignore
|
||||
import { BulkEncryptService } from "@bitwarden/common/key-management/crypto/abstractions/bulk-encrypt.service"; |
||||
import { Decryptable } from "@bitwarden/common/platform/interfaces/decryptable.interface"; |
||||
import { InitializerMetadata } from "@bitwarden/common/platform/interfaces/initializer-metadata.interface"; |
||||
import { SymmetricCryptoKey } from "@bitwarden/common/platform/models/domain/symmetric-crypto-key"; |
||||
|
||||
import { ServerConfig } from "../../../platform/abstractions/config/server-config"; |
||||
import { EncryptService } from "../abstractions/encrypt.service"; |
||||
|
||||
/** |
||||
* @deprecated Will be deleted in an immediate subsequent PR |
||||
*/ |
||||
export class FallbackBulkEncryptService implements BulkEncryptService { |
||||
private featureFlagEncryptService: BulkEncryptService; |
||||
private currentServerConfig: ServerConfig | undefined = undefined; |
||||
|
||||
constructor(protected encryptService: EncryptService) {} |
||||
|
||||
/** |
||||
* Decrypts items using a web worker if the environment supports it. |
||||
* Will fall back to the main thread if the window object is not available. |
||||
*/ |
||||
async decryptItems<T extends InitializerMetadata>( |
||||
items: Decryptable<T>[], |
||||
key: SymmetricCryptoKey, |
||||
): Promise<T[]> { |
||||
return await this.encryptService.decryptItems(items, key); |
||||
} |
||||
|
||||
async setFeatureFlagEncryptService(featureFlagEncryptService: BulkEncryptService) {} |
||||
|
||||
onServerConfigChange(newConfig: ServerConfig): void {} |
||||
} |
||||
@ -1,27 +0,0 @@
@@ -1,27 +0,0 @@
|
||||
import { Decryptable } from "@bitwarden/common/platform/interfaces/decryptable.interface"; |
||||
import { InitializerMetadata } from "@bitwarden/common/platform/interfaces/initializer-metadata.interface"; |
||||
import { SymmetricCryptoKey } from "@bitwarden/common/platform/models/domain/symmetric-crypto-key"; |
||||
|
||||
import { ServerConfig } from "../../../platform/abstractions/config/server-config"; |
||||
|
||||
import { EncryptServiceImplementation } from "./encrypt.service.implementation"; |
||||
|
||||
/** |
||||
* @deprecated Will be deleted in an immediate subsequent PR |
||||
*/ |
||||
export class MultithreadEncryptServiceImplementation extends EncryptServiceImplementation { |
||||
protected useSDKForDecryption: boolean = true; |
||||
|
||||
/** |
||||
* 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[]> { |
||||
return await super.decryptItems(items, key); |
||||
} |
||||
|
||||
override onServerConfigChange(newConfig: ServerConfig): void {} |
||||
} |
||||
@ -1,67 +0,0 @@
@@ -1,67 +0,0 @@
|
||||
import { mock } from "jest-mock-extended"; |
||||
|
||||
import { makeStaticByteArray } from "../../../../spec"; |
||||
import { ServerConfig } from "../../../platform/abstractions/config/server-config"; |
||||
import { Decryptable } from "../../../platform/interfaces/decryptable.interface"; |
||||
import { SymmetricCryptoKey } from "../../../platform/models/domain/symmetric-crypto-key"; |
||||
|
||||
import { |
||||
DECRYPT_COMMAND, |
||||
DecryptCommandData, |
||||
SET_CONFIG_COMMAND, |
||||
buildDecryptMessage, |
||||
buildSetConfigMessage, |
||||
} from "./worker-command.type"; |
||||
|
||||
describe("Worker command types", () => { |
||||
describe("buildDecryptMessage", () => { |
||||
it("builds a message with the correct command", () => { |
||||
const commandData = createDecryptCommandData(); |
||||
|
||||
const result = buildDecryptMessage(commandData); |
||||
|
||||
const parsedResult = JSON.parse(result); |
||||
expect(parsedResult.command).toBe(DECRYPT_COMMAND); |
||||
}); |
||||
|
||||
it("includes the provided data in the message", () => { |
||||
const mockItems = [{ encrypted: "test-encrypted" } as unknown as Decryptable<any>]; |
||||
const commandData = createDecryptCommandData(mockItems); |
||||
|
||||
const result = buildDecryptMessage(commandData); |
||||
|
||||
const parsedResult = JSON.parse(result); |
||||
expect(parsedResult.command).toBe(DECRYPT_COMMAND); |
||||
expect(parsedResult.id).toBe("test-id"); |
||||
expect(parsedResult.items).toEqual(mockItems); |
||||
expect(SymmetricCryptoKey.fromJSON(parsedResult.key)).toEqual(commandData.key); |
||||
}); |
||||
}); |
||||
|
||||
describe("buildSetConfigMessage", () => { |
||||
it("builds a message with the correct command", () => { |
||||
const result = buildSetConfigMessage({ newConfig: mock<ServerConfig>() }); |
||||
|
||||
const parsedResult = JSON.parse(result); |
||||
expect(parsedResult.command).toBe(SET_CONFIG_COMMAND); |
||||
}); |
||||
|
||||
it("includes the provided data in the message", () => { |
||||
const serverConfig = { version: "test-version" } as unknown as ServerConfig; |
||||
|
||||
const result = buildSetConfigMessage({ newConfig: serverConfig }); |
||||
|
||||
const parsedResult = JSON.parse(result); |
||||
expect(parsedResult.command).toBe(SET_CONFIG_COMMAND); |
||||
expect(ServerConfig.fromJSON(parsedResult.newConfig).version).toEqual(serverConfig.version); |
||||
}); |
||||
}); |
||||
}); |
||||
|
||||
function createDecryptCommandData(items?: Decryptable<any>[]): DecryptCommandData { |
||||
return { |
||||
id: "test-id", |
||||
items: items ?? [], |
||||
key: new SymmetricCryptoKey(makeStaticByteArray(64)), |
||||
}; |
||||
} |
||||
@ -1,36 +0,0 @@
@@ -1,36 +0,0 @@
|
||||
import { Jsonify } from "type-fest"; |
||||
|
||||
import { ServerConfig } from "../../../platform/abstractions/config/server-config"; |
||||
import { Decryptable } from "../../../platform/interfaces/decryptable.interface"; |
||||
import { SymmetricCryptoKey } from "../../../platform/models/domain/symmetric-crypto-key"; |
||||
|
||||
export const DECRYPT_COMMAND = "decrypt"; |
||||
export const SET_CONFIG_COMMAND = "updateConfig"; |
||||
|
||||
export type DecryptCommandData = { |
||||
id: string; |
||||
items: Decryptable<any>[]; |
||||
key: SymmetricCryptoKey; |
||||
}; |
||||
|
||||
export type ParsedDecryptCommandData = { |
||||
id: string; |
||||
items: Jsonify<Decryptable<any>>[]; |
||||
key: Jsonify<SymmetricCryptoKey>; |
||||
}; |
||||
|
||||
type SetConfigCommandData = { newConfig: ServerConfig }; |
||||
|
||||
export function buildDecryptMessage(data: DecryptCommandData): string { |
||||
return JSON.stringify({ |
||||
command: DECRYPT_COMMAND, |
||||
...data, |
||||
}); |
||||
} |
||||
|
||||
export function buildSetConfigMessage(data: SetConfigCommandData): string { |
||||
return JSON.stringify({ |
||||
command: SET_CONFIG_COMMAND, |
||||
...data, |
||||
}); |
||||
} |
||||
Loading…
Reference in new issue