1
0
mirror of https://github.com/bitwarden/browser synced 2025-12-16 08:13:42 +00:00

[Pm-13097] Rename cryptoservice to keyservice and move it to km ownership (#11358)

* Rename cryptoservice to keyservice

* Rename cryptoservice to keyservice

* Move key service to key management ownership

* Remove accidentally added file

* Fix cli build

* Fix browser build

* Run prettier

* Fix builds

* Fix cli build

* Fix tests

* Fix incorrect renames

* Rename webauthn-login-crypto-service

* Fix build errors due to merge conflicts

* Fix linting
This commit is contained in:
Bernd Schoolmann
2024-10-24 19:41:30 +02:00
committed by GitHub
parent 554171b688
commit b486fcc689
229 changed files with 1385 additions and 1446 deletions

View File

@@ -1,7 +1,7 @@
import { mock, MockProxy } from "jest-mock-extended";
import { KeyService } from "../../../../../key-management/src/abstractions/key.service";
import { makeStaticByteArray, mockEnc, mockFromJson } from "../../../../spec";
import { CryptoService } from "../../../platform/abstractions/crypto.service";
import { EncryptService } from "../../../platform/abstractions/encrypt.service";
import { EncryptedString, EncString } from "../../../platform/models/domain/enc-string";
import { SymmetricCryptoKey } from "../../../platform/models/domain/symmetric-crypto-key";
@@ -57,17 +57,14 @@ describe("Attachment", () => {
});
describe("decrypt", () => {
let cryptoService: MockProxy<CryptoService>;
let keyService: MockProxy<KeyService>;
let encryptService: MockProxy<EncryptService>;
beforeEach(() => {
cryptoService = mock<CryptoService>();
keyService = mock<KeyService>();
encryptService = mock<EncryptService>();
(window as any).bitwardenContainerService = new ContainerService(
cryptoService,
encryptService,
);
(window as any).bitwardenContainerService = new ContainerService(keyService, encryptService);
});
it("expected output", async () => {
@@ -101,32 +98,32 @@ describe("Attachment", () => {
attachment.key = mock<EncString>();
});
it("uses the provided key without depending on CryptoService", async () => {
it("uses the provided key without depending on KeyService", async () => {
const providedKey = mock<SymmetricCryptoKey>();
await attachment.decrypt(null, providedKey);
expect(cryptoService.getUserKeyWithLegacySupport).not.toHaveBeenCalled();
expect(keyService.getUserKeyWithLegacySupport).not.toHaveBeenCalled();
expect(encryptService.decryptToBytes).toHaveBeenCalledWith(attachment.key, providedKey);
});
it("gets an organization key if required", async () => {
const orgKey = mock<OrgKey>();
cryptoService.getOrgKey.calledWith("orgId").mockResolvedValue(orgKey);
keyService.getOrgKey.calledWith("orgId").mockResolvedValue(orgKey);
await attachment.decrypt("orgId", null);
expect(cryptoService.getOrgKey).toHaveBeenCalledWith("orgId");
expect(keyService.getOrgKey).toHaveBeenCalledWith("orgId");
expect(encryptService.decryptToBytes).toHaveBeenCalledWith(attachment.key, orgKey);
});
it("gets the user's decryption key if required", async () => {
const userKey = mock<UserKey>();
cryptoService.getUserKeyWithLegacySupport.mockResolvedValue(userKey);
keyService.getUserKeyWithLegacySupport.mockResolvedValue(userKey);
await attachment.decrypt(null, null);
expect(cryptoService.getUserKeyWithLegacySupport).toHaveBeenCalled();
expect(keyService.getUserKeyWithLegacySupport).toHaveBeenCalled();
expect(encryptService.decryptToBytes).toHaveBeenCalledWith(attachment.key, userKey);
});
});

View File

@@ -68,10 +68,10 @@ export class Attachment extends Domain {
}
private async getKeyForDecryption(orgId: string) {
const cryptoService = Utils.getContainerService().getCryptoService();
const keyService = Utils.getContainerService().getKeyService();
return orgId != null
? await cryptoService.getOrgKey(orgId)
: await cryptoService.getUserKeyWithLegacySupport();
? await keyService.getOrgKey(orgId)
: await keyService.getUserKeyWithLegacySupport();
}
toAttachmentData(): AttachmentData {

View File

@@ -3,9 +3,9 @@ import { Jsonify } from "type-fest";
import { UserId } from "@bitwarden/common/types/guid";
import { KeyService } from "../../../../../key-management/src/abstractions/key.service";
import { makeStaticByteArray, mockEnc, mockFromJson } from "../../../../spec/utils";
import { UriMatchStrategy } from "../../../models/domain/domain-service";
import { CryptoService } from "../../../platform/abstractions/crypto.service";
import { EncryptService } from "../../../platform/abstractions/encrypt.service";
import { EncString } from "../../../platform/models/domain/enc-string";
import { ContainerService } from "../../../platform/services/container.service";
@@ -237,16 +237,13 @@ describe("Cipher DTO", () => {
login.decrypt.mockResolvedValue(loginView);
cipher.login = login;
const cryptoService = mock<CryptoService>();
const keyService = mock<KeyService>();
const encryptService = mock<EncryptService>();
const cipherService = mock<CipherService>();
encryptService.decryptToBytes.mockResolvedValue(makeStaticByteArray(64));
(window as any).bitwardenContainerService = new ContainerService(
cryptoService,
encryptService,
);
(window as any).bitwardenContainerService = new ContainerService(keyService, encryptService);
const cipherView = await cipher.decrypt(
await cipherService.getKeyForCipherKeyDecryption(cipher, mockUserId),
@@ -357,16 +354,13 @@ describe("Cipher DTO", () => {
cipher.secureNote.type = SecureNoteType.Generic;
cipher.key = mockEnc("EncKey");
const cryptoService = mock<CryptoService>();
const keyService = mock<KeyService>();
const encryptService = mock<EncryptService>();
const cipherService = mock<CipherService>();
encryptService.decryptToBytes.mockResolvedValue(makeStaticByteArray(64));
(window as any).bitwardenContainerService = new ContainerService(
cryptoService,
encryptService,
);
(window as any).bitwardenContainerService = new ContainerService(keyService, encryptService);
const cipherView = await cipher.decrypt(
await cipherService.getKeyForCipherKeyDecryption(cipher, mockUserId),
@@ -495,16 +489,13 @@ describe("Cipher DTO", () => {
card.decrypt.mockResolvedValue(cardView);
cipher.card = card;
const cryptoService = mock<CryptoService>();
const keyService = mock<KeyService>();
const encryptService = mock<EncryptService>();
const cipherService = mock<CipherService>();
encryptService.decryptToBytes.mockResolvedValue(makeStaticByteArray(64));
(window as any).bitwardenContainerService = new ContainerService(
cryptoService,
encryptService,
);
(window as any).bitwardenContainerService = new ContainerService(keyService, encryptService);
const cipherView = await cipher.decrypt(
await cipherService.getKeyForCipherKeyDecryption(cipher, mockUserId),
@@ -657,16 +648,13 @@ describe("Cipher DTO", () => {
identity.decrypt.mockResolvedValue(identityView);
cipher.identity = identity;
const cryptoService = mock<CryptoService>();
const keyService = mock<KeyService>();
const encryptService = mock<EncryptService>();
const cipherService = mock<CipherService>();
encryptService.decryptToBytes.mockResolvedValue(makeStaticByteArray(64));
(window as any).bitwardenContainerService = new ContainerService(
cryptoService,
encryptService,
);
(window as any).bitwardenContainerService = new ContainerService(keyService, encryptService);
const cipherView = await cipher.decrypt(
await cipherService.getKeyForCipherKeyDecryption(cipher, mockUserId),

View File

@@ -70,7 +70,7 @@ describe("LoginUri", () => {
encryptService = mock();
global.bitwardenContainerService = {
getEncryptService: () => encryptService,
getCryptoService: () => null,
getKeyService: () => null,
};
});

View File

@@ -47,8 +47,8 @@ export class LoginUri extends Domain {
return false;
}
const cryptoService = Utils.getContainerService().getEncryptService();
const localChecksum = await cryptoService.hash(clearTextUri, "sha256");
const keyService = Utils.getContainerService().getEncryptService();
const localChecksum = await keyService.hash(clearTextUri, "sha256");
const remoteChecksum = await this.uriChecksum.decrypt(orgId, encKey);
return remoteChecksum === localChecksum;

View File

@@ -3,6 +3,10 @@ import { BehaviorSubject, map, of } from "rxjs";
import { BulkEncryptService } from "@bitwarden/common/platform/abstractions/bulk-encrypt.service";
import {
CipherDecryptionKeys,
KeyService,
} from "../../../../key-management/src/abstractions/key.service";
import { FakeAccountService, mockAccountServiceWith } from "../../../spec/fake-account-service";
import { FakeStateProvider } from "../../../spec/fake-state-provider";
import { makeStaticByteArray } from "../../../spec/utils";
@@ -12,7 +16,6 @@ import { AutofillSettingsService } from "../../autofill/services/autofill-settin
import { DomainSettingsService } from "../../autofill/services/domain-settings.service";
import { UriMatchStrategy } from "../../models/domain/domain-service";
import { ConfigService } from "../../platform/abstractions/config/config.service";
import { CipherDecryptionKeys, CryptoService } from "../../platform/abstractions/crypto.service";
import { EncryptService } from "../../platform/abstractions/encrypt.service";
import { I18nService } from "../../platform/abstractions/i18n.service";
import { StateService } from "../../platform/abstractions/state.service";
@@ -107,7 +110,7 @@ const mockUserId = Utils.newGuid() as UserId;
let accountService: FakeAccountService;
describe("Cipher Service", () => {
const cryptoService = mock<CryptoService>();
const keyService = mock<KeyService>();
const stateService = mock<StateService>();
const autofillSettingsService = mock<AutofillSettingsService>();
const domainSettingsService = mock<DomainSettingsService>();
@@ -130,10 +133,10 @@ describe("Cipher Service", () => {
encryptService.encryptToBytes.mockReturnValue(Promise.resolve(ENCRYPTED_BYTES));
encryptService.encrypt.mockReturnValue(Promise.resolve(new EncString(ENCRYPTED_TEXT)));
(window as any).bitwardenContainerService = new ContainerService(cryptoService, encryptService);
(window as any).bitwardenContainerService = new ContainerService(keyService, encryptService);
cipherService = new CipherService(
cryptoService,
keyService,
domainSettingsService,
apiService,
i18nService,
@@ -159,10 +162,10 @@ describe("Cipher Service", () => {
it("should upload encrypted file contents with save attachments", async () => {
const fileName = "filename";
const fileData = new Uint8Array(10);
cryptoService.getOrgKey.mockReturnValue(
keyService.getOrgKey.mockReturnValue(
Promise.resolve<any>(new SymmetricCryptoKey(new Uint8Array(32)) as OrgKey),
);
cryptoService.makeDataEncKey.mockReturnValue(
keyService.makeDataEncKey.mockReturnValue(
Promise.resolve<any>(new SymmetricCryptoKey(new Uint8Array(32))),
);
@@ -271,7 +274,7 @@ describe("Cipher Service", () => {
encryptService.decryptToBytes.mockReturnValue(Promise.resolve(makeStaticByteArray(64)));
configService.checkServerMeetsVersionRequirement$.mockReturnValue(of(true));
cryptoService.makeCipherKey.mockReturnValue(
keyService.makeCipherKey.mockReturnValue(
Promise.resolve(new SymmetricCryptoKey(makeStaticByteArray(64)) as CipherKey),
);
encryptService.encrypt.mockImplementation(encryptText);
@@ -286,7 +289,7 @@ describe("Cipher Service", () => {
{ uri: "uri", match: UriMatchStrategy.RegularExpression } as LoginUriView,
];
cryptoService.getOrgKey.mockReturnValue(
keyService.getOrgKey.mockReturnValue(
Promise.resolve<any>(new SymmetricCryptoKey(new Uint8Array(32)) as OrgKey),
);
@@ -306,7 +309,7 @@ describe("Cipher Service", () => {
it("is null when feature flag is false", async () => {
configService.getFeatureFlag.mockResolvedValue(false);
cryptoService.getOrgKey.mockReturnValue(
keyService.getOrgKey.mockReturnValue(
Promise.resolve<any>(new SymmetricCryptoKey(new Uint8Array(32)) as OrgKey),
);
const cipher = await cipherService.encrypt(cipherView, userId);
@@ -330,7 +333,7 @@ describe("Cipher Service", () => {
it("is not called when feature flag is false", async () => {
configService.getFeatureFlag.mockResolvedValue(false);
cryptoService.getOrgKey.mockReturnValue(
keyService.getOrgKey.mockReturnValue(
Promise.resolve<any>(new SymmetricCryptoKey(new Uint8Array(32)) as OrgKey),
);
@@ -341,7 +344,7 @@ describe("Cipher Service", () => {
it("is called when feature flag is true", async () => {
configService.getFeatureFlag.mockResolvedValue(true);
cryptoService.getOrgKey.mockReturnValue(
keyService.getOrgKey.mockReturnValue(
Promise.resolve<any>(new SymmetricCryptoKey(new Uint8Array(32)) as OrgKey),
);
@@ -368,7 +371,7 @@ describe("Cipher Service", () => {
const keys = {
userKey: originalUserKey,
} as CipherDecryptionKeys;
cryptoService.cipherDecryptionKeys$.mockReturnValue(of(keys));
keyService.cipherDecryptionKeys$.mockReturnValue(of(keys));
const cipher1 = new CipherView(cipherObj);
cipher1.id = "Cipher 1";
@@ -387,7 +390,7 @@ describe("Cipher Service", () => {
encryptedKey = new EncString("Re-encrypted Cipher Key");
encryptService.encrypt.mockResolvedValue(encryptedKey);
cryptoService.makeCipherKey.mockResolvedValue(
keyService.makeCipherKey.mockResolvedValue(
new SymmetricCryptoKey(new Uint8Array(32)) as CipherKey,
);
});

View File

@@ -15,6 +15,7 @@ import { AccountService } from "@bitwarden/common/auth/abstractions/account.serv
import { FeatureFlag } from "@bitwarden/common/enums/feature-flag.enum";
import { BulkEncryptService } from "@bitwarden/common/platform/abstractions/bulk-encrypt.service";
import { KeyService } from "../../../../key-management/src/abstractions/key.service";
import { ApiService } from "../../abstractions/api.service";
import { SearchService } from "../../abstractions/search.service";
import { AutofillSettingsServiceAbstraction } from "../../autofill/services/autofill-settings.service";
@@ -24,7 +25,6 @@ import { ErrorResponse } from "../../models/response/error.response";
import { ListResponse } from "../../models/response/list.response";
import { View } from "../../models/view/view";
import { ConfigService } from "../../platform/abstractions/config/config.service";
import { CryptoService } from "../../platform/abstractions/crypto.service";
import { EncryptService } from "../../platform/abstractions/encrypt.service";
import { I18nService } from "../../platform/abstractions/i18n.service";
import { StateService } from "../../platform/abstractions/state.service";
@@ -112,7 +112,7 @@ export class CipherService implements CipherServiceAbstraction {
private addEditCipherInfoState: ActiveUserState<AddEditCipherInfo>;
constructor(
private cryptoService: CryptoService,
private keyService: KeyService,
private domainSettingsService: DomainSettingsService,
private apiService: ApiService,
private i18nService: I18nService,
@@ -400,7 +400,7 @@ export class CipherService implements CipherServiceAbstraction {
}
private async decryptCiphers(ciphers: Cipher[], userId: UserId) {
const keys = await firstValueFrom(this.cryptoService.cipherDecryptionKeys$(userId, true));
const keys = await firstValueFrom(this.keyService.cipherDecryptionKeys$(userId, true));
if (keys == null || (keys.userKey == null && Object.keys(keys.orgKeys).length === 0)) {
// return early if there are no keys to decrypt with
@@ -550,7 +550,7 @@ export class CipherService implements CipherServiceAbstraction {
}
const ciphers = response.data.map((cr) => new Cipher(new CipherData(cr)));
const key = await this.cryptoService.getOrgKey(organizationId);
const key = await this.keyService.getOrgKey(organizationId);
let decCiphers: CipherView[] = [];
if (await this.configService.getFeatureFlag(FeatureFlag.PM4154_BulkEncryptionService)) {
decCiphers = await this.bulkEncryptService.decryptItems(ciphers, key);
@@ -848,7 +848,7 @@ export class CipherService implements CipherServiceAbstraction {
const encFileName = await this.encryptService.encrypt(filename, cipherEncKey);
const dataEncKey = await this.cryptoService.makeDataEncKey(cipherEncKey);
const dataEncKey = await this.keyService.makeDataEncKey(cipherEncKey);
const encData = await this.encryptService.encryptToBytes(new Uint8Array(data), dataEncKey[0]);
const response = await this.cipherFileUploadService.upload(
@@ -1245,8 +1245,8 @@ export class CipherService implements CipherServiceAbstraction {
async getKeyForCipherKeyDecryption(cipher: Cipher, userId: UserId): Promise<UserKey | OrgKey> {
return (
(await this.cryptoService.getOrgKey(cipher.organizationId)) ||
((await this.cryptoService.getUserKeyWithLegacySupport(userId)) as UserKey)
(await this.keyService.getOrgKey(cipher.organizationId)) ||
((await this.keyService.getUserKeyWithLegacySupport(userId)) as UserKey)
);
}
@@ -1294,7 +1294,7 @@ export class CipherService implements CipherServiceAbstraction {
// In the case of a cipher that is being shared with an organization, we want to decrypt the
// cipher key with the user's key and then re-encrypt it with the organization's key.
private async encryptSharedCipher(model: CipherView, userId: UserId): Promise<Cipher> {
const keyForCipherKeyDecryption = await this.cryptoService.getUserKeyWithLegacySupport(userId);
const keyForCipherKeyDecryption = await this.keyService.getUserKeyWithLegacySupport(userId);
return await this.encrypt(model, userId, null, keyForCipherKeyDecryption);
}
@@ -1371,14 +1371,14 @@ export class CipherService implements CipherServiceAbstraction {
const encBuf = await EncArrayBuffer.fromResponse(attachmentResponse);
const activeUserId = await firstValueFrom(this.accountService.activeAccount$);
const userKey = await this.cryptoService.getUserKeyWithLegacySupport(activeUserId.id);
const userKey = await this.keyService.getUserKeyWithLegacySupport(activeUserId.id);
const decBuf = await this.encryptService.decryptToBytes(encBuf, userKey);
let encKey: UserKey | OrgKey;
encKey = await this.cryptoService.getOrgKey(organizationId);
encKey ||= (await this.cryptoService.getUserKeyWithLegacySupport()) as UserKey;
encKey = await this.keyService.getOrgKey(organizationId);
encKey ||= (await this.keyService.getUserKeyWithLegacySupport()) as UserKey;
const dataEncKey = await this.cryptoService.makeDataEncKey(encKey);
const dataEncKey = await this.keyService.makeDataEncKey(encKey);
const encFileName = await this.encryptService.encrypt(attachmentView.fileName, encKey);
const encData = await this.encryptService.encryptToBytes(new Uint8Array(decBuf), dataEncKey[0]);
@@ -1679,7 +1679,7 @@ export class CipherService implements CipherServiceAbstraction {
// First, we get the key for cipher key encryption, in its decrypted form
let decryptedCipherKey: SymmetricCryptoKey;
if (cipher.key == null) {
decryptedCipherKey = await this.cryptoService.makeCipherKey();
decryptedCipherKey = await this.keyService.makeCipherKey();
} else {
decryptedCipherKey = new SymmetricCryptoKey(
await this.encryptService.decryptToBytes(cipher.key, keyForCipherKeyDecryption),

View File

@@ -1,11 +1,11 @@
import { mock, MockProxy } from "jest-mock-extended";
import { firstValueFrom } from "rxjs";
import { KeyService } from "../../../../../key-management/src/abstractions/key.service";
import { makeStaticByteArray } from "../../../../spec";
import { FakeAccountService, mockAccountServiceWith } from "../../../../spec/fake-account-service";
import { FakeActiveUserState } from "../../../../spec/fake-state";
import { FakeStateProvider } from "../../../../spec/fake-state-provider";
import { CryptoService } from "../../../platform/abstractions/crypto.service";
import { EncryptService } from "../../../platform/abstractions/encrypt.service";
import { I18nService } from "../../../platform/abstractions/i18n.service";
import { Utils } from "../../../platform/misc/utils";
@@ -22,7 +22,7 @@ import { FOLDER_ENCRYPTED_FOLDERS } from "../key-state/folder.state";
describe("Folder Service", () => {
let folderService: FolderService;
let cryptoService: MockProxy<CryptoService>;
let keyService: MockProxy<KeyService>;
let encryptService: MockProxy<EncryptService>;
let i18nService: MockProxy<I18nService>;
let cipherService: MockProxy<CipherService>;
@@ -33,7 +33,7 @@ describe("Folder Service", () => {
let folderState: FakeActiveUserState<Record<string, FolderData>>;
beforeEach(() => {
cryptoService = mock<CryptoService>();
keyService = mock<KeyService>();
encryptService = mock<EncryptService>();
i18nService = mock<I18nService>();
cipherService = mock<CipherService>();
@@ -43,14 +43,14 @@ describe("Folder Service", () => {
i18nService.collator = new Intl.Collator("en");
cryptoService.hasUserKey.mockResolvedValue(true);
cryptoService.getUserKeyWithLegacySupport.mockResolvedValue(
keyService.hasUserKey.mockResolvedValue(true);
keyService.getUserKeyWithLegacySupport.mockResolvedValue(
new SymmetricCryptoKey(makeStaticByteArray(32)) as UserKey,
);
encryptService.decryptToUtf8.mockResolvedValue("DEC");
folderService = new FolderService(
cryptoService,
keyService,
encryptService,
i18nService,
cipherService,

View File

@@ -2,7 +2,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 { KeyService } from "../../../../../key-management/src/abstractions/key.service";
import { I18nService } from "../../../platform/abstractions/i18n.service";
import { Utils } from "../../../platform/misc/utils";
import { SymmetricCryptoKey } from "../../../platform/models/domain/symmetric-crypto-key";
@@ -26,7 +26,7 @@ export class FolderService implements InternalFolderServiceAbstraction {
private decryptedFoldersState: DerivedState<FolderView[]>;
constructor(
private cryptoService: CryptoService,
private keyService: KeyService,
private encryptService: EncryptService,
private i18nService: I18nService,
private cipherService: CipherService,
@@ -36,7 +36,7 @@ export class FolderService implements InternalFolderServiceAbstraction {
this.decryptedFoldersState = this.stateProvider.getDerived(
this.encryptedFoldersState.state$,
FOLDER_DECRYPTED_FOLDERS,
{ folderService: this, cryptoService: this.cryptoService },
{ folderService: this, keyService: this.keyService },
);
this.folders$ = this.encryptedFoldersState.state$.pipe(

View File

@@ -1,6 +1,6 @@
import { mock } from "jest-mock-extended";
import { CryptoService } from "../../../platform/abstractions/crypto.service";
import { KeyService } from "../../../../../key-management/src/abstractions/key.service";
import { FolderService } from "../../abstractions/folder/folder.service.abstraction";
import { FolderData } from "../../models/data/folder.data";
import { Folder } from "../../models/domain/folder";
@@ -31,7 +31,7 @@ describe("encrypted folders", () => {
});
describe("derived decrypted folders", () => {
const cryptoService = mock<CryptoService>();
const keyService = mock<KeyService>();
const folderService = mock<FolderService>();
const sut = FOLDER_DECRYPTED_FOLDERS;
let data: FolderData;
@@ -64,13 +64,13 @@ describe("derived decrypted folders", () => {
it("should derive encrypted folders", async () => {
const folderViewMock = new FolderView(new Folder(data));
cryptoService.hasUserKey.mockResolvedValue(true);
keyService.hasUserKey.mockResolvedValue(true);
folderService.decryptFolders.mockResolvedValue([folderViewMock]);
const encryptedFoldersState = { id: data };
const derivedStateResult = await sut.derive(encryptedFoldersState, {
folderService,
cryptoService,
keyService,
});
expect(derivedStateResult).toEqual([folderViewMock]);

View File

@@ -1,6 +1,6 @@
import { Jsonify } from "type-fest";
import { CryptoService } from "../../../platform/abstractions/crypto.service";
import { KeyService } from "../../../../../key-management/src/abstractions/key.service";
import { DeriveDefinition, FOLDER_DISK, UserKeyDefinition } from "../../../platform/state";
import { FolderService } from "../../abstractions/folder/folder.service.abstraction";
import { FolderData } from "../../models/data/folder.data";
@@ -19,13 +19,13 @@ export const FOLDER_ENCRYPTED_FOLDERS = UserKeyDefinition.record<FolderData>(
export const FOLDER_DECRYPTED_FOLDERS = DeriveDefinition.from<
Record<string, FolderData>,
FolderView[],
{ folderService: FolderService; cryptoService: CryptoService }
{ folderService: FolderService; keyService: KeyService }
>(FOLDER_ENCRYPTED_FOLDERS, {
deserializer: (obj) => obj.map((f) => FolderView.fromJSON(f)),
derive: async (from, { folderService, cryptoService }) => {
derive: async (from, { folderService, keyService }) => {
const folders = Object.values(from || {}).map((f) => new Folder(f));
if (await cryptoService.hasUserKey()) {
if (await keyService.hasUserKey()) {
return await folderService.decryptFolders(folders);
} else {
return [];