mirror of
https://github.com/bitwarden/browser
synced 2025-12-17 16:53:34 +00:00
[PM-6789] finish key rotation distribution and fix legacy user (#9498)
* finish key rotation distribution and fix legacy user * add ticket to TODO * PR feedback: docs and renaming * fix webauthn tests * add test for send service * add await to test
This commit is contained in:
@@ -1,14 +1,17 @@
|
||||
import { Observable } from "rxjs";
|
||||
|
||||
import { UserKeyRotationDataProvider } from "@bitwarden/auth/common";
|
||||
|
||||
import { EncArrayBuffer } from "../../../platform/models/domain/enc-array-buffer";
|
||||
import { SymmetricCryptoKey } from "../../../platform/models/domain/symmetric-crypto-key";
|
||||
import { UserId } from "../../../types/guid";
|
||||
import { UserKey } from "../../../types/key";
|
||||
import { SendData } from "../models/data/send.data";
|
||||
import { Send } from "../models/domain/send";
|
||||
import { SendWithIdRequest } from "../models/request/send-with-id.request";
|
||||
import { SendView } from "../models/view/send.view";
|
||||
|
||||
export abstract class SendService {
|
||||
export abstract class SendService implements UserKeyRotationDataProvider<SendWithIdRequest> {
|
||||
sends$: Observable<Send[]>;
|
||||
sendViews$: Observable<SendView[]>;
|
||||
|
||||
@@ -31,7 +34,11 @@ export abstract class SendService {
|
||||
* @throws Error if the new user key is null or undefined
|
||||
* @returns A list of user sends that have been re-encrypted with the new user key
|
||||
*/
|
||||
getRotatedKeys: (newUserKey: UserKey) => Promise<SendWithIdRequest[]>;
|
||||
getRotatedData: (
|
||||
originalUserKey: UserKey,
|
||||
newUserKey: UserKey,
|
||||
userId: UserId,
|
||||
) => Promise<SendWithIdRequest[]>;
|
||||
/**
|
||||
* @deprecated Do not call this, use the sends$ observable collection
|
||||
*/
|
||||
|
||||
@@ -400,8 +400,11 @@ describe("SendService", () => {
|
||||
expect(sends[0]).toMatchObject(testSendViewData("1", "Test Send"));
|
||||
});
|
||||
|
||||
describe("getRotatedKeys", () => {
|
||||
describe("getRotatedData", () => {
|
||||
const originalUserKey = new SymmetricCryptoKey(new Uint8Array(32)) as UserKey;
|
||||
const newUserKey = new SymmetricCryptoKey(new Uint8Array(32)) as UserKey;
|
||||
let encryptedKey: EncString;
|
||||
|
||||
beforeEach(() => {
|
||||
encryptService.decryptToBytes.mockResolvedValue(new Uint8Array(32));
|
||||
encryptedKey = new EncString("Re-encrypted Send Key");
|
||||
@@ -409,27 +412,30 @@ describe("SendService", () => {
|
||||
});
|
||||
|
||||
it("returns re-encrypted user sends", async () => {
|
||||
const newUserKey = new SymmetricCryptoKey(new Uint8Array(32)) as UserKey;
|
||||
const result = await sendService.getRotatedKeys(newUserKey);
|
||||
const result = await sendService.getRotatedData(originalUserKey, newUserKey, mockUserId);
|
||||
|
||||
expect(result).toMatchObject([{ id: "1", key: "Re-encrypted Send Key" }]);
|
||||
});
|
||||
|
||||
it("returns null if there are no sends", async () => {
|
||||
// FIXME: Verify that this floating promise is intentional. If it is, add an explanatory comment and ensure there is proper error handling.
|
||||
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
||||
sendService.replace(null);
|
||||
it("returns empty array if there are no sends", async () => {
|
||||
await sendService.replace(null);
|
||||
|
||||
await awaitAsync();
|
||||
|
||||
const newUserKey = new SymmetricCryptoKey(new Uint8Array(32)) as UserKey;
|
||||
const result = await sendService.getRotatedKeys(newUserKey);
|
||||
const result = await sendService.getRotatedData(originalUserKey, newUserKey, mockUserId);
|
||||
|
||||
expect(result).toEqual([]);
|
||||
});
|
||||
|
||||
it("throws if the original user key is null", async () => {
|
||||
await expect(sendService.getRotatedData(null, newUserKey, mockUserId)).rejects.toThrow(
|
||||
"Original user key is required for rotation.",
|
||||
);
|
||||
});
|
||||
|
||||
it("throws if the new user key is null", async () => {
|
||||
await expect(sendService.getRotatedKeys(null)).rejects.toThrowError(
|
||||
await expect(sendService.getRotatedData(originalUserKey, null, mockUserId)).rejects.toThrow(
|
||||
"New user key is required for rotation.",
|
||||
);
|
||||
});
|
||||
|
||||
@@ -9,6 +9,7 @@ import { Utils } from "../../../platform/misc/utils";
|
||||
import { EncArrayBuffer } from "../../../platform/models/domain/enc-array-buffer";
|
||||
import { EncString } from "../../../platform/models/domain/enc-string";
|
||||
import { SymmetricCryptoKey } from "../../../platform/models/domain/symmetric-crypto-key";
|
||||
import { UserId } from "../../../types/guid";
|
||||
import { UserKey } from "../../../types/key";
|
||||
import { SendType } from "../enums/send-type";
|
||||
import { SendData } from "../models/data/send.data";
|
||||
@@ -258,12 +259,17 @@ export class SendService implements InternalSendServiceAbstraction {
|
||||
await this.stateProvider.setEncryptedSends(sends);
|
||||
}
|
||||
|
||||
async getRotatedKeys(newUserKey: UserKey): Promise<SendWithIdRequest[]> {
|
||||
async getRotatedData(
|
||||
originalUserKey: UserKey,
|
||||
newUserKey: UserKey,
|
||||
userId: UserId,
|
||||
): Promise<SendWithIdRequest[]> {
|
||||
if (newUserKey == null) {
|
||||
throw new Error("New user key is required for rotation.");
|
||||
}
|
||||
|
||||
const originalUserKey = await this.cryptoService.getUserKey();
|
||||
if (originalUserKey == null) {
|
||||
throw new Error("Original user key is required for rotation.");
|
||||
}
|
||||
|
||||
const req = await firstValueFrom(
|
||||
this.sends$.pipe(
|
||||
|
||||
Reference in New Issue
Block a user