1
0
mirror of https://github.com/bitwarden/browser synced 2025-12-17 16:53:34 +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

@@ -3,11 +3,13 @@ import { ComponentFixture, TestBed } from "@angular/core/testing";
import { By } from "@angular/platform-browser";
import { mock } from "jest-mock-extended";
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service";
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
import { LogService } from "@bitwarden/common/platform/abstractions/log.service";
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
import { CipherId } from "@bitwarden/common/types/guid";
import { Utils } from "@bitwarden/common/platform/misc/utils";
import { CipherId, UserId } from "@bitwarden/common/types/guid";
import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service";
import { CipherType } from "@bitwarden/common/vault/enums";
import { AttachmentView } from "@bitwarden/common/vault/models/view/attachment.view";
@@ -15,6 +17,8 @@ import { CipherView } from "@bitwarden/common/vault/models/view/cipher.view";
import { ButtonComponent, ToastService } from "@bitwarden/components";
import { DownloadAttachmentComponent } from "@bitwarden/vault";
import { FakeAccountService, mockAccountServiceWith } from "../../../../../common/spec";
import { CipherAttachmentsComponent } from "./cipher-attachments.component";
import { DeleteAttachmentComponent } from "./delete-attachment/delete-attachment.component";
@@ -49,6 +53,9 @@ describe("CipherAttachmentsComponent", () => {
const cipherServiceGet = jest.fn().mockResolvedValue(cipherDomain);
const saveAttachmentWithServer = jest.fn().mockResolvedValue(cipherDomain);
const mockUserId = Utils.newGuid() as UserId;
const accountService: FakeAccountService = mockAccountServiceWith(mockUserId);
beforeEach(async () => {
cipherServiceGet.mockClear();
showToast.mockClear();
@@ -75,6 +82,10 @@ describe("CipherAttachmentsComponent", () => {
{ provide: LogService, useValue: mock<LogService>() },
{ provide: ConfigService, useValue: mock<ConfigService>() },
{ provide: PlatformUtilsService, useValue: mock<PlatformUtilsService>() },
{
provide: AccountService,
useValue: accountService,
},
],
})
.overrideComponent(CipherAttachmentsComponent, {
@@ -219,7 +230,7 @@ describe("CipherAttachmentsComponent", () => {
it("calls `saveAttachmentWithServer`", async () => {
await component.submit();
expect(saveAttachmentWithServer).toHaveBeenCalledWith(cipherDomain, file);
expect(saveAttachmentWithServer).toHaveBeenCalledWith(cipherDomain, file, mockUserId);
});
it("resets form and input values", async () => {

View File

@@ -19,11 +19,13 @@ import {
ReactiveFormsModule,
Validators,
} from "@angular/forms";
import { firstValueFrom, map } from "rxjs";
import { JslibModule } from "@bitwarden/angular/jslib.module";
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
import { LogService } from "@bitwarden/common/platform/abstractions/log.service";
import { CipherId } from "@bitwarden/common/types/guid";
import { CipherId, UserId } from "@bitwarden/common/types/guid";
import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service";
import { Cipher } from "@bitwarden/common/vault/models/domain/cipher";
import { AttachmentView } from "@bitwarden/common/vault/models/view/attachment.view";
@@ -90,6 +92,7 @@ export class CipherAttachmentsComponent implements OnInit, AfterViewInit {
});
private cipherDomain: Cipher;
private activeUserId: UserId;
private destroy$ = inject(DestroyRef);
constructor(
@@ -98,6 +101,7 @@ export class CipherAttachmentsComponent implements OnInit, AfterViewInit {
private formBuilder: FormBuilder,
private logService: LogService,
private toastService: ToastService,
private accountService: AccountService,
) {
this.attachmentForm.statusChanges.pipe(takeUntilDestroyed()).subscribe((status) => {
if (!this.submitBtn) {
@@ -110,8 +114,11 @@ export class CipherAttachmentsComponent implements OnInit, AfterViewInit {
async ngOnInit(): Promise<void> {
this.cipherDomain = await this.cipherService.get(this.cipherId);
this.activeUserId = await firstValueFrom(
this.accountService.activeAccount$.pipe(map((a) => a?.id)),
);
this.cipher = await this.cipherDomain.decrypt(
await this.cipherService.getKeyForCipherKeyDecryption(this.cipherDomain),
await this.cipherService.getKeyForCipherKeyDecryption(this.cipherDomain, this.activeUserId),
);
// Update the initial state of the submit button
@@ -178,11 +185,12 @@ export class CipherAttachmentsComponent implements OnInit, AfterViewInit {
this.cipherDomain = await this.cipherService.saveAttachmentWithServer(
this.cipherDomain,
file,
this.activeUserId,
);
// re-decrypt the cipher to update the attachments
this.cipher = await this.cipherDomain.decrypt(
await this.cipherService.getKeyForCipherKeyDecryption(this.cipherDomain),
await this.cipherService.getKeyForCipherKeyDecryption(this.cipherDomain, this.activeUserId),
);
// Reset reactive form and input element

View File

@@ -1,5 +1,7 @@
import { inject, Injectable } from "@angular/core";
import { firstValueFrom, map } from "rxjs";
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service";
import { Cipher } from "@bitwarden/common/vault/models/domain/cipher";
import { CipherView } from "@bitwarden/common/vault/models/view/cipher.view";
@@ -14,15 +16,25 @@ function isSetEqual(a: Set<string>, b: Set<string>) {
@Injectable()
export class DefaultCipherFormService implements CipherFormService {
private cipherService: CipherService = inject(CipherService);
private accountService: AccountService = inject(AccountService);
async decryptCipher(cipher: Cipher): Promise<CipherView> {
return await cipher.decrypt(await this.cipherService.getKeyForCipherKeyDecryption(cipher));
const activeUserId = await firstValueFrom(
this.accountService.activeAccount$.pipe(map((a) => a?.id)),
);
return await cipher.decrypt(
await this.cipherService.getKeyForCipherKeyDecryption(cipher, activeUserId),
);
}
async saveCipher(cipher: CipherView, config: CipherFormConfig): Promise<CipherView> {
// Passing the original cipher is important here as it is responsible for appending to password history
const activeUserId = await firstValueFrom(
this.accountService.activeAccount$.pipe(map((a) => a?.id)),
);
const encryptedCipher = await this.cipherService.encrypt(
cipher,
activeUserId,
null,
null,
config.originalCipher ?? null,
@@ -34,7 +46,7 @@ export class DefaultCipherFormService implements CipherFormService {
if (cipher.id == null) {
savedCipher = await this.cipherService.createWithServer(encryptedCipher, config.admin);
return await savedCipher.decrypt(
await this.cipherService.getKeyForCipherKeyDecryption(savedCipher),
await this.cipherService.getKeyForCipherKeyDecryption(savedCipher, activeUserId),
);
}
@@ -68,7 +80,7 @@ export class DefaultCipherFormService implements CipherFormService {
}
return await savedCipher.decrypt(
await this.cipherService.getKeyForCipherKeyDecryption(savedCipher),
await this.cipherService.getKeyForCipherKeyDecryption(savedCipher, activeUserId),
);
}
}