mirror of
https://github.com/bitwarden/browser
synced 2025-12-16 16:23:44 +00:00
[PM-24099] Tools - Remove getOrgKey from the key service (#16351)
* replace deprecated getOrgKey() method • obtain account using `accountService.activeAccount$` and then use id property to guarentee validity of UserId
This commit is contained in:
@@ -64,12 +64,13 @@ export class BitwardenJsonImporter extends BaseImporter implements Importer {
|
|||||||
private async parseEncrypted(
|
private async parseEncrypted(
|
||||||
results: BitwardenEncryptedIndividualJsonExport | BitwardenEncryptedOrgJsonExport,
|
results: BitwardenEncryptedIndividualJsonExport | BitwardenEncryptedOrgJsonExport,
|
||||||
) {
|
) {
|
||||||
|
const account = await firstValueFrom(this.accountService.activeAccount$);
|
||||||
|
|
||||||
if (results.encKeyValidation_DO_NOT_EDIT != null) {
|
if (results.encKeyValidation_DO_NOT_EDIT != null) {
|
||||||
let keyForDecryption: SymmetricCryptoKey = await this.keyService.getOrgKey(
|
const orgKeys = await firstValueFrom(this.keyService.orgKeys$(account.id));
|
||||||
this.organizationId,
|
let keyForDecryption: SymmetricCryptoKey = orgKeys?.[this.organizationId];
|
||||||
);
|
|
||||||
if (keyForDecryption == null) {
|
if (keyForDecryption == null) {
|
||||||
keyForDecryption = await this.keyService.getUserKey();
|
keyForDecryption = await firstValueFrom(this.keyService.userKey$(account.id));
|
||||||
}
|
}
|
||||||
const encKeyValidation = new EncString(results.encKeyValidation_DO_NOT_EDIT);
|
const encKeyValidation = new EncString(results.encKeyValidation_DO_NOT_EDIT);
|
||||||
try {
|
try {
|
||||||
@@ -113,10 +114,7 @@ export class BitwardenJsonImporter extends BaseImporter implements Importer {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const activeUserId = await firstValueFrom(
|
const view = await this.cipherService.decrypt(cipher, account.id);
|
||||||
this.accountService.activeAccount$.pipe(map((a) => a?.id)),
|
|
||||||
);
|
|
||||||
const view = await this.cipherService.decrypt(cipher, activeUserId);
|
|
||||||
this.cleanupCipher(view);
|
this.cleanupCipher(view);
|
||||||
this.result.ciphers.push(view);
|
this.result.ciphers.push(view);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,12 +1,17 @@
|
|||||||
import { mock, MockProxy } from "jest-mock-extended";
|
import { mock, MockProxy } from "jest-mock-extended";
|
||||||
|
import { of } from "rxjs";
|
||||||
|
|
||||||
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
|
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
|
||||||
import { EncryptService } from "@bitwarden/common/key-management/crypto/abstractions/encrypt.service";
|
import { EncryptService } from "@bitwarden/common/key-management/crypto/abstractions/encrypt.service";
|
||||||
import { PinServiceAbstraction } from "@bitwarden/common/key-management/pin/pin.service.abstraction";
|
import { PinServiceAbstraction } from "@bitwarden/common/key-management/pin/pin.service.abstraction";
|
||||||
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
||||||
import { Utils } from "@bitwarden/common/platform/misc/utils";
|
import { Utils } from "@bitwarden/common/platform/misc/utils";
|
||||||
|
import { emptyGuid, OrganizationId } from "@bitwarden/common/types/guid";
|
||||||
|
import { OrgKey, UserKey } from "@bitwarden/common/types/key";
|
||||||
import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service";
|
import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service";
|
||||||
|
import { newGuid } from "@bitwarden/guid";
|
||||||
import { KdfType, KeyService } from "@bitwarden/key-management";
|
import { KdfType, KeyService } from "@bitwarden/key-management";
|
||||||
|
import { UserId } from "@bitwarden/user-core";
|
||||||
|
|
||||||
import { emptyAccountEncrypted } from "../spec-data/bitwarden-json/account-encrypted.json";
|
import { emptyAccountEncrypted } from "../spec-data/bitwarden-json/account-encrypted.json";
|
||||||
import { emptyUnencryptedExport } from "../spec-data/bitwarden-json/unencrypted.json";
|
import { emptyUnencryptedExport } from "../spec-data/bitwarden-json/unencrypted.json";
|
||||||
@@ -35,6 +40,36 @@ describe("BitwardenPasswordProtectedImporter", () => {
|
|||||||
pinService = mock<PinServiceAbstraction>();
|
pinService = mock<PinServiceAbstraction>();
|
||||||
accountService = mock<AccountService>();
|
accountService = mock<AccountService>();
|
||||||
|
|
||||||
|
accountService.activeAccount$ = of({
|
||||||
|
id: newGuid() as UserId,
|
||||||
|
email: "test@example.com",
|
||||||
|
emailVerified: true,
|
||||||
|
name: "Test User",
|
||||||
|
});
|
||||||
|
|
||||||
|
const mockOrgId = emptyGuid as OrganizationId;
|
||||||
|
/*
|
||||||
|
The key values below are never read, empty objects are cast as types for compilation type checking only.
|
||||||
|
Tests specific to key contents are in key-service.spec.ts
|
||||||
|
*/
|
||||||
|
const mockOrgKey = {} as unknown as OrgKey;
|
||||||
|
const mockUserKey = {} as unknown as UserKey;
|
||||||
|
|
||||||
|
keyService.orgKeys$.mockImplementation(() =>
|
||||||
|
of({ [mockOrgId]: mockOrgKey } as Record<OrganizationId, OrgKey>),
|
||||||
|
);
|
||||||
|
keyService.userKey$.mockImplementation(() => of(mockUserKey));
|
||||||
|
(keyService as any).activeUserOrgKeys$ = of({
|
||||||
|
[mockOrgId]: mockOrgKey,
|
||||||
|
} as Record<OrganizationId, OrgKey>);
|
||||||
|
|
||||||
|
/*
|
||||||
|
Crypto isn’t under test here; keys are just placeholders.
|
||||||
|
Decryption methods are stubbed to always return empty CipherView or string allowing OK import flow.
|
||||||
|
*/
|
||||||
|
cipherService.decrypt.mockResolvedValue({} as any);
|
||||||
|
encryptService.decryptString.mockResolvedValue("ok");
|
||||||
|
|
||||||
importer = new BitwardenPasswordProtectedImporter(
|
importer = new BitwardenPasswordProtectedImporter(
|
||||||
keyService,
|
keyService,
|
||||||
encryptService,
|
encryptService,
|
||||||
@@ -62,6 +97,24 @@ describe("BitwardenPasswordProtectedImporter", () => {
|
|||||||
jest.spyOn(BitwardenJsonImporter.prototype, "parse");
|
jest.spyOn(BitwardenJsonImporter.prototype, "parse");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
accountService.activeAccount$ = of({
|
||||||
|
id: newGuid() as UserId,
|
||||||
|
email: "test@example.com",
|
||||||
|
emailVerified: true,
|
||||||
|
name: "Test User",
|
||||||
|
});
|
||||||
|
importer = new BitwardenPasswordProtectedImporter(
|
||||||
|
keyService,
|
||||||
|
encryptService,
|
||||||
|
i18nService,
|
||||||
|
cipherService,
|
||||||
|
pinService,
|
||||||
|
accountService,
|
||||||
|
promptForPassword_callback,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
it("Should call BitwardenJsonImporter", async () => {
|
it("Should call BitwardenJsonImporter", async () => {
|
||||||
expect((await importer.parse(emptyAccountEncrypted)).success).toEqual(true);
|
expect((await importer.parse(emptyAccountEncrypted)).success).toEqual(true);
|
||||||
expect(BitwardenJsonImporter.prototype.parse).toHaveBeenCalledWith(emptyAccountEncrypted);
|
expect(BitwardenJsonImporter.prototype.parse).toHaveBeenCalledWith(emptyAccountEncrypted);
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ import { EncryptService } from "@bitwarden/common/key-management/crypto/abstract
|
|||||||
import { PinServiceAbstraction } from "@bitwarden/common/key-management/pin/pin.service.abstraction";
|
import { PinServiceAbstraction } from "@bitwarden/common/key-management/pin/pin.service.abstraction";
|
||||||
import { CipherWithIdExport, CollectionWithIdExport } from "@bitwarden/common/models/export";
|
import { CipherWithIdExport, CollectionWithIdExport } from "@bitwarden/common/models/export";
|
||||||
import { Utils } from "@bitwarden/common/platform/misc/utils";
|
import { Utils } from "@bitwarden/common/platform/misc/utils";
|
||||||
|
import { SymmetricCryptoKey } from "@bitwarden/common/platform/models/domain/symmetric-crypto-key";
|
||||||
import { OrganizationId, UserId } from "@bitwarden/common/types/guid";
|
import { OrganizationId, UserId } from "@bitwarden/common/types/guid";
|
||||||
import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service";
|
import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service";
|
||||||
import { CipherType } from "@bitwarden/common/vault/enums";
|
import { CipherType } from "@bitwarden/common/vault/enums";
|
||||||
@@ -22,6 +23,7 @@ import { CipherData } from "@bitwarden/common/vault/models/data/cipher.data";
|
|||||||
import { Cipher } from "@bitwarden/common/vault/models/domain/cipher";
|
import { Cipher } from "@bitwarden/common/vault/models/domain/cipher";
|
||||||
import { CipherView } from "@bitwarden/common/vault/models/view/cipher.view";
|
import { CipherView } from "@bitwarden/common/vault/models/view/cipher.view";
|
||||||
import { RestrictedItemTypesService } from "@bitwarden/common/vault/services/restricted-item-types.service";
|
import { RestrictedItemTypesService } from "@bitwarden/common/vault/services/restricted-item-types.service";
|
||||||
|
import { newGuid } from "@bitwarden/guid";
|
||||||
import { KdfConfigService, KeyService } from "@bitwarden/key-management";
|
import { KdfConfigService, KeyService } from "@bitwarden/key-management";
|
||||||
|
|
||||||
import {
|
import {
|
||||||
@@ -112,7 +114,7 @@ export class OrganizationVaultExportService
|
|||||||
type: "text/plain",
|
type: "text/plain",
|
||||||
data: onlyManagedCollections
|
data: onlyManagedCollections
|
||||||
? await this.getEncryptedManagedExport(userId, organizationId)
|
? await this.getEncryptedManagedExport(userId, organizationId)
|
||||||
: await this.getOrganizationEncryptedExport(organizationId),
|
: await this.getOrganizationEncryptedExport(userId, organizationId),
|
||||||
fileName: ExportHelper.getFileName("org", "encrypted_json"),
|
fileName: ExportHelper.getFileName("org", "encrypted_json"),
|
||||||
} as ExportedVaultAsString;
|
} as ExportedVaultAsString;
|
||||||
}
|
}
|
||||||
@@ -184,7 +186,10 @@ export class OrganizationVaultExportService
|
|||||||
return this.buildJsonExport(decCollections, decCiphers);
|
return this.buildJsonExport(decCollections, decCiphers);
|
||||||
}
|
}
|
||||||
|
|
||||||
private async getOrganizationEncryptedExport(organizationId: OrganizationId): Promise<string> {
|
private async getOrganizationEncryptedExport(
|
||||||
|
userId: UserId,
|
||||||
|
organizationId: OrganizationId,
|
||||||
|
): Promise<string> {
|
||||||
const collections: Collection[] = [];
|
const collections: Collection[] = [];
|
||||||
const ciphers: Cipher[] = [];
|
const ciphers: Cipher[] = [];
|
||||||
|
|
||||||
@@ -215,7 +220,7 @@ export class OrganizationVaultExportService
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
return this.BuildEncryptedExport(organizationId, collections, ciphers);
|
return this.BuildEncryptedExport(userId, organizationId, collections, ciphers);
|
||||||
}
|
}
|
||||||
|
|
||||||
private async getDecryptedManagedExport(
|
private async getDecryptedManagedExport(
|
||||||
@@ -295,16 +300,21 @@ export class OrganizationVaultExportService
|
|||||||
!this.restrictedItemTypesService.isCipherRestricted(f, restrictions),
|
!this.restrictedItemTypesService.isCipherRestricted(f, restrictions),
|
||||||
);
|
);
|
||||||
|
|
||||||
return this.BuildEncryptedExport(organizationId, encCollections, encCiphers);
|
return this.BuildEncryptedExport(activeUserId, organizationId, encCollections, encCiphers);
|
||||||
}
|
}
|
||||||
|
|
||||||
private async BuildEncryptedExport(
|
private async BuildEncryptedExport(
|
||||||
|
activeUserId: UserId,
|
||||||
organizationId: OrganizationId,
|
organizationId: OrganizationId,
|
||||||
collections: Collection[],
|
collections: Collection[],
|
||||||
ciphers: Cipher[],
|
ciphers: Cipher[],
|
||||||
): Promise<string> {
|
): Promise<string> {
|
||||||
const orgKey = await this.keyService.getOrgKey(organizationId);
|
const orgKeys = await firstValueFrom(this.keyService.orgKeys$(activeUserId));
|
||||||
const encKeyValidation = await this.encryptService.encryptString(Utils.newGuid(), orgKey);
|
const keyForEncryption: SymmetricCryptoKey = orgKeys?.[organizationId];
|
||||||
|
if (keyForEncryption == null) {
|
||||||
|
throw new Error("No encryption key found for organization");
|
||||||
|
}
|
||||||
|
const encKeyValidation = await this.encryptService.encryptString(newGuid(), keyForEncryption);
|
||||||
|
|
||||||
const jsonDoc: BitwardenEncryptedOrgJsonExport = {
|
const jsonDoc: BitwardenEncryptedOrgJsonExport = {
|
||||||
encrypted: true,
|
encrypted: true,
|
||||||
|
|||||||
Reference in New Issue
Block a user