mirror of
https://github.com/bitwarden/browser
synced 2025-12-22 03:03:43 +00:00
[PM-7604] Require target UserID for KdfConfigService (#14380)
* Require userId for KdfConfigService * Update auth team callers * Update tools team callers
This commit is contained in:
@@ -4,6 +4,7 @@ import { PinServiceAbstraction } from "@bitwarden/auth/common";
|
||||
import { CryptoFunctionService } from "@bitwarden/common/key-management/crypto/abstractions/crypto-function.service";
|
||||
import { EncryptService } from "@bitwarden/common/key-management/crypto/abstractions/encrypt.service";
|
||||
import { Utils } from "@bitwarden/common/platform/misc/utils";
|
||||
import { UserId } from "@bitwarden/common/types/guid";
|
||||
import { CipherType } from "@bitwarden/common/vault/enums";
|
||||
import { CipherView } from "@bitwarden/common/vault/models/view/cipher.view";
|
||||
import { KdfConfig, KdfConfigService, KdfType } from "@bitwarden/key-management";
|
||||
@@ -17,8 +18,12 @@ export class BaseVaultExportService {
|
||||
private kdfConfigService: KdfConfigService,
|
||||
) {}
|
||||
|
||||
protected async buildPasswordExport(clearText: string, password: string): Promise<string> {
|
||||
const kdfConfig: KdfConfig = await this.kdfConfigService.getKdfConfig();
|
||||
protected async buildPasswordExport(
|
||||
userId: UserId,
|
||||
clearText: string,
|
||||
password: string,
|
||||
): Promise<string> {
|
||||
const kdfConfig: KdfConfig = await this.kdfConfigService.getKdfConfig(userId);
|
||||
|
||||
const salt = Utils.fromBufferToB64(await this.cryptoFunctionService.randomBytes(16));
|
||||
const key = await this.pinService.makePinKey(password, salt, kdfConfig);
|
||||
|
||||
@@ -13,6 +13,7 @@ import { EncryptService } from "@bitwarden/common/key-management/crypto/abstract
|
||||
import { CipherWithIdExport, FolderWithIdExport } from "@bitwarden/common/models/export";
|
||||
import { Utils } from "@bitwarden/common/platform/misc/utils";
|
||||
import { EncArrayBuffer } from "@bitwarden/common/platform/models/domain/enc-array-buffer";
|
||||
import { UserId } from "@bitwarden/common/types/guid";
|
||||
import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service";
|
||||
import { FolderService } from "@bitwarden/common/vault/abstractions/folder/folder.service.abstraction";
|
||||
import { CipherType } from "@bitwarden/common/vault/enums";
|
||||
@@ -59,19 +60,21 @@ export class IndividualVaultExportService
|
||||
* @param format The format of the export
|
||||
*/
|
||||
async getExport(format: ExportFormat = "csv"): Promise<ExportedVault> {
|
||||
const userId = await firstValueFrom(this.accountService.activeAccount$.pipe(getUserId));
|
||||
if (format === "encrypted_json") {
|
||||
return this.getEncryptedExport();
|
||||
return this.getEncryptedExport(userId);
|
||||
} else if (format === "zip") {
|
||||
return this.getDecryptedExportZip();
|
||||
return this.getDecryptedExportZip(userId);
|
||||
}
|
||||
return this.getDecryptedExport(format);
|
||||
return this.getDecryptedExport(userId, format);
|
||||
}
|
||||
|
||||
/** Creates a password protected export of an individiual vault (My Vault) as a JSON file
|
||||
/** Creates a password protected export of an individual vault (My Vault) as a JSON file
|
||||
* @param password The password to encrypt the export with
|
||||
* @returns A password-protected encrypted individual vault export
|
||||
*/
|
||||
async getPasswordProtectedExport(password: string): Promise<ExportedVaultAsString> {
|
||||
const userId = await firstValueFrom(this.accountService.activeAccount$.pipe(getUserId));
|
||||
const exportVault = await this.getExport("json");
|
||||
|
||||
if (exportVault.type !== "text/plain") {
|
||||
@@ -80,19 +83,20 @@ export class IndividualVaultExportService
|
||||
|
||||
return {
|
||||
type: "text/plain",
|
||||
data: await this.buildPasswordExport(exportVault.data, password),
|
||||
data: await this.buildPasswordExport(userId, exportVault.data, password),
|
||||
fileName: ExportHelper.getFileName("", "encrypted_json"),
|
||||
} as ExportedVaultAsString;
|
||||
}
|
||||
|
||||
/** Creates a unencrypted export of an individual vault including attachments
|
||||
* @param activeUserId The user ID of the user requesting the export
|
||||
* @returns A unencrypted export including attachments
|
||||
*/
|
||||
async getDecryptedExportZip(): Promise<ExportedVaultAsBlob> {
|
||||
async getDecryptedExportZip(activeUserId: UserId): Promise<ExportedVaultAsBlob> {
|
||||
const zip = new JSZip();
|
||||
|
||||
// ciphers
|
||||
const exportedVault = await this.getDecryptedExport("json");
|
||||
const exportedVault = await this.getDecryptedExport(activeUserId, "json");
|
||||
zip.file("data.json", exportedVault.data);
|
||||
|
||||
const attachmentsFolder = zip.folder("attachments");
|
||||
@@ -100,8 +104,6 @@ export class IndividualVaultExportService
|
||||
throw new Error("Error creating attachments folder");
|
||||
}
|
||||
|
||||
const activeUserId = await firstValueFrom(this.accountService.activeAccount$.pipe(getUserId));
|
||||
|
||||
// attachments
|
||||
for (const cipher of await this.cipherService.getAllDecrypted(activeUserId)) {
|
||||
if (
|
||||
@@ -161,11 +163,13 @@ export class IndividualVaultExportService
|
||||
}
|
||||
}
|
||||
|
||||
private async getDecryptedExport(format: "json" | "csv"): Promise<ExportedVaultAsString> {
|
||||
private async getDecryptedExport(
|
||||
activeUserId: UserId,
|
||||
format: "json" | "csv",
|
||||
): Promise<ExportedVaultAsString> {
|
||||
let decFolders: FolderView[] = [];
|
||||
let decCiphers: CipherView[] = [];
|
||||
const promises = [];
|
||||
const activeUserId = await firstValueFrom(this.accountService.activeAccount$.pipe(getUserId));
|
||||
|
||||
promises.push(
|
||||
firstValueFrom(this.folderService.folderViews$(activeUserId)).then((folders) => {
|
||||
@@ -196,11 +200,10 @@ export class IndividualVaultExportService
|
||||
} as ExportedVaultAsString;
|
||||
}
|
||||
|
||||
private async getEncryptedExport(): Promise<ExportedVaultAsString> {
|
||||
private async getEncryptedExport(activeUserId: UserId): Promise<ExportedVaultAsString> {
|
||||
let folders: Folder[] = [];
|
||||
let ciphers: Cipher[] = [];
|
||||
const promises = [];
|
||||
const activeUserId = await firstValueFrom(this.accountService.activeAccount$.pipe(getUserId));
|
||||
|
||||
promises.push(
|
||||
firstValueFrom(this.folderService.folders$(activeUserId)).then((f) => {
|
||||
@@ -216,9 +219,7 @@ export class IndividualVaultExportService
|
||||
|
||||
await Promise.all(promises);
|
||||
|
||||
const userKey = await this.keyService.getUserKeyWithLegacySupport(
|
||||
await firstValueFrom(this.accountService.activeAccount$.pipe(getUserId)),
|
||||
);
|
||||
const userKey = await this.keyService.getUserKeyWithLegacySupport(activeUserId);
|
||||
const encKeyValidation = await this.encryptService.encrypt(Utils.newGuid(), userKey);
|
||||
|
||||
const jsonDoc: BitwardenEncryptedIndividualJsonExport = {
|
||||
|
||||
@@ -18,7 +18,7 @@ import { CryptoFunctionService } from "@bitwarden/common/key-management/crypto/a
|
||||
import { EncryptService } from "@bitwarden/common/key-management/crypto/abstractions/encrypt.service";
|
||||
import { CipherWithIdExport, CollectionWithIdExport } from "@bitwarden/common/models/export";
|
||||
import { Utils } from "@bitwarden/common/platform/misc/utils";
|
||||
import { OrganizationId } from "@bitwarden/common/types/guid";
|
||||
import { OrganizationId, UserId } from "@bitwarden/common/types/guid";
|
||||
import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service";
|
||||
import { CipherType } from "@bitwarden/common/vault/enums";
|
||||
import { CipherData } from "@bitwarden/common/vault/models/data/cipher.data";
|
||||
@@ -67,6 +67,7 @@ export class OrganizationVaultExportService
|
||||
password: string,
|
||||
onlyManagedCollections: boolean,
|
||||
): Promise<ExportedVaultAsString> {
|
||||
const userId = await firstValueFrom(this.accountService.activeAccount$.pipe(getUserId));
|
||||
const exportVault = await this.getOrganizationExport(
|
||||
organizationId,
|
||||
"json",
|
||||
@@ -75,7 +76,7 @@ export class OrganizationVaultExportService
|
||||
|
||||
return {
|
||||
type: "text/plain",
|
||||
data: await this.buildPasswordExport(exportVault.data, password),
|
||||
data: await this.buildPasswordExport(userId, exportVault.data, password),
|
||||
fileName: ExportHelper.getFileName("org", "encrypted_json"),
|
||||
} as ExportedVaultAsString;
|
||||
}
|
||||
@@ -102,12 +103,13 @@ export class OrganizationVaultExportService
|
||||
if (format === "zip") {
|
||||
throw new Error("Zip export not supported for organization");
|
||||
}
|
||||
const userId = await firstValueFrom(this.accountService.activeAccount$.pipe(getUserId));
|
||||
|
||||
if (format === "encrypted_json") {
|
||||
return {
|
||||
type: "text/plain",
|
||||
data: onlyManagedCollections
|
||||
? await this.getEncryptedManagedExport(organizationId)
|
||||
? await this.getEncryptedManagedExport(userId, organizationId)
|
||||
: await this.getOrganizationEncryptedExport(organizationId),
|
||||
fileName: ExportHelper.getFileName("org", "encrypted_json"),
|
||||
} as ExportedVaultAsString;
|
||||
@@ -116,20 +118,20 @@ export class OrganizationVaultExportService
|
||||
return {
|
||||
type: "text/plain",
|
||||
data: onlyManagedCollections
|
||||
? await this.getDecryptedManagedExport(organizationId, format)
|
||||
: await this.getOrganizationDecryptedExport(organizationId, format),
|
||||
? await this.getDecryptedManagedExport(userId, organizationId, format)
|
||||
: await this.getOrganizationDecryptedExport(userId, organizationId, format),
|
||||
fileName: ExportHelper.getFileName("org", format),
|
||||
} as ExportedVaultAsString;
|
||||
}
|
||||
|
||||
private async getOrganizationDecryptedExport(
|
||||
activeUserId: UserId,
|
||||
organizationId: string,
|
||||
format: "json" | "csv",
|
||||
): Promise<string> {
|
||||
const decCollections: CollectionView[] = [];
|
||||
const decCiphers: CipherView[] = [];
|
||||
const promises = [];
|
||||
const activeUserId = await firstValueFrom(this.accountService.activeAccount$.pipe(getUserId));
|
||||
|
||||
promises.push(
|
||||
this.apiService.getOrganizationExport(organizationId).then((exportData) => {
|
||||
@@ -210,6 +212,7 @@ export class OrganizationVaultExportService
|
||||
}
|
||||
|
||||
private async getDecryptedManagedExport(
|
||||
activeUserId: UserId,
|
||||
organizationId: string,
|
||||
format: "json" | "csv",
|
||||
): Promise<string> {
|
||||
@@ -217,7 +220,6 @@ export class OrganizationVaultExportService
|
||||
let allDecCiphers: CipherView[] = [];
|
||||
let decCollections: CollectionView[] = [];
|
||||
const promises = [];
|
||||
const activeUserId = await firstValueFrom(this.accountService.activeAccount$.pipe(getUserId));
|
||||
|
||||
promises.push(
|
||||
this.collectionService.getAllDecrypted().then(async (collections) => {
|
||||
@@ -245,12 +247,14 @@ export class OrganizationVaultExportService
|
||||
return this.buildJsonExport(decCollections, decCiphers);
|
||||
}
|
||||
|
||||
private async getEncryptedManagedExport(organizationId: string): Promise<string> {
|
||||
private async getEncryptedManagedExport(
|
||||
activeUserId: UserId,
|
||||
organizationId: string,
|
||||
): Promise<string> {
|
||||
let encCiphers: Cipher[] = [];
|
||||
let allCiphers: Cipher[] = [];
|
||||
let encCollections: Collection[] = [];
|
||||
const promises = [];
|
||||
const activeUserId = await firstValueFrom(this.accountService.activeAccount$.pipe(getUserId));
|
||||
|
||||
promises.push(
|
||||
this.collectionService.getAll().then((collections) => {
|
||||
|
||||
Reference in New Issue
Block a user