cojson 0.13.28 → 0.13.29
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.turbo/turbo-build.log +1 -1
- package/CHANGELOG.md +8 -0
- package/dist/coValueCore/coValueCore.d.ts +1 -0
- package/dist/coValueCore/coValueCore.d.ts.map +1 -1
- package/dist/coValueCore/coValueCore.js +13 -1
- package/dist/coValueCore/coValueCore.js.map +1 -1
- package/dist/coValues/group.d.ts.map +1 -1
- package/dist/coValues/group.js +1 -1
- package/dist/coValues/group.js.map +1 -1
- package/dist/crypto/PureJSCrypto.d.ts +1 -1
- package/dist/crypto/PureJSCrypto.js +3 -3
- package/dist/crypto/PureJSCrypto.js.map +1 -1
- package/dist/exports.d.ts +1 -0
- package/dist/exports.d.ts.map +1 -1
- package/dist/exports.js +3 -0
- package/dist/exports.js.map +1 -1
- package/dist/localNode.d.ts.map +1 -1
- package/dist/localNode.js +7 -1
- package/dist/localNode.js.map +1 -1
- package/dist/tests/crypto.test.js +5 -5
- package/dist/tests/crypto.test.js.map +1 -1
- package/dist/tests/group.addMember.test.d.ts +2 -0
- package/dist/tests/group.addMember.test.d.ts.map +1 -0
- package/dist/tests/group.addMember.test.js +272 -0
- package/dist/tests/group.addMember.test.js.map +1 -0
- package/dist/tests/testUtils.d.ts +1 -1
- package/dist/tests/testUtils.d.ts.map +1 -1
- package/package.json +4 -4
- package/src/coValueCore/coValueCore.ts +15 -1
- package/src/coValues/group.ts +3 -6
- package/src/crypto/PureJSCrypto.ts +3 -3
- package/src/exports.ts +3 -0
- package/src/localNode.ts +11 -3
- package/src/tests/crypto.test.ts +5 -5
- package/src/tests/group.addMember.test.ts +432 -0
- package/src/tests/testUtils.ts +6 -6
|
@@ -0,0 +1,432 @@
|
|
|
1
|
+
import { beforeEach, describe, expect, test } from "vitest";
|
|
2
|
+
import { expectMap } from "../coValue.js";
|
|
3
|
+
import {
|
|
4
|
+
SyncMessagesLog,
|
|
5
|
+
loadCoValueOrFail,
|
|
6
|
+
setupTestAccount,
|
|
7
|
+
setupTestNode,
|
|
8
|
+
waitFor,
|
|
9
|
+
} from "./testUtils.js";
|
|
10
|
+
|
|
11
|
+
beforeEach(async () => {
|
|
12
|
+
SyncMessagesLog.clear();
|
|
13
|
+
setupTestNode({ isSyncServer: true });
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
describe("Group.addMember", () => {
|
|
17
|
+
test("an admin should be able to grant read access", async () => {
|
|
18
|
+
const admin = await setupTestAccount({
|
|
19
|
+
connected: true,
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
const reader = await setupTestAccount({
|
|
23
|
+
connected: true,
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
const group = admin.node.createGroup();
|
|
27
|
+
const person = group.createMap({
|
|
28
|
+
name: "John Doe",
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
const personOnReaderNode = await loadCoValueOrFail(reader.node, person.id);
|
|
32
|
+
|
|
33
|
+
expect(personOnReaderNode.get("name")).toEqual(undefined);
|
|
34
|
+
|
|
35
|
+
const readerOnAdminNode = await loadCoValueOrFail(
|
|
36
|
+
admin.node,
|
|
37
|
+
reader.accountID,
|
|
38
|
+
);
|
|
39
|
+
group.addMember(readerOnAdminNode, "reader");
|
|
40
|
+
|
|
41
|
+
expect(group.roleOf(reader.accountID)).toEqual("reader");
|
|
42
|
+
|
|
43
|
+
await waitFor(() => {
|
|
44
|
+
expect(
|
|
45
|
+
expectMap(personOnReaderNode.core.getCurrentContent()).get("name"),
|
|
46
|
+
).toEqual("John Doe");
|
|
47
|
+
});
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
test("an admin should be able to grant write access", async () => {
|
|
51
|
+
const admin = await setupTestAccount({
|
|
52
|
+
connected: true,
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
const writer = await setupTestAccount({
|
|
56
|
+
connected: true,
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
const group = admin.node.createGroup();
|
|
60
|
+
const person = group.createMap({
|
|
61
|
+
name: "John Doe",
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
const personOnWriterNode = await loadCoValueOrFail(writer.node, person.id);
|
|
65
|
+
|
|
66
|
+
expect(personOnWriterNode.get("name")).toEqual(undefined);
|
|
67
|
+
|
|
68
|
+
const writerOnAdminNode = await loadCoValueOrFail(
|
|
69
|
+
admin.node,
|
|
70
|
+
writer.accountID,
|
|
71
|
+
);
|
|
72
|
+
group.addMember(writerOnAdminNode, "writer");
|
|
73
|
+
expect(group.roleOf(writer.accountID)).toEqual("writer");
|
|
74
|
+
|
|
75
|
+
await waitFor(() => {
|
|
76
|
+
expect(
|
|
77
|
+
expectMap(personOnWriterNode.core.getCurrentContent()).get("name"),
|
|
78
|
+
).toEqual("John Doe");
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
personOnWriterNode.set("name", "Jane Doe");
|
|
82
|
+
expect(personOnWriterNode.get("name")).toEqual("Jane Doe");
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
test("an admin should be able to grant writeOnly access", async () => {
|
|
86
|
+
const admin = await setupTestAccount({
|
|
87
|
+
connected: true,
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
const writeOnlyUser = await setupTestAccount({
|
|
91
|
+
connected: true,
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
const group = admin.node.createGroup();
|
|
95
|
+
const person = group.createMap({
|
|
96
|
+
name: "John Doe",
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
const writeOnlyUserOnAdminNode = await loadCoValueOrFail(
|
|
100
|
+
admin.node,
|
|
101
|
+
writeOnlyUser.accountID,
|
|
102
|
+
);
|
|
103
|
+
group.addMember(writeOnlyUserOnAdminNode, "writeOnly");
|
|
104
|
+
expect(group.roleOf(writeOnlyUser.accountID)).toEqual("writeOnly");
|
|
105
|
+
const personOnWriteOnlyNode = await loadCoValueOrFail(
|
|
106
|
+
writeOnlyUser.node,
|
|
107
|
+
person.id,
|
|
108
|
+
);
|
|
109
|
+
|
|
110
|
+
// Should not be able to read
|
|
111
|
+
expect(personOnWriteOnlyNode.get("name")).toEqual(undefined);
|
|
112
|
+
|
|
113
|
+
// Should be able to write
|
|
114
|
+
personOnWriteOnlyNode.set("name", "Jane Doe");
|
|
115
|
+
|
|
116
|
+
expect(personOnWriteOnlyNode.get("name")).toEqual("Jane Doe");
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
test("an admin should be able to grant admin access", async () => {
|
|
120
|
+
const admin = await setupTestAccount({
|
|
121
|
+
connected: true,
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
const otherAdmin = await setupTestAccount({
|
|
125
|
+
connected: true,
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
const reader = await setupTestAccount({
|
|
129
|
+
connected: true,
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
const group = admin.node.createGroup();
|
|
133
|
+
const person = group.createMap({
|
|
134
|
+
name: "John Doe",
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
const otherAdminOnAdminNode = await loadCoValueOrFail(
|
|
138
|
+
admin.node,
|
|
139
|
+
otherAdmin.accountID,
|
|
140
|
+
);
|
|
141
|
+
group.addMember(otherAdminOnAdminNode, "admin");
|
|
142
|
+
|
|
143
|
+
const personOnReaderNode = await loadCoValueOrFail(reader.node, person.id);
|
|
144
|
+
|
|
145
|
+
expect(personOnReaderNode.get("name")).toEqual(undefined);
|
|
146
|
+
|
|
147
|
+
const readerOnOtherAdminNode = await loadCoValueOrFail(
|
|
148
|
+
otherAdmin.node,
|
|
149
|
+
reader.accountID,
|
|
150
|
+
);
|
|
151
|
+
group.addMember(readerOnOtherAdminNode, "reader");
|
|
152
|
+
|
|
153
|
+
await waitFor(() => {
|
|
154
|
+
expect(
|
|
155
|
+
expectMap(personOnReaderNode.core.getCurrentContent()).get("name"),
|
|
156
|
+
).toEqual("John Doe");
|
|
157
|
+
});
|
|
158
|
+
});
|
|
159
|
+
|
|
160
|
+
test("an admin should be able downgrade a writer to reader", async () => {
|
|
161
|
+
const admin = await setupTestAccount({
|
|
162
|
+
connected: true,
|
|
163
|
+
});
|
|
164
|
+
|
|
165
|
+
const writer = await setupTestAccount({
|
|
166
|
+
connected: true,
|
|
167
|
+
});
|
|
168
|
+
|
|
169
|
+
const group = admin.node.createGroup();
|
|
170
|
+
const person = group.createMap({
|
|
171
|
+
name: "John Doe",
|
|
172
|
+
});
|
|
173
|
+
|
|
174
|
+
const writerOnAdminNode = await loadCoValueOrFail(
|
|
175
|
+
admin.node,
|
|
176
|
+
writer.accountID,
|
|
177
|
+
);
|
|
178
|
+
group.addMember(writerOnAdminNode, "writer");
|
|
179
|
+
group.addMember(writerOnAdminNode, "reader");
|
|
180
|
+
|
|
181
|
+
expect(group.roleOf(writer.accountID)).toEqual("reader");
|
|
182
|
+
|
|
183
|
+
// Verify writer can read and write
|
|
184
|
+
const personOnWriterNode = await loadCoValueOrFail(writer.node, person.id);
|
|
185
|
+
|
|
186
|
+
// Should not be able to write
|
|
187
|
+
personOnWriterNode.set("name", "Jane Doe");
|
|
188
|
+
|
|
189
|
+
expect(personOnWriterNode.get("name")).toEqual("John Doe");
|
|
190
|
+
});
|
|
191
|
+
|
|
192
|
+
test("an admin should be able downgrade a reader to writeOnly", async () => {
|
|
193
|
+
const admin = await setupTestAccount({
|
|
194
|
+
connected: true,
|
|
195
|
+
});
|
|
196
|
+
|
|
197
|
+
const reader = await setupTestAccount({
|
|
198
|
+
connected: true,
|
|
199
|
+
});
|
|
200
|
+
|
|
201
|
+
const group = admin.node.createGroup();
|
|
202
|
+
|
|
203
|
+
const readerOnAdminNode = await loadCoValueOrFail(
|
|
204
|
+
admin.node,
|
|
205
|
+
reader.accountID,
|
|
206
|
+
);
|
|
207
|
+
group.addMember(readerOnAdminNode, "reader");
|
|
208
|
+
group.addMember(readerOnAdminNode, "writeOnly");
|
|
209
|
+
|
|
210
|
+
expect(group.roleOf(reader.accountID)).toEqual("writeOnly");
|
|
211
|
+
|
|
212
|
+
const person = group.createMap({
|
|
213
|
+
name: "John Doe",
|
|
214
|
+
});
|
|
215
|
+
|
|
216
|
+
// Verify reader can read
|
|
217
|
+
const personOnReaderNode = await loadCoValueOrFail(reader.node, person.id);
|
|
218
|
+
|
|
219
|
+
expect(personOnReaderNode.get("name")).toEqual(undefined);
|
|
220
|
+
});
|
|
221
|
+
|
|
222
|
+
test("an admin should not be able downgrade an admin", async () => {
|
|
223
|
+
const admin = await setupTestAccount({
|
|
224
|
+
connected: true,
|
|
225
|
+
});
|
|
226
|
+
|
|
227
|
+
const otherAdmin = await setupTestAccount({
|
|
228
|
+
connected: true,
|
|
229
|
+
});
|
|
230
|
+
|
|
231
|
+
const group = admin.node.createGroup();
|
|
232
|
+
const person = group.createMap({
|
|
233
|
+
name: "John Doe",
|
|
234
|
+
});
|
|
235
|
+
|
|
236
|
+
const otherAdminOnAdminNode = await loadCoValueOrFail(
|
|
237
|
+
admin.node,
|
|
238
|
+
otherAdmin.accountID,
|
|
239
|
+
);
|
|
240
|
+
group.addMember(otherAdminOnAdminNode, "admin");
|
|
241
|
+
|
|
242
|
+
// Try to downgrade other admin
|
|
243
|
+
try {
|
|
244
|
+
group.addMember(otherAdminOnAdminNode, "writer");
|
|
245
|
+
} catch (e) {
|
|
246
|
+
expect(e).toBeDefined();
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
expect(group.roleOf(otherAdmin.accountID)).toEqual("admin");
|
|
250
|
+
|
|
251
|
+
// Verify other admin still has admin access by adding a new member
|
|
252
|
+
const reader = await setupTestAccount({
|
|
253
|
+
connected: true,
|
|
254
|
+
});
|
|
255
|
+
|
|
256
|
+
const readerOnOtherAdminNode = await loadCoValueOrFail(
|
|
257
|
+
otherAdmin.node,
|
|
258
|
+
reader.accountID,
|
|
259
|
+
);
|
|
260
|
+
group.addMember(readerOnOtherAdminNode, "reader");
|
|
261
|
+
|
|
262
|
+
const personOnReaderNode = await loadCoValueOrFail(reader.node, person.id);
|
|
263
|
+
|
|
264
|
+
await waitFor(() => {
|
|
265
|
+
expect(
|
|
266
|
+
expectMap(personOnReaderNode.core.getCurrentContent()).get("name"),
|
|
267
|
+
).toEqual("John Doe");
|
|
268
|
+
});
|
|
269
|
+
});
|
|
270
|
+
|
|
271
|
+
test("an admin should be able downgrade themselves", async () => {
|
|
272
|
+
const admin = await setupTestAccount({
|
|
273
|
+
connected: true,
|
|
274
|
+
});
|
|
275
|
+
|
|
276
|
+
const group = admin.node.createGroup();
|
|
277
|
+
|
|
278
|
+
const account = await loadCoValueOrFail(admin.node, admin.accountID);
|
|
279
|
+
|
|
280
|
+
// Downgrade self to writer
|
|
281
|
+
group.addMember(account, "writer");
|
|
282
|
+
expect(group.roleOf(admin.accountID)).toEqual("writer");
|
|
283
|
+
});
|
|
284
|
+
|
|
285
|
+
test("an admin should be able downgrade a writeOnly to reader", async () => {
|
|
286
|
+
const admin = await setupTestAccount({
|
|
287
|
+
connected: true,
|
|
288
|
+
});
|
|
289
|
+
|
|
290
|
+
const writeOnlyUser = await setupTestAccount({
|
|
291
|
+
connected: true,
|
|
292
|
+
});
|
|
293
|
+
|
|
294
|
+
const group = admin.node.createGroup();
|
|
295
|
+
const person = group.createMap({
|
|
296
|
+
name: "John Doe",
|
|
297
|
+
});
|
|
298
|
+
|
|
299
|
+
const writeOnlyUserOnAdminNode = await loadCoValueOrFail(
|
|
300
|
+
admin.node,
|
|
301
|
+
writeOnlyUser.accountID,
|
|
302
|
+
);
|
|
303
|
+
group.addMember(writeOnlyUserOnAdminNode, "writeOnly");
|
|
304
|
+
group.addMember(writeOnlyUserOnAdminNode, "reader");
|
|
305
|
+
|
|
306
|
+
expect(group.roleOf(writeOnlyUser.accountID)).toEqual("reader");
|
|
307
|
+
|
|
308
|
+
const personOnWriteOnlyNode = await loadCoValueOrFail(
|
|
309
|
+
writeOnlyUser.node,
|
|
310
|
+
person.id,
|
|
311
|
+
);
|
|
312
|
+
|
|
313
|
+
expect(personOnWriteOnlyNode.get("name")).toEqual("John Doe");
|
|
314
|
+
});
|
|
315
|
+
|
|
316
|
+
test("a reader should not be able to add a member", async () => {
|
|
317
|
+
const admin = await setupTestAccount({
|
|
318
|
+
connected: true,
|
|
319
|
+
});
|
|
320
|
+
|
|
321
|
+
const reader = await setupTestAccount({
|
|
322
|
+
connected: true,
|
|
323
|
+
});
|
|
324
|
+
|
|
325
|
+
const newUser = await setupTestAccount({
|
|
326
|
+
connected: true,
|
|
327
|
+
});
|
|
328
|
+
|
|
329
|
+
const group = admin.node.createGroup();
|
|
330
|
+
const readerOnAdminNode = await loadCoValueOrFail(
|
|
331
|
+
admin.node,
|
|
332
|
+
reader.accountID,
|
|
333
|
+
);
|
|
334
|
+
group.addMember(readerOnAdminNode, "reader");
|
|
335
|
+
|
|
336
|
+
const newUserOnReaderNode = await loadCoValueOrFail(
|
|
337
|
+
reader.node,
|
|
338
|
+
newUser.accountID,
|
|
339
|
+
);
|
|
340
|
+
|
|
341
|
+
const groupOnReaderNode = await loadCoValueOrFail(reader.node, group.id);
|
|
342
|
+
|
|
343
|
+
// Try to add member as reader
|
|
344
|
+
try {
|
|
345
|
+
groupOnReaderNode.addMember(newUserOnReaderNode, "reader");
|
|
346
|
+
throw new Error("Should not be able to add member as reader");
|
|
347
|
+
} catch (e) {
|
|
348
|
+
expect(e).toBeDefined();
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
expect(groupOnReaderNode.roleOf(newUser.accountID)).toBeUndefined();
|
|
352
|
+
});
|
|
353
|
+
|
|
354
|
+
test("a writer should not be able to add a member", async () => {
|
|
355
|
+
const admin = await setupTestAccount({
|
|
356
|
+
connected: true,
|
|
357
|
+
});
|
|
358
|
+
|
|
359
|
+
const writer = await setupTestAccount({
|
|
360
|
+
connected: true,
|
|
361
|
+
});
|
|
362
|
+
|
|
363
|
+
const newUser = await setupTestAccount({
|
|
364
|
+
connected: true,
|
|
365
|
+
});
|
|
366
|
+
|
|
367
|
+
const group = admin.node.createGroup();
|
|
368
|
+
const writerOnAdminNode = await loadCoValueOrFail(
|
|
369
|
+
admin.node,
|
|
370
|
+
writer.accountID,
|
|
371
|
+
);
|
|
372
|
+
group.addMember(writerOnAdminNode, "writer");
|
|
373
|
+
|
|
374
|
+
const newUserOnWriterNode = await loadCoValueOrFail(
|
|
375
|
+
writer.node,
|
|
376
|
+
newUser.accountID,
|
|
377
|
+
);
|
|
378
|
+
|
|
379
|
+
const groupOnWriterNode = await loadCoValueOrFail(writer.node, group.id);
|
|
380
|
+
|
|
381
|
+
// Try to add member as writer
|
|
382
|
+
try {
|
|
383
|
+
groupOnWriterNode.addMember(newUserOnWriterNode, "reader");
|
|
384
|
+
throw new Error("Should not be able to add member as writer");
|
|
385
|
+
} catch (e) {
|
|
386
|
+
expect(e).toBeDefined();
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
expect(groupOnWriterNode.roleOf(newUser.accountID)).toBeUndefined();
|
|
390
|
+
});
|
|
391
|
+
|
|
392
|
+
test("a writeOnly should not be able to add a member", async () => {
|
|
393
|
+
const admin = await setupTestAccount({
|
|
394
|
+
connected: true,
|
|
395
|
+
});
|
|
396
|
+
|
|
397
|
+
const writeOnlyUser = await setupTestAccount({
|
|
398
|
+
connected: true,
|
|
399
|
+
});
|
|
400
|
+
|
|
401
|
+
const newUser = await setupTestAccount({
|
|
402
|
+
connected: true,
|
|
403
|
+
});
|
|
404
|
+
|
|
405
|
+
const group = admin.node.createGroup();
|
|
406
|
+
const writeOnlyUserOnAdminNode = await loadCoValueOrFail(
|
|
407
|
+
admin.node,
|
|
408
|
+
writeOnlyUser.accountID,
|
|
409
|
+
);
|
|
410
|
+
group.addMember(writeOnlyUserOnAdminNode, "writeOnly");
|
|
411
|
+
|
|
412
|
+
const newUserOnWriteOnlyNode = await loadCoValueOrFail(
|
|
413
|
+
writeOnlyUser.node,
|
|
414
|
+
newUser.accountID,
|
|
415
|
+
);
|
|
416
|
+
|
|
417
|
+
const groupOnWriteOnlyNode = await loadCoValueOrFail(
|
|
418
|
+
writeOnlyUser.node,
|
|
419
|
+
group.id,
|
|
420
|
+
);
|
|
421
|
+
|
|
422
|
+
// Try to add member as writeOnly user
|
|
423
|
+
try {
|
|
424
|
+
groupOnWriteOnlyNode.addMember(newUserOnWriteOnlyNode, "reader");
|
|
425
|
+
throw new Error("Should not be able to add member as writeOnly user");
|
|
426
|
+
} catch (e) {
|
|
427
|
+
expect(e).toBeDefined();
|
|
428
|
+
}
|
|
429
|
+
|
|
430
|
+
expect(groupOnWriteOnlyNode.roleOf(newUser.accountID)).toBeUndefined();
|
|
431
|
+
});
|
|
432
|
+
});
|
package/src/tests/testUtils.ts
CHANGED
|
@@ -8,12 +8,12 @@ import {
|
|
|
8
8
|
import { expect, onTestFinished, vi } from "vitest";
|
|
9
9
|
import { ControlledAccount, ControlledAgent } from "../coValues/account.js";
|
|
10
10
|
import { WasmCrypto } from "../crypto/WasmCrypto.js";
|
|
11
|
-
import
|
|
12
|
-
AgentSecret,
|
|
13
|
-
CoID,
|
|
14
|
-
CoValueCore,
|
|
15
|
-
RawAccount,
|
|
16
|
-
RawCoValue,
|
|
11
|
+
import {
|
|
12
|
+
type AgentSecret,
|
|
13
|
+
type CoID,
|
|
14
|
+
type CoValueCore,
|
|
15
|
+
type RawAccount,
|
|
16
|
+
type RawCoValue,
|
|
17
17
|
} from "../exports.js";
|
|
18
18
|
import type { SessionID } from "../ids.js";
|
|
19
19
|
import { LocalNode } from "../localNode.js";
|