cojson 0.16.4 → 0.16.5
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 +13 -0
- package/dist/coValue.d.ts.map +1 -1
- package/dist/coValue.js.map +1 -1
- package/dist/coValueCore/coValueCore.d.ts +6 -10
- package/dist/coValueCore/coValueCore.d.ts.map +1 -1
- package/dist/coValueCore/coValueCore.js +15 -122
- package/dist/coValueCore/coValueCore.js.map +1 -1
- package/dist/coValues/group.d.ts +18 -10
- package/dist/coValues/group.d.ts.map +1 -1
- package/dist/coValues/group.js +221 -59
- package/dist/coValues/group.js.map +1 -1
- package/dist/ids.d.ts +3 -3
- package/dist/ids.d.ts.map +1 -1
- package/dist/ids.js.map +1 -1
- package/dist/localNode.d.ts +5 -5
- package/dist/localNode.d.ts.map +1 -1
- package/dist/tests/group.inheritance.test.js +195 -0
- package/dist/tests/group.inheritance.test.js.map +1 -1
- package/dist/tests/group.removeMember.test.js +152 -1
- package/dist/tests/group.removeMember.test.js.map +1 -1
- package/dist/tests/group.roleOf.test.js +2 -2
- package/dist/tests/group.roleOf.test.js.map +1 -1
- package/dist/tests/group.test.js +81 -3
- package/dist/tests/group.test.js.map +1 -1
- package/dist/tests/sync.load.test.js +6 -3
- package/dist/tests/sync.load.test.js.map +1 -1
- package/dist/tests/testUtils.d.ts +1 -0
- package/dist/tests/testUtils.d.ts.map +1 -1
- package/dist/tests/testUtils.js +5 -0
- package/dist/tests/testUtils.js.map +1 -1
- package/dist/typeUtils/accountOrAgentIDfromSessionID.d.ts +2 -2
- package/dist/typeUtils/accountOrAgentIDfromSessionID.d.ts.map +1 -1
- package/dist/typeUtils/expectGroup.d.ts.map +1 -1
- package/dist/typeUtils/expectGroup.js +6 -5
- package/dist/typeUtils/expectGroup.js.map +1 -1
- package/package.json +1 -1
- package/src/coValue.ts +1 -4
- package/src/coValueCore/coValueCore.ts +23 -188
- package/src/coValues/group.ts +310 -91
- package/src/ids.ts +3 -3
- package/src/localNode.ts +7 -7
- package/src/tests/group.inheritance.test.ts +279 -0
- package/src/tests/group.removeMember.test.ts +244 -1
- package/src/tests/group.roleOf.test.ts +2 -2
- package/src/tests/group.test.ts +105 -5
- package/src/tests/sync.load.test.ts +6 -3
- package/src/tests/testUtils.ts +5 -0
- package/src/typeUtils/accountOrAgentIDfromSessionID.ts +2 -2
- package/src/typeUtils/expectGroup.ts +8 -5
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import { beforeEach, describe, expect, test } from "vitest";
|
|
2
|
+
import type { CoID, RawGroup } from "../exports";
|
|
3
|
+
import { NewContentMessage } from "../sync";
|
|
2
4
|
import {
|
|
3
5
|
SyncMessagesLog,
|
|
4
6
|
createThreeConnectedNodes,
|
|
@@ -96,6 +98,32 @@ describe("extend", () => {
|
|
|
96
98
|
expect(mapOnNode2.get("test")).toEqual("Written from node2");
|
|
97
99
|
});
|
|
98
100
|
|
|
101
|
+
test("inherited everyone roles should work correctly", async () => {
|
|
102
|
+
const { node1, node2 } = await createTwoConnectedNodes("server", "server");
|
|
103
|
+
|
|
104
|
+
const group = node1.node.createGroup();
|
|
105
|
+
group.addMember("everyone", "writer");
|
|
106
|
+
|
|
107
|
+
const childGroup = node1.node.createGroup();
|
|
108
|
+
childGroup.extend(group);
|
|
109
|
+
|
|
110
|
+
expect(childGroup.roleOf("everyone")).toEqual("writer");
|
|
111
|
+
|
|
112
|
+
const map = childGroup.createMap();
|
|
113
|
+
map.set("test", "Written from the admin");
|
|
114
|
+
|
|
115
|
+
await map.core.waitForSync();
|
|
116
|
+
|
|
117
|
+
const mapOnNode2 = await loadCoValueOrFail(node2.node, map.id);
|
|
118
|
+
|
|
119
|
+
// The writer role should be able to see the edits from the admin
|
|
120
|
+
expect(mapOnNode2.get("test")).toEqual("Written from the admin");
|
|
121
|
+
|
|
122
|
+
mapOnNode2.set("hello", "from node 2");
|
|
123
|
+
|
|
124
|
+
expect(mapOnNode2.get("hello")).toEqual("from node 2");
|
|
125
|
+
});
|
|
126
|
+
|
|
99
127
|
test("a user should be able to extend a group when his role on the parent group is writeOnly", async () => {
|
|
100
128
|
const { node1, node2 } = await createTwoConnectedNodes("server", "server");
|
|
101
129
|
|
|
@@ -315,6 +343,257 @@ describe("extend", () => {
|
|
|
315
343
|
|
|
316
344
|
expect(childGroup.roleOf(alice.id)).toBe("writer");
|
|
317
345
|
});
|
|
346
|
+
|
|
347
|
+
test("should be possible to extend a group after getting revoked from the parent group", async () => {
|
|
348
|
+
const { node1, node2, node3 } = await createThreeConnectedNodes(
|
|
349
|
+
"server",
|
|
350
|
+
"server",
|
|
351
|
+
"server",
|
|
352
|
+
);
|
|
353
|
+
|
|
354
|
+
const parentGroup = node1.node.createGroup();
|
|
355
|
+
|
|
356
|
+
const alice = await loadCoValueOrFail(node1.node, node3.accountID);
|
|
357
|
+
const bob = await loadCoValueOrFail(node1.node, node2.accountID);
|
|
358
|
+
parentGroup.addMember(alice, "writer");
|
|
359
|
+
parentGroup.addMember(bob, "reader");
|
|
360
|
+
parentGroup.removeMember(bob);
|
|
361
|
+
|
|
362
|
+
const parentGroupOnNode2 = await loadCoValueOrFail(
|
|
363
|
+
node2.node,
|
|
364
|
+
parentGroup.id,
|
|
365
|
+
);
|
|
366
|
+
|
|
367
|
+
const childGroup = node2.node.createGroup();
|
|
368
|
+
childGroup.extend(parentGroupOnNode2);
|
|
369
|
+
|
|
370
|
+
expect(childGroup.roleOf(alice.id)).toBe("writer");
|
|
371
|
+
});
|
|
372
|
+
|
|
373
|
+
test("should be possible to extend when access is everyone reader and the account is revoked from the parent group", async () => {
|
|
374
|
+
const { node1, node2, node3 } = await createThreeConnectedNodes(
|
|
375
|
+
"server",
|
|
376
|
+
"server",
|
|
377
|
+
"server",
|
|
378
|
+
);
|
|
379
|
+
|
|
380
|
+
const parentGroup = node1.node.createGroup();
|
|
381
|
+
parentGroup.addMember("everyone", "reader");
|
|
382
|
+
const alice = await loadCoValueOrFail(node1.node, node3.accountID);
|
|
383
|
+
const bob = await loadCoValueOrFail(node1.node, node2.accountID);
|
|
384
|
+
parentGroup.addMember(alice, "writer");
|
|
385
|
+
parentGroup.addMember(bob, "reader");
|
|
386
|
+
parentGroup.removeMember(bob);
|
|
387
|
+
|
|
388
|
+
const parentGroupOnNode2 = await loadCoValueOrFail(
|
|
389
|
+
node2.node,
|
|
390
|
+
parentGroup.id,
|
|
391
|
+
);
|
|
392
|
+
|
|
393
|
+
const childGroup = node2.node.createGroup();
|
|
394
|
+
childGroup.extend(parentGroupOnNode2);
|
|
395
|
+
|
|
396
|
+
expect(childGroup.roleOf(alice.id)).toBe("writer");
|
|
397
|
+
});
|
|
398
|
+
|
|
399
|
+
test("should be able to extend when the last read key is healed", async () => {
|
|
400
|
+
const clientWithAccess = setupTestNode({
|
|
401
|
+
secret:
|
|
402
|
+
"sealerSecret_zBTPp7U58Fzq9o7EvJpu4KEziepi8QVf2Xaxuy5xmmXFx/signerSecret_z62DuviZdXCjz4EZWofvr9vaLYFXDeTaC9KWhoQiQjzKk",
|
|
403
|
+
connected: true,
|
|
404
|
+
});
|
|
405
|
+
const clientWithoutAccess = setupTestNode({
|
|
406
|
+
connected: true,
|
|
407
|
+
});
|
|
408
|
+
|
|
409
|
+
const brokenGroupContent = {
|
|
410
|
+
action: "content",
|
|
411
|
+
id: "co_zW7F36Nnop9A7Er4gUzBcUXnZCK",
|
|
412
|
+
header: {
|
|
413
|
+
type: "comap",
|
|
414
|
+
ruleset: {
|
|
415
|
+
type: "group",
|
|
416
|
+
initialAdmin:
|
|
417
|
+
"sealer_z12QDazYB3ygPZtBV7sMm7iYKMRnNZ6Aaj1dfLXR7LSBm/signer_z2AskZQbc82qxo7iA3oiXoNExHLsAEXC2pHbwJzRnATWv",
|
|
418
|
+
},
|
|
419
|
+
meta: null,
|
|
420
|
+
createdAt: "2025-08-06T10:14:39.617Z",
|
|
421
|
+
uniqueness: "z3LJjnuPiPJaf5Qb9A",
|
|
422
|
+
},
|
|
423
|
+
priority: 0,
|
|
424
|
+
new: {
|
|
425
|
+
"sealer_z12QDazYB3ygPZtBV7sMm7iYKMRnNZ6Aaj1dfLXR7LSBm/signer_z2AskZQbc82qxo7iA3oiXoNExHLsAEXC2pHbwJzRnATWv_session_zYLsz2CiW9pW":
|
|
426
|
+
{
|
|
427
|
+
after: 0,
|
|
428
|
+
newTransactions: [
|
|
429
|
+
{
|
|
430
|
+
privacy: "trusting",
|
|
431
|
+
madeAt: 1754475279619,
|
|
432
|
+
changes:
|
|
433
|
+
'[{"key":"sealer_z12QDazYB3ygPZtBV7sMm7iYKMRnNZ6Aaj1dfLXR7LSBm/signer_z2AskZQbc82qxo7iA3oiXoNExHLsAEXC2pHbwJzRnATWv","op":"set","value":"admin"}]',
|
|
434
|
+
},
|
|
435
|
+
{
|
|
436
|
+
privacy: "trusting",
|
|
437
|
+
madeAt: 1754475279621,
|
|
438
|
+
changes:
|
|
439
|
+
'[{"key":"key_z5CVahfMkEWPj1B3zH_for_sealer_z12QDazYB3ygPZtBV7sMm7iYKMRnNZ6Aaj1dfLXR7LSBm/signer_z2AskZQbc82qxo7iA3oiXoNExHLsAEXC2pHbwJzRnATWv","op":"set","value":"sealed_UCg4UkytXF-W8PaIvaDffO3pZ3d9hdXUuNkQQEikPTAuOD9us92Pqb5Vgu7lx1Fpb0X8V5BJ2yxz6_D5WOzK3qjWBSsc7J1xDJA=="}]',
|
|
440
|
+
},
|
|
441
|
+
{
|
|
442
|
+
privacy: "trusting",
|
|
443
|
+
madeAt: 1754475279621,
|
|
444
|
+
changes:
|
|
445
|
+
'[{"key":"readKey","op":"set","value":"key_z5CVahfMkEWPj1B3zH"}]',
|
|
446
|
+
},
|
|
447
|
+
{
|
|
448
|
+
privacy: "trusting",
|
|
449
|
+
madeAt: 1754475279622,
|
|
450
|
+
changes: '[{"key":"everyone","op":"set","value":"reader"}]',
|
|
451
|
+
},
|
|
452
|
+
{
|
|
453
|
+
privacy: "trusting",
|
|
454
|
+
madeAt: 1754475279623,
|
|
455
|
+
changes:
|
|
456
|
+
'[{"key":"key_z5CVahfMkEWPj1B3zH_for_everyone","op":"set","value":"keySecret_z9U9gzkahQXCxDoSw7isiUnbobXwuLdcSkL9Ci6ZEEkaL"}]',
|
|
457
|
+
},
|
|
458
|
+
{
|
|
459
|
+
privacy: "trusting",
|
|
460
|
+
madeAt: 1754475279623,
|
|
461
|
+
changes:
|
|
462
|
+
'[{"key":"key_z4Fi7hZNBx7XoVAKkP_for_sealer_z12QDazYB3ygPZtBV7sMm7iYKMRnNZ6Aaj1dfLXR7LSBm/signer_z2AskZQbc82qxo7iA3oiXoNExHLsAEXC2pHbwJzRnATWv","op":"set","value":"sealed_UuCBBfZkTnRTrGraqWWlzm9JE-VFduhsfu7WaZjpCbJYOTXpPhSNOnzGeS8qVuIsG6dORbME22lc5ltLxPjRqofQdDCNGQehCeQ=="}]',
|
|
463
|
+
},
|
|
464
|
+
{
|
|
465
|
+
privacy: "trusting",
|
|
466
|
+
madeAt: 1754475279624,
|
|
467
|
+
changes:
|
|
468
|
+
'[{"key":"key_z5CVahfMkEWPj1B3zH_for_key_z4Fi7hZNBx7XoVAKkP","op":"set","value":"encrypted_USTrBuobwTCORwy5yHxy4sFZ7swfrafP6k5ZwcTf76f0MBu9Ie-JmsX3mNXad4mluI47gvGXzi8I_"}]',
|
|
469
|
+
},
|
|
470
|
+
{
|
|
471
|
+
privacy: "trusting",
|
|
472
|
+
madeAt: 1754475279624,
|
|
473
|
+
changes:
|
|
474
|
+
'[{"key":"readKey","op":"set","value":"key_z4Fi7hZNBx7XoVAKkP"}]',
|
|
475
|
+
},
|
|
476
|
+
],
|
|
477
|
+
lastSignature:
|
|
478
|
+
"signature_z3tsE7U1JaeNeUmZ4EY3Xq5uQ9jq9jDi6Rkhdt7T7b7z4NCnpMgB4bo8TwLXYVCrRdBm6PoyyPdK8fYFzHJUh5EzA",
|
|
479
|
+
},
|
|
480
|
+
},
|
|
481
|
+
} as unknown as NewContentMessage;
|
|
482
|
+
|
|
483
|
+
clientWithAccess.node.syncManager.handleNewContent(
|
|
484
|
+
brokenGroupContent,
|
|
485
|
+
"import",
|
|
486
|
+
);
|
|
487
|
+
|
|
488
|
+
// Load the CoValue to recover the key_for_everyone
|
|
489
|
+
await loadCoValueOrFail(
|
|
490
|
+
clientWithAccess.node,
|
|
491
|
+
brokenGroupContent.id as CoID<RawGroup>,
|
|
492
|
+
);
|
|
493
|
+
|
|
494
|
+
const group = await loadCoValueOrFail(
|
|
495
|
+
clientWithoutAccess.node,
|
|
496
|
+
brokenGroupContent.id as CoID<RawGroup>,
|
|
497
|
+
);
|
|
498
|
+
const childGroup = clientWithoutAccess.node.createGroup();
|
|
499
|
+
childGroup.extend(group);
|
|
500
|
+
|
|
501
|
+
expect(childGroup.getParentGroups()).toEqual([group]);
|
|
502
|
+
});
|
|
503
|
+
|
|
504
|
+
test("should be able to extend when the last read key is missing", async () => {
|
|
505
|
+
const clientWithoutAccess = setupTestNode({
|
|
506
|
+
connected: true,
|
|
507
|
+
});
|
|
508
|
+
|
|
509
|
+
const brokenGroupContent = {
|
|
510
|
+
action: "content",
|
|
511
|
+
id: "co_zW7F36Nnop9A7Er4gUzBcUXnZCK",
|
|
512
|
+
header: {
|
|
513
|
+
type: "comap",
|
|
514
|
+
ruleset: {
|
|
515
|
+
type: "group",
|
|
516
|
+
initialAdmin:
|
|
517
|
+
"sealer_z12QDazYB3ygPZtBV7sMm7iYKMRnNZ6Aaj1dfLXR7LSBm/signer_z2AskZQbc82qxo7iA3oiXoNExHLsAEXC2pHbwJzRnATWv",
|
|
518
|
+
},
|
|
519
|
+
meta: null,
|
|
520
|
+
createdAt: "2025-08-06T10:14:39.617Z",
|
|
521
|
+
uniqueness: "z3LJjnuPiPJaf5Qb9A",
|
|
522
|
+
},
|
|
523
|
+
priority: 0,
|
|
524
|
+
new: {
|
|
525
|
+
"sealer_z12QDazYB3ygPZtBV7sMm7iYKMRnNZ6Aaj1dfLXR7LSBm/signer_z2AskZQbc82qxo7iA3oiXoNExHLsAEXC2pHbwJzRnATWv_session_zYLsz2CiW9pW":
|
|
526
|
+
{
|
|
527
|
+
after: 0,
|
|
528
|
+
newTransactions: [
|
|
529
|
+
{
|
|
530
|
+
privacy: "trusting",
|
|
531
|
+
madeAt: 1754475279619,
|
|
532
|
+
changes:
|
|
533
|
+
'[{"key":"sealer_z12QDazYB3ygPZtBV7sMm7iYKMRnNZ6Aaj1dfLXR7LSBm/signer_z2AskZQbc82qxo7iA3oiXoNExHLsAEXC2pHbwJzRnATWv","op":"set","value":"admin"}]',
|
|
534
|
+
},
|
|
535
|
+
{
|
|
536
|
+
privacy: "trusting",
|
|
537
|
+
madeAt: 1754475279621,
|
|
538
|
+
changes:
|
|
539
|
+
'[{"key":"key_z5CVahfMkEWPj1B3zH_for_sealer_z12QDazYB3ygPZtBV7sMm7iYKMRnNZ6Aaj1dfLXR7LSBm/signer_z2AskZQbc82qxo7iA3oiXoNExHLsAEXC2pHbwJzRnATWv","op":"set","value":"sealed_UCg4UkytXF-W8PaIvaDffO3pZ3d9hdXUuNkQQEikPTAuOD9us92Pqb5Vgu7lx1Fpb0X8V5BJ2yxz6_D5WOzK3qjWBSsc7J1xDJA=="}]',
|
|
540
|
+
},
|
|
541
|
+
{
|
|
542
|
+
privacy: "trusting",
|
|
543
|
+
madeAt: 1754475279621,
|
|
544
|
+
changes:
|
|
545
|
+
'[{"key":"readKey","op":"set","value":"key_z5CVahfMkEWPj1B3zH"}]',
|
|
546
|
+
},
|
|
547
|
+
{
|
|
548
|
+
privacy: "trusting",
|
|
549
|
+
madeAt: 1754475279622,
|
|
550
|
+
changes: '[{"key":"everyone","op":"set","value":"reader"}]',
|
|
551
|
+
},
|
|
552
|
+
{
|
|
553
|
+
privacy: "trusting",
|
|
554
|
+
madeAt: 1754475279623,
|
|
555
|
+
changes:
|
|
556
|
+
'[{"key":"key_z5CVahfMkEWPj1B3zH_for_everyone","op":"set","value":"keySecret_z9U9gzkahQXCxDoSw7isiUnbobXwuLdcSkL9Ci6ZEEkaL"}]',
|
|
557
|
+
},
|
|
558
|
+
{
|
|
559
|
+
privacy: "trusting",
|
|
560
|
+
madeAt: 1754475279623,
|
|
561
|
+
changes:
|
|
562
|
+
'[{"key":"key_z4Fi7hZNBx7XoVAKkP_for_sealer_z12QDazYB3ygPZtBV7sMm7iYKMRnNZ6Aaj1dfLXR7LSBm/signer_z2AskZQbc82qxo7iA3oiXoNExHLsAEXC2pHbwJzRnATWv","op":"set","value":"sealed_UuCBBfZkTnRTrGraqWWlzm9JE-VFduhsfu7WaZjpCbJYOTXpPhSNOnzGeS8qVuIsG6dORbME22lc5ltLxPjRqofQdDCNGQehCeQ=="}]',
|
|
563
|
+
},
|
|
564
|
+
{
|
|
565
|
+
privacy: "trusting",
|
|
566
|
+
madeAt: 1754475279624,
|
|
567
|
+
changes:
|
|
568
|
+
'[{"key":"key_z5CVahfMkEWPj1B3zH_for_key_z4Fi7hZNBx7XoVAKkP","op":"set","value":"encrypted_USTrBuobwTCORwy5yHxy4sFZ7swfrafP6k5ZwcTf76f0MBu9Ie-JmsX3mNXad4mluI47gvGXzi8I_"}]',
|
|
569
|
+
},
|
|
570
|
+
{
|
|
571
|
+
privacy: "trusting",
|
|
572
|
+
madeAt: 1754475279624,
|
|
573
|
+
changes:
|
|
574
|
+
'[{"key":"readKey","op":"set","value":"key_z4Fi7hZNBx7XoVAKkP"}]',
|
|
575
|
+
},
|
|
576
|
+
],
|
|
577
|
+
lastSignature:
|
|
578
|
+
"signature_z3tsE7U1JaeNeUmZ4EY3Xq5uQ9jq9jDi6Rkhdt7T7b7z4NCnpMgB4bo8TwLXYVCrRdBm6PoyyPdK8fYFzHJUh5EzA",
|
|
579
|
+
},
|
|
580
|
+
},
|
|
581
|
+
} as unknown as NewContentMessage;
|
|
582
|
+
|
|
583
|
+
clientWithoutAccess.node.syncManager.handleNewContent(
|
|
584
|
+
brokenGroupContent,
|
|
585
|
+
"import",
|
|
586
|
+
);
|
|
587
|
+
|
|
588
|
+
const group = await loadCoValueOrFail(
|
|
589
|
+
clientWithoutAccess.node,
|
|
590
|
+
brokenGroupContent.id as CoID<RawGroup>,
|
|
591
|
+
);
|
|
592
|
+
const childGroup = clientWithoutAccess.node.createGroup();
|
|
593
|
+
childGroup.extend(group);
|
|
594
|
+
|
|
595
|
+
expect(childGroup.getParentGroups()).toEqual([group]);
|
|
596
|
+
});
|
|
318
597
|
});
|
|
319
598
|
|
|
320
599
|
describe("unextend", () => {
|
|
@@ -1,12 +1,15 @@
|
|
|
1
1
|
import { beforeEach, describe, expect, test } from "vitest";
|
|
2
|
+
import { setCoValueLoadingRetryDelay } from "../config.js";
|
|
2
3
|
import {
|
|
3
4
|
SyncMessagesLog,
|
|
4
|
-
|
|
5
|
+
blockMessageTypeOnOutgoingPeer,
|
|
5
6
|
loadCoValueOrFail,
|
|
6
7
|
setupTestAccount,
|
|
7
8
|
setupTestNode,
|
|
8
9
|
} from "./testUtils.js";
|
|
9
10
|
|
|
11
|
+
setCoValueLoadingRetryDelay(10);
|
|
12
|
+
|
|
10
13
|
let jazzCloud: ReturnType<typeof setupTestNode>;
|
|
11
14
|
|
|
12
15
|
beforeEach(async () => {
|
|
@@ -15,6 +18,65 @@ beforeEach(async () => {
|
|
|
15
18
|
});
|
|
16
19
|
|
|
17
20
|
describe("Group.removeMember", () => {
|
|
21
|
+
test("revoking a member access should not affect everyone access", async () => {
|
|
22
|
+
const admin = await setupTestAccount({
|
|
23
|
+
connected: true,
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
const alice = await setupTestAccount({
|
|
27
|
+
connected: true,
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
const group = admin.node.createGroup();
|
|
31
|
+
group.addMember("everyone", "writer");
|
|
32
|
+
|
|
33
|
+
const aliceOnAdminNode = await loadCoValueOrFail(
|
|
34
|
+
admin.node,
|
|
35
|
+
alice.accountID,
|
|
36
|
+
);
|
|
37
|
+
group.addMember(aliceOnAdminNode, "writer");
|
|
38
|
+
group.removeMember(aliceOnAdminNode);
|
|
39
|
+
|
|
40
|
+
const groupOnAliceNode = await loadCoValueOrFail(alice.node, group.id);
|
|
41
|
+
expect(groupOnAliceNode.myRole()).toEqual("writer");
|
|
42
|
+
|
|
43
|
+
const map = groupOnAliceNode.createMap();
|
|
44
|
+
|
|
45
|
+
map.set("test", "test");
|
|
46
|
+
expect(map.get("test")).toEqual("test");
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
test("revoking a member access should not affect everyone access when everyone access is gained through a group extension", async () => {
|
|
50
|
+
const admin = await setupTestAccount({
|
|
51
|
+
connected: true,
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
const alice = await setupTestAccount({
|
|
55
|
+
connected: true,
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
const parentGroup = admin.node.createGroup();
|
|
59
|
+
const group = admin.node.createGroup();
|
|
60
|
+
parentGroup.addMember("everyone", "reader");
|
|
61
|
+
group.extend(parentGroup);
|
|
62
|
+
|
|
63
|
+
const aliceOnAdminNode = await loadCoValueOrFail(
|
|
64
|
+
admin.node,
|
|
65
|
+
alice.accountID,
|
|
66
|
+
);
|
|
67
|
+
group.addMember(aliceOnAdminNode, "writer");
|
|
68
|
+
group.removeMember(aliceOnAdminNode);
|
|
69
|
+
|
|
70
|
+
const map = group.createMap();
|
|
71
|
+
map.set("test", "test");
|
|
72
|
+
|
|
73
|
+
const groupOnAliceNode = await loadCoValueOrFail(alice.node, group.id);
|
|
74
|
+
expect(groupOnAliceNode.myRole()).toEqual("reader");
|
|
75
|
+
|
|
76
|
+
const mapOnAliceNode = await loadCoValueOrFail(alice.node, map.id);
|
|
77
|
+
expect(mapOnAliceNode.get("test")).toEqual("test");
|
|
78
|
+
});
|
|
79
|
+
|
|
18
80
|
test("a reader member should be able to revoke themselves", async () => {
|
|
19
81
|
const admin = await setupTestAccount({
|
|
20
82
|
connected: true,
|
|
@@ -294,4 +356,185 @@ describe("Group.removeMember", () => {
|
|
|
294
356
|
undefined,
|
|
295
357
|
);
|
|
296
358
|
});
|
|
359
|
+
|
|
360
|
+
test("removing a member should rotate the readKey on available child groups", async () => {
|
|
361
|
+
const admin = await setupTestAccount({
|
|
362
|
+
connected: true,
|
|
363
|
+
});
|
|
364
|
+
|
|
365
|
+
const alice = await setupTestAccount({
|
|
366
|
+
connected: true,
|
|
367
|
+
});
|
|
368
|
+
|
|
369
|
+
const aliceOnAdminNode = await loadCoValueOrFail(
|
|
370
|
+
admin.node,
|
|
371
|
+
alice.accountID,
|
|
372
|
+
);
|
|
373
|
+
|
|
374
|
+
const group = admin.node.createGroup();
|
|
375
|
+
const childGroup = admin.node.createGroup();
|
|
376
|
+
group.addMember(aliceOnAdminNode, "reader");
|
|
377
|
+
|
|
378
|
+
childGroup.extend(group);
|
|
379
|
+
|
|
380
|
+
group.removeMember(aliceOnAdminNode);
|
|
381
|
+
|
|
382
|
+
const map = childGroup.createMap();
|
|
383
|
+
map.set("test", "Not readable by alice");
|
|
384
|
+
|
|
385
|
+
await map.core.waitForSync();
|
|
386
|
+
|
|
387
|
+
const mapOnAliceNode = await loadCoValueOrFail(alice.node, map.id);
|
|
388
|
+
expect(mapOnAliceNode.get("test")).toBeUndefined();
|
|
389
|
+
});
|
|
390
|
+
|
|
391
|
+
test("removing a member should rotate the readKey on unloaded child groups", async () => {
|
|
392
|
+
const admin = await setupTestAccount({
|
|
393
|
+
connected: true,
|
|
394
|
+
});
|
|
395
|
+
|
|
396
|
+
const bob = await setupTestAccount({
|
|
397
|
+
connected: true,
|
|
398
|
+
});
|
|
399
|
+
|
|
400
|
+
const alice = await setupTestAccount({
|
|
401
|
+
connected: true,
|
|
402
|
+
});
|
|
403
|
+
|
|
404
|
+
const bobOnAdminNode = await loadCoValueOrFail(admin.node, bob.accountID);
|
|
405
|
+
|
|
406
|
+
const aliceOnAdminNode = await loadCoValueOrFail(
|
|
407
|
+
admin.node,
|
|
408
|
+
alice.accountID,
|
|
409
|
+
);
|
|
410
|
+
|
|
411
|
+
const group = admin.node.createGroup();
|
|
412
|
+
|
|
413
|
+
const childGroup = bob.node.createGroup();
|
|
414
|
+
group.addMember(bobOnAdminNode, "reader");
|
|
415
|
+
group.addMember(aliceOnAdminNode, "reader");
|
|
416
|
+
|
|
417
|
+
const groupOnBobNode = await loadCoValueOrFail(bob.node, group.id);
|
|
418
|
+
|
|
419
|
+
childGroup.extend(groupOnBobNode);
|
|
420
|
+
|
|
421
|
+
await childGroup.core.waitForSync();
|
|
422
|
+
|
|
423
|
+
group.removeMember(aliceOnAdminNode);
|
|
424
|
+
|
|
425
|
+
// Rotating the child group keys is async when the child group is not loaded
|
|
426
|
+
await admin.node.getCoValue(childGroup.id).waitForAvailableOrUnavailable();
|
|
427
|
+
await admin.node.syncManager.waitForAllCoValuesSync();
|
|
428
|
+
|
|
429
|
+
const map = childGroup.createMap();
|
|
430
|
+
map.set("test", "Not readable by alice");
|
|
431
|
+
|
|
432
|
+
await map.core.waitForSync();
|
|
433
|
+
|
|
434
|
+
const mapOnAliceNode = await loadCoValueOrFail(alice.node, map.id);
|
|
435
|
+
expect(mapOnAliceNode.get("test")).toBeUndefined();
|
|
436
|
+
});
|
|
437
|
+
|
|
438
|
+
test("removing a member should work even if there are partially available child groups", async () => {
|
|
439
|
+
const admin = await setupTestAccount({
|
|
440
|
+
connected: true,
|
|
441
|
+
});
|
|
442
|
+
|
|
443
|
+
const bob = await setupTestAccount();
|
|
444
|
+
const { peer } = bob.connectToSyncServer();
|
|
445
|
+
|
|
446
|
+
const alice = await setupTestAccount({
|
|
447
|
+
connected: true,
|
|
448
|
+
});
|
|
449
|
+
|
|
450
|
+
const bobOnAdminNode = await loadCoValueOrFail(admin.node, bob.accountID);
|
|
451
|
+
|
|
452
|
+
const aliceOnAdminNode = await loadCoValueOrFail(
|
|
453
|
+
admin.node,
|
|
454
|
+
alice.accountID,
|
|
455
|
+
);
|
|
456
|
+
|
|
457
|
+
const group = admin.node.createGroup();
|
|
458
|
+
const childGroup = bob.node.createGroup();
|
|
459
|
+
|
|
460
|
+
group.addMember(bobOnAdminNode, "reader");
|
|
461
|
+
group.addMember(aliceOnAdminNode, "reader");
|
|
462
|
+
|
|
463
|
+
await group.core.waitForSync();
|
|
464
|
+
|
|
465
|
+
blockMessageTypeOnOutgoingPeer(peer, "content", {
|
|
466
|
+
id: childGroup.id,
|
|
467
|
+
});
|
|
468
|
+
|
|
469
|
+
const groupOnBobNode = await loadCoValueOrFail(bob.node, group.id);
|
|
470
|
+
|
|
471
|
+
childGroup.extend(groupOnBobNode);
|
|
472
|
+
|
|
473
|
+
await groupOnBobNode.core.waitForSync();
|
|
474
|
+
|
|
475
|
+
group.removeMember(aliceOnAdminNode);
|
|
476
|
+
|
|
477
|
+
await admin.node.syncManager.waitForAllCoValuesSync();
|
|
478
|
+
|
|
479
|
+
const map = group.createMap();
|
|
480
|
+
map.set("test", "Not readable by alice");
|
|
481
|
+
|
|
482
|
+
await map.core.waitForSync();
|
|
483
|
+
|
|
484
|
+
const mapOnAliceNode = await loadCoValueOrFail(alice.node, map.id);
|
|
485
|
+
expect(mapOnAliceNode.get("test")).toBeUndefined();
|
|
486
|
+
});
|
|
487
|
+
|
|
488
|
+
test("removing a member should work even if there are unavailable child groups", async () => {
|
|
489
|
+
const admin = await setupTestAccount({
|
|
490
|
+
connected: true,
|
|
491
|
+
});
|
|
492
|
+
|
|
493
|
+
const { peerOnServer } = admin.connectToSyncServer();
|
|
494
|
+
|
|
495
|
+
const bob = await setupTestAccount({
|
|
496
|
+
connected: true,
|
|
497
|
+
});
|
|
498
|
+
|
|
499
|
+
const alice = await setupTestAccount({
|
|
500
|
+
connected: true,
|
|
501
|
+
});
|
|
502
|
+
|
|
503
|
+
const bobOnAdminNode = await loadCoValueOrFail(admin.node, bob.accountID);
|
|
504
|
+
|
|
505
|
+
const aliceOnAdminNode = await loadCoValueOrFail(
|
|
506
|
+
admin.node,
|
|
507
|
+
alice.accountID,
|
|
508
|
+
);
|
|
509
|
+
|
|
510
|
+
const group = admin.node.createGroup();
|
|
511
|
+
const childGroup = bob.node.createGroup();
|
|
512
|
+
|
|
513
|
+
blockMessageTypeOnOutgoingPeer(peerOnServer, "content", {
|
|
514
|
+
id: childGroup.id,
|
|
515
|
+
});
|
|
516
|
+
|
|
517
|
+
group.addMember(bobOnAdminNode, "reader");
|
|
518
|
+
group.addMember(aliceOnAdminNode, "reader");
|
|
519
|
+
|
|
520
|
+
await group.core.waitForSync();
|
|
521
|
+
|
|
522
|
+
const groupOnBobNode = await loadCoValueOrFail(bob.node, group.id);
|
|
523
|
+
|
|
524
|
+
childGroup.extend(groupOnBobNode);
|
|
525
|
+
|
|
526
|
+
await groupOnBobNode.core.waitForSync();
|
|
527
|
+
|
|
528
|
+
group.removeMember(aliceOnAdminNode);
|
|
529
|
+
|
|
530
|
+
await group.core.waitForSync();
|
|
531
|
+
|
|
532
|
+
const map = group.createMap();
|
|
533
|
+
map.set("test", "Not readable by alice");
|
|
534
|
+
|
|
535
|
+
await map.core.waitForSync();
|
|
536
|
+
|
|
537
|
+
const mapOnAliceNode = await loadCoValueOrFail(alice.node, map.id);
|
|
538
|
+
expect(mapOnAliceNode.get("test")).toBeUndefined();
|
|
539
|
+
});
|
|
297
540
|
});
|
|
@@ -33,7 +33,7 @@ describe("roleOf", () => {
|
|
|
33
33
|
const [agent2] = randomAgentAndSessionID();
|
|
34
34
|
|
|
35
35
|
group.addMember(agent2, "writer");
|
|
36
|
-
group.
|
|
36
|
+
group.removeMember(agent2);
|
|
37
37
|
expect(group.roleOfInternal(agent2.id)).toEqual(undefined);
|
|
38
38
|
});
|
|
39
39
|
|
|
@@ -63,7 +63,7 @@ describe("roleOf", () => {
|
|
|
63
63
|
|
|
64
64
|
group.addMemberInternal("everyone", "reader");
|
|
65
65
|
group.addMember(agent2, "writer");
|
|
66
|
-
group.
|
|
66
|
+
group.removeMember("everyone");
|
|
67
67
|
expect(group.roleOfInternal(agent2.id)).toEqual("writer");
|
|
68
68
|
expect(group.roleOfInternal("123" as RawAccountID)).toEqual(undefined);
|
|
69
69
|
});
|