cojson 0.17.11 → 0.17.13
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 +17 -0
- package/dist/coValueCore/SessionMap.d.ts +4 -3
- package/dist/coValueCore/SessionMap.d.ts.map +1 -1
- package/dist/coValueCore/SessionMap.js +15 -4
- package/dist/coValueCore/SessionMap.js.map +1 -1
- package/dist/coValueCore/coValueCore.d.ts +2 -2
- package/dist/coValueCore/coValueCore.d.ts.map +1 -1
- package/dist/coValueCore/coValueCore.js +33 -32
- package/dist/coValueCore/coValueCore.js.map +1 -1
- package/dist/coValueCore/utils.d.ts.map +1 -1
- package/dist/coValueCore/utils.js.map +1 -1
- package/dist/coValueCore/verifiedState.d.ts +8 -2
- package/dist/coValueCore/verifiedState.d.ts.map +1 -1
- package/dist/coValueCore/verifiedState.js +7 -4
- package/dist/coValueCore/verifiedState.js.map +1 -1
- package/dist/crypto/PureJSCrypto.d.ts +4 -3
- package/dist/crypto/PureJSCrypto.d.ts.map +1 -1
- package/dist/crypto/PureJSCrypto.js +34 -2
- package/dist/crypto/PureJSCrypto.js.map +1 -1
- package/dist/crypto/WasmCrypto.d.ts +4 -3
- package/dist/crypto/WasmCrypto.d.ts.map +1 -1
- package/dist/crypto/WasmCrypto.js +10 -4
- package/dist/crypto/WasmCrypto.js.map +1 -1
- package/dist/crypto/crypto.d.ts +4 -3
- package/dist/crypto/crypto.d.ts.map +1 -1
- package/dist/localNode.js +1 -1
- package/dist/localNode.js.map +1 -1
- package/dist/queue/LocalTransactionsSyncQueue.d.ts +15 -0
- package/dist/queue/LocalTransactionsSyncQueue.d.ts.map +1 -1
- package/dist/queue/LocalTransactionsSyncQueue.js +25 -0
- package/dist/queue/LocalTransactionsSyncQueue.js.map +1 -1
- package/dist/sync.d.ts +10 -7
- package/dist/sync.d.ts.map +1 -1
- package/dist/sync.js +33 -31
- package/dist/sync.js.map +1 -1
- package/dist/tests/PureJSCrypto.test.js +43 -0
- package/dist/tests/PureJSCrypto.test.js.map +1 -1
- package/dist/tests/WasmCrypto.test.js +55 -0
- package/dist/tests/WasmCrypto.test.js.map +1 -1
- package/dist/tests/coList.test.js +13 -0
- package/dist/tests/coList.test.js.map +1 -1
- package/dist/tests/coMap.test.js +14 -0
- package/dist/tests/coMap.test.js.map +1 -1
- package/dist/tests/coPlainText.test.js +13 -0
- package/dist/tests/coPlainText.test.js.map +1 -1
- package/dist/tests/coStream.test.js +25 -0
- package/dist/tests/coStream.test.js.map +1 -1
- package/dist/tests/coValueCore.test.js +28 -2
- package/dist/tests/coValueCore.test.js.map +1 -1
- package/dist/tests/coreWasm.test.js +1 -1
- package/dist/tests/coreWasm.test.js.map +1 -1
- package/dist/tests/sync.known.test.d.ts +2 -0
- package/dist/tests/sync.known.test.d.ts.map +1 -0
- package/dist/tests/sync.known.test.js +78 -0
- package/dist/tests/sync.known.test.js.map +1 -0
- package/dist/tests/sync.sharding.test.d.ts +2 -0
- package/dist/tests/sync.sharding.test.d.ts.map +1 -0
- package/dist/tests/sync.sharding.test.js +85 -0
- package/dist/tests/sync.sharding.test.js.map +1 -0
- package/dist/tests/sync.storage.test.js +31 -1
- package/dist/tests/sync.storage.test.js.map +1 -1
- package/dist/tests/sync.storageAsync.test.js +1 -1
- package/dist/tests/sync.storageAsync.test.js.map +1 -1
- package/dist/tests/sync.test.js +31 -2
- package/dist/tests/sync.test.js.map +1 -1
- package/dist/tests/sync.upload.test.js +26 -0
- package/dist/tests/sync.upload.test.js.map +1 -1
- package/dist/tests/testUtils.d.ts.map +1 -1
- package/dist/tests/testUtils.js +3 -1
- package/dist/tests/testUtils.js.map +1 -1
- package/package.json +2 -2
- package/src/coValueCore/SessionMap.ts +24 -1
- package/src/coValueCore/coValueCore.ts +46 -41
- package/src/coValueCore/utils.ts +0 -1
- package/src/coValueCore/verifiedState.ts +14 -3
- package/src/crypto/PureJSCrypto.ts +49 -1
- package/src/crypto/WasmCrypto.ts +15 -1
- package/src/crypto/crypto.ts +7 -1
- package/src/localNode.ts +1 -1
- package/src/queue/LocalTransactionsSyncQueue.ts +32 -1
- package/src/sync.ts +50 -36
- package/src/tests/PureJSCrypto.test.ts +66 -0
- package/src/tests/WasmCrypto.test.ts +88 -0
- package/src/tests/coList.test.ts +19 -0
- package/src/tests/coMap.test.ts +21 -0
- package/src/tests/coPlainText.test.ts +18 -0
- package/src/tests/coStream.test.ts +36 -0
- package/src/tests/coValueCore.test.ts +49 -0
- package/src/tests/coreWasm.test.ts +1 -0
- package/src/tests/sync.known.test.ts +109 -0
- package/src/tests/sync.sharding.test.ts +119 -0
- package/src/tests/sync.storage.test.ts +43 -1
- package/src/tests/sync.storageAsync.test.ts +1 -1
- package/src/tests/sync.test.ts +49 -2
- package/src/tests/sync.upload.test.ts +35 -0
- package/src/tests/testUtils.ts +3 -1
|
@@ -11,7 +11,7 @@ import type {
|
|
|
11
11
|
} from "../crypto/crypto.js";
|
|
12
12
|
import { RawCoID, SessionID } from "../ids.js";
|
|
13
13
|
import { parseJSON, stableStringify, Stringified } from "../jsonStringify.js";
|
|
14
|
-
import { JsonValue } from "../jsonValue.js";
|
|
14
|
+
import { JsonObject, JsonValue } from "../jsonValue.js";
|
|
15
15
|
import { CoValueKnownState } from "../sync.js";
|
|
16
16
|
import { TryAddTransactionsError } from "./coValueCore.js";
|
|
17
17
|
import { Transaction } from "./verifiedState.js";
|
|
@@ -91,6 +91,7 @@ export class SessionMap {
|
|
|
91
91
|
changes: JsonValue[],
|
|
92
92
|
keyID: KeyID,
|
|
93
93
|
keySecret: KeySecret,
|
|
94
|
+
meta: JsonObject | undefined,
|
|
94
95
|
): { signature: Signature; transaction: Transaction } {
|
|
95
96
|
const sessionLog = this.getOrCreateSessionLog(
|
|
96
97
|
sessionID,
|
|
@@ -104,6 +105,7 @@ export class SessionMap {
|
|
|
104
105
|
keyID,
|
|
105
106
|
keySecret,
|
|
106
107
|
madeAt,
|
|
108
|
+
meta,
|
|
107
109
|
);
|
|
108
110
|
|
|
109
111
|
this.addTransactionsToJsLog(
|
|
@@ -119,6 +121,7 @@ export class SessionMap {
|
|
|
119
121
|
sessionID: SessionID,
|
|
120
122
|
signerAgent: ControlledAccountOrAgent,
|
|
121
123
|
changes: JsonValue[],
|
|
124
|
+
meta: JsonObject | undefined,
|
|
122
125
|
): { signature: Signature; transaction: Transaction } {
|
|
123
126
|
const sessionLog = this.getOrCreateSessionLog(
|
|
124
127
|
sessionID,
|
|
@@ -130,6 +133,7 @@ export class SessionMap {
|
|
|
130
133
|
signerAgent,
|
|
131
134
|
changes,
|
|
132
135
|
madeAt,
|
|
136
|
+
meta,
|
|
133
137
|
);
|
|
134
138
|
|
|
135
139
|
this.addTransactionsToJsLog(
|
|
@@ -193,6 +197,25 @@ export class SessionMap {
|
|
|
193
197
|
return parseJSON(decrypted as Stringified<JsonValue[] | undefined>);
|
|
194
198
|
}
|
|
195
199
|
|
|
200
|
+
decryptTransactionMeta(
|
|
201
|
+
sessionID: SessionID,
|
|
202
|
+
txIndex: number,
|
|
203
|
+
keySecret: KeySecret,
|
|
204
|
+
): JsonObject | undefined {
|
|
205
|
+
const sessionLog = this.sessions.get(sessionID);
|
|
206
|
+
if (!sessionLog?.transactions[txIndex]?.meta) {
|
|
207
|
+
return undefined;
|
|
208
|
+
}
|
|
209
|
+
const decrypted = sessionLog.impl.decryptNextTransactionMetaJson(
|
|
210
|
+
txIndex,
|
|
211
|
+
keySecret,
|
|
212
|
+
);
|
|
213
|
+
if (!decrypted) {
|
|
214
|
+
return undefined;
|
|
215
|
+
}
|
|
216
|
+
return parseJSON(decrypted as Stringified<JsonObject | undefined>);
|
|
217
|
+
}
|
|
218
|
+
|
|
196
219
|
get size() {
|
|
197
220
|
return this.sessions.size;
|
|
198
221
|
}
|
|
@@ -14,11 +14,10 @@ import {
|
|
|
14
14
|
KeySecret,
|
|
15
15
|
Signature,
|
|
16
16
|
SignerID,
|
|
17
|
-
StreamingHash,
|
|
18
17
|
} from "../crypto/crypto.js";
|
|
19
18
|
import { RawCoID, SessionID, TransactionID } from "../ids.js";
|
|
20
|
-
import {
|
|
21
|
-
import {
|
|
19
|
+
import { JsonObject, JsonValue } from "../jsonValue.js";
|
|
20
|
+
import { parseJSON } from "../jsonStringify.js";
|
|
22
21
|
import { LocalNode, ResolveAccountAgentError } from "../localNode.js";
|
|
23
22
|
import { logger } from "../logger.js";
|
|
24
23
|
import { determineValidTransactions } from "../permissions.js";
|
|
@@ -85,6 +84,7 @@ export class CoValueCore {
|
|
|
85
84
|
new Set();
|
|
86
85
|
private readonly _decryptionCache: {
|
|
87
86
|
[key: Encrypted<JsonValue[], JsonValue>]: JsonValue[] | undefined;
|
|
87
|
+
[key: Encrypted<JsonObject, JsonValue>]: JsonObject | undefined;
|
|
88
88
|
} = {};
|
|
89
89
|
private _cachedDependentOn?: Set<RawCoID>;
|
|
90
90
|
private counter: UpDownCounter;
|
|
@@ -552,6 +552,7 @@ export class CoValueCore {
|
|
|
552
552
|
makeTransaction(
|
|
553
553
|
changes: JsonValue[],
|
|
554
554
|
privacy: "private" | "trusting",
|
|
555
|
+
meta?: JsonObject,
|
|
555
556
|
): boolean {
|
|
556
557
|
if (!this.verified) {
|
|
557
558
|
throw new Error(
|
|
@@ -585,16 +586,22 @@ export class CoValueCore {
|
|
|
585
586
|
changes,
|
|
586
587
|
keyID,
|
|
587
588
|
keySecret,
|
|
589
|
+
meta,
|
|
588
590
|
);
|
|
589
591
|
|
|
590
592
|
if (result.transaction.privacy === "private") {
|
|
591
593
|
this._decryptionCache[result.transaction.encryptedChanges] = changes;
|
|
594
|
+
|
|
595
|
+
if (result.transaction.meta) {
|
|
596
|
+
this._decryptionCache[result.transaction.meta] = meta;
|
|
597
|
+
}
|
|
592
598
|
}
|
|
593
599
|
} else {
|
|
594
600
|
result = this.verified.makeNewTrustingTransaction(
|
|
595
601
|
sessionID,
|
|
596
602
|
signerAgent,
|
|
597
603
|
changes,
|
|
604
|
+
meta,
|
|
598
605
|
);
|
|
599
606
|
}
|
|
600
607
|
|
|
@@ -661,57 +668,55 @@ export class CoValueCore {
|
|
|
661
668
|
continue;
|
|
662
669
|
}
|
|
663
670
|
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
changes: parseJSON(tx.changes),
|
|
670
|
-
trusting: true,
|
|
671
|
-
});
|
|
672
|
-
} catch (e) {
|
|
673
|
-
logger.error("Failed to parse trusting transaction on " + this.id, {
|
|
674
|
-
err: e,
|
|
675
|
-
txID,
|
|
676
|
-
changes: tx.changes.slice(0, 50),
|
|
677
|
-
});
|
|
671
|
+
let changes: JsonValue[];
|
|
672
|
+
|
|
673
|
+
if (tx.privacy === "private") {
|
|
674
|
+
if (options?.ignorePrivateTransactions) {
|
|
675
|
+
continue;
|
|
678
676
|
}
|
|
679
|
-
continue;
|
|
680
|
-
}
|
|
681
677
|
|
|
682
|
-
|
|
683
|
-
continue;
|
|
684
|
-
}
|
|
678
|
+
const readKey = this.getReadKey(tx.keyUsed);
|
|
685
679
|
|
|
686
|
-
|
|
680
|
+
if (!readKey) {
|
|
681
|
+
continue;
|
|
682
|
+
}
|
|
687
683
|
|
|
688
|
-
|
|
689
|
-
continue;
|
|
690
|
-
}
|
|
684
|
+
let decryptedChanges = this._decryptionCache[tx.encryptedChanges];
|
|
691
685
|
|
|
692
|
-
|
|
686
|
+
if (!decryptedChanges) {
|
|
687
|
+
decryptedChanges = this.verified.decryptTransaction(
|
|
688
|
+
txID.sessionID,
|
|
689
|
+
txID.txIndex,
|
|
690
|
+
readKey,
|
|
691
|
+
);
|
|
693
692
|
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
txID.sessionID,
|
|
697
|
-
txID.txIndex,
|
|
698
|
-
readKey,
|
|
699
|
-
);
|
|
693
|
+
this._decryptionCache[tx.encryptedChanges] = decryptedChanges;
|
|
694
|
+
}
|
|
700
695
|
|
|
701
|
-
|
|
702
|
-
|
|
696
|
+
if (!decryptedChanges) {
|
|
697
|
+
logger.error("Failed to decrypt transaction despite having key", {
|
|
698
|
+
err: new Error("Failed to decrypt transaction despite having key"),
|
|
699
|
+
});
|
|
700
|
+
continue;
|
|
701
|
+
}
|
|
703
702
|
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
703
|
+
changes = decryptedChanges;
|
|
704
|
+
} else {
|
|
705
|
+
try {
|
|
706
|
+
changes = parseJSON(tx.changes);
|
|
707
|
+
} catch (e) {
|
|
708
|
+
logger.error("Failed to parse trusting transaction on " + this.id, {
|
|
709
|
+
err: e,
|
|
710
|
+
});
|
|
711
|
+
continue;
|
|
712
|
+
}
|
|
709
713
|
}
|
|
710
714
|
|
|
711
715
|
allTransactions.push({
|
|
712
716
|
txID,
|
|
713
717
|
madeAt: tx.madeAt,
|
|
714
|
-
changes
|
|
718
|
+
changes,
|
|
719
|
+
trusting: tx.privacy === "trusting",
|
|
715
720
|
});
|
|
716
721
|
}
|
|
717
722
|
|
package/src/coValueCore/utils.ts
CHANGED
|
@@ -2,7 +2,6 @@ import { getGroupDependentKey } from "../ids.js";
|
|
|
2
2
|
import { RawCoID, SessionID } from "../ids.js";
|
|
3
3
|
import { Stringified, parseJSON } from "../jsonStringify.js";
|
|
4
4
|
import { JsonValue } from "../jsonValue.js";
|
|
5
|
-
import { NewContentMessage } from "../sync.js";
|
|
6
5
|
import { accountOrAgentIDfromSessionID } from "../typeUtils/accountOrAgentIDfromSessionID.js";
|
|
7
6
|
import { isAccountID } from "../typeUtils/isAccountID.js";
|
|
8
7
|
import { CoValueHeader, Transaction } from "./verifiedState.js";
|
|
@@ -8,19 +8,16 @@ import {
|
|
|
8
8
|
import {
|
|
9
9
|
CryptoProvider,
|
|
10
10
|
Encrypted,
|
|
11
|
-
Hash,
|
|
12
11
|
KeyID,
|
|
13
12
|
KeySecret,
|
|
14
13
|
Signature,
|
|
15
14
|
SignerID,
|
|
16
|
-
StreamingHash,
|
|
17
15
|
} from "../crypto/crypto.js";
|
|
18
16
|
import { RawCoID, SessionID, TransactionID } from "../ids.js";
|
|
19
17
|
import { Stringified } from "../jsonStringify.js";
|
|
20
18
|
import { JsonObject, JsonValue } from "../jsonValue.js";
|
|
21
19
|
import { PermissionsDef as RulesetDef } from "../permissions.js";
|
|
22
20
|
import { CoValueKnownState, NewContentMessage } from "../sync.js";
|
|
23
|
-
import { InvalidHashError, InvalidSignatureError } from "./coValueCore.js";
|
|
24
21
|
import { TryAddTransactionsError } from "./coValueCore.js";
|
|
25
22
|
import { SessionLog, SessionMap } from "./SessionMap.js";
|
|
26
23
|
import { ControlledAccountOrAgent } from "../coValues/account.js";
|
|
@@ -41,12 +38,14 @@ export type PrivateTransaction = {
|
|
|
41
38
|
madeAt: number;
|
|
42
39
|
keyUsed: KeyID;
|
|
43
40
|
encryptedChanges: Encrypted<JsonValue[], { in: RawCoID; tx: TransactionID }>;
|
|
41
|
+
meta?: Encrypted<JsonObject, { in: RawCoID; tx: TransactionID }>;
|
|
44
42
|
};
|
|
45
43
|
|
|
46
44
|
export type TrustingTransaction = {
|
|
47
45
|
privacy: "trusting";
|
|
48
46
|
madeAt: number;
|
|
49
47
|
changes: Stringified<JsonValue[]>;
|
|
48
|
+
meta?: Stringified<JsonObject>;
|
|
50
49
|
};
|
|
51
50
|
|
|
52
51
|
export type Transaction = PrivateTransaction | TrustingTransaction;
|
|
@@ -114,11 +113,13 @@ export class VerifiedState {
|
|
|
114
113
|
sessionID: SessionID,
|
|
115
114
|
signerAgent: ControlledAccountOrAgent,
|
|
116
115
|
changes: JsonValue[],
|
|
116
|
+
meta: JsonObject | undefined,
|
|
117
117
|
) {
|
|
118
118
|
const result = this.sessions.makeNewTrustingTransaction(
|
|
119
119
|
sessionID,
|
|
120
120
|
signerAgent,
|
|
121
121
|
changes,
|
|
122
|
+
meta,
|
|
122
123
|
);
|
|
123
124
|
|
|
124
125
|
this._cachedNewContentSinceEmpty = undefined;
|
|
@@ -133,6 +134,7 @@ export class VerifiedState {
|
|
|
133
134
|
changes: JsonValue[],
|
|
134
135
|
keyID: KeyID,
|
|
135
136
|
keySecret: KeySecret,
|
|
137
|
+
meta: JsonObject | undefined,
|
|
136
138
|
) {
|
|
137
139
|
const result = this.sessions.makeNewPrivateTransaction(
|
|
138
140
|
sessionID,
|
|
@@ -140,6 +142,7 @@ export class VerifiedState {
|
|
|
140
142
|
changes,
|
|
141
143
|
keyID,
|
|
142
144
|
keySecret,
|
|
145
|
+
meta,
|
|
143
146
|
);
|
|
144
147
|
|
|
145
148
|
this._cachedNewContentSinceEmpty = undefined;
|
|
@@ -353,6 +356,14 @@ export class VerifiedState {
|
|
|
353
356
|
): JsonValue[] | undefined {
|
|
354
357
|
return this.sessions.decryptTransaction(sessionID, txIndex, keySecret);
|
|
355
358
|
}
|
|
359
|
+
|
|
360
|
+
decryptTransactionMeta(
|
|
361
|
+
sessionID: SessionID,
|
|
362
|
+
txIndex: number,
|
|
363
|
+
keySecret: KeySecret,
|
|
364
|
+
): JsonObject | undefined {
|
|
365
|
+
return this.sessions.decryptTransactionMeta(sessionID, txIndex, keySecret);
|
|
366
|
+
}
|
|
356
367
|
}
|
|
357
368
|
|
|
358
369
|
function getNextKnownSignatureIdx(
|
|
@@ -10,7 +10,7 @@ import {
|
|
|
10
10
|
} from "../coValueCore/verifiedState.js";
|
|
11
11
|
import { RawCoID, SessionID, TransactionID } from "../ids.js";
|
|
12
12
|
import { Stringified, stableStringify } from "../jsonStringify.js";
|
|
13
|
-
import { JsonValue } from "../jsonValue.js";
|
|
13
|
+
import { JsonObject, JsonValue } from "../jsonValue.js";
|
|
14
14
|
import { logger } from "../logger.js";
|
|
15
15
|
import {
|
|
16
16
|
CryptoProvider,
|
|
@@ -328,16 +328,26 @@ export class PureJSSessionLog implements SessionLogImpl {
|
|
|
328
328
|
keyID: KeyID,
|
|
329
329
|
keySecret: KeySecret,
|
|
330
330
|
madeAt: number,
|
|
331
|
+
meta: JsonObject | undefined,
|
|
331
332
|
): { signature: Signature; transaction: PrivateTransaction } {
|
|
332
333
|
const encryptedChanges = this.crypto.encrypt(changes, keySecret, {
|
|
333
334
|
in: this.coID,
|
|
334
335
|
tx: { sessionID: this.sessionID, txIndex: this.transactions.length },
|
|
335
336
|
});
|
|
337
|
+
|
|
338
|
+
const encryptedMeta = meta
|
|
339
|
+
? this.crypto.encrypt(meta, keySecret, {
|
|
340
|
+
in: this.coID,
|
|
341
|
+
tx: { sessionID: this.sessionID, txIndex: this.transactions.length },
|
|
342
|
+
})
|
|
343
|
+
: undefined;
|
|
344
|
+
|
|
336
345
|
const tx = {
|
|
337
346
|
encryptedChanges: encryptedChanges,
|
|
338
347
|
madeAt: madeAt,
|
|
339
348
|
privacy: "private",
|
|
340
349
|
keyUsed: keyID,
|
|
350
|
+
meta: encryptedMeta,
|
|
341
351
|
} satisfies Transaction;
|
|
342
352
|
const signature = this.internalAddNewTransaction(
|
|
343
353
|
stableStringify(tx),
|
|
@@ -353,11 +363,13 @@ export class PureJSSessionLog implements SessionLogImpl {
|
|
|
353
363
|
signerAgent: ControlledAccountOrAgent,
|
|
354
364
|
changes: JsonValue[],
|
|
355
365
|
madeAt: number,
|
|
366
|
+
meta: JsonObject | undefined,
|
|
356
367
|
): { signature: Signature; transaction: TrustingTransaction } {
|
|
357
368
|
const tx = {
|
|
358
369
|
changes: stableStringify(changes),
|
|
359
370
|
madeAt: madeAt,
|
|
360
371
|
privacy: "trusting",
|
|
372
|
+
meta: meta ? stableStringify(meta) : undefined,
|
|
361
373
|
} satisfies Transaction;
|
|
362
374
|
const signature = this.internalAddNewTransaction(
|
|
363
375
|
stableStringify(tx),
|
|
@@ -400,6 +412,42 @@ export class PureJSSessionLog implements SessionLogImpl {
|
|
|
400
412
|
}
|
|
401
413
|
}
|
|
402
414
|
|
|
415
|
+
decryptNextTransactionMetaJson(
|
|
416
|
+
txIndex: number,
|
|
417
|
+
keySecret: KeySecret,
|
|
418
|
+
): string | undefined {
|
|
419
|
+
const txJson = this.transactions[txIndex];
|
|
420
|
+
if (!txJson) {
|
|
421
|
+
throw new Error("Transaction not found");
|
|
422
|
+
}
|
|
423
|
+
const tx = JSON.parse(txJson) as Transaction;
|
|
424
|
+
|
|
425
|
+
if (!tx.meta) {
|
|
426
|
+
return undefined;
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
if (tx.privacy === "private") {
|
|
430
|
+
const nOnceMaterial = {
|
|
431
|
+
in: this.coID,
|
|
432
|
+
tx: { sessionID: this.sessionID, txIndex: txIndex },
|
|
433
|
+
};
|
|
434
|
+
|
|
435
|
+
const nOnce = this.crypto.generateJsonNonce(nOnceMaterial);
|
|
436
|
+
|
|
437
|
+
const ciphertext = base64URLtoBytes(
|
|
438
|
+
tx.meta.substring("encrypted_U".length),
|
|
439
|
+
);
|
|
440
|
+
const keySecretBytes = base58.decode(
|
|
441
|
+
keySecret.substring("keySecret_z".length),
|
|
442
|
+
);
|
|
443
|
+
const plaintext = xsalsa20(keySecretBytes, nOnce, ciphertext);
|
|
444
|
+
|
|
445
|
+
return textDecoder.decode(plaintext);
|
|
446
|
+
} else {
|
|
447
|
+
return tx.meta;
|
|
448
|
+
}
|
|
449
|
+
}
|
|
450
|
+
|
|
403
451
|
free(): void {
|
|
404
452
|
// no-op
|
|
405
453
|
}
|
package/src/crypto/WasmCrypto.ts
CHANGED
|
@@ -19,7 +19,7 @@ import {
|
|
|
19
19
|
import { base64URLtoBytes, bytesToBase64url } from "../base64url.js";
|
|
20
20
|
import { RawCoID, SessionID, TransactionID } from "../ids.js";
|
|
21
21
|
import { Stringified, stableStringify } from "../jsonStringify.js";
|
|
22
|
-
import { JsonValue } from "../jsonValue.js";
|
|
22
|
+
import { JsonObject, JsonValue } from "../jsonValue.js";
|
|
23
23
|
import { logger } from "../logger.js";
|
|
24
24
|
import { PureJSCrypto } from "./PureJSCrypto.js";
|
|
25
25
|
import {
|
|
@@ -231,6 +231,7 @@ class SessionLogAdapter {
|
|
|
231
231
|
keyID: KeyID,
|
|
232
232
|
keySecret: KeySecret,
|
|
233
233
|
madeAt: number,
|
|
234
|
+
meta: JsonObject | undefined,
|
|
234
235
|
): { signature: Signature; transaction: PrivateTransaction } {
|
|
235
236
|
const output = this.sessionLog.addNewPrivateTransaction(
|
|
236
237
|
stableStringify(changes),
|
|
@@ -238,6 +239,7 @@ class SessionLogAdapter {
|
|
|
238
239
|
keySecret,
|
|
239
240
|
keyID,
|
|
240
241
|
madeAt,
|
|
242
|
+
meta ? stableStringify(meta) : undefined,
|
|
241
243
|
);
|
|
242
244
|
const parsedOutput = JSON.parse(output);
|
|
243
245
|
const transaction: PrivateTransaction = {
|
|
@@ -245,6 +247,7 @@ class SessionLogAdapter {
|
|
|
245
247
|
madeAt,
|
|
246
248
|
encryptedChanges: parsedOutput.encrypted_changes,
|
|
247
249
|
keyUsed: keyID,
|
|
250
|
+
meta: parsedOutput.meta,
|
|
248
251
|
};
|
|
249
252
|
return { signature: parsedOutput.signature, transaction };
|
|
250
253
|
}
|
|
@@ -253,17 +256,21 @@ class SessionLogAdapter {
|
|
|
253
256
|
signerAgent: ControlledAccountOrAgent,
|
|
254
257
|
changes: JsonValue[],
|
|
255
258
|
madeAt: number,
|
|
259
|
+
meta: JsonObject | undefined,
|
|
256
260
|
): { signature: Signature; transaction: TrustingTransaction } {
|
|
257
261
|
const stringifiedChanges = stableStringify(changes);
|
|
262
|
+
const stringifiedMeta = meta ? stableStringify(meta) : undefined;
|
|
258
263
|
const output = this.sessionLog.addNewTrustingTransaction(
|
|
259
264
|
stringifiedChanges,
|
|
260
265
|
signerAgent.currentSignerSecret(),
|
|
261
266
|
madeAt,
|
|
267
|
+
stringifiedMeta,
|
|
262
268
|
);
|
|
263
269
|
const transaction: TrustingTransaction = {
|
|
264
270
|
privacy: "trusting",
|
|
265
271
|
madeAt,
|
|
266
272
|
changes: stringifiedChanges,
|
|
273
|
+
meta: stringifiedMeta,
|
|
267
274
|
};
|
|
268
275
|
return { signature: output as Signature, transaction };
|
|
269
276
|
}
|
|
@@ -279,6 +286,13 @@ class SessionLogAdapter {
|
|
|
279
286
|
return output;
|
|
280
287
|
}
|
|
281
288
|
|
|
289
|
+
decryptNextTransactionMetaJson(
|
|
290
|
+
txIndex: number,
|
|
291
|
+
keySecret: KeySecret,
|
|
292
|
+
): string | undefined {
|
|
293
|
+
return this.sessionLog.decryptNextTransactionMetaJson(txIndex, keySecret);
|
|
294
|
+
}
|
|
295
|
+
|
|
282
296
|
free() {
|
|
283
297
|
this.sessionLog.free();
|
|
284
298
|
}
|
package/src/crypto/crypto.ts
CHANGED
|
@@ -3,7 +3,7 @@ import { ControlledAccountOrAgent, RawAccountID } from "../coValues/account.js";
|
|
|
3
3
|
import { AgentID, RawCoID, TransactionID } from "../ids.js";
|
|
4
4
|
import { SessionID } from "../ids.js";
|
|
5
5
|
import { Stringified, parseJSON, stableStringify } from "../jsonStringify.js";
|
|
6
|
-
import { JsonValue } from "../jsonValue.js";
|
|
6
|
+
import { JsonObject, JsonValue } from "../jsonValue.js";
|
|
7
7
|
import { logger } from "../logger.js";
|
|
8
8
|
import {
|
|
9
9
|
PrivateTransaction,
|
|
@@ -366,15 +366,21 @@ export interface SessionLogImpl {
|
|
|
366
366
|
keyID: KeyID,
|
|
367
367
|
keySecret: KeySecret,
|
|
368
368
|
madeAt: number,
|
|
369
|
+
meta: JsonObject | undefined,
|
|
369
370
|
): { signature: Signature; transaction: PrivateTransaction };
|
|
370
371
|
addNewTrustingTransaction(
|
|
371
372
|
signerAgent: ControlledAccountOrAgent,
|
|
372
373
|
changes: JsonValue[],
|
|
373
374
|
madeAt: number,
|
|
375
|
+
meta: JsonObject | undefined,
|
|
374
376
|
): { signature: Signature; transaction: TrustingTransaction };
|
|
375
377
|
decryptNextTransactionChangesJson(
|
|
376
378
|
tx_index: number,
|
|
377
379
|
key_secret: KeySecret,
|
|
378
380
|
): string;
|
|
379
381
|
free(): void;
|
|
382
|
+
decryptNextTransactionMetaJson(
|
|
383
|
+
tx_index: number,
|
|
384
|
+
key_secret: KeySecret,
|
|
385
|
+
): string | undefined;
|
|
380
386
|
}
|
package/src/localNode.ts
CHANGED
|
@@ -408,7 +408,7 @@ export class LocalNode {
|
|
|
408
408
|
coValue.loadingState === "unknown" ||
|
|
409
409
|
coValue.loadingState === "unavailable"
|
|
410
410
|
) {
|
|
411
|
-
const peers = this.syncManager.getServerPeers(skipLoadingFromPeer);
|
|
411
|
+
const peers = this.syncManager.getServerPeers(id, skipLoadingFromPeer);
|
|
412
412
|
|
|
413
413
|
if (!this.storage && peers.length === 0) {
|
|
414
414
|
return coValue;
|
|
@@ -4,7 +4,7 @@ import {
|
|
|
4
4
|
} from "../coValueContentMessage.js";
|
|
5
5
|
import { Transaction, VerifiedState } from "../coValueCore/verifiedState.js";
|
|
6
6
|
import { Signature } from "../crypto/crypto.js";
|
|
7
|
-
import { SessionID } from "../ids.js";
|
|
7
|
+
import { RawCoID, SessionID } from "../ids.js";
|
|
8
8
|
import { NewContentMessage } from "../sync.js";
|
|
9
9
|
import { LinkedList } from "./LinkedList.js";
|
|
10
10
|
|
|
@@ -73,8 +73,39 @@ export class LocalTransactionsSyncQueue {
|
|
|
73
73
|
this.queue.push(content);
|
|
74
74
|
|
|
75
75
|
this.processPendingSyncs();
|
|
76
|
+
|
|
77
|
+
for (const trackingSet of this.dirtyCoValuesTrackingSets) {
|
|
78
|
+
trackingSet.add(content.id);
|
|
79
|
+
}
|
|
76
80
|
}
|
|
77
81
|
|
|
82
|
+
private dirtyCoValuesTrackingSets: Set<Set<RawCoID>> = new Set();
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* It starts tracking all changed CoValues. Returns a `done()` function that returns a set of coValues' ids that have been modified since the start.
|
|
86
|
+
*
|
|
87
|
+
* @example
|
|
88
|
+
* ```ts
|
|
89
|
+
* const tracking = node.syncManager.trackDirtyCoValues();
|
|
90
|
+
* // Any CoValue mutation
|
|
91
|
+
* const tracked = tracking.done();
|
|
92
|
+
* console.log("CoValue mutated: " Array.from(tracked))
|
|
93
|
+
* ```
|
|
94
|
+
*/
|
|
95
|
+
trackDirtyCoValues = () => {
|
|
96
|
+
const trackingSet = new Set<RawCoID>();
|
|
97
|
+
|
|
98
|
+
this.dirtyCoValuesTrackingSets.add(trackingSet);
|
|
99
|
+
|
|
100
|
+
return {
|
|
101
|
+
done: () => {
|
|
102
|
+
this.dirtyCoValuesTrackingSets.delete(trackingSet);
|
|
103
|
+
|
|
104
|
+
return trackingSet;
|
|
105
|
+
},
|
|
106
|
+
};
|
|
107
|
+
};
|
|
108
|
+
|
|
78
109
|
private processingSyncs = false;
|
|
79
110
|
processPendingSyncs() {
|
|
80
111
|
if (this.processingSyncs) return;
|