cojson 0.13.5 → 0.13.10
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 +16 -0
- package/LICENSE.txt +1 -1
- package/dist/PeerState.d.ts +6 -0
- package/dist/PeerState.d.ts.map +1 -1
- package/dist/PeerState.js +43 -0
- package/dist/PeerState.js.map +1 -1
- package/dist/coValueCore.d.ts +3 -1
- package/dist/coValueCore.d.ts.map +1 -1
- package/dist/coValueCore.js +26 -8
- package/dist/coValueCore.js.map +1 -1
- package/dist/coValueState.d.ts +1 -0
- package/dist/coValueState.d.ts.map +1 -1
- package/dist/coValueState.js +27 -2
- package/dist/coValueState.js.map +1 -1
- package/dist/coValues/group.d.ts +1 -0
- package/dist/coValues/group.d.ts.map +1 -1
- package/dist/coValues/group.js +45 -21
- package/dist/coValues/group.js.map +1 -1
- package/dist/crypto/crypto.d.ts +2 -2
- package/dist/crypto/crypto.d.ts.map +1 -1
- package/dist/permissions.d.ts +1 -0
- package/dist/permissions.d.ts.map +1 -1
- package/dist/permissions.js +19 -3
- package/dist/permissions.js.map +1 -1
- package/dist/storage/FileSystem.d.ts +2 -2
- package/dist/storage/FileSystem.d.ts.map +1 -1
- package/dist/sync.d.ts +14 -4
- package/dist/sync.d.ts.map +1 -1
- package/dist/sync.js +146 -146
- package/dist/sync.js.map +1 -1
- package/dist/tests/SyncStateManager.test.js +51 -46
- package/dist/tests/SyncStateManager.test.js.map +1 -1
- package/dist/tests/coValueCore.test.js +66 -4
- package/dist/tests/coValueCore.test.js.map +1 -1
- package/dist/tests/coValueState.test.js +31 -4
- package/dist/tests/coValueState.test.js.map +1 -1
- package/dist/tests/group.test.js +135 -2
- package/dist/tests/group.test.js.map +1 -1
- package/dist/tests/messagesTestUtils.d.ts +13 -0
- package/dist/tests/messagesTestUtils.d.ts.map +1 -0
- package/dist/tests/messagesTestUtils.js +42 -0
- package/dist/tests/messagesTestUtils.js.map +1 -0
- package/dist/tests/sync.load.test.d.ts +2 -0
- package/dist/tests/sync.load.test.d.ts.map +1 -0
- package/dist/tests/sync.load.test.js +249 -0
- package/dist/tests/sync.load.test.js.map +1 -0
- package/dist/tests/sync.mesh.test.d.ts +2 -0
- package/dist/tests/sync.mesh.test.d.ts.map +1 -0
- package/dist/tests/sync.mesh.test.js +157 -0
- package/dist/tests/sync.mesh.test.js.map +1 -0
- package/dist/tests/sync.peerReconciliation.test.d.ts +2 -0
- package/dist/tests/sync.peerReconciliation.test.d.ts.map +1 -0
- package/dist/tests/sync.peerReconciliation.test.js +166 -0
- package/dist/tests/sync.peerReconciliation.test.js.map +1 -0
- package/dist/tests/sync.storage.test.d.ts +2 -0
- package/dist/tests/sync.storage.test.d.ts.map +1 -0
- package/dist/tests/sync.storage.test.js +201 -0
- package/dist/tests/sync.storage.test.js.map +1 -0
- package/dist/tests/sync.test.js +139 -1048
- package/dist/tests/sync.test.js.map +1 -1
- package/dist/tests/sync.upload.test.d.ts +2 -0
- package/dist/tests/sync.upload.test.d.ts.map +1 -0
- package/dist/tests/sync.upload.test.js +156 -0
- package/dist/tests/sync.upload.test.js.map +1 -0
- package/dist/tests/testUtils.d.ts +76 -33
- package/dist/tests/testUtils.d.ts.map +1 -1
- package/dist/tests/testUtils.js +154 -47
- package/dist/tests/testUtils.js.map +1 -1
- package/package.json +2 -2
- package/src/PeerState.ts +59 -1
- package/src/coValueCore.ts +37 -7
- package/src/coValueState.ts +34 -3
- package/src/coValues/group.ts +83 -45
- package/src/permissions.ts +31 -3
- package/src/sync.ts +169 -185
- package/src/tests/SyncStateManager.test.ts +58 -70
- package/src/tests/coValueCore.test.ts +90 -3
- package/src/tests/coValueState.test.ts +59 -5
- package/src/tests/group.test.ts +250 -2
- package/src/tests/messagesTestUtils.ts +75 -0
- package/src/tests/sync.load.test.ts +327 -0
- package/src/tests/sync.mesh.test.ts +219 -0
- package/src/tests/sync.peerReconciliation.test.ts +251 -0
- package/src/tests/sync.storage.test.ts +259 -0
- package/src/tests/sync.test.ts +170 -1245
- package/src/tests/sync.upload.test.ts +202 -0
- package/src/tests/testUtils.ts +215 -61
package/src/coValues/group.ts
CHANGED
|
@@ -258,29 +258,38 @@ export class RawGroup<
|
|
|
258
258
|
role: Role,
|
|
259
259
|
) {
|
|
260
260
|
if (account === EVERYONE) {
|
|
261
|
-
if (!(role === "reader" || role === "writer")) {
|
|
261
|
+
if (!(role === "reader" || role === "writer" || role === "writeOnly")) {
|
|
262
262
|
throw new Error(
|
|
263
|
-
"Can't make everyone something other than reader or
|
|
263
|
+
"Can't make everyone something other than reader, writer or writeOnly",
|
|
264
264
|
);
|
|
265
265
|
}
|
|
266
|
-
|
|
267
266
|
const currentReadKey = this.core.getCurrentReadKey();
|
|
268
267
|
|
|
269
268
|
if (!currentReadKey.secret) {
|
|
270
269
|
throw new Error("Can't add member without read key secret");
|
|
271
270
|
}
|
|
272
271
|
|
|
272
|
+
const previousRole = this.get(account);
|
|
273
|
+
|
|
273
274
|
this.set(account, role, "trusting");
|
|
274
275
|
|
|
275
276
|
if (this.get(account) !== role) {
|
|
276
277
|
throw new Error("Failed to set role");
|
|
277
278
|
}
|
|
278
279
|
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
280
|
+
if (role === "writeOnly") {
|
|
281
|
+
if (previousRole === "reader" || previousRole === "writer") {
|
|
282
|
+
this.rotateReadKey();
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
this.delete(`${currentReadKey.id}_for_${EVERYONE}`);
|
|
286
|
+
} else {
|
|
287
|
+
this.set(
|
|
288
|
+
`${currentReadKey.id}_for_${EVERYONE}`,
|
|
289
|
+
currentReadKey.secret,
|
|
290
|
+
"trusting",
|
|
291
|
+
);
|
|
292
|
+
}
|
|
284
293
|
|
|
285
294
|
return;
|
|
286
295
|
}
|
|
@@ -299,44 +308,18 @@ export class RawGroup<
|
|
|
299
308
|
* invite.
|
|
300
309
|
*/
|
|
301
310
|
if (role === "writeOnly" || role === "writeOnlyInvite") {
|
|
302
|
-
const
|
|
311
|
+
const previousRole = this.get(memberKey);
|
|
303
312
|
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
writeKeyForNewMember.id,
|
|
311
|
-
writeKeyForNewMember.secret,
|
|
312
|
-
);
|
|
313
|
-
|
|
314
|
-
for (const otherMemberKey of this.getMemberKeys()) {
|
|
315
|
-
const memberRole = this.get(otherMemberKey);
|
|
316
|
-
|
|
317
|
-
if (
|
|
318
|
-
memberRole === "reader" ||
|
|
319
|
-
memberRole === "writer" ||
|
|
320
|
-
memberRole === "admin" ||
|
|
321
|
-
memberRole === "readerInvite" ||
|
|
322
|
-
memberRole === "writerInvite" ||
|
|
323
|
-
memberRole === "adminInvite"
|
|
324
|
-
) {
|
|
325
|
-
const otherMemberAgent = this.core.node
|
|
326
|
-
.resolveAccountAgent(
|
|
327
|
-
otherMemberKey,
|
|
328
|
-
"Expected member agent to be loaded",
|
|
329
|
-
)
|
|
330
|
-
._unsafeUnwrap({ withStackTrace: true });
|
|
331
|
-
|
|
332
|
-
this.storeKeyRevelationForMember(
|
|
333
|
-
otherMemberKey,
|
|
334
|
-
otherMemberAgent,
|
|
335
|
-
writeKeyForNewMember.id,
|
|
336
|
-
writeKeyForNewMember.secret,
|
|
337
|
-
);
|
|
338
|
-
}
|
|
313
|
+
if (
|
|
314
|
+
previousRole === "reader" ||
|
|
315
|
+
previousRole === "writer" ||
|
|
316
|
+
previousRole === "admin"
|
|
317
|
+
) {
|
|
318
|
+
this.rotateReadKey();
|
|
339
319
|
}
|
|
320
|
+
|
|
321
|
+
this.set(memberKey, role, "trusting");
|
|
322
|
+
this.internalCreateWriteOnlyKeyForMember(memberKey, agent);
|
|
340
323
|
} else {
|
|
341
324
|
const currentReadKey = this.core.getCurrentReadKey();
|
|
342
325
|
|
|
@@ -370,6 +353,49 @@ export class RawGroup<
|
|
|
370
353
|
}
|
|
371
354
|
}
|
|
372
355
|
|
|
356
|
+
internalCreateWriteOnlyKeyForMember(
|
|
357
|
+
memberKey: RawAccountID | AgentID,
|
|
358
|
+
agent: AgentID,
|
|
359
|
+
) {
|
|
360
|
+
const writeKeyForNewMember = this.core.crypto.newRandomKeySecret();
|
|
361
|
+
|
|
362
|
+
this.set(`writeKeyFor_${memberKey}`, writeKeyForNewMember.id, "trusting");
|
|
363
|
+
|
|
364
|
+
this.storeKeyRevelationForMember(
|
|
365
|
+
memberKey,
|
|
366
|
+
agent,
|
|
367
|
+
writeKeyForNewMember.id,
|
|
368
|
+
writeKeyForNewMember.secret,
|
|
369
|
+
);
|
|
370
|
+
|
|
371
|
+
for (const otherMemberKey of this.getMemberKeys()) {
|
|
372
|
+
const memberRole = this.get(otherMemberKey);
|
|
373
|
+
|
|
374
|
+
if (
|
|
375
|
+
memberRole === "reader" ||
|
|
376
|
+
memberRole === "writer" ||
|
|
377
|
+
memberRole === "admin" ||
|
|
378
|
+
memberRole === "readerInvite" ||
|
|
379
|
+
memberRole === "writerInvite" ||
|
|
380
|
+
memberRole === "adminInvite"
|
|
381
|
+
) {
|
|
382
|
+
const otherMemberAgent = this.core.node
|
|
383
|
+
.resolveAccountAgent(
|
|
384
|
+
otherMemberKey,
|
|
385
|
+
"Expected member agent to be loaded",
|
|
386
|
+
)
|
|
387
|
+
._unsafeUnwrap({ withStackTrace: true });
|
|
388
|
+
|
|
389
|
+
this.storeKeyRevelationForMember(
|
|
390
|
+
otherMemberKey,
|
|
391
|
+
otherMemberAgent,
|
|
392
|
+
writeKeyForNewMember.id,
|
|
393
|
+
writeKeyForNewMember.secret,
|
|
394
|
+
);
|
|
395
|
+
}
|
|
396
|
+
}
|
|
397
|
+
}
|
|
398
|
+
|
|
373
399
|
private storeKeyRevelationForMember(
|
|
374
400
|
memberKey: RawAccountID | AgentID,
|
|
375
401
|
agent: AgentID,
|
|
@@ -409,7 +435,19 @@ export class RawGroup<
|
|
|
409
435
|
if (this.myRole() === "writeOnly") {
|
|
410
436
|
const accountId = this.core.node.account.id;
|
|
411
437
|
|
|
412
|
-
|
|
438
|
+
const key = this.get(`writeKeyFor_${accountId}`) as KeyID;
|
|
439
|
+
|
|
440
|
+
// When everyone is writeOnly, we need to create a writeOnly key for the current account if missing
|
|
441
|
+
if (!key && this.get("everyone") === "writeOnly") {
|
|
442
|
+
this.internalCreateWriteOnlyKeyForMember(
|
|
443
|
+
accountId,
|
|
444
|
+
this.core.node.account.currentAgentID(),
|
|
445
|
+
);
|
|
446
|
+
|
|
447
|
+
return this.get(`writeKeyFor_${accountId}`) as KeyID;
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
return key;
|
|
413
451
|
}
|
|
414
452
|
|
|
415
453
|
return this.get("readKey");
|
package/src/permissions.ts
CHANGED
|
@@ -225,6 +225,7 @@ function determineValidTransactionsForGroup(
|
|
|
225
225
|
});
|
|
226
226
|
|
|
227
227
|
const memberState: MemberState = {};
|
|
228
|
+
const writeOnlyKeys: Record<RawAccountID | AgentID, KeyID> = {};
|
|
228
229
|
const validTransactions: ValidTransactionsResult[] = [];
|
|
229
230
|
|
|
230
231
|
const keyRevelations = new Set<string>();
|
|
@@ -302,7 +303,8 @@ function determineValidTransactionsForGroup(
|
|
|
302
303
|
memberState[transactor] !== "adminInvite" &&
|
|
303
304
|
memberState[transactor] !== "writerInvite" &&
|
|
304
305
|
memberState[transactor] !== "readerInvite" &&
|
|
305
|
-
memberState[transactor] !== "writeOnlyInvite"
|
|
306
|
+
memberState[transactor] !== "writeOnlyInvite" &&
|
|
307
|
+
!isOwnWriteKeyRevelation(change.key, transactor, writeOnlyKeys)
|
|
306
308
|
) {
|
|
307
309
|
logPermissionError("Only admins can reveal keys");
|
|
308
310
|
continue;
|
|
@@ -370,14 +372,19 @@ function determineValidTransactionsForGroup(
|
|
|
370
372
|
validTransactions.push({ txID: { sessionID, txIndex }, tx });
|
|
371
373
|
continue;
|
|
372
374
|
} else if (isWriteKeyForMember(change.key)) {
|
|
375
|
+
const memberKey = getAccountOrAgentFromWriteKeyForMember(change.key);
|
|
376
|
+
|
|
373
377
|
if (
|
|
374
378
|
memberState[transactor] !== "admin" &&
|
|
375
|
-
memberState[transactor] !== "writeOnlyInvite"
|
|
379
|
+
memberState[transactor] !== "writeOnlyInvite" &&
|
|
380
|
+
memberKey !== transactor
|
|
376
381
|
) {
|
|
377
382
|
logPermissionError("Only admins can set writeKeys");
|
|
378
383
|
continue;
|
|
379
384
|
}
|
|
380
385
|
|
|
386
|
+
writeOnlyKeys[memberKey] = change.value as KeyID;
|
|
387
|
+
|
|
381
388
|
/**
|
|
382
389
|
* writeOnlyInvite need to be able to set writeKeys because every new writeOnly
|
|
383
390
|
* member comes with their own write key.
|
|
@@ -422,11 +429,12 @@ function determineValidTransactionsForGroup(
|
|
|
422
429
|
!(
|
|
423
430
|
change.value === "reader" ||
|
|
424
431
|
change.value === "writer" ||
|
|
432
|
+
change.value === "writeOnly" ||
|
|
425
433
|
change.value === "revoked"
|
|
426
434
|
)
|
|
427
435
|
) {
|
|
428
436
|
logPermissionError(
|
|
429
|
-
"Everyone can only be set to reader, writer or revoked",
|
|
437
|
+
"Everyone can only be set to reader, writer, writeOnly or revoked",
|
|
430
438
|
);
|
|
431
439
|
continue;
|
|
432
440
|
}
|
|
@@ -499,6 +507,12 @@ export function isWriteKeyForMember(
|
|
|
499
507
|
return co.startsWith("writeKeyFor_");
|
|
500
508
|
}
|
|
501
509
|
|
|
510
|
+
export function getAccountOrAgentFromWriteKeyForMember(
|
|
511
|
+
co: `writeKeyFor_${RawAccountID | AgentID}`,
|
|
512
|
+
): RawAccountID | AgentID {
|
|
513
|
+
return co.slice("writeKeyFor_".length) as RawAccountID | AgentID;
|
|
514
|
+
}
|
|
515
|
+
|
|
502
516
|
export function isKeyForKeyField(co: string): co is `${KeyID}_for_${KeyID}` {
|
|
503
517
|
return co.startsWith("key_") && co.includes("_for_key");
|
|
504
518
|
}
|
|
@@ -520,3 +534,17 @@ function isParentExtension(key: string): key is `parent_${CoID<RawGroup>}` {
|
|
|
520
534
|
function isChildExtension(key: string): key is `child_${CoID<RawGroup>}` {
|
|
521
535
|
return key.startsWith("child_");
|
|
522
536
|
}
|
|
537
|
+
|
|
538
|
+
function isOwnWriteKeyRevelation(
|
|
539
|
+
key: `${KeyID}_for_${string}`,
|
|
540
|
+
memberKey: RawAccountID | AgentID,
|
|
541
|
+
writeOnlyKeys: Record<RawAccountID | AgentID, KeyID>,
|
|
542
|
+
): key is `${KeyID}_for_${RawAccountID | AgentID}` {
|
|
543
|
+
if (Object.keys(writeOnlyKeys).length === 0) {
|
|
544
|
+
return false;
|
|
545
|
+
}
|
|
546
|
+
|
|
547
|
+
const keyID = key.slice(0, key.indexOf("_for_"));
|
|
548
|
+
|
|
549
|
+
return writeOnlyKeys[memberKey] === keyID;
|
|
550
|
+
}
|