mirror of
https://github.com/bitwarden/browser
synced 2025-12-10 05:13:29 +00:00
[PM-11477] Remove deprecated cryptoservice functions (#10854)
* Remove deprecated cryptoservice functions * Use getUserkeyWithLegacySupport to get userkey * Fix tests * Fix tests * Fix tests * Remove unused cryptoservice instances * Fix build * Remove unused apiService in constructor * Fix encryption * Ensure passed in key is used if present * Fix sends and folders * Fix tests * Remove logged key * Fix import for account restricted keys
This commit is contained in:
@@ -15,7 +15,6 @@ import {
|
||||
UserPublicKey,
|
||||
} from "../../types/key";
|
||||
import { KeySuffixOptions, HashPurpose } from "../enums";
|
||||
import { EncArrayBuffer } from "../models/domain/enc-array-buffer";
|
||||
import { EncString } from "../models/domain/enc-string";
|
||||
import { SymmetricCryptoKey } from "../models/domain/symmetric-crypto-key";
|
||||
|
||||
@@ -373,37 +372,6 @@ export abstract class CryptoService {
|
||||
* @param userId The desired user
|
||||
*/
|
||||
abstract clearDeprecatedKeys(keySuffix: KeySuffixOptions, userId?: string): Promise<void>;
|
||||
/**
|
||||
* @deprecated July 25 2022: Get the key you need from CryptoService (getKeyForUserEncryption or getOrgKey)
|
||||
* and then call encryptService.encrypt
|
||||
*/
|
||||
abstract encrypt(plainValue: string | Uint8Array, key?: SymmetricCryptoKey): Promise<EncString>;
|
||||
/**
|
||||
* @deprecated July 25 2022: Get the key you need from CryptoService (getKeyForUserEncryption or getOrgKey)
|
||||
* and then call encryptService.encryptToBytes
|
||||
*/
|
||||
abstract encryptToBytes(
|
||||
plainValue: Uint8Array,
|
||||
key?: SymmetricCryptoKey,
|
||||
): Promise<EncArrayBuffer>;
|
||||
/**
|
||||
* @deprecated July 25 2022: Get the key you need from CryptoService (getKeyForUserEncryption or getOrgKey)
|
||||
* and then call encryptService.decryptToBytes
|
||||
*/
|
||||
abstract decryptToBytes(encString: EncString, key?: SymmetricCryptoKey): Promise<Uint8Array>;
|
||||
/**
|
||||
* @deprecated July 25 2022: Get the key you need from CryptoService (getKeyForUserEncryption or getOrgKey)
|
||||
* and then call encryptService.decryptToUtf8
|
||||
*/
|
||||
abstract decryptToUtf8(encString: EncString, key?: SymmetricCryptoKey): Promise<string>;
|
||||
/**
|
||||
* @deprecated July 25 2022: Get the key you need from CryptoService (getKeyForUserEncryption or getOrgKey)
|
||||
* and then call encryptService.decryptToBytes
|
||||
*/
|
||||
abstract decryptFromBytes(
|
||||
encBuffer: EncArrayBuffer,
|
||||
key: SymmetricCryptoKey,
|
||||
): Promise<Uint8Array>;
|
||||
|
||||
/**
|
||||
* Retrieves all the keys needed for decrypting Ciphers
|
||||
|
||||
@@ -48,7 +48,6 @@ import { StateService } from "../abstractions/state.service";
|
||||
import { KeySuffixOptions, HashPurpose, EncryptionType } from "../enums";
|
||||
import { convertValues } from "../misc/convert-values";
|
||||
import { EFFLongWordList } from "../misc/wordlist";
|
||||
import { EncArrayBuffer } from "../models/domain/enc-array-buffer";
|
||||
import { EncString, EncryptedString } from "../models/domain/enc-string";
|
||||
import { SymmetricCryptoKey } from "../models/domain/symmetric-crypto-key";
|
||||
import { ActiveUserState, StateProvider } from "../state";
|
||||
@@ -859,58 +858,6 @@ export class CryptoService implements CryptoServiceAbstraction {
|
||||
}
|
||||
}
|
||||
|
||||
// --DEPRECATED METHODS--
|
||||
|
||||
/**
|
||||
* @deprecated July 25 2022: Get the key you need from CryptoService (getKeyForUserEncryption or getOrgKey)
|
||||
* and then call encryptService.encrypt
|
||||
*/
|
||||
async encrypt(plainValue: string | Uint8Array, key?: SymmetricCryptoKey): Promise<EncString> {
|
||||
key ||= await this.getUserKeyWithLegacySupport();
|
||||
return await this.encryptService.encrypt(plainValue, key);
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated July 25 2022: Get the key you need from CryptoService (getKeyForUserEncryption or getOrgKey)
|
||||
* and then call encryptService.encryptToBytes
|
||||
*/
|
||||
async encryptToBytes(plainValue: Uint8Array, key?: SymmetricCryptoKey): Promise<EncArrayBuffer> {
|
||||
key ||= await this.getUserKeyWithLegacySupport();
|
||||
return this.encryptService.encryptToBytes(plainValue, key);
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated July 25 2022: Get the key you need from CryptoService (getKeyForUserEncryption or getOrgKey)
|
||||
* and then call encryptService.decryptToBytes
|
||||
*/
|
||||
async decryptToBytes(encString: EncString, key?: SymmetricCryptoKey): Promise<Uint8Array> {
|
||||
key ||= await this.getUserKeyWithLegacySupport();
|
||||
return this.encryptService.decryptToBytes(encString, key);
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated July 25 2022: Get the key you need from CryptoService (getKeyForUserEncryption or getOrgKey)
|
||||
* and then call encryptService.decryptToUtf8
|
||||
*/
|
||||
async decryptToUtf8(encString: EncString, key?: SymmetricCryptoKey): Promise<string> {
|
||||
key ||= await this.getUserKeyWithLegacySupport();
|
||||
return await this.encryptService.decryptToUtf8(encString, key);
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated July 25 2022: Get the key you need from CryptoService (getKeyForUserEncryption or getOrgKey)
|
||||
* and then call encryptService.decryptToBytes
|
||||
*/
|
||||
async decryptFromBytes(encBuffer: EncArrayBuffer, key: SymmetricCryptoKey): Promise<Uint8Array> {
|
||||
if (encBuffer == null) {
|
||||
throw new Error("No buffer provided for decryption.");
|
||||
}
|
||||
|
||||
key ||= await this.getUserKeyWithLegacySupport();
|
||||
|
||||
return this.encryptService.decryptToBytes(encBuffer, key);
|
||||
}
|
||||
|
||||
userKey$(userId: UserId): Observable<UserKey> {
|
||||
return this.stateProvider.getUser(userId, USER_KEY).state$;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
import { mock } from "jest-mock-extended";
|
||||
|
||||
import { SymmetricCryptoKey } from "@bitwarden/common/platform/models/domain/symmetric-crypto-key";
|
||||
import { UserKey } from "@bitwarden/common/types/key";
|
||||
|
||||
import { makeStaticByteArray, mockEnc } from "../../../../../spec";
|
||||
import { CryptoService } from "../../../../platform/abstractions/crypto.service";
|
||||
import { EncryptService } from "../../../../platform/abstractions/encrypt.service";
|
||||
@@ -89,6 +92,7 @@ describe("Send", () => {
|
||||
it("Decrypt", async () => {
|
||||
const text = mock<SendText>();
|
||||
text.decrypt.mockResolvedValue("textView" as any);
|
||||
const userKey = new SymmetricCryptoKey(new Uint8Array(32)) as UserKey;
|
||||
|
||||
const send = new Send();
|
||||
send.id = "id";
|
||||
@@ -106,13 +110,13 @@ describe("Send", () => {
|
||||
send.disabled = false;
|
||||
send.hideEmail = true;
|
||||
|
||||
const encryptService = mock<EncryptService>();
|
||||
const cryptoService = mock<CryptoService>();
|
||||
cryptoService.decryptToBytes
|
||||
.calledWith(send.key, null)
|
||||
encryptService.decryptToBytes
|
||||
.calledWith(send.key, userKey)
|
||||
.mockResolvedValue(makeStaticByteArray(32));
|
||||
cryptoService.makeSendKey.mockResolvedValue("cryptoKey" as any);
|
||||
|
||||
const encryptService = mock<EncryptService>();
|
||||
cryptoService.getUserKey.mockResolvedValue(userKey);
|
||||
|
||||
(window as any).bitwardenContainerService = new ContainerService(cryptoService, encryptService);
|
||||
|
||||
|
||||
@@ -73,9 +73,11 @@ export class Send extends Domain {
|
||||
const model = new SendView(this);
|
||||
|
||||
const cryptoService = Utils.getContainerService().getCryptoService();
|
||||
const encryptService = Utils.getContainerService().getEncryptService();
|
||||
|
||||
try {
|
||||
model.key = await cryptoService.decryptToBytes(this.key, null);
|
||||
const sendKeyEncryptionKey = await cryptoService.getUserKey();
|
||||
model.key = await encryptService.decryptToBytes(this.key, sendKeyEncryptionKey);
|
||||
model.cryptoKey = await cryptoService.makeSendKey(model.key);
|
||||
} catch (e) {
|
||||
// TODO: error?
|
||||
|
||||
@@ -15,7 +15,7 @@ export abstract class FolderService implements UserKeyRotationDataProvider<Folde
|
||||
folderViews$: Observable<FolderView[]>;
|
||||
|
||||
clearCache: () => Promise<void>;
|
||||
encrypt: (model: FolderView, key?: SymmetricCryptoKey) => Promise<Folder>;
|
||||
encrypt: (model: FolderView, key: SymmetricCryptoKey) => Promise<Folder>;
|
||||
get: (id: string) => Promise<Folder>;
|
||||
getDecrypted$: (id: string) => Observable<FolderView | undefined>;
|
||||
getAllFromState: () => Promise<Folder[]>;
|
||||
|
||||
@@ -145,6 +145,7 @@ describe("Cipher Service", () => {
|
||||
cipherFileUploadService,
|
||||
configService,
|
||||
stateProvider,
|
||||
accountService,
|
||||
);
|
||||
|
||||
cipherObj = new Cipher(cipherData);
|
||||
@@ -273,7 +274,7 @@ describe("Cipher Service", () => {
|
||||
cryptoService.makeCipherKey.mockReturnValue(
|
||||
Promise.resolve(new SymmetricCryptoKey(makeStaticByteArray(64)) as CipherKey),
|
||||
);
|
||||
cryptoService.encrypt.mockImplementation(encryptText);
|
||||
encryptService.encrypt.mockImplementation(encryptText);
|
||||
|
||||
jest.spyOn(cipherService as any, "getAutofillOnPageLoadDefault").mockResolvedValue(true);
|
||||
});
|
||||
@@ -285,6 +286,10 @@ describe("Cipher Service", () => {
|
||||
{ uri: "uri", match: UriMatchStrategy.RegularExpression } as LoginUriView,
|
||||
];
|
||||
|
||||
cryptoService.getOrgKey.mockReturnValue(
|
||||
Promise.resolve<any>(new SymmetricCryptoKey(new Uint8Array(32)) as OrgKey),
|
||||
);
|
||||
|
||||
const domain = await cipherService.encrypt(cipherView, userId);
|
||||
|
||||
expect(domain.login.uris).toEqual([
|
||||
@@ -301,6 +306,9 @@ describe("Cipher Service", () => {
|
||||
it("is null when feature flag is false", async () => {
|
||||
configService.getFeatureFlag.mockResolvedValue(false);
|
||||
|
||||
cryptoService.getOrgKey.mockReturnValue(
|
||||
Promise.resolve<any>(new SymmetricCryptoKey(new Uint8Array(32)) as OrgKey),
|
||||
);
|
||||
const cipher = await cipherService.encrypt(cipherView, userId);
|
||||
|
||||
expect(cipher.key).toBeNull();
|
||||
@@ -322,6 +330,9 @@ describe("Cipher Service", () => {
|
||||
|
||||
it("is not called when feature flag is false", async () => {
|
||||
configService.getFeatureFlag.mockResolvedValue(false);
|
||||
cryptoService.getOrgKey.mockReturnValue(
|
||||
Promise.resolve<any>(new SymmetricCryptoKey(new Uint8Array(32)) as OrgKey),
|
||||
);
|
||||
|
||||
await cipherService.encrypt(cipherView, userId);
|
||||
|
||||
@@ -330,6 +341,9 @@ describe("Cipher Service", () => {
|
||||
|
||||
it("is called when feature flag is true", async () => {
|
||||
configService.getFeatureFlag.mockResolvedValue(true);
|
||||
cryptoService.getOrgKey.mockReturnValue(
|
||||
Promise.resolve<any>(new SymmetricCryptoKey(new Uint8Array(32)) as OrgKey),
|
||||
);
|
||||
|
||||
await cipherService.encrypt(cipherView, userId);
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { firstValueFrom, map, Observable, skipWhile, switchMap } from "rxjs";
|
||||
import { SemVer } from "semver";
|
||||
|
||||
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
|
||||
import { FeatureFlag } from "@bitwarden/common/enums/feature-flag.enum";
|
||||
import { BulkEncryptService } from "@bitwarden/common/platform/abstractions/bulk-encrypt.service";
|
||||
|
||||
@@ -108,6 +109,7 @@ export class CipherService implements CipherServiceAbstraction {
|
||||
private cipherFileUploadService: CipherFileUploadService,
|
||||
private configService: ConfigService,
|
||||
private stateProvider: StateProvider,
|
||||
private accountService: AccountService,
|
||||
) {
|
||||
this.localDataState = this.stateProvider.getActive(LOCAL_DATA_KEY);
|
||||
this.encryptedCiphersState = this.stateProvider.getActive(ENCRYPTED_CIPHERS);
|
||||
@@ -165,7 +167,7 @@ export class CipherService implements CipherServiceAbstraction {
|
||||
async encrypt(
|
||||
model: CipherView,
|
||||
userId: UserId,
|
||||
keyForEncryption?: SymmetricCryptoKey,
|
||||
keyForCipherEncryption?: SymmetricCryptoKey,
|
||||
keyForCipherKeyDecryption?: SymmetricCryptoKey,
|
||||
originalCipher: Cipher = null,
|
||||
): Promise<Cipher> {
|
||||
@@ -195,26 +197,21 @@ export class CipherService implements CipherServiceAbstraction {
|
||||
const userOrOrgKey = await this.getKeyForCipherKeyDecryption(cipher, userId);
|
||||
// The keyForEncryption is only used for encrypting the cipher key, not the cipher itself, since cipher key encryption is enabled.
|
||||
// If the caller has provided a key for cipher key encryption, use it. Otherwise, use the user or org key.
|
||||
keyForEncryption ||= userOrOrgKey;
|
||||
keyForCipherEncryption ||= userOrOrgKey;
|
||||
// If the caller has provided a key for cipher key decryption, use it. Otherwise, use the user or org key.
|
||||
keyForCipherKeyDecryption ||= userOrOrgKey;
|
||||
return this.encryptCipherWithCipherKey(
|
||||
model,
|
||||
cipher,
|
||||
keyForEncryption,
|
||||
keyForCipherEncryption,
|
||||
keyForCipherKeyDecryption,
|
||||
);
|
||||
} else {
|
||||
if (keyForEncryption == null && cipher.organizationId != null) {
|
||||
keyForEncryption = await this.cryptoService.getOrgKey(cipher.organizationId);
|
||||
if (keyForEncryption == null) {
|
||||
throw new Error("Cannot encrypt cipher for organization. No key.");
|
||||
}
|
||||
}
|
||||
keyForCipherEncryption ||= await this.getKeyForCipherKeyDecryption(cipher, userId);
|
||||
// We want to ensure that the cipher key is null if cipher key encryption is disabled
|
||||
// so that decryption uses the proper key.
|
||||
cipher.key = null;
|
||||
return this.encryptCipher(model, cipher, keyForEncryption);
|
||||
return this.encryptCipher(model, cipher, keyForCipherEncryption);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -243,7 +240,7 @@ export class CipherService implements CipherServiceAbstraction {
|
||||
key,
|
||||
).then(async () => {
|
||||
if (model.key != null) {
|
||||
attachment.key = await this.cryptoService.encrypt(model.key.key, key);
|
||||
attachment.key = await this.encryptService.encrypt(model.key.key, key);
|
||||
}
|
||||
encAttachments.push(attachment);
|
||||
});
|
||||
@@ -1348,7 +1345,9 @@ export class CipherService implements CipherServiceAbstraction {
|
||||
}
|
||||
|
||||
const encBuf = await EncArrayBuffer.fromResponse(attachmentResponse);
|
||||
const decBuf = await this.cryptoService.decryptFromBytes(encBuf, null);
|
||||
const activeUserId = await firstValueFrom(this.accountService.activeAccount$);
|
||||
const userKey = await this.cryptoService.getUserKeyWithLegacySupport(activeUserId.id);
|
||||
const decBuf = await this.encryptService.decryptToBytes(encBuf, userKey);
|
||||
|
||||
let encKey: UserKey | OrgKey;
|
||||
encKey = await this.cryptoService.getOrgKey(organizationId);
|
||||
@@ -1412,7 +1411,7 @@ export class CipherService implements CipherServiceAbstraction {
|
||||
.then(() => {
|
||||
const modelProp = (model as any)[map[theProp] || theProp];
|
||||
if (modelProp && modelProp !== "") {
|
||||
return self.cryptoService.encrypt(modelProp, key);
|
||||
return self.encryptService.encrypt(modelProp, key);
|
||||
}
|
||||
return null;
|
||||
})
|
||||
@@ -1458,7 +1457,7 @@ export class CipherService implements CipherServiceAbstraction {
|
||||
key,
|
||||
);
|
||||
const uriHash = await this.encryptService.hash(model.login.uris[i].uri, "sha256");
|
||||
loginUri.uriChecksum = await this.cryptoService.encrypt(uriHash, key);
|
||||
loginUri.uriChecksum = await this.encryptService.encrypt(uriHash, key);
|
||||
cipher.login.uris.push(loginUri);
|
||||
}
|
||||
}
|
||||
@@ -1485,8 +1484,8 @@ export class CipherService implements CipherServiceAbstraction {
|
||||
},
|
||||
key,
|
||||
);
|
||||
domainKey.counter = await this.cryptoService.encrypt(String(viewKey.counter), key);
|
||||
domainKey.discoverable = await this.cryptoService.encrypt(
|
||||
domainKey.counter = await this.encryptService.encrypt(String(viewKey.counter), key);
|
||||
domainKey.discoverable = await this.encryptService.encrypt(
|
||||
String(viewKey.discoverable),
|
||||
key,
|
||||
);
|
||||
@@ -1605,11 +1604,23 @@ export class CipherService implements CipherServiceAbstraction {
|
||||
this.sortedCiphersCache.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* Encrypts a cipher object.
|
||||
* @param model The cipher view model.
|
||||
* @param cipher The cipher object.
|
||||
* @param key The encryption key to encrypt with. This can be the org key, user key or cipher key, but must never be null
|
||||
*/
|
||||
private async encryptCipher(
|
||||
model: CipherView,
|
||||
cipher: Cipher,
|
||||
key: SymmetricCryptoKey,
|
||||
): Promise<Cipher> {
|
||||
if (key == null) {
|
||||
throw new Error(
|
||||
"Key to encrypt cipher must not be null. Use the org key, user key or cipher key.",
|
||||
);
|
||||
}
|
||||
|
||||
await Promise.all([
|
||||
this.encryptObjProperty(
|
||||
model,
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
import { firstValueFrom, map, Observable } from "rxjs";
|
||||
import { Jsonify } from "type-fest";
|
||||
|
||||
import { EncryptService } from "@bitwarden/common/platform/abstractions/encrypt.service";
|
||||
|
||||
import { CryptoService } from "../../platform/abstractions/crypto.service";
|
||||
import { I18nService } from "../../platform/abstractions/i18n.service";
|
||||
import { Utils } from "../../platform/misc/utils";
|
||||
@@ -61,6 +63,7 @@ export class CollectionService implements CollectionServiceAbstraction {
|
||||
|
||||
constructor(
|
||||
private cryptoService: CryptoService,
|
||||
private encryptService: EncryptService,
|
||||
private i18nService: I18nService,
|
||||
protected stateProvider: StateProvider,
|
||||
) {
|
||||
@@ -101,7 +104,7 @@ export class CollectionService implements CollectionServiceAbstraction {
|
||||
collection.organizationId = model.organizationId;
|
||||
collection.readOnly = model.readOnly;
|
||||
collection.externalId = model.externalId;
|
||||
collection.name = await this.cryptoService.encrypt(model.name, key);
|
||||
collection.name = await this.encryptService.encrypt(model.name, key);
|
||||
return collection;
|
||||
}
|
||||
|
||||
|
||||
@@ -49,7 +49,13 @@ describe("Folder Service", () => {
|
||||
);
|
||||
encryptService.decryptToUtf8.mockResolvedValue("DEC");
|
||||
|
||||
folderService = new FolderService(cryptoService, i18nService, cipherService, stateProvider);
|
||||
folderService = new FolderService(
|
||||
cryptoService,
|
||||
encryptService,
|
||||
i18nService,
|
||||
cipherService,
|
||||
stateProvider,
|
||||
);
|
||||
|
||||
folderState = stateProvider.activeUser.getFake(FOLDER_ENCRYPTED_FOLDERS);
|
||||
|
||||
@@ -62,9 +68,9 @@ describe("Folder Service", () => {
|
||||
model.id = "2";
|
||||
model.name = "Test Folder";
|
||||
|
||||
cryptoService.encrypt.mockResolvedValue(new EncString("ENC"));
|
||||
encryptService.encrypt.mockResolvedValue(new EncString("ENC"));
|
||||
|
||||
const result = await folderService.encrypt(model);
|
||||
const result = await folderService.encrypt(model, null);
|
||||
|
||||
expect(result).toEqual({
|
||||
id: "2",
|
||||
@@ -185,7 +191,7 @@ describe("Folder Service", () => {
|
||||
|
||||
beforeEach(() => {
|
||||
encryptedKey = new EncString("Re-encrypted Folder");
|
||||
cryptoService.encrypt.mockResolvedValue(encryptedKey);
|
||||
encryptService.encrypt.mockResolvedValue(encryptedKey);
|
||||
});
|
||||
|
||||
it("returns re-encrypted user folders", async () => {
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
import { Observable, firstValueFrom, map, shareReplay } from "rxjs";
|
||||
|
||||
import { EncryptService } from "@bitwarden/common/platform/abstractions/encrypt.service";
|
||||
|
||||
import { CryptoService } from "../../../platform/abstractions/crypto.service";
|
||||
import { I18nService } from "../../../platform/abstractions/i18n.service";
|
||||
import { Utils } from "../../../platform/misc/utils";
|
||||
@@ -25,6 +27,7 @@ export class FolderService implements InternalFolderServiceAbstraction {
|
||||
|
||||
constructor(
|
||||
private cryptoService: CryptoService,
|
||||
private encryptService: EncryptService,
|
||||
private i18nService: I18nService,
|
||||
private cipherService: CipherService,
|
||||
private stateProvider: StateProvider,
|
||||
@@ -48,10 +51,10 @@ export class FolderService implements InternalFolderServiceAbstraction {
|
||||
}
|
||||
|
||||
// TODO: This should be moved to EncryptService or something
|
||||
async encrypt(model: FolderView, key?: SymmetricCryptoKey): Promise<Folder> {
|
||||
async encrypt(model: FolderView, key: SymmetricCryptoKey): Promise<Folder> {
|
||||
const folder = new Folder();
|
||||
folder.id = model.id;
|
||||
folder.name = await this.cryptoService.encrypt(model.name, key);
|
||||
folder.name = await this.encryptService.encrypt(model.name, key);
|
||||
return folder;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user