1
0
mirror of https://github.com/bitwarden/browser synced 2025-12-18 09:13:33 +00:00

[PM-10607] Require userId for getKeyForCipherKeyDecryption (#10509)

* updated cipher service to stop using the deprecated getUserKeyWithLegacySupport and use the version that requires a user id

* Added account service mock

* fixed cipher test

* Fixed test

* removed async from encryptCipher

* updated encryptSharedCipher to pass userId to the encrypt function

* Pass userId to getUserKeyWithLegacySupport on encryptSharedCipher

* pass in userid when setting masterKeyEncryptedUserKey

* Added activer usedId to new web refresh function
This commit is contained in:
SmithThe4th
2024-08-20 12:00:48 -04:00
committed by GitHub
parent ed719f835a
commit dedd7f1b5c
67 changed files with 534 additions and 118 deletions

View File

@@ -1,3 +1,6 @@
import { firstValueFrom, map } from "rxjs";
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service";
import { Response } from "../../models/response";
@@ -5,7 +8,10 @@ import { CliUtils } from "../../utils";
import { CipherResponse } from "../../vault/models/cipher.response";
export class ShareCommand {
constructor(private cipherService: CipherService) {}
constructor(
private cipherService: CipherService,
private accountService: AccountService,
) {}
async run(id: string, organizationId: string, requestJson: string): Promise<Response> {
if (process.env.BW_SERVE !== "true" && (requestJson == null || requestJson === "")) {
@@ -45,14 +51,18 @@ export class ShareCommand {
if (cipher.organizationId != null) {
return Response.badRequest("This item already belongs to an organization.");
}
const activeUserId = await firstValueFrom(
this.accountService.activeAccount$.pipe(map((a) => a?.id)),
);
const cipherView = await cipher.decrypt(
await this.cipherService.getKeyForCipherKeyDecryption(cipher),
await this.cipherService.getKeyForCipherKeyDecryption(cipher, activeUserId),
);
try {
await this.cipherService.shareWithServer(cipherView, organizationId, req);
await this.cipherService.shareWithServer(cipherView, organizationId, req, activeUserId);
const updatedCipher = await this.cipherService.get(cipher.id);
const decCipher = await updatedCipher.decrypt(
await this.cipherService.getKeyForCipherKeyDecryption(updatedCipher),
await this.cipherService.getKeyForCipherKeyDecryption(updatedCipher, activeUserId),
);
const res = new CipherResponse(decCipher);
return Response.success(res);

View File

@@ -1,5 +1,8 @@
import { firstValueFrom, map } from "rxjs";
import { ApiService } from "@bitwarden/common/abstractions/api.service";
import { SelectionReadOnlyRequest } from "@bitwarden/common/admin-console/models/request/selection-read-only.request";
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
import { CipherExport } from "@bitwarden/common/models/export/cipher.export";
import { CollectionExport } from "@bitwarden/common/models/export/collection.export";
import { FolderExport } from "@bitwarden/common/models/export/folder.export";
@@ -24,6 +27,7 @@ export class EditCommand {
private cryptoService: CryptoService,
private apiService: ApiService,
private folderApiService: FolderApiServiceAbstraction,
private accountService: AccountService,
) {}
async run(
@@ -77,18 +81,21 @@ export class EditCommand {
return Response.notFound();
}
const activeUserId = await firstValueFrom(
this.accountService.activeAccount$.pipe(map((a) => a?.id)),
);
let cipherView = await cipher.decrypt(
await this.cipherService.getKeyForCipherKeyDecryption(cipher),
await this.cipherService.getKeyForCipherKeyDecryption(cipher, activeUserId),
);
if (cipherView.isDeleted) {
return Response.badRequest("You may not edit a deleted item. Use the restore command first.");
}
cipherView = CipherExport.toView(req, cipherView);
const encCipher = await this.cipherService.encrypt(cipherView);
const encCipher = await this.cipherService.encrypt(cipherView, activeUserId);
try {
const updatedCipher = await this.cipherService.updateWithServer(encCipher);
const decCipher = await updatedCipher.decrypt(
await this.cipherService.getKeyForCipherKeyDecryption(updatedCipher),
await this.cipherService.getKeyForCipherKeyDecryption(updatedCipher, activeUserId),
);
const res = new CipherResponse(decCipher);
return Response.success(res);
@@ -110,9 +117,12 @@ export class EditCommand {
cipher.collectionIds = req;
try {
const activeUserId = await firstValueFrom(
this.accountService.activeAccount$.pipe(map((a) => a?.id)),
);
const updatedCipher = await this.cipherService.saveCollectionsWithServer(cipher);
const decCipher = await updatedCipher.decrypt(
await this.cipherService.getKeyForCipherKeyDecryption(updatedCipher),
await this.cipherService.getKeyForCipherKeyDecryption(updatedCipher, activeUserId),
);
const res = new CipherResponse(decCipher);
return Response.success(res);

View File

@@ -1,4 +1,4 @@
import { firstValueFrom } from "rxjs";
import { firstValueFrom, map } from "rxjs";
import { ApiService } from "@bitwarden/common/abstractions/api.service";
import { AuditService } from "@bitwarden/common/abstractions/audit.service";
@@ -6,6 +6,7 @@ import { EventCollectionService } from "@bitwarden/common/abstractions/event/eve
import { SearchService } from "@bitwarden/common/abstractions/search.service";
import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction";
import { Organization } from "@bitwarden/common/admin-console/models/domain/organization";
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
import { BillingAccountProfileStateService } from "@bitwarden/common/billing/abstractions/account/billing-account-profile-state.service";
import { EventType } from "@bitwarden/common/enums";
import { CardExport } from "@bitwarden/common/models/export/card.export";
@@ -62,6 +63,7 @@ export class GetCommand extends DownloadCommand {
private organizationService: OrganizationService,
private eventCollectionService: EventCollectionService,
private accountProfileService: BillingAccountProfileStateService,
private accountService: AccountService,
) {
super(cryptoService);
}
@@ -110,9 +112,12 @@ export class GetCommand extends DownloadCommand {
let decCipher: CipherView = null;
if (Utils.isGuid(id)) {
const cipher = await this.cipherService.get(id);
const activeUserId = await firstValueFrom(
this.accountService.activeAccount$.pipe(map((a) => a?.id)),
);
if (cipher != null) {
decCipher = await cipher.decrypt(
await this.cipherService.getKeyForCipherKeyDecryption(cipher),
await this.cipherService.getKeyForCipherKeyDecryption(cipher, activeUserId),
);
}
} else if (id.trim() !== "") {

View File

@@ -63,6 +63,7 @@ export class OssServeConfigurator {
this.serviceContainer.organizationService,
this.serviceContainer.eventCollectionService,
this.serviceContainer.billingAccountProfileStateService,
this.serviceContainer.accountService,
);
this.listCommand = new ListCommand(
this.serviceContainer.cipherService,
@@ -82,6 +83,7 @@ export class OssServeConfigurator {
this.serviceContainer.folderApiService,
this.serviceContainer.billingAccountProfileStateService,
this.serviceContainer.organizationService,
this.serviceContainer.accountService,
);
this.editCommand = new EditCommand(
this.serviceContainer.cipherService,
@@ -89,6 +91,7 @@ export class OssServeConfigurator {
this.serviceContainer.cryptoService,
this.serviceContainer.apiService,
this.serviceContainer.folderApiService,
this.serviceContainer.accountService,
);
this.generateCommand = new GenerateCommand(
this.serviceContainer.passwordGenerationService,
@@ -114,7 +117,10 @@ export class OssServeConfigurator {
this.serviceContainer.organizationUserService,
);
this.restoreCommand = new RestoreCommand(this.serviceContainer.cipherService);
this.shareCommand = new ShareCommand(this.serviceContainer.cipherService);
this.shareCommand = new ShareCommand(
this.serviceContainer.cipherService,
this.serviceContainer.accountService,
);
this.lockCommand = new LockCommand(this.serviceContainer.vaultTimeoutService);
this.unlockCommand = new UnlockCommand(
this.serviceContainer.accountService,

View File

@@ -714,6 +714,7 @@ export class ServiceContainer {
this.collectionService,
this.cryptoService,
this.pinService,
this.accountService,
);
this.individualExportService = new IndividualVaultExportService(
@@ -733,6 +734,7 @@ export class ServiceContainer {
this.cryptoFunctionService,
this.collectionService,
this.kdfConfigService,
this.accountService,
);
this.exportService = new VaultExportService(

View File

@@ -149,6 +149,7 @@ export class SendProgram extends BaseProgram {
this.serviceContainer.organizationService,
this.serviceContainer.eventCollectionService,
this.serviceContainer.billingAccountProfileStateService,
this.serviceContainer.accountService,
);
const response = await cmd.run("template", object, null);
this.processResponse(response);

View File

@@ -184,6 +184,7 @@ export class VaultProgram extends BaseProgram {
this.serviceContainer.organizationService,
this.serviceContainer.eventCollectionService,
this.serviceContainer.billingAccountProfileStateService,
this.serviceContainer.accountService,
);
const response = await command.run(object, id, cmd);
this.processResponse(response);
@@ -227,6 +228,7 @@ export class VaultProgram extends BaseProgram {
this.serviceContainer.folderApiService,
this.serviceContainer.billingAccountProfileStateService,
this.serviceContainer.organizationService,
this.serviceContainer.accountService,
);
const response = await command.run(object, encodedJson, cmd);
this.processResponse(response);
@@ -272,6 +274,7 @@ export class VaultProgram extends BaseProgram {
this.serviceContainer.cryptoService,
this.serviceContainer.apiService,
this.serviceContainer.folderApiService,
this.serviceContainer.accountService,
);
const response = await command.run(object, id, encodedJson, cmd);
this.processResponse(response);
@@ -375,7 +378,10 @@ export class VaultProgram extends BaseProgram {
})
.action(async (id, organizationId, encodedJson, cmd) => {
await this.exitIfLocked();
const command = new ShareCommand(this.serviceContainer.cipherService);
const command = new ShareCommand(
this.serviceContainer.cipherService,
this.serviceContainer.accountService,
);
const response = await command.run(id, organizationId, encodedJson);
this.processResponse(response);
});

View File

@@ -1,11 +1,12 @@
import * as fs from "fs";
import * as path from "path";
import { firstValueFrom } from "rxjs";
import { firstValueFrom, map } from "rxjs";
import { ApiService } from "@bitwarden/common/abstractions/api.service";
import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction";
import { SelectionReadOnlyRequest } from "@bitwarden/common/admin-console/models/request/selection-read-only.request";
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
import { BillingAccountProfileStateService } from "@bitwarden/common/billing/abstractions/account/billing-account-profile-state.service";
import { CipherExport } from "@bitwarden/common/models/export/cipher.export";
import { CollectionExport } from "@bitwarden/common/models/export/collection.export";
@@ -34,6 +35,7 @@ export class CreateCommand {
private folderApiService: FolderApiServiceAbstraction,
private accountProfileService: BillingAccountProfileStateService,
private organizationService: OrganizationService,
private accountService: AccountService,
) {}
async run(
@@ -80,11 +82,14 @@ export class CreateCommand {
}
private async createCipher(req: CipherExport) {
const cipher = await this.cipherService.encrypt(CipherExport.toView(req));
const activeUserId = await firstValueFrom(
this.accountService.activeAccount$.pipe(map((a) => a?.id)),
);
const cipher = await this.cipherService.encrypt(CipherExport.toView(req), activeUserId);
try {
const newCipher = await this.cipherService.createWithServer(cipher);
const decCipher = await newCipher.decrypt(
await this.cipherService.getKeyForCipherKeyDecryption(newCipher),
await this.cipherService.getKeyForCipherKeyDecryption(newCipher, activeUserId),
);
const res = new CipherResponse(decCipher);
return Response.success(res);
@@ -143,13 +148,17 @@ export class CreateCommand {
}
try {
const activeUserId = await firstValueFrom(
this.accountService.activeAccount$.pipe(map((a) => a?.id)),
);
const updatedCipher = await this.cipherService.saveAttachmentRawWithServer(
cipher,
fileName,
new Uint8Array(fileBuf).buffer,
activeUserId,
);
const decCipher = await updatedCipher.decrypt(
await this.cipherService.getKeyForCipherKeyDecryption(updatedCipher),
await this.cipherService.getKeyForCipherKeyDecryption(updatedCipher, activeUserId),
);
return Response.success(new CipherResponse(decCipher));
} catch (e) {