cojson 0.7.0-alpha.5 → 0.7.0
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/.eslintrc.cjs +3 -2
- package/.prettierrc.js +9 -0
- package/.turbo/turbo-build.log +3 -30
- package/.turbo/turbo-lint.log +4 -0
- package/.turbo/turbo-test.log +1106 -0
- package/CHANGELOG.md +104 -0
- package/README.md +3 -1
- package/dist/base64url.test.js +25 -0
- package/dist/base64url.test.js.map +1 -0
- package/dist/coValueCore.js +60 -37
- package/dist/coValueCore.js.map +1 -1
- package/dist/coValues/account.js +16 -15
- package/dist/coValues/account.js.map +1 -1
- package/dist/coValues/coList.js +1 -1
- package/dist/coValues/coList.js.map +1 -1
- package/dist/coValues/coMap.js +17 -8
- package/dist/coValues/coMap.js.map +1 -1
- package/dist/coValues/group.js +13 -14
- package/dist/coValues/group.js.map +1 -1
- package/dist/coreToCoValue.js.map +1 -1
- package/dist/crypto/PureJSCrypto.js +89 -0
- package/dist/crypto/PureJSCrypto.js.map +1 -0
- package/dist/crypto/WasmCrypto.js +127 -0
- package/dist/crypto/WasmCrypto.js.map +1 -0
- package/dist/crypto/crypto.js +151 -0
- package/dist/crypto/crypto.js.map +1 -0
- package/dist/ids.js +4 -2
- package/dist/ids.js.map +1 -1
- package/dist/index.js +6 -8
- package/dist/index.js.map +1 -1
- package/dist/jsonStringify.js.map +1 -1
- package/dist/localNode.js +41 -38
- package/dist/localNode.js.map +1 -1
- package/dist/permissions.js +6 -6
- package/dist/permissions.js.map +1 -1
- package/dist/storage/FileSystem.js +61 -0
- package/dist/storage/FileSystem.js.map +1 -0
- package/dist/storage/chunksAndKnownStates.js +97 -0
- package/dist/storage/chunksAndKnownStates.js.map +1 -0
- package/dist/storage/index.js +265 -0
- package/dist/storage/index.js.map +1 -0
- package/dist/sync.js +29 -25
- package/dist/sync.js.map +1 -1
- package/dist/tests/account.test.js +58 -0
- package/dist/tests/account.test.js.map +1 -0
- package/dist/tests/coList.test.js +76 -0
- package/dist/tests/coList.test.js.map +1 -0
- package/dist/tests/coMap.test.js +136 -0
- package/dist/tests/coMap.test.js.map +1 -0
- package/dist/tests/coStream.test.js +172 -0
- package/dist/tests/coStream.test.js.map +1 -0
- package/dist/tests/coValueCore.test.js +114 -0
- package/dist/tests/coValueCore.test.js.map +1 -0
- package/dist/tests/crypto.test.js +118 -0
- package/dist/tests/crypto.test.js.map +1 -0
- package/dist/tests/cryptoImpl.test.js +113 -0
- package/dist/tests/cryptoImpl.test.js.map +1 -0
- package/dist/tests/group.test.js +34 -0
- package/dist/tests/group.test.js.map +1 -0
- package/dist/tests/permissions.test.js +1060 -0
- package/dist/tests/permissions.test.js.map +1 -0
- package/dist/tests/sync.test.js +816 -0
- package/dist/tests/sync.test.js.map +1 -0
- package/dist/tests/testUtils.js +12 -11
- package/dist/tests/testUtils.js.map +1 -1
- package/dist/typeUtils/accountOrAgentIDfromSessionID.js.map +1 -1
- package/dist/typeUtils/isAccountID.js.map +1 -1
- package/dist/typeUtils/isCoValue.js.map +1 -1
- package/package.json +14 -27
- package/src/base64url.test.ts +6 -5
- package/src/coValue.ts +1 -1
- package/src/coValueCore.ts +179 -126
- package/src/coValues/account.ts +30 -32
- package/src/coValues/coList.ts +11 -11
- package/src/coValues/coMap.ts +27 -17
- package/src/coValues/coStream.ts +17 -17
- package/src/coValues/group.ts +93 -109
- package/src/coreToCoValue.ts +5 -2
- package/src/crypto/PureJSCrypto.ts +200 -0
- package/src/crypto/WasmCrypto.ts +259 -0
- package/src/crypto/crypto.ts +336 -0
- package/src/ids.ts +8 -7
- package/src/index.ts +24 -24
- package/src/jsonStringify.ts +6 -4
- package/src/jsonValue.ts +2 -2
- package/src/localNode.ts +103 -109
- package/src/media.ts +3 -3
- package/src/permissions.ts +19 -21
- package/src/storage/FileSystem.ts +152 -0
- package/src/storage/chunksAndKnownStates.ts +139 -0
- package/src/storage/index.ts +479 -0
- package/src/streamUtils.ts +12 -12
- package/src/sync.ts +79 -63
- package/src/tests/account.test.ts +15 -15
- package/src/tests/coList.test.ts +94 -0
- package/src/tests/coMap.test.ts +162 -0
- package/src/tests/coStream.test.ts +246 -0
- package/src/tests/coValueCore.test.ts +36 -37
- package/src/tests/crypto.test.ts +66 -72
- package/src/tests/cryptoImpl.test.ts +183 -0
- package/src/tests/group.test.ts +16 -17
- package/src/tests/permissions.test.ts +269 -283
- package/src/tests/sync.test.ts +122 -123
- package/src/tests/testUtils.ts +24 -21
- package/src/typeUtils/accountOrAgentIDfromSessionID.ts +1 -2
- package/src/typeUtils/expectGroup.ts +1 -1
- package/src/typeUtils/isAccountID.ts +0 -1
- package/src/typeUtils/isCoValue.ts +1 -2
- package/tsconfig.json +0 -1
- package/dist/crypto.js +0 -254
- package/dist/crypto.js.map +0 -1
- package/src/crypto.ts +0 -484
- package/src/tests/coValue.test.ts +0 -497
package/src/coValueCore.ts
CHANGED
|
@@ -5,17 +5,9 @@ import {
|
|
|
5
5
|
KeySecret,
|
|
6
6
|
Signature,
|
|
7
7
|
StreamingHash,
|
|
8
|
-
unseal,
|
|
9
|
-
shortHash,
|
|
10
|
-
sign,
|
|
11
|
-
verify,
|
|
12
|
-
encryptForTransaction,
|
|
13
8
|
KeyID,
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
getAgentSealerID,
|
|
17
|
-
decryptRawForTransaction,
|
|
18
|
-
} from "./crypto.js";
|
|
9
|
+
CryptoProvider,
|
|
10
|
+
} from "./crypto/crypto.js";
|
|
19
11
|
import { JsonObject, JsonValue } from "./jsonValue.js";
|
|
20
12
|
import { base58 } from "@scure/base";
|
|
21
13
|
import {
|
|
@@ -44,15 +36,18 @@ export type CoValueHeader = {
|
|
|
44
36
|
uniqueness: `z${string}` | null;
|
|
45
37
|
};
|
|
46
38
|
|
|
47
|
-
export function idforHeader(
|
|
48
|
-
|
|
39
|
+
export function idforHeader(
|
|
40
|
+
header: CoValueHeader,
|
|
41
|
+
crypto: CryptoProvider,
|
|
42
|
+
): RawCoID {
|
|
43
|
+
const hash = crypto.shortHash(header);
|
|
49
44
|
return `co_z${hash.slice("shortHash_z".length)}`;
|
|
50
45
|
}
|
|
51
46
|
|
|
52
47
|
export function newRandomSessionID(accountID: AccountID | AgentID): SessionID {
|
|
53
48
|
return `${accountID}_session_z${base58.encode(
|
|
54
49
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
55
|
-
(globalThis as any).crypto.getRandomValues(new Uint8Array(8))
|
|
50
|
+
(globalThis as any).crypto.getRandomValues(new Uint8Array(8)),
|
|
56
51
|
)}`;
|
|
57
52
|
}
|
|
58
53
|
|
|
@@ -93,6 +88,7 @@ const readKeyCache = new WeakMap<CoValueCore, { [id: KeyID]: KeySecret }>();
|
|
|
93
88
|
export class CoValueCore {
|
|
94
89
|
id: RawCoID;
|
|
95
90
|
node: LocalNode;
|
|
91
|
+
crypto: CryptoProvider;
|
|
96
92
|
header: CoValueHeader;
|
|
97
93
|
_sessionLogs: Map<SessionID, SessionLog>;
|
|
98
94
|
_cachedContent?: RawCoValue;
|
|
@@ -108,9 +104,10 @@ export class CoValueCore {
|
|
|
108
104
|
constructor(
|
|
109
105
|
header: CoValueHeader,
|
|
110
106
|
node: LocalNode,
|
|
111
|
-
internalInitSessions: Map<SessionID, SessionLog> = new Map()
|
|
107
|
+
internalInitSessions: Map<SessionID, SessionLog> = new Map(),
|
|
112
108
|
) {
|
|
113
|
-
this.
|
|
109
|
+
this.crypto = node.crypto;
|
|
110
|
+
this.id = idforHeader(header, node.crypto);
|
|
114
111
|
this.header = header;
|
|
115
112
|
this._sessionLogs = internalInitSessions;
|
|
116
113
|
this.node = node;
|
|
@@ -134,11 +131,11 @@ export class CoValueCore {
|
|
|
134
131
|
|
|
135
132
|
testWithDifferentAccount(
|
|
136
133
|
account: ControlledAccountOrAgent,
|
|
137
|
-
currentSessionID: SessionID
|
|
134
|
+
currentSessionID: SessionID,
|
|
138
135
|
): CoValueCore {
|
|
139
136
|
const newNode = this.node.testWithDifferentAccount(
|
|
140
137
|
account,
|
|
141
|
-
currentSessionID
|
|
138
|
+
currentSessionID,
|
|
142
139
|
);
|
|
143
140
|
|
|
144
141
|
return newNode.expectCoValueLoaded(this.id);
|
|
@@ -163,7 +160,7 @@ export class CoValueCore {
|
|
|
163
160
|
[...this.sessionLogs.entries()].map(([k, v]) => [
|
|
164
161
|
k,
|
|
165
162
|
v.transactions.length,
|
|
166
|
-
])
|
|
163
|
+
]),
|
|
167
164
|
),
|
|
168
165
|
};
|
|
169
166
|
}
|
|
@@ -178,7 +175,7 @@ export class CoValueCore {
|
|
|
178
175
|
this.header.meta?.type === "account"
|
|
179
176
|
? (this.node.currentSessionID.replace(
|
|
180
177
|
this.node.account.id,
|
|
181
|
-
this.node.account.currentAgentID()
|
|
178
|
+
this.node.account.currentAgentID(),
|
|
182
179
|
) as SessionID)
|
|
183
180
|
: this.node.currentSessionID;
|
|
184
181
|
|
|
@@ -192,19 +189,19 @@ export class CoValueCore {
|
|
|
192
189
|
sessionID: SessionID,
|
|
193
190
|
newTransactions: Transaction[],
|
|
194
191
|
givenExpectedNewHash: Hash | undefined,
|
|
195
|
-
newSignature: Signature
|
|
192
|
+
newSignature: Signature,
|
|
196
193
|
): boolean {
|
|
197
|
-
const signerID = getAgentSignerID(
|
|
194
|
+
const signerID = this.crypto.getAgentSignerID(
|
|
198
195
|
this.node.resolveAccountAgent(
|
|
199
196
|
accountOrAgentIDfromSessionID(sessionID),
|
|
200
|
-
"Expected to know signer of transaction"
|
|
201
|
-
)
|
|
197
|
+
"Expected to know signer of transaction",
|
|
198
|
+
),
|
|
202
199
|
);
|
|
203
200
|
|
|
204
201
|
if (!signerID) {
|
|
205
202
|
console.warn(
|
|
206
203
|
"Unknown agent",
|
|
207
|
-
accountOrAgentIDfromSessionID(sessionID)
|
|
204
|
+
accountOrAgentIDfromSessionID(sessionID),
|
|
208
205
|
);
|
|
209
206
|
return false;
|
|
210
207
|
}
|
|
@@ -212,7 +209,7 @@ export class CoValueCore {
|
|
|
212
209
|
// const beforeHash = performance.now();
|
|
213
210
|
const { expectedNewHash, newStreamingHash } = this.expectedNewHashAfter(
|
|
214
211
|
sessionID,
|
|
215
|
-
newTransactions
|
|
212
|
+
newTransactions,
|
|
216
213
|
);
|
|
217
214
|
// const afterHash = performance.now();
|
|
218
215
|
// console.log(
|
|
@@ -229,13 +226,13 @@ export class CoValueCore {
|
|
|
229
226
|
}
|
|
230
227
|
|
|
231
228
|
// const beforeVerify = performance.now();
|
|
232
|
-
if (!verify(newSignature, expectedNewHash, signerID)) {
|
|
229
|
+
if (!this.crypto.verify(newSignature, expectedNewHash, signerID)) {
|
|
233
230
|
console.warn(
|
|
234
231
|
"Invalid signature in",
|
|
235
232
|
this.id,
|
|
236
233
|
newSignature,
|
|
237
234
|
expectedNewHash,
|
|
238
|
-
signerID
|
|
235
|
+
signerID,
|
|
239
236
|
);
|
|
240
237
|
return false;
|
|
241
238
|
}
|
|
@@ -250,7 +247,8 @@ export class CoValueCore {
|
|
|
250
247
|
newTransactions,
|
|
251
248
|
newSignature,
|
|
252
249
|
expectedNewHash,
|
|
253
|
-
newStreamingHash
|
|
250
|
+
newStreamingHash,
|
|
251
|
+
"immediate",
|
|
254
252
|
);
|
|
255
253
|
|
|
256
254
|
return true;
|
|
@@ -260,7 +258,7 @@ export class CoValueCore {
|
|
|
260
258
|
sessionID: SessionID,
|
|
261
259
|
newTransactions: Transaction[],
|
|
262
260
|
givenExpectedNewHash: Hash | undefined,
|
|
263
|
-
newSignature: Signature
|
|
261
|
+
newSignature: Signature,
|
|
264
262
|
): Promise<boolean> {
|
|
265
263
|
if (this.currentlyAsyncApplyingTxDone) {
|
|
266
264
|
await this.currentlyAsyncApplyingTxDone;
|
|
@@ -271,23 +269,24 @@ export class CoValueCore {
|
|
|
271
269
|
resolveDone = resolve;
|
|
272
270
|
});
|
|
273
271
|
|
|
274
|
-
const signerID = getAgentSignerID(
|
|
272
|
+
const signerID = this.crypto.getAgentSignerID(
|
|
275
273
|
await this.node.resolveAccountAgentAsync(
|
|
276
274
|
accountOrAgentIDfromSessionID(sessionID),
|
|
277
|
-
"Expected to know signer of transaction"
|
|
278
|
-
)
|
|
275
|
+
"Expected to know signer of transaction",
|
|
276
|
+
),
|
|
279
277
|
);
|
|
280
278
|
|
|
281
279
|
if (!signerID) {
|
|
282
280
|
console.warn(
|
|
283
281
|
"Unknown agent",
|
|
284
|
-
accountOrAgentIDfromSessionID(sessionID)
|
|
282
|
+
accountOrAgentIDfromSessionID(sessionID),
|
|
285
283
|
);
|
|
286
284
|
resolveDone();
|
|
287
285
|
return false;
|
|
288
286
|
}
|
|
289
287
|
|
|
290
|
-
const nTxBefore =
|
|
288
|
+
const nTxBefore =
|
|
289
|
+
this.sessionLogs.get(sessionID)?.transactions.length ?? 0;
|
|
291
290
|
|
|
292
291
|
// const beforeHash = performance.now();
|
|
293
292
|
const { expectedNewHash, newStreamingHash } =
|
|
@@ -298,7 +297,8 @@ export class CoValueCore {
|
|
|
298
297
|
// afterHash - beforeHash
|
|
299
298
|
// );
|
|
300
299
|
|
|
301
|
-
const nTxAfter =
|
|
300
|
+
const nTxAfter =
|
|
301
|
+
this.sessionLogs.get(sessionID)?.transactions.length ?? 0;
|
|
302
302
|
|
|
303
303
|
if (nTxAfter !== nTxBefore) {
|
|
304
304
|
const newTransactionLengthBefore = newTransactions.length;
|
|
@@ -320,30 +320,32 @@ export class CoValueCore {
|
|
|
320
320
|
return false;
|
|
321
321
|
}
|
|
322
322
|
|
|
323
|
-
|
|
324
|
-
if (!verify(newSignature, expectedNewHash, signerID)) {
|
|
323
|
+
performance.mark("verifyStart" + this.id);
|
|
324
|
+
if (!this.crypto.verify(newSignature, expectedNewHash, signerID)) {
|
|
325
325
|
console.warn(
|
|
326
326
|
"Invalid signature in",
|
|
327
327
|
this.id,
|
|
328
328
|
newSignature,
|
|
329
329
|
expectedNewHash,
|
|
330
|
-
signerID
|
|
330
|
+
signerID,
|
|
331
331
|
);
|
|
332
332
|
resolveDone();
|
|
333
333
|
return false;
|
|
334
334
|
}
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
335
|
+
performance.mark("verifyEnd" + this.id);
|
|
336
|
+
performance.measure(
|
|
337
|
+
"verify" + this.id,
|
|
338
|
+
"verifyStart" + this.id,
|
|
339
|
+
"verifyEnd" + this.id,
|
|
340
|
+
);
|
|
340
341
|
|
|
341
342
|
this.doAddTransactions(
|
|
342
343
|
sessionID,
|
|
343
344
|
newTransactions,
|
|
344
345
|
newSignature,
|
|
345
346
|
expectedNewHash,
|
|
346
|
-
newStreamingHash
|
|
347
|
+
newStreamingHash,
|
|
348
|
+
"deferred",
|
|
347
349
|
);
|
|
348
350
|
|
|
349
351
|
resolveDone();
|
|
@@ -355,16 +357,19 @@ export class CoValueCore {
|
|
|
355
357
|
newTransactions: Transaction[],
|
|
356
358
|
newSignature: Signature,
|
|
357
359
|
expectedNewHash: Hash,
|
|
358
|
-
newStreamingHash: StreamingHash
|
|
360
|
+
newStreamingHash: StreamingHash,
|
|
361
|
+
notifyMode: "immediate" | "deferred",
|
|
359
362
|
) {
|
|
360
|
-
const transactions =
|
|
363
|
+
const transactions =
|
|
364
|
+
this.sessionLogs.get(sessionID)?.transactions ?? [];
|
|
361
365
|
transactions.push(...newTransactions);
|
|
362
366
|
|
|
363
|
-
const signatureAfter =
|
|
367
|
+
const signatureAfter =
|
|
368
|
+
this.sessionLogs.get(sessionID)?.signatureAfter ?? {};
|
|
364
369
|
|
|
365
370
|
const lastInbetweenSignatureIdx = Object.keys(signatureAfter).reduce(
|
|
366
371
|
(max, idx) => (parseInt(idx) > max ? parseInt(idx) : max),
|
|
367
|
-
-1
|
|
372
|
+
-1,
|
|
368
373
|
);
|
|
369
374
|
|
|
370
375
|
const sizeOfTxsSinceLastInbetweenSignature = transactions
|
|
@@ -375,7 +380,7 @@ export class CoValueCore {
|
|
|
375
380
|
(tx.privacy === "private"
|
|
376
381
|
? tx.encryptedChanges.length
|
|
377
382
|
: tx.changes.length),
|
|
378
|
-
0
|
|
383
|
+
0,
|
|
379
384
|
);
|
|
380
385
|
|
|
381
386
|
if (sizeOfTxsSinceLastInbetweenSignature > 100 * 1024) {
|
|
@@ -402,13 +407,33 @@ export class CoValueCore {
|
|
|
402
407
|
this._cachedNewContentSinceEmpty = undefined;
|
|
403
408
|
|
|
404
409
|
if (this.listeners.size > 0) {
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
listener
|
|
410
|
+
if (notifyMode === "immediate") {
|
|
411
|
+
const content = this.getCurrentContent();
|
|
412
|
+
for (const listener of this.listeners) {
|
|
413
|
+
listener(content);
|
|
414
|
+
}
|
|
415
|
+
} else {
|
|
416
|
+
if (!this.nextDeferredNotify) {
|
|
417
|
+
this.nextDeferredNotify = new Promise((resolve) => {
|
|
418
|
+
setTimeout(() => {
|
|
419
|
+
this.nextDeferredNotify = undefined;
|
|
420
|
+
this.deferredUpdates = 0;
|
|
421
|
+
const content = this.getCurrentContent();
|
|
422
|
+
for (const listener of this.listeners) {
|
|
423
|
+
listener(content);
|
|
424
|
+
}
|
|
425
|
+
resolve();
|
|
426
|
+
}, 0);
|
|
427
|
+
});
|
|
428
|
+
}
|
|
429
|
+
this.deferredUpdates++;
|
|
408
430
|
}
|
|
409
431
|
}
|
|
410
432
|
}
|
|
411
433
|
|
|
434
|
+
deferredUpdates = 0;
|
|
435
|
+
nextDeferredNotify: Promise<void> | undefined;
|
|
436
|
+
|
|
412
437
|
subscribe(listener: (content?: RawCoValue) => void): () => void {
|
|
413
438
|
this.listeners.add(listener);
|
|
414
439
|
listener(this.getCurrentContent());
|
|
@@ -420,11 +445,11 @@ export class CoValueCore {
|
|
|
420
445
|
|
|
421
446
|
expectedNewHashAfter(
|
|
422
447
|
sessionID: SessionID,
|
|
423
|
-
newTransactions: Transaction[]
|
|
448
|
+
newTransactions: Transaction[],
|
|
424
449
|
): { expectedNewHash: Hash; newStreamingHash: StreamingHash } {
|
|
425
450
|
const streamingHash =
|
|
426
451
|
this.sessionLogs.get(sessionID)?.streamingHash.clone() ??
|
|
427
|
-
new StreamingHash();
|
|
452
|
+
new StreamingHash(this.crypto);
|
|
428
453
|
for (const transaction of newTransactions) {
|
|
429
454
|
streamingHash.update(transaction);
|
|
430
455
|
}
|
|
@@ -439,11 +464,11 @@ export class CoValueCore {
|
|
|
439
464
|
|
|
440
465
|
async expectedNewHashAfterAsync(
|
|
441
466
|
sessionID: SessionID,
|
|
442
|
-
newTransactions: Transaction[]
|
|
467
|
+
newTransactions: Transaction[],
|
|
443
468
|
): Promise<{ expectedNewHash: Hash; newStreamingHash: StreamingHash }> {
|
|
444
469
|
const streamingHash =
|
|
445
470
|
this.sessionLogs.get(sessionID)?.streamingHash.clone() ??
|
|
446
|
-
new StreamingHash();
|
|
471
|
+
new StreamingHash(this.crypto);
|
|
447
472
|
let before = performance.now();
|
|
448
473
|
for (const transaction of newTransactions) {
|
|
449
474
|
streamingHash.update(transaction);
|
|
@@ -465,7 +490,7 @@ export class CoValueCore {
|
|
|
465
490
|
|
|
466
491
|
makeTransaction(
|
|
467
492
|
changes: JsonValue[],
|
|
468
|
-
privacy: "private" | "trusting"
|
|
493
|
+
privacy: "private" | "trusting",
|
|
469
494
|
): boolean {
|
|
470
495
|
const madeAt = Date.now();
|
|
471
496
|
|
|
@@ -476,14 +501,18 @@ export class CoValueCore {
|
|
|
476
501
|
|
|
477
502
|
if (!keySecret) {
|
|
478
503
|
throw new Error(
|
|
479
|
-
"Can't make transaction without read key secret"
|
|
504
|
+
"Can't make transaction without read key secret",
|
|
480
505
|
);
|
|
481
506
|
}
|
|
482
507
|
|
|
483
|
-
const encrypted = encryptForTransaction(
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
508
|
+
const encrypted = this.crypto.encryptForTransaction(
|
|
509
|
+
changes,
|
|
510
|
+
keySecret,
|
|
511
|
+
{
|
|
512
|
+
in: this.id,
|
|
513
|
+
tx: this.nextTransactionID(),
|
|
514
|
+
},
|
|
515
|
+
);
|
|
487
516
|
|
|
488
517
|
this._decryptionCache[encrypted] = changes;
|
|
489
518
|
|
|
@@ -506,7 +535,7 @@ export class CoValueCore {
|
|
|
506
535
|
this.header.meta?.type === "account"
|
|
507
536
|
? (this.node.currentSessionID.replace(
|
|
508
537
|
this.node.account.id,
|
|
509
|
-
this.node.account.currentAgentID()
|
|
538
|
+
this.node.account.currentAgentID(),
|
|
510
539
|
) as SessionID)
|
|
511
540
|
: this.node.currentSessionID;
|
|
512
541
|
|
|
@@ -514,16 +543,16 @@ export class CoValueCore {
|
|
|
514
543
|
transaction,
|
|
515
544
|
]);
|
|
516
545
|
|
|
517
|
-
const signature = sign(
|
|
546
|
+
const signature = this.crypto.sign(
|
|
518
547
|
this.node.account.currentSignerSecret(),
|
|
519
|
-
expectedNewHash
|
|
548
|
+
expectedNewHash,
|
|
520
549
|
);
|
|
521
550
|
|
|
522
551
|
const success = this.tryAddTransactions(
|
|
523
552
|
sessionID,
|
|
524
553
|
[transaction],
|
|
525
554
|
expectedNewHash,
|
|
526
|
-
signature
|
|
555
|
+
signature,
|
|
527
556
|
);
|
|
528
557
|
|
|
529
558
|
if (success) {
|
|
@@ -533,7 +562,9 @@ export class CoValueCore {
|
|
|
533
562
|
return success;
|
|
534
563
|
}
|
|
535
564
|
|
|
536
|
-
getCurrentContent(options?: {
|
|
565
|
+
getCurrentContent(options?: {
|
|
566
|
+
ignorePrivateTransactions: true;
|
|
567
|
+
}): RawCoValue {
|
|
537
568
|
if (!options?.ignorePrivateTransactions && this._cachedContent) {
|
|
538
569
|
return this._cachedContent;
|
|
539
570
|
}
|
|
@@ -573,14 +604,15 @@ export class CoValueCore {
|
|
|
573
604
|
this._decryptionCache[tx.encryptedChanges];
|
|
574
605
|
|
|
575
606
|
if (!decrytedChanges) {
|
|
576
|
-
const decryptedString =
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
607
|
+
const decryptedString =
|
|
608
|
+
this.crypto.decryptRawForTransaction(
|
|
609
|
+
tx.encryptedChanges,
|
|
610
|
+
readKey,
|
|
611
|
+
{
|
|
612
|
+
in: this.id,
|
|
613
|
+
tx: txID,
|
|
614
|
+
},
|
|
615
|
+
);
|
|
584
616
|
decrytedChanges =
|
|
585
617
|
decryptedString && parseJSON(decryptedString);
|
|
586
618
|
this._decryptionCache[tx.encryptedChanges] =
|
|
@@ -589,7 +621,7 @@ export class CoValueCore {
|
|
|
589
621
|
|
|
590
622
|
if (!decrytedChanges) {
|
|
591
623
|
console.error(
|
|
592
|
-
"Failed to decrypt transaction despite having key"
|
|
624
|
+
"Failed to decrypt transaction despite having key",
|
|
593
625
|
);
|
|
594
626
|
return undefined;
|
|
595
627
|
}
|
|
@@ -606,7 +638,7 @@ export class CoValueCore {
|
|
|
606
638
|
(a, b) =>
|
|
607
639
|
a.madeAt - b.madeAt ||
|
|
608
640
|
(a.txID.sessionID < b.txID.sessionID ? -1 : 1) ||
|
|
609
|
-
a.txID.txIndex - b.txID.txIndex
|
|
641
|
+
a.txID.txIndex - b.txID.txIndex,
|
|
610
642
|
);
|
|
611
643
|
|
|
612
644
|
return allTransactions;
|
|
@@ -634,7 +666,7 @@ export class CoValueCore {
|
|
|
634
666
|
.getCurrentReadKey();
|
|
635
667
|
} else {
|
|
636
668
|
throw new Error(
|
|
637
|
-
"Only groups or values owned by groups have read secrets"
|
|
669
|
+
"Only groups or values owned by groups have read secrets",
|
|
638
670
|
);
|
|
639
671
|
}
|
|
640
672
|
}
|
|
@@ -658,7 +690,7 @@ export class CoValueCore {
|
|
|
658
690
|
getUncachedReadKey(keyID: KeyID): KeySecret | undefined {
|
|
659
691
|
if (this.header.ruleset.type === "group") {
|
|
660
692
|
const content = expectGroup(
|
|
661
|
-
this.getCurrentContent({ ignorePrivateTransactions: true })
|
|
693
|
+
this.getCurrentContent({ ignorePrivateTransactions: true }),
|
|
662
694
|
);
|
|
663
695
|
|
|
664
696
|
const keyForEveryone = content.get(`${keyID}_for_everyone`);
|
|
@@ -671,24 +703,24 @@ export class CoValueCore {
|
|
|
671
703
|
: this.node.account.id;
|
|
672
704
|
|
|
673
705
|
const lastReadyKeyEdit = content.lastEditAt(
|
|
674
|
-
`${keyID}_for_${lookupAccountOrAgentID}
|
|
706
|
+
`${keyID}_for_${lookupAccountOrAgentID}`,
|
|
675
707
|
);
|
|
676
708
|
|
|
677
709
|
if (lastReadyKeyEdit?.value) {
|
|
678
710
|
const revealer = lastReadyKeyEdit.by;
|
|
679
711
|
const revealerAgent = this.node.resolveAccountAgent(
|
|
680
712
|
revealer,
|
|
681
|
-
"Expected to know revealer"
|
|
713
|
+
"Expected to know revealer",
|
|
682
714
|
);
|
|
683
715
|
|
|
684
|
-
const secret = unseal(
|
|
716
|
+
const secret = this.crypto.unseal(
|
|
685
717
|
lastReadyKeyEdit.value,
|
|
686
718
|
this.node.account.currentSealerSecret(),
|
|
687
|
-
getAgentSealerID(revealerAgent),
|
|
719
|
+
this.crypto.getAgentSealerID(revealerAgent),
|
|
688
720
|
{
|
|
689
721
|
in: this.id,
|
|
690
722
|
tx: lastReadyKeyEdit.tx,
|
|
691
|
-
}
|
|
723
|
+
},
|
|
692
724
|
);
|
|
693
725
|
|
|
694
726
|
if (secret) {
|
|
@@ -698,9 +730,9 @@ export class CoValueCore {
|
|
|
698
730
|
|
|
699
731
|
// Try to find indirect revelation through previousKeys
|
|
700
732
|
|
|
701
|
-
for (const
|
|
702
|
-
if (isKeyForKeyField(
|
|
703
|
-
const encryptingKeyID =
|
|
733
|
+
for (const co of content.keys()) {
|
|
734
|
+
if (isKeyForKeyField(co) && co.startsWith(keyID)) {
|
|
735
|
+
const encryptingKeyID = co.split("_for_")[1] as KeyID;
|
|
704
736
|
const encryptingKeySecret =
|
|
705
737
|
this.getReadKey(encryptingKeyID);
|
|
706
738
|
|
|
@@ -708,22 +740,22 @@ export class CoValueCore {
|
|
|
708
740
|
continue;
|
|
709
741
|
}
|
|
710
742
|
|
|
711
|
-
const encryptedPreviousKey = content.get(
|
|
743
|
+
const encryptedPreviousKey = content.get(co)!;
|
|
712
744
|
|
|
713
|
-
const secret = decryptKeySecret(
|
|
745
|
+
const secret = this.crypto.decryptKeySecret(
|
|
714
746
|
{
|
|
715
747
|
encryptedID: keyID,
|
|
716
748
|
encryptingID: encryptingKeyID,
|
|
717
749
|
encrypted: encryptedPreviousKey,
|
|
718
750
|
},
|
|
719
|
-
encryptingKeySecret
|
|
751
|
+
encryptingKeySecret,
|
|
720
752
|
);
|
|
721
753
|
|
|
722
754
|
if (secret) {
|
|
723
755
|
return secret as KeySecret;
|
|
724
756
|
} else {
|
|
725
757
|
console.error(
|
|
726
|
-
`Encrypting ${encryptingKeyID} key didn't decrypt ${keyID}
|
|
758
|
+
`Encrypting ${encryptingKeyID} key didn't decrypt ${keyID}`,
|
|
727
759
|
);
|
|
728
760
|
}
|
|
729
761
|
}
|
|
@@ -736,7 +768,7 @@ export class CoValueCore {
|
|
|
736
768
|
.getReadKey(keyID);
|
|
737
769
|
} else {
|
|
738
770
|
throw new Error(
|
|
739
|
-
"Only groups or values owned by groups have read secrets"
|
|
771
|
+
"Only groups or values owned by groups have read secrets",
|
|
740
772
|
);
|
|
741
773
|
}
|
|
742
774
|
}
|
|
@@ -749,7 +781,7 @@ export class CoValueCore {
|
|
|
749
781
|
return expectGroup(
|
|
750
782
|
this.node
|
|
751
783
|
.expectCoValueLoaded(this.header.ruleset.group)
|
|
752
|
-
.getCurrentContent()
|
|
784
|
+
.getCurrentContent(),
|
|
753
785
|
);
|
|
754
786
|
}
|
|
755
787
|
|
|
@@ -758,7 +790,7 @@ export class CoValueCore {
|
|
|
758
790
|
}
|
|
759
791
|
|
|
760
792
|
newContentSince(
|
|
761
|
-
knownState: CoValueKnownState | undefined
|
|
793
|
+
knownState: CoValueKnownState | undefined,
|
|
762
794
|
): NewContentMessage[] | undefined {
|
|
763
795
|
const isKnownStateEmpty = !knownState?.header && !knownState?.sessions;
|
|
764
796
|
|
|
@@ -781,7 +813,11 @@ export class CoValueCore {
|
|
|
781
813
|
|
|
782
814
|
let sessionsTodoAgain: Set<SessionID> | undefined | "first" = "first";
|
|
783
815
|
|
|
784
|
-
while (
|
|
816
|
+
while (
|
|
817
|
+
sessionsTodoAgain === "first" ||
|
|
818
|
+
sessionsTodoAgain?.size ||
|
|
819
|
+
0 > 0
|
|
820
|
+
) {
|
|
785
821
|
if (sessionsTodoAgain === "first") {
|
|
786
822
|
sessionsTodoAgain = undefined;
|
|
787
823
|
}
|
|
@@ -795,13 +831,15 @@ export class CoValueCore {
|
|
|
795
831
|
const nextKnownSignatureIdx = getNextKnownSignatureIdx(
|
|
796
832
|
log,
|
|
797
833
|
knownStateForSessionID,
|
|
798
|
-
sentStateForSessionID
|
|
834
|
+
sentStateForSessionID,
|
|
799
835
|
);
|
|
800
836
|
|
|
801
|
-
const firstNewTxIdx =
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
837
|
+
const firstNewTxIdx =
|
|
838
|
+
sentStateForSessionID ?? knownStateForSessionID ?? 0;
|
|
839
|
+
const afterLastNewTxIdx =
|
|
840
|
+
nextKnownSignatureIdx === undefined
|
|
841
|
+
? log.transactions.length
|
|
842
|
+
: nextKnownSignatureIdx + 1;
|
|
805
843
|
|
|
806
844
|
const nNewTx = Math.max(0, afterLastNewTxIdx - firstNewTxIdx);
|
|
807
845
|
|
|
@@ -818,11 +856,16 @@ export class CoValueCore {
|
|
|
818
856
|
}
|
|
819
857
|
|
|
820
858
|
const oldPieceSize = pieceSize;
|
|
821
|
-
for (
|
|
859
|
+
for (
|
|
860
|
+
let txIdx = firstNewTxIdx;
|
|
861
|
+
txIdx < afterLastNewTxIdx;
|
|
862
|
+
txIdx++
|
|
863
|
+
) {
|
|
822
864
|
const tx = log.transactions[txIdx]!;
|
|
823
|
-
pieceSize +=
|
|
824
|
-
|
|
825
|
-
|
|
865
|
+
pieceSize +=
|
|
866
|
+
tx.privacy === "private"
|
|
867
|
+
? tx.encryptedChanges.length
|
|
868
|
+
: tx.changes.length;
|
|
826
869
|
}
|
|
827
870
|
|
|
828
871
|
if (pieceSize >= MAX_RECOMMENDED_TX_SIZE) {
|
|
@@ -839,31 +882,38 @@ export class CoValueCore {
|
|
|
839
882
|
let sessionEntry = currentPiece.new[sessionID];
|
|
840
883
|
if (!sessionEntry) {
|
|
841
884
|
sessionEntry = {
|
|
842
|
-
after:
|
|
885
|
+
after:
|
|
886
|
+
sentStateForSessionID ??
|
|
887
|
+
knownStateForSessionID ??
|
|
888
|
+
0,
|
|
843
889
|
newTransactions: [],
|
|
844
890
|
lastSignature: "WILL_BE_REPLACED" as Signature,
|
|
845
891
|
};
|
|
846
892
|
currentPiece.new[sessionID] = sessionEntry;
|
|
847
893
|
}
|
|
848
894
|
|
|
849
|
-
for (
|
|
895
|
+
for (
|
|
896
|
+
let txIdx = firstNewTxIdx;
|
|
897
|
+
txIdx < afterLastNewTxIdx;
|
|
898
|
+
txIdx++
|
|
899
|
+
) {
|
|
850
900
|
const tx = log.transactions[txIdx]!;
|
|
851
901
|
sessionEntry.newTransactions.push(tx);
|
|
852
902
|
}
|
|
853
903
|
|
|
854
|
-
|
|
855
904
|
sessionEntry.lastSignature =
|
|
856
905
|
nextKnownSignatureIdx === undefined
|
|
857
906
|
? log.lastSignature!
|
|
858
907
|
: log.signatureAfter[nextKnownSignatureIdx]!;
|
|
859
908
|
|
|
860
909
|
sentState[sessionID] =
|
|
861
|
-
(sentStateForSessionID ?? knownStateForSessionID ?? 0) +
|
|
910
|
+
(sentStateForSessionID ?? knownStateForSessionID ?? 0) +
|
|
911
|
+
nNewTx;
|
|
862
912
|
}
|
|
863
913
|
}
|
|
864
914
|
|
|
865
915
|
const piecesWithContent = pieces.filter(
|
|
866
|
-
(piece) => Object.keys(piece.new).length > 0 || piece.header
|
|
916
|
+
(piece) => Object.keys(piece.new).length > 0 || piece.header,
|
|
867
917
|
);
|
|
868
918
|
|
|
869
919
|
if (piecesWithContent.length === 0) {
|
|
@@ -894,22 +944,22 @@ export class CoValueCore {
|
|
|
894
944
|
.keys()
|
|
895
945
|
.filter((k): k is AccountID => k.startsWith("co_"))
|
|
896
946
|
: this.header.ruleset.type === "ownedByGroup"
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
947
|
+
? [
|
|
948
|
+
this.header.ruleset.group,
|
|
949
|
+
...new Set(
|
|
950
|
+
[...this.sessionLogs.keys()]
|
|
951
|
+
.map((sessionID) =>
|
|
952
|
+
accountOrAgentIDfromSessionID(
|
|
953
|
+
sessionID as SessionID,
|
|
954
|
+
),
|
|
955
|
+
)
|
|
956
|
+
.filter(
|
|
957
|
+
(session): session is AccountID =>
|
|
958
|
+
isAccountID(session) && session !== this.id,
|
|
959
|
+
),
|
|
960
|
+
),
|
|
961
|
+
]
|
|
962
|
+
: [];
|
|
913
963
|
}
|
|
914
964
|
}
|
|
915
965
|
|
|
@@ -921,5 +971,8 @@ function getNextKnownSignatureIdx(
|
|
|
921
971
|
return Object.keys(log.signatureAfter)
|
|
922
972
|
.map(Number)
|
|
923
973
|
.sort((a, b) => a - b)
|
|
924
|
-
.find(
|
|
974
|
+
.find(
|
|
975
|
+
(idx) =>
|
|
976
|
+
idx >= (sentStateForSessionID ?? knownStateForSessionID ?? -1),
|
|
977
|
+
);
|
|
925
978
|
}
|