forked from bitwarden/clients
-
Notifications
You must be signed in to change notification settings - Fork 0
/
send.service.spec.ts
216 lines (172 loc) · 6.76 KB
/
send.service.spec.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
import { any, mock, MockProxy } from "jest-mock-extended";
import { BehaviorSubject, firstValueFrom } from "rxjs";
import { CryptoFunctionService } from "../../../platform/abstractions/crypto-function.service";
import { CryptoService } from "../../../platform/abstractions/crypto.service";
import { EncryptService } from "../../../platform/abstractions/encrypt.service";
import { I18nService } from "../../../platform/abstractions/i18n.service";
import { StateService } from "../../../platform/abstractions/state.service";
import { EncString } from "../../../platform/models/domain/enc-string";
import { SymmetricCryptoKey } from "../../../platform/models/domain/symmetric-crypto-key";
import { ContainerService } from "../../../platform/services/container.service";
import { UserKey } from "../../../types/key";
import { SendData } from "../models/data/send.data";
import { Send } from "../models/domain/send";
import { SendView } from "../models/view/send.view";
import { SendService } from "./send.service";
describe("SendService", () => {
const cryptoService = mock<CryptoService>();
const i18nService = mock<I18nService>();
const cryptoFunctionService = mock<CryptoFunctionService>();
const encryptService = mock<EncryptService>();
let sendService: SendService;
let stateService: MockProxy<StateService>;
let activeAccount: BehaviorSubject<string>;
let activeAccountUnlocked: BehaviorSubject<boolean>;
beforeEach(() => {
activeAccount = new BehaviorSubject("123");
activeAccountUnlocked = new BehaviorSubject(true);
stateService = mock<StateService>();
stateService.activeAccount$ = activeAccount;
stateService.activeAccountUnlocked$ = activeAccountUnlocked;
(window as any).bitwardenContainerService = new ContainerService(cryptoService, encryptService);
stateService.getEncryptedSends.calledWith(any()).mockResolvedValue({
"1": sendData("1", "Test Send"),
});
stateService.getDecryptedSends
.calledWith(any())
.mockResolvedValue([sendView("1", "Test Send")]);
sendService = new SendService(cryptoService, i18nService, cryptoFunctionService, stateService);
});
afterEach(() => {
activeAccount.complete();
activeAccountUnlocked.complete();
});
describe("get", () => {
it("exists", async () => {
const result = sendService.get("1");
expect(result).toEqual(send("1", "Test Send"));
});
it("does not exist", async () => {
const result = sendService.get("2");
expect(result).toBe(undefined);
});
});
it("getAll", async () => {
const sends = await sendService.getAll();
const send1 = sends[0];
expect(sends).toHaveLength(1);
expect(send1).toEqual(send("1", "Test Send"));
});
describe("getFromState", () => {
it("exists", async () => {
const result = await sendService.getFromState("1");
expect(result).toEqual(send("1", "Test Send"));
});
it("does not exist", async () => {
const result = await sendService.getFromState("2");
expect(result).toBe(null);
});
});
it("getAllDecryptedFromState", async () => {
await sendService.getAllDecryptedFromState();
expect(stateService.getDecryptedSends).toHaveBeenCalledTimes(1);
});
describe("getRotatedKeys", () => {
let encryptedKey: EncString;
beforeEach(() => {
cryptoService.decryptToBytes.mockResolvedValue(new Uint8Array(32));
encryptedKey = new EncString("Re-encrypted Send Key");
cryptoService.encrypt.mockResolvedValue(encryptedKey);
});
it("returns re-encrypted user sends", async () => {
const newUserKey = new SymmetricCryptoKey(new Uint8Array(32)) as UserKey;
const result = await sendService.getRotatedKeys(newUserKey);
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);
const newUserKey = new SymmetricCryptoKey(new Uint8Array(32)) as UserKey;
const result = await sendService.getRotatedKeys(newUserKey);
expect(result).toEqual([]);
});
it("throws if the new user key is null", async () => {
await expect(sendService.getRotatedKeys(null)).rejects.toThrowError(
"New user key is required for rotation.",
);
});
});
// InternalSendService
it("upsert", async () => {
await sendService.upsert(sendData("2", "Test 2"));
expect(await firstValueFrom(sendService.sends$)).toEqual([
send("1", "Test Send"),
send("2", "Test 2"),
]);
});
it("replace", async () => {
await sendService.replace({ "2": sendData("2", "test 2") });
expect(await firstValueFrom(sendService.sends$)).toEqual([send("2", "test 2")]);
});
it("clear", async () => {
await sendService.clear();
expect(await firstValueFrom(sendService.sends$)).toEqual([]);
});
describe("delete", () => {
it("exists", async () => {
await sendService.delete("1");
expect(stateService.getEncryptedSends).toHaveBeenCalledTimes(2);
expect(stateService.setEncryptedSends).toHaveBeenCalledTimes(1);
});
it("does not exist", 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.delete("1");
expect(stateService.getEncryptedSends).toHaveBeenCalledTimes(2);
});
});
// Send object helper functions
function sendData(id: string, name: string) {
const data = new SendData({} as any);
data.id = id;
data.name = name;
data.disabled = false;
data.accessCount = 2;
data.accessId = "1";
data.revisionDate = null;
data.expirationDate = null;
data.deletionDate = null;
data.notes = "Notes!!";
data.key = null;
return data;
}
function sendView(id: string, name: string) {
const data = new SendView({} as any);
data.id = id;
data.name = name;
data.disabled = false;
data.accessCount = 2;
data.accessId = "1";
data.revisionDate = null;
data.expirationDate = null;
data.deletionDate = null;
data.notes = "Notes!!";
data.key = null;
return data;
}
function send(id: string, name: string) {
const data = new Send({} as any);
data.id = id;
data.name = new EncString(name);
data.disabled = false;
data.accessCount = 2;
data.accessId = "1";
data.revisionDate = null;
data.expirationDate = null;
data.deletionDate = null;
data.notes = new EncString("Notes!!");
data.key = null;
return data;
}
});