1
0
mirror of https://github.com/bitwarden/browser synced 2026-01-27 14:53:44 +00:00

fix claude finding and add test coverage

This commit is contained in:
John Harrington
2026-01-22 11:14:30 -07:00
parent acb415340f
commit 849ef9ec1e
7 changed files with 675 additions and 9 deletions

View File

@@ -1025,6 +1025,7 @@ export default class MainBackground {
this.keyGenerationService,
this.sendStateProvider,
this.encryptService,
this.cryptoFunctionService,
);
this.sendApiService = new SendApiService(
this.apiService,

View File

@@ -605,6 +605,7 @@ export class ServiceContainer {
this.keyGenerationService,
this.sendStateProvider,
this.encryptService,
this.cryptoFunctionService,
);
this.cipherFileUploadService = new CipherFileUploadService(

View File

@@ -848,6 +848,7 @@ const safeProviders: SafeProvider[] = [
KeyGenerationService,
SendStateProviderAbstraction,
EncryptService,
CryptoFunctionServiceAbstraction,
],
}),
safeProvider({

View File

@@ -40,7 +40,8 @@ describe("Send", () => {
expirationDate: "2022-01-31T12:00:00.000Z",
deletionDate: "2022-01-31T12:00:00.000Z",
password: "password",
emails: null!,
emails: "",
emailHashes: "",
disabled: false,
hideEmail: true,
authType: AuthType.None,
@@ -69,6 +70,8 @@ describe("Send", () => {
expirationDate: null,
deletionDate: null,
password: undefined,
emails: null,
emailHashes: undefined,
disabled: undefined,
hideEmail: undefined,
});
@@ -94,7 +97,8 @@ describe("Send", () => {
expirationDate: new Date("2022-01-31T12:00:00.000Z"),
deletionDate: new Date("2022-01-31T12:00:00.000Z"),
password: "password",
emails: null!,
emails: null,
emailHashes: "",
disabled: false,
hideEmail: true,
authType: AuthType.None,
@@ -121,6 +125,7 @@ describe("Send", () => {
send.expirationDate = new Date("2022-01-31T12:00:00.000Z");
send.deletionDate = new Date("2022-01-31T12:00:00.000Z");
send.password = "password";
send.emails = null;
send.disabled = false;
send.hideEmail = true;
send.authType = AuthType.None;
@@ -130,6 +135,12 @@ describe("Send", () => {
encryptService.decryptBytes
.calledWith(send.key, userKey)
.mockResolvedValue(makeStaticByteArray(32));
encryptService.decryptString
.calledWith(send.name, "cryptoKey" as any)
.mockResolvedValue("name");
encryptService.decryptString
.calledWith(send.notes, "cryptoKey" as any)
.mockResolvedValue("notes");
keyService.makeSendKey.mockResolvedValue("cryptoKey" as any);
keyService.userKey$.calledWith(userId).mockReturnValue(of(userKey));
@@ -138,12 +149,6 @@ describe("Send", () => {
const view = await send.decrypt(userId);
expect(text.decrypt).toHaveBeenNthCalledWith(1, "cryptoKey");
expect(send.name.decrypt).toHaveBeenNthCalledWith(
1,
null,
"cryptoKey",
"Property: name; ObjectContext: No Domain Context",
);
expect(view).toMatchObject({
id: "id",
@@ -161,9 +166,265 @@ describe("Send", () => {
expirationDate: new Date("2022-01-31T12:00:00.000Z"),
deletionDate: new Date("2022-01-31T12:00:00.000Z"),
password: "password",
emails: [],
disabled: false,
hideEmail: true,
authType: AuthType.None,
});
});
describe("Email decryption", () => {
let encryptService: jest.Mocked<EncryptService>;
let keyService: jest.Mocked<KeyService>;
const userKey = new SymmetricCryptoKey(new Uint8Array(32)) as UserKey;
const userId = emptyGuid as UserId;
beforeEach(() => {
encryptService = mock<EncryptService>();
keyService = mock<KeyService>();
encryptService.decryptBytes.mockResolvedValue(makeStaticByteArray(32));
keyService.makeSendKey.mockResolvedValue("cryptoKey" as any);
keyService.userKey$.mockReturnValue(of(userKey));
(window as any).bitwardenContainerService = new ContainerService(keyService, encryptService);
});
it("should decrypt and parse single email", async () => {
const send = new Send();
send.id = "id";
send.type = SendType.Text;
send.name = mockEnc("name");
send.notes = mockEnc("notes");
send.key = mockEnc("key");
send.emails = mockEnc("test@example.com");
send.text = mock<SendText>();
send.text.decrypt = jest.fn().mockResolvedValue("textView" as any);
encryptService.decryptString.mockImplementation((encString, key) => {
if (encString === send.emails) {
return Promise.resolve("test@example.com");
}
if (encString === send.name) {
return Promise.resolve("name");
}
if (encString === send.notes) {
return Promise.resolve("notes");
}
return Promise.resolve("");
});
const view = await send.decrypt(userId);
expect(encryptService.decryptString).toHaveBeenCalledWith(send.emails, "cryptoKey");
expect(view.emails).toEqual(["test@example.com"]);
});
it("should decrypt and parse multiple emails", async () => {
const send = new Send();
send.id = "id";
send.type = SendType.Text;
send.name = mockEnc("name");
send.notes = mockEnc("notes");
send.key = mockEnc("key");
send.emails = mockEnc("test@example.com,user@test.com,admin@domain.com");
send.text = mock<SendText>();
send.text.decrypt = jest.fn().mockResolvedValue("textView" as any);
encryptService.decryptString.mockImplementation((encString, key) => {
if (encString === send.emails) {
return Promise.resolve("test@example.com,user@test.com,admin@domain.com");
}
if (encString === send.name) {
return Promise.resolve("name");
}
if (encString === send.notes) {
return Promise.resolve("notes");
}
return Promise.resolve("");
});
const view = await send.decrypt(userId);
expect(view.emails).toEqual(["test@example.com", "user@test.com", "admin@domain.com"]);
});
it("should trim whitespace from decrypted emails", async () => {
const send = new Send();
send.id = "id";
send.type = SendType.Text;
send.name = mockEnc("name");
send.notes = mockEnc("notes");
send.key = mockEnc("key");
send.emails = mockEnc(" test@example.com , user@test.com ");
send.text = mock<SendText>();
send.text.decrypt = jest.fn().mockResolvedValue("textView" as any);
encryptService.decryptString.mockImplementation((encString, key) => {
if (encString === send.emails) {
return Promise.resolve(" test@example.com , user@test.com ");
}
if (encString === send.name) {
return Promise.resolve("name");
}
if (encString === send.notes) {
return Promise.resolve("notes");
}
return Promise.resolve("");
});
const view = await send.decrypt(userId);
expect(view.emails).toEqual(["test@example.com", "user@test.com"]);
});
it("should return empty array when emails is null", async () => {
const send = new Send();
send.id = "id";
send.type = SendType.Text;
send.name = mockEnc("name");
send.notes = mockEnc("notes");
send.key = mockEnc("key");
send.emails = null;
send.text = mock<SendText>();
send.text.decrypt = jest.fn().mockResolvedValue("textView" as any);
const view = await send.decrypt(userId);
expect(view.emails).toEqual([]);
expect(encryptService.decryptString).not.toHaveBeenCalledWith(expect.anything(), "cryptoKey");
});
it("should return empty array when decrypted emails is empty string", async () => {
const send = new Send();
send.id = "id";
send.type = SendType.Text;
send.name = mockEnc("name");
send.notes = mockEnc("notes");
send.key = mockEnc("key");
send.emails = mockEnc("");
send.text = mock<SendText>();
send.text.decrypt = jest.fn().mockResolvedValue("textView" as any);
encryptService.decryptString.mockImplementation((encString, key) => {
if (encString === send.emails) {
return Promise.resolve("");
}
if (encString === send.name) {
return Promise.resolve("name");
}
if (encString === send.notes) {
return Promise.resolve("notes");
}
return Promise.resolve("");
});
const view = await send.decrypt(userId);
expect(view.emails).toEqual([]);
});
it("should return empty array when decrypted emails is null", async () => {
const send = new Send();
send.id = "id";
send.type = SendType.Text;
send.name = mockEnc("name");
send.notes = mockEnc("notes");
send.key = mockEnc("key");
send.emails = mockEnc("something");
send.text = mock<SendText>();
send.text.decrypt = jest.fn().mockResolvedValue("textView" as any);
encryptService.decryptString.mockImplementation((encString, key) => {
if (encString === send.emails) {
return Promise.resolve(null);
}
if (encString === send.name) {
return Promise.resolve("name");
}
if (encString === send.notes) {
return Promise.resolve("notes");
}
return Promise.resolve("");
});
const view = await send.decrypt(userId);
expect(view.emails).toEqual([]);
});
});
describe("Null handling for name and notes decryption", () => {
let encryptService: jest.Mocked<EncryptService>;
let keyService: jest.Mocked<KeyService>;
const userKey = new SymmetricCryptoKey(new Uint8Array(32)) as UserKey;
const userId = emptyGuid as UserId;
beforeEach(() => {
encryptService = mock<EncryptService>();
keyService = mock<KeyService>();
encryptService.decryptBytes.mockResolvedValue(makeStaticByteArray(32));
keyService.makeSendKey.mockResolvedValue("cryptoKey" as any);
keyService.userKey$.mockReturnValue(of(userKey));
(window as any).bitwardenContainerService = new ContainerService(keyService, encryptService);
});
it("should return null for name when name is null", async () => {
const send = new Send();
send.id = "id";
send.type = SendType.Text;
send.name = null;
send.notes = mockEnc("notes");
send.key = mockEnc("key");
send.emails = null;
send.text = mock<SendText>();
send.text.decrypt = jest.fn().mockResolvedValue("textView" as any);
const view = await send.decrypt(userId);
expect(view.name).toBeNull();
expect(encryptService.decryptString).not.toHaveBeenCalledWith(null, expect.anything());
});
it("should return null for notes when notes is null", async () => {
const send = new Send();
send.id = "id";
send.type = SendType.Text;
send.name = mockEnc("name");
send.notes = null;
send.key = mockEnc("key");
send.emails = null;
send.text = mock<SendText>();
send.text.decrypt = jest.fn().mockResolvedValue("textView" as any);
const view = await send.decrypt(userId);
expect(view.notes).toBeNull();
});
it("should decrypt non-null name and notes", async () => {
const send = new Send();
send.id = "id";
send.type = SendType.Text;
send.name = mockEnc("Test Name");
send.notes = mockEnc("Test Notes");
send.key = mockEnc("key");
send.emails = null;
send.text = mock<SendText>();
send.text.decrypt = jest.fn().mockResolvedValue("textView" as any);
encryptService.decryptString.mockImplementation((encString, key) => {
if (encString === send.name) {
return Promise.resolve("Test Name");
}
if (encString === send.notes) {
return Promise.resolve("Test Notes");
}
return Promise.resolve("");
});
const view = await send.decrypt(userId);
expect(view.name).toBe("Test Name");
expect(view.notes).toBe("Test Notes");
});
});
});

View File

@@ -0,0 +1,193 @@
import { Send } from "@bitwarden/common/tools/send/models/domain/send";
import { EncString } from "../../../../key-management/crypto/models/enc-string";
import { SendType } from "../../types/send-type";
import { SendText } from "../domain/send-text";
import { SendRequest } from "./send.request";
describe("SendRequest", () => {
describe("constructor", () => {
it("should populate emails with encrypted string from Send.emails", () => {
const send = new Send();
send.type = SendType.Text;
send.name = new EncString("encryptedName");
send.notes = new EncString("encryptedNotes");
send.key = new EncString("encryptedKey");
send.emails = new EncString("encryptedEmailList");
send.emailHashes = "HASH1,HASH2,HASH3";
send.disabled = false;
send.hideEmail = false;
send.text = new SendText();
send.text.text = new EncString("text");
send.text.hidden = false;
const request = new SendRequest(send);
expect(request.emails).toBe("encryptedEmailList");
});
it("should populate emailHashes from Send.emailHashes", () => {
const send = new Send();
send.type = SendType.Text;
send.name = new EncString("encryptedName");
send.notes = new EncString("encryptedNotes");
send.key = new EncString("encryptedKey");
send.emails = new EncString("encryptedEmailList");
send.emailHashes = "HASH1,HASH2,HASH3";
send.disabled = false;
send.hideEmail = false;
send.text = new SendText();
send.text.text = new EncString("text");
send.text.hidden = false;
const request = new SendRequest(send);
expect(request.emailHashes).toBe("HASH1,HASH2,HASH3");
});
it("should set emails to null when Send.emails is null", () => {
const send = new Send();
send.type = SendType.Text;
send.name = new EncString("encryptedName");
send.notes = new EncString("encryptedNotes");
send.key = new EncString("encryptedKey");
send.emails = null;
send.emailHashes = "";
send.disabled = false;
send.hideEmail = false;
send.text = new SendText();
send.text.text = new EncString("text");
send.text.hidden = false;
const request = new SendRequest(send);
expect(request.emails).toBeNull();
expect(request.emailHashes).toBe("");
});
it("should handle empty emailHashes", () => {
const send = new Send();
send.type = SendType.Text;
send.name = new EncString("encryptedName");
send.key = new EncString("encryptedKey");
send.emails = null;
send.emailHashes = "";
send.disabled = false;
send.hideEmail = false;
send.text = new SendText();
send.text.text = new EncString("text");
send.text.hidden = false;
const request = new SendRequest(send);
expect(request.emailHashes).toBe("");
});
it("should not expose plaintext emails", () => {
const send = new Send();
send.type = SendType.Text;
send.name = new EncString("encryptedName");
send.key = new EncString("encryptedKey");
send.emails = new EncString("2.encrypted|emaildata|here");
send.emailHashes = "ABC123,DEF456";
send.disabled = false;
send.hideEmail = false;
send.text = new SendText();
send.text.text = new EncString("text");
send.text.hidden = false;
const request = new SendRequest(send);
// Ensure the request contains the encrypted string format, not plaintext
expect(request.emails).toBe("2.encrypted|emaildata|here");
expect(request.emails).not.toContain("@");
});
it("should handle name being null", () => {
const send = new Send();
send.type = SendType.Text;
send.name = null;
send.notes = new EncString("encryptedNotes");
send.key = new EncString("encryptedKey");
send.emails = null;
send.emailHashes = "";
send.disabled = false;
send.hideEmail = false;
send.text = new SendText();
send.text.text = new EncString("text");
send.text.hidden = false;
const request = new SendRequest(send);
expect(request.name).toBeNull();
});
it("should handle notes being null", () => {
const send = new Send();
send.type = SendType.Text;
send.name = new EncString("encryptedName");
send.notes = null;
send.key = new EncString("encryptedKey");
send.emails = null;
send.emailHashes = "";
send.disabled = false;
send.hideEmail = false;
send.text = new SendText();
send.text.text = new EncString("text");
send.text.hidden = false;
const request = new SendRequest(send);
expect(request.notes).toBeNull();
});
it("should include fileLength when provided for text send", () => {
const send = new Send();
send.type = SendType.Text;
send.name = new EncString("encryptedName");
send.key = new EncString("encryptedKey");
send.emails = null;
send.emailHashes = "";
send.disabled = false;
send.hideEmail = false;
send.text = new SendText();
send.text.text = new EncString("text");
send.text.hidden = false;
const request = new SendRequest(send, 1024);
expect(request.fileLength).toBe(1024);
});
});
describe("acceptance criteria validation", () => {
it("should create request with encrypted emails and plaintext emailHashes", () => {
// Setup: A Send with encrypted emails and computed hashes
const send = new Send();
send.type = SendType.Text;
send.name = new EncString("encryptedName");
send.key = new EncString("encryptedKey");
send.emails = new EncString("2.encryptedEmailString|data");
send.emailHashes = "A1B2C3D4,E5F6G7H8"; // Plaintext hashes
send.disabled = false;
send.hideEmail = false;
send.text = new SendText();
send.text.text = new EncString("text");
send.text.hidden = false;
// Act: Create the request
const request = new SendRequest(send);
// Assert: Verify acceptance criteria
// 1. emails field contains encrypted value
expect(request.emails).toBe("2.encryptedEmailString|data");
expect(request.emails).toContain("encrypted");
// 2. emailHashes field contains plaintext comma-separated hashes
expect(request.emailHashes).toBe("A1B2C3D4,E5F6G7H8");
expect(request.emailHashes).not.toContain("encrypted");
expect(request.emailHashes.split(",")).toHaveLength(2);
});
});
});

View File

@@ -1,6 +1,7 @@
import { mock } from "jest-mock-extended";
import { firstValueFrom, of } from "rxjs";
import { CryptoFunctionService } from "@bitwarden/common/key-management/crypto/abstractions/crypto-function.service";
// This import has been flagged as unallowed for this class. It may be involved in a circular dependency loop.
// eslint-disable-next-line no-restricted-imports
import { KeyService } from "@bitwarden/key-management";
@@ -29,6 +30,7 @@ import { SendTextApi } from "../models/api/send-text.api";
import { SendFileData } from "../models/data/send-file.data";
import { SendTextData } from "../models/data/send-text.data";
import { SendData } from "../models/data/send.data";
import { SendTextView } from "../models/view/send-text.view";
import { SendView } from "../models/view/send.view";
import { SendType } from "../types/send-type";
@@ -48,7 +50,7 @@ describe("SendService", () => {
const keyGenerationService = mock<KeyGenerationService>();
const encryptService = mock<EncryptService>();
const environmentService = mock<EnvironmentService>();
const cryptoFunctionService = mock<CryptoFunctionService>();
let sendStateProvider: SendStateProvider;
let sendService: SendService;
@@ -94,6 +96,7 @@ describe("SendService", () => {
keyGenerationService,
sendStateProvider,
encryptService,
cryptoFunctionService,
);
});
@@ -573,4 +576,203 @@ describe("SendService", () => {
expect(sendsAfterDelete.length).toBe(0);
});
});
describe("encrypt", () => {
let sendView: SendView;
const userKey = new SymmetricCryptoKey(new Uint8Array(32)) as UserKey;
const mockCryptoKey = new SymmetricCryptoKey(new Uint8Array(32));
beforeEach(() => {
sendView = new SendView();
sendView.id = "sendId";
sendView.type = SendType.Text;
sendView.name = "Test Send";
sendView.notes = "Test Notes";
const sendTextView = new SendTextView();
sendTextView.text = "test text";
sendTextView.hidden = false;
sendView.text = sendTextView;
sendView.key = new Uint8Array(16);
sendView.cryptoKey = mockCryptoKey;
sendView.maxAccessCount = 5;
sendView.disabled = false;
sendView.hideEmail = false;
sendView.deletionDate = new Date("2024-12-31");
sendView.expirationDate = null;
keyService.userKey$.mockReturnValue(of(userKey));
keyService.makeSendKey.mockResolvedValue(mockCryptoKey);
encryptService.encryptBytes.mockResolvedValue({ encryptedString: "encryptedKey" } as any);
encryptService.encryptString.mockResolvedValue({ encryptedString: "encrypted" } as any);
});
describe("email encryption", () => {
beforeEach(() => {
cryptoFunctionService.hash.mockClear();
});
it("should encrypt emails when email list is provided", async () => {
sendView.emails = ["test@example.com", "user@test.com"];
cryptoFunctionService.hash.mockResolvedValue(new Uint8Array([0xab, 0xcd]));
const [send] = await sendService.encrypt(sendView, null, null);
expect(encryptService.encryptString).toHaveBeenCalledWith(
"test@example.com,user@test.com",
mockCryptoKey,
);
expect(send.emails).toEqual({ encryptedString: "encrypted" });
expect(send.password).toBeNull();
});
it("should set emails to null when email list is empty", async () => {
sendView.emails = [];
const [send] = await sendService.encrypt(sendView, null, null);
expect(send.emails).toBeNull();
expect(send.emailHashes).toBe("");
});
it("should set emails to null when email list is null", async () => {
sendView.emails = null;
const [send] = await sendService.encrypt(sendView, null, null);
expect(send.emails).toBeNull();
expect(send.emailHashes).toBe("");
});
it("should set emails to null when email list is undefined", async () => {
sendView.emails = undefined;
const [send] = await sendService.encrypt(sendView, null, null);
expect(send.emails).toBeNull();
expect(send.emailHashes).toBe("");
});
});
describe("email hashing", () => {
beforeEach(() => {
cryptoFunctionService.hash.mockClear();
});
it("should hash emails using SHA-256 and return uppercase hex", async () => {
sendView.emails = ["test@example.com"];
const mockHash = new Uint8Array([0xab, 0xcd, 0xef]);
cryptoFunctionService.hash.mockResolvedValue(mockHash);
const [send] = await sendService.encrypt(sendView, null, null);
expect(cryptoFunctionService.hash).toHaveBeenCalledWith("test@example.com", "sha256");
expect(send.emailHashes).toBe("ABCDEF");
});
it("should hash multiple emails and return comma-separated hashes", async () => {
sendView.emails = ["test@example.com", "user@test.com"];
const mockHash1 = new Uint8Array([0xab, 0xcd]);
const mockHash2 = new Uint8Array([0x12, 0x34]);
cryptoFunctionService.hash
.mockResolvedValueOnce(mockHash1)
.mockResolvedValueOnce(mockHash2);
const [send] = await sendService.encrypt(sendView, null, null);
expect(cryptoFunctionService.hash).toHaveBeenCalledWith("test@example.com", "sha256");
expect(cryptoFunctionService.hash).toHaveBeenCalledWith("user@test.com", "sha256");
expect(send.emailHashes).toBe("ABCD,1234");
});
it("should trim and lowercase emails before hashing", async () => {
sendView.emails = [" Test@Example.COM ", "USER@test.com"];
const mockHash = new Uint8Array([0xff]);
cryptoFunctionService.hash.mockResolvedValue(mockHash);
await sendService.encrypt(sendView, null, null);
expect(cryptoFunctionService.hash).toHaveBeenCalledWith("test@example.com", "sha256");
expect(cryptoFunctionService.hash).toHaveBeenCalledWith("user@test.com", "sha256");
});
it("should set emailHashes to empty string when no emails", async () => {
sendView.emails = [];
const [send] = await sendService.encrypt(sendView, null, null);
expect(send.emailHashes).toBe("");
expect(cryptoFunctionService.hash).not.toHaveBeenCalled();
});
it("should handle single email correctly", async () => {
sendView.emails = ["single@test.com"];
const mockHash = new Uint8Array([0xa1, 0xb2, 0xc3]);
cryptoFunctionService.hash.mockResolvedValue(mockHash);
const [send] = await sendService.encrypt(sendView, null, null);
expect(send.emailHashes).toBe("A1B2C3");
});
});
describe("emails and password mutual exclusivity", () => {
it("should set password to null when emails are provided", async () => {
sendView.emails = ["test@example.com"];
const [send] = await sendService.encrypt(sendView, null, "password123");
expect(send.emails).toBeDefined();
expect(send.password).toBeNull();
});
it("should set password when no emails are provided", async () => {
sendView.emails = [];
keyGenerationService.deriveKeyFromPassword.mockResolvedValue({
keyB64: "hashedPassword",
} as any);
const [send] = await sendService.encrypt(sendView, null, "password123");
expect(send.emails).toBeNull();
expect(send.password).toBe("hashedPassword");
});
});
describe("null handling for name and notes", () => {
it("should handle null name correctly", async () => {
sendView.name = null;
sendView.emails = [];
const [send] = await sendService.encrypt(sendView, null, null);
expect(send.name).toBeNull();
});
it("should handle null notes correctly", async () => {
sendView.notes = null;
sendView.emails = [];
const [send] = await sendService.encrypt(sendView, null, null);
expect(send.notes).toBeNull();
});
it("should encrypt non-null name and notes", async () => {
sendView.name = "Test Name";
sendView.notes = "Test Notes";
sendView.emails = [];
const [send] = await sendService.encrypt(sendView, null, null);
expect(encryptService.encryptString).toHaveBeenCalledWith("Test Name", mockCryptoKey);
expect(encryptService.encryptString).toHaveBeenCalledWith("Test Notes", mockCryptoKey);
expect(send.name).toEqual({ encryptedString: "encrypted" });
expect(send.notes).toEqual({ encryptedString: "encrypted" });
});
});
});
});

View File

@@ -20,6 +20,7 @@ export function testSendViewData(id: string, name: string) {
data.deletionDate = null;
data.notes = "Notes!!";
data.key = null;
data.emails = [];
return data;
}
@@ -39,6 +40,8 @@ export function createSendData(value: Partial<SendData> = {}) {
expirationDate: "2024-09-04",
deletionDate: "2024-09-04",
password: "password",
emails: "",
emailHashes: "",
disabled: false,
hideEmail: false,
};
@@ -62,6 +65,8 @@ export function testSendData(id: string, name: string) {
data.deletionDate = null;
data.notes = "Notes!!";
data.key = null;
data.emails = "";
data.emailHashes = "";
return data;
}
@@ -77,5 +82,7 @@ export function testSend(id: string, name: string) {
data.deletionDate = null;
data.notes = new EncString("Notes!!");
data.key = null;
data.emails = null;
data.emailHashes = "";
return data;
}