cojson 0.17.8 → 0.17.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 +13 -0
- package/dist/coValueCore/SessionMap.d.ts +44 -0
- package/dist/coValueCore/SessionMap.d.ts.map +1 -0
- package/dist/coValueCore/SessionMap.js +118 -0
- package/dist/coValueCore/SessionMap.js.map +1 -0
- package/dist/coValueCore/coValueCore.d.ts +1 -0
- package/dist/coValueCore/coValueCore.d.ts.map +1 -1
- package/dist/coValueCore/coValueCore.js +40 -61
- package/dist/coValueCore/coValueCore.js.map +1 -1
- package/dist/coValueCore/verifiedState.d.ts +14 -18
- package/dist/coValueCore/verifiedState.d.ts.map +1 -1
- package/dist/coValueCore/verifiedState.js +23 -86
- package/dist/coValueCore/verifiedState.js.map +1 -1
- package/dist/coValues/account.d.ts +4 -0
- package/dist/coValues/account.d.ts.map +1 -1
- package/dist/coValues/account.js +24 -4
- package/dist/coValues/account.js.map +1 -1
- package/dist/crypto/PureJSCrypto.d.ts +31 -3
- package/dist/crypto/PureJSCrypto.d.ts.map +1 -1
- package/dist/crypto/PureJSCrypto.js +112 -0
- package/dist/crypto/PureJSCrypto.js.map +1 -1
- package/dist/crypto/WasmCrypto.d.ts +23 -4
- package/dist/crypto/WasmCrypto.d.ts.map +1 -1
- package/dist/crypto/WasmCrypto.js +44 -2
- package/dist/crypto/WasmCrypto.js.map +1 -1
- package/dist/crypto/crypto.d.ts +17 -1
- package/dist/crypto/crypto.d.ts.map +1 -1
- package/dist/crypto/crypto.js.map +1 -1
- package/dist/localNode.d.ts +1 -0
- package/dist/localNode.d.ts.map +1 -1
- package/dist/localNode.js +10 -5
- package/dist/localNode.js.map +1 -1
- package/dist/sync.d.ts +2 -0
- package/dist/sync.d.ts.map +1 -1
- package/dist/sync.js +8 -1
- package/dist/sync.js.map +1 -1
- package/dist/tests/PureJSCrypto.test.d.ts +2 -0
- package/dist/tests/PureJSCrypto.test.d.ts.map +1 -0
- package/dist/tests/PureJSCrypto.test.js +88 -0
- package/dist/tests/PureJSCrypto.test.js.map +1 -0
- package/dist/tests/WasmCrypto.test.d.ts +2 -0
- package/dist/tests/WasmCrypto.test.d.ts.map +1 -0
- package/dist/tests/WasmCrypto.test.js +88 -0
- package/dist/tests/WasmCrypto.test.js.map +1 -0
- package/dist/tests/coValueCore.test.js +62 -187
- package/dist/tests/coValueCore.test.js.map +1 -1
- package/dist/tests/coreWasm.test.d.ts +2 -0
- package/dist/tests/coreWasm.test.d.ts.map +1 -0
- package/dist/tests/coreWasm.test.js +80 -0
- package/dist/tests/coreWasm.test.js.map +1 -0
- package/dist/tests/sync.test.js +19 -1
- package/dist/tests/sync.test.js.map +1 -1
- package/dist/tests/testUtils.d.ts +3 -0
- package/dist/tests/testUtils.d.ts.map +1 -1
- package/dist/tests/testUtils.js +4 -1
- package/dist/tests/testUtils.js.map +1 -1
- package/package.json +3 -3
- package/src/coValueCore/SessionMap.ts +230 -0
- package/src/coValueCore/coValueCore.ts +66 -91
- package/src/coValueCore/verifiedState.ts +60 -129
- package/src/coValues/account.ts +28 -4
- package/src/crypto/PureJSCrypto.ts +202 -2
- package/src/crypto/WasmCrypto.ts +95 -4
- package/src/crypto/crypto.ts +38 -1
- package/src/localNode.ts +18 -10
- package/src/sync.ts +10 -0
- package/src/tests/PureJSCrypto.test.ts +130 -0
- package/src/tests/WasmCrypto.test.ts +130 -0
- package/src/tests/coValueCore.test.ts +84 -292
- package/src/tests/coreWasm.test.ts +142 -0
- package/src/tests/sync.test.ts +32 -0
- package/src/tests/testUtils.ts +9 -1
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
import { assert, beforeEach, describe, expect, it } from "vitest";
|
|
2
|
+
import {
|
|
3
|
+
loadCoValueOrFail,
|
|
4
|
+
setCurrentTestCryptoProvider,
|
|
5
|
+
setupTestNode,
|
|
6
|
+
setupTestAccount,
|
|
7
|
+
} from "./testUtils";
|
|
8
|
+
import { stableStringify } from "../jsonStringify";
|
|
9
|
+
import { WasmCrypto } from "../crypto/WasmCrypto";
|
|
10
|
+
|
|
11
|
+
const wasmCrypto = await WasmCrypto.create();
|
|
12
|
+
setCurrentTestCryptoProvider(wasmCrypto);
|
|
13
|
+
|
|
14
|
+
let syncServer: ReturnType<typeof setupTestNode>;
|
|
15
|
+
|
|
16
|
+
beforeEach(() => {
|
|
17
|
+
syncServer = setupTestNode({ isSyncServer: true });
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
// A suite of tests focused on high-level tests that verify:
|
|
21
|
+
// - Keys creation and unsealing
|
|
22
|
+
// - Signature creation and verification
|
|
23
|
+
// - Encryption and decryption of values
|
|
24
|
+
describe("WasmCrypto", () => {
|
|
25
|
+
it("successfully creates a private CoValue and reads it in another session", async () => {
|
|
26
|
+
const client = setupTestNode({
|
|
27
|
+
connected: true,
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
const group = client.node.createGroup();
|
|
31
|
+
const map = group.createMap();
|
|
32
|
+
map.set("count", 0, "private");
|
|
33
|
+
map.set("count", 1, "private");
|
|
34
|
+
map.set("count", 2, "private");
|
|
35
|
+
|
|
36
|
+
const client2 = client.spawnNewSession();
|
|
37
|
+
|
|
38
|
+
const mapInTheOtherSession = await loadCoValueOrFail(client2.node, map.id);
|
|
39
|
+
|
|
40
|
+
expect(mapInTheOtherSession.get("count")).toEqual(2);
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
it("successfully updates a private CoValue and reads it in another session", async () => {
|
|
44
|
+
const client = setupTestNode({
|
|
45
|
+
connected: true,
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
const group = client.node.createGroup();
|
|
49
|
+
const map = group.createMap();
|
|
50
|
+
map.set("count", 0, "private");
|
|
51
|
+
map.set("count", 1, "private");
|
|
52
|
+
map.set("count", 2, "private");
|
|
53
|
+
|
|
54
|
+
const client2 = client.spawnNewSession();
|
|
55
|
+
|
|
56
|
+
const mapInTheOtherSession = await loadCoValueOrFail(client2.node, map.id);
|
|
57
|
+
mapInTheOtherSession.set("count", 3, "private");
|
|
58
|
+
|
|
59
|
+
await mapInTheOtherSession.core.waitForSync();
|
|
60
|
+
|
|
61
|
+
expect(mapInTheOtherSession.get("count")).toEqual(3);
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
it("can invite another account to a group and share a private CoValue", async () => {
|
|
65
|
+
const client = setupTestNode({
|
|
66
|
+
connected: true,
|
|
67
|
+
});
|
|
68
|
+
const account = await setupTestAccount({
|
|
69
|
+
connected: true,
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
const group = client.node.createGroup();
|
|
73
|
+
const invite = group.createInvite("admin");
|
|
74
|
+
|
|
75
|
+
await account.node.acceptInvite(group.id, invite);
|
|
76
|
+
|
|
77
|
+
const map = group.createMap();
|
|
78
|
+
map.set("secret", "private-data", "private");
|
|
79
|
+
|
|
80
|
+
// The other account should be able to read the private value
|
|
81
|
+
const mapInOtherSession = await loadCoValueOrFail(account.node, map.id);
|
|
82
|
+
expect(mapInOtherSession.get("secret")).toEqual("private-data");
|
|
83
|
+
|
|
84
|
+
mapInOtherSession.set("secret", "modified", "private");
|
|
85
|
+
|
|
86
|
+
await mapInOtherSession.core.waitForSync();
|
|
87
|
+
|
|
88
|
+
expect(map.get("secret")).toEqual("modified");
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
it("rejects sessions with invalid signatures", async () => {
|
|
92
|
+
const client = setupTestNode({
|
|
93
|
+
connected: true,
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
const group = client.node.createGroup();
|
|
97
|
+
const map = group.createMap();
|
|
98
|
+
map.set("count", 0, "trusting");
|
|
99
|
+
|
|
100
|
+
// Create a new session with the same agent
|
|
101
|
+
const client2 = client.spawnNewSession();
|
|
102
|
+
|
|
103
|
+
// This should work normally
|
|
104
|
+
const mapInOtherSession = await loadCoValueOrFail(client2.node, map.id);
|
|
105
|
+
expect(mapInOtherSession.get("count")).toEqual(0);
|
|
106
|
+
|
|
107
|
+
mapInOtherSession.core.tryAddTransactions(
|
|
108
|
+
client2.node.currentSessionID,
|
|
109
|
+
[
|
|
110
|
+
{
|
|
111
|
+
privacy: "trusting",
|
|
112
|
+
changes: stableStringify([{ op: "set", key: "count", value: 1 }]),
|
|
113
|
+
madeAt: Date.now(),
|
|
114
|
+
},
|
|
115
|
+
],
|
|
116
|
+
"hash_z12345678",
|
|
117
|
+
"signature_z12345678",
|
|
118
|
+
"immediate",
|
|
119
|
+
true,
|
|
120
|
+
);
|
|
121
|
+
|
|
122
|
+
const content =
|
|
123
|
+
mapInOtherSession.core.verified.newContentSince(undefined)?.[0];
|
|
124
|
+
assert(content);
|
|
125
|
+
|
|
126
|
+
client.node.syncManager.handleNewContent(content, "storage");
|
|
127
|
+
|
|
128
|
+
expect(map.get("count")).toEqual(0);
|
|
129
|
+
});
|
|
130
|
+
});
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { encrypt } from "jazz-crypto-rs";
|
|
2
1
|
import {
|
|
3
2
|
assert,
|
|
4
3
|
afterEach,
|
|
@@ -8,15 +7,13 @@ import {
|
|
|
8
7
|
test,
|
|
9
8
|
vi,
|
|
10
9
|
} from "vitest";
|
|
11
|
-
import { bytesToBase64url } from "../base64url.js";
|
|
12
10
|
import { CoValueCore } from "../coValueCore/coValueCore.js";
|
|
13
11
|
import { Transaction } from "../coValueCore/verifiedState.js";
|
|
14
|
-
import { MapOpPayload } from "../coValues/coMap.js";
|
|
15
12
|
import { WasmCrypto } from "../crypto/WasmCrypto.js";
|
|
16
13
|
import { stableStringify } from "../jsonStringify.js";
|
|
17
14
|
import { LocalNode } from "../localNode.js";
|
|
18
|
-
import { Role } from "../permissions.js";
|
|
19
15
|
import {
|
|
16
|
+
agentAndSessionIDFromSecret,
|
|
20
17
|
createTestMetricReader,
|
|
21
18
|
createTestNode,
|
|
22
19
|
createTwoConnectedNodes,
|
|
@@ -25,10 +22,13 @@ import {
|
|
|
25
22
|
randomAgentAndSessionID,
|
|
26
23
|
tearDownTestMetricReader,
|
|
27
24
|
} from "./testUtils.js";
|
|
25
|
+
import { CO_VALUE_PRIORITY } from "../priority.js";
|
|
28
26
|
|
|
29
27
|
const Crypto = await WasmCrypto.create();
|
|
30
28
|
|
|
31
29
|
let metricReader: ReturnType<typeof createTestMetricReader>;
|
|
30
|
+
const agentSecret =
|
|
31
|
+
"sealerSecret_zE3Nr7YFr1KkVbJSx4JDCzYn4ApYdm8kJ5ghNBxREHQya/signerSecret_z9fEu4eNG1eXHMak3YSzY7uLdoG8HESSJ8YW4xWdNNDSP";
|
|
32
32
|
|
|
33
33
|
beforeEach(() => {
|
|
34
34
|
metricReader = createTestMetricReader();
|
|
@@ -38,47 +38,7 @@ afterEach(() => {
|
|
|
38
38
|
tearDownTestMetricReader();
|
|
39
39
|
});
|
|
40
40
|
|
|
41
|
-
test("Can create coValue with new agent credentials and add transaction to it", () => {
|
|
42
|
-
const [agent, sessionID] = randomAgentAndSessionID();
|
|
43
|
-
const node = new LocalNode(agent.agentSecret, sessionID, Crypto);
|
|
44
|
-
|
|
45
|
-
const coValue = node.createCoValue({
|
|
46
|
-
type: "costream",
|
|
47
|
-
ruleset: { type: "unsafeAllowAll" },
|
|
48
|
-
meta: null,
|
|
49
|
-
...Crypto.createdNowUnique(),
|
|
50
|
-
});
|
|
51
|
-
|
|
52
|
-
const transaction: Transaction = {
|
|
53
|
-
privacy: "trusting",
|
|
54
|
-
madeAt: Date.now(),
|
|
55
|
-
changes: stableStringify([
|
|
56
|
-
{
|
|
57
|
-
hello: "world",
|
|
58
|
-
},
|
|
59
|
-
]),
|
|
60
|
-
};
|
|
61
|
-
|
|
62
|
-
const { expectedNewHash } = coValue.verified.expectedNewHashAfter(
|
|
63
|
-
node.currentSessionID,
|
|
64
|
-
[transaction],
|
|
65
|
-
);
|
|
66
|
-
|
|
67
|
-
expect(
|
|
68
|
-
coValue
|
|
69
|
-
.tryAddTransactions(
|
|
70
|
-
node.currentSessionID,
|
|
71
|
-
[transaction],
|
|
72
|
-
expectedNewHash,
|
|
73
|
-
Crypto.sign(agent.currentSignerSecret(), expectedNewHash),
|
|
74
|
-
"immediate",
|
|
75
|
-
)
|
|
76
|
-
._unsafeUnwrap(),
|
|
77
|
-
).toBe(true);
|
|
78
|
-
});
|
|
79
|
-
|
|
80
41
|
test("transactions with wrong signature are rejected", () => {
|
|
81
|
-
const wrongAgent = Crypto.newRandomAgentSecret();
|
|
82
42
|
const node = nodeWithRandomAgentAndSessionID();
|
|
83
43
|
|
|
84
44
|
const coValue = node.createCoValue({
|
|
@@ -88,88 +48,53 @@ test("transactions with wrong signature are rejected", () => {
|
|
|
88
48
|
...Crypto.createdNowUnique(),
|
|
89
49
|
});
|
|
90
50
|
|
|
91
|
-
const transaction
|
|
92
|
-
|
|
93
|
-
madeAt: Date.now(),
|
|
94
|
-
changes: stableStringify([
|
|
95
|
-
{
|
|
96
|
-
hello: "world",
|
|
97
|
-
},
|
|
98
|
-
]),
|
|
99
|
-
};
|
|
100
|
-
|
|
101
|
-
const { expectedNewHash } = coValue.verified.expectedNewHashAfter(
|
|
102
|
-
node.currentSessionID,
|
|
103
|
-
[transaction],
|
|
104
|
-
);
|
|
105
|
-
|
|
106
|
-
// eslint-disable-next-line neverthrow/must-use-result
|
|
107
|
-
coValue
|
|
108
|
-
.tryAddTransactions(
|
|
51
|
+
const { transaction, signature } =
|
|
52
|
+
coValue.verified.makeNewTrustingTransaction(
|
|
109
53
|
node.currentSessionID,
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
"immediate",
|
|
114
|
-
)
|
|
115
|
-
._unsafeUnwrapErr({ withStackTrace: true });
|
|
116
|
-
});
|
|
54
|
+
node.getCurrentAgent(),
|
|
55
|
+
[{ hello: "world" }],
|
|
56
|
+
);
|
|
117
57
|
|
|
118
|
-
|
|
119
|
-
const [agent, sessionID] = randomAgentAndSessionID();
|
|
120
|
-
const node = new LocalNode(agent.agentSecret, sessionID, Crypto);
|
|
58
|
+
transaction.madeAt = Date.now() + 1000;
|
|
121
59
|
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
60
|
+
// Delete the transaction from the coValue
|
|
61
|
+
node.internalDeleteCoValue(coValue.id);
|
|
62
|
+
node.syncManager.handleNewContent(
|
|
63
|
+
{
|
|
64
|
+
action: "content",
|
|
65
|
+
id: coValue.id,
|
|
66
|
+
header: coValue.verified.header,
|
|
67
|
+
priority: CO_VALUE_PRIORITY.LOW,
|
|
68
|
+
new: {},
|
|
69
|
+
},
|
|
70
|
+
"import",
|
|
71
|
+
);
|
|
128
72
|
|
|
129
|
-
const
|
|
130
|
-
privacy: "trusting",
|
|
131
|
-
madeAt: Date.now(),
|
|
132
|
-
changes: stableStringify([
|
|
133
|
-
{
|
|
134
|
-
hello: "world",
|
|
135
|
-
},
|
|
136
|
-
]),
|
|
137
|
-
};
|
|
73
|
+
const newEntry = node.getCoValue(coValue.id);
|
|
138
74
|
|
|
139
|
-
|
|
75
|
+
// eslint-disable-next-line neverthrow/must-use-result
|
|
76
|
+
const result = newEntry.tryAddTransactions(
|
|
140
77
|
node.currentSessionID,
|
|
141
|
-
[
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
changes: stableStringify([
|
|
146
|
-
{
|
|
147
|
-
hello: "wrong",
|
|
148
|
-
},
|
|
149
|
-
]),
|
|
150
|
-
},
|
|
151
|
-
],
|
|
78
|
+
[transaction],
|
|
79
|
+
undefined,
|
|
80
|
+
signature,
|
|
81
|
+
"immediate",
|
|
152
82
|
);
|
|
153
83
|
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
.tryAddTransactions(
|
|
157
|
-
node.currentSessionID,
|
|
158
|
-
[transaction],
|
|
159
|
-
expectedNewHash,
|
|
160
|
-
Crypto.sign(agent.currentSignerSecret(), expectedNewHash),
|
|
161
|
-
"immediate",
|
|
162
|
-
)
|
|
163
|
-
._unsafeUnwrapErr({ withStackTrace: true });
|
|
84
|
+
expect(result.isErr()).toBe(true);
|
|
85
|
+
expect(newEntry.getValidSortedTransactions().length).toBe(0);
|
|
164
86
|
});
|
|
165
87
|
|
|
166
88
|
test("New transactions in a group correctly update owned values, including subscriptions", async () => {
|
|
167
89
|
const [agent, sessionID] = randomAgentAndSessionID();
|
|
168
90
|
const node = new LocalNode(agent.agentSecret, sessionID, Crypto);
|
|
169
91
|
|
|
170
|
-
const
|
|
92
|
+
const timeBeforeEdit = Date.now() - 1000;
|
|
93
|
+
const dateNowMock = vi
|
|
94
|
+
.spyOn(Date, "now")
|
|
95
|
+
.mockImplementation(() => timeBeforeEdit);
|
|
171
96
|
|
|
172
|
-
const
|
|
97
|
+
const group = node.createGroup();
|
|
173
98
|
|
|
174
99
|
await new Promise((resolve) => setTimeout(resolve, 10));
|
|
175
100
|
|
|
@@ -179,49 +104,31 @@ test("New transactions in a group correctly update owned values, including subsc
|
|
|
179
104
|
|
|
180
105
|
const listener = vi.fn();
|
|
181
106
|
|
|
182
|
-
map.subscribe(
|
|
107
|
+
map.subscribe((map) => {
|
|
108
|
+
listener(map.get("hello"));
|
|
109
|
+
});
|
|
183
110
|
|
|
184
|
-
expect(listener
|
|
111
|
+
expect(listener).toHaveBeenLastCalledWith("world");
|
|
185
112
|
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
113
|
+
expect(map.core.getValidSortedTransactions().length).toBe(1);
|
|
114
|
+
expect(group.get(agent.id)).toBe("admin");
|
|
115
|
+
|
|
116
|
+
group.core.makeTransaction(
|
|
117
|
+
[
|
|
190
118
|
{
|
|
191
119
|
op: "set",
|
|
192
120
|
key: agent.id,
|
|
193
121
|
value: "revoked",
|
|
194
|
-
}
|
|
195
|
-
]
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
const { expectedNewHash } = group.core.verified.expectedNewHashAfter(
|
|
199
|
-
sessionID,
|
|
200
|
-
[resignationThatWeJustLearnedAbout],
|
|
122
|
+
},
|
|
123
|
+
],
|
|
124
|
+
"trusting",
|
|
201
125
|
);
|
|
202
126
|
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
expectedNewHash,
|
|
206
|
-
);
|
|
207
|
-
|
|
208
|
-
expect(map.core.getValidSortedTransactions().length).toBe(1);
|
|
209
|
-
|
|
210
|
-
const manuallyAdddedTxSuccess = group.core
|
|
211
|
-
.tryAddTransactions(
|
|
212
|
-
node.currentSessionID,
|
|
213
|
-
[resignationThatWeJustLearnedAbout],
|
|
214
|
-
expectedNewHash,
|
|
215
|
-
signature,
|
|
216
|
-
"immediate",
|
|
217
|
-
)
|
|
218
|
-
._unsafeUnwrap({ withStackTrace: true });
|
|
219
|
-
|
|
220
|
-
expect(manuallyAdddedTxSuccess).toBe(true);
|
|
221
|
-
|
|
222
|
-
expect(listener.mock.calls.length).toBe(2);
|
|
223
|
-
expect(listener.mock.calls[1]?.[0].get("hello")).toBe(undefined);
|
|
127
|
+
expect(group.get(agent.id)).toBe("revoked");
|
|
128
|
+
dateNowMock.mockReset();
|
|
224
129
|
|
|
130
|
+
expect(listener).toHaveBeenCalledTimes(2);
|
|
131
|
+
expect(listener).toHaveBeenLastCalledWith(undefined);
|
|
225
132
|
expect(map.core.getValidSortedTransactions().length).toBe(0);
|
|
226
133
|
});
|
|
227
134
|
|
|
@@ -359,166 +266,51 @@ test("listeners are notified even if the previous listener threw an error", asyn
|
|
|
359
266
|
errorLog.mockRestore();
|
|
360
267
|
});
|
|
361
268
|
|
|
362
|
-
test("getValidTransactions should skip trusting transactions with invalid JSON", () => {
|
|
363
|
-
const [agent, sessionID] = randomAgentAndSessionID();
|
|
364
|
-
const node = new LocalNode(agent.agentSecret, sessionID, Crypto);
|
|
365
|
-
|
|
366
|
-
const coValue = node.createCoValue({
|
|
367
|
-
type: "costream",
|
|
368
|
-
ruleset: { type: "unsafeAllowAll" },
|
|
369
|
-
meta: null,
|
|
370
|
-
...Crypto.createdNowUnique(),
|
|
371
|
-
});
|
|
372
|
-
|
|
373
|
-
// Create a valid transaction first
|
|
374
|
-
const validTransaction: Transaction = {
|
|
375
|
-
privacy: "trusting",
|
|
376
|
-
madeAt: Date.now(),
|
|
377
|
-
changes: stableStringify([{ hello: "world" }]),
|
|
378
|
-
};
|
|
379
|
-
|
|
380
|
-
const { expectedNewHash: expectedNewHash1 } =
|
|
381
|
-
coValue.verified.expectedNewHashAfter(node.currentSessionID, [
|
|
382
|
-
validTransaction,
|
|
383
|
-
]);
|
|
384
|
-
|
|
385
|
-
coValue
|
|
386
|
-
.tryAddTransactions(
|
|
387
|
-
node.currentSessionID,
|
|
388
|
-
[validTransaction],
|
|
389
|
-
expectedNewHash1,
|
|
390
|
-
Crypto.sign(agent.currentSignerSecret(), expectedNewHash1),
|
|
391
|
-
"immediate",
|
|
392
|
-
)
|
|
393
|
-
._unsafeUnwrap();
|
|
394
|
-
|
|
395
|
-
// Create an invalid transaction with malformed JSON
|
|
396
|
-
const invalidTransaction: Transaction = {
|
|
397
|
-
privacy: "trusting",
|
|
398
|
-
madeAt: Date.now() + 1,
|
|
399
|
-
changes: '{"invalid": json}' as any, // Invalid JSON string
|
|
400
|
-
};
|
|
401
|
-
|
|
402
|
-
const { expectedNewHash: expectedNewHash2 } =
|
|
403
|
-
coValue.verified.expectedNewHashAfter(node.currentSessionID, [
|
|
404
|
-
invalidTransaction,
|
|
405
|
-
]);
|
|
406
|
-
|
|
407
|
-
coValue
|
|
408
|
-
.tryAddTransactions(
|
|
409
|
-
node.currentSessionID,
|
|
410
|
-
[invalidTransaction],
|
|
411
|
-
expectedNewHash2,
|
|
412
|
-
Crypto.sign(agent.currentSignerSecret(), expectedNewHash2),
|
|
413
|
-
"immediate",
|
|
414
|
-
)
|
|
415
|
-
._unsafeUnwrap();
|
|
416
|
-
|
|
417
|
-
// Get valid transactions - should only include the valid one
|
|
418
|
-
const validTransactions = coValue.getValidTransactions();
|
|
419
|
-
|
|
420
|
-
expect(validTransactions).toHaveLength(1);
|
|
421
|
-
expect(validTransactions[0]?.changes).toEqual([{ hello: "world" }]);
|
|
422
|
-
});
|
|
423
|
-
|
|
424
269
|
test("getValidTransactions should skip private transactions with invalid JSON", () => {
|
|
425
|
-
const [agent, sessionID] =
|
|
270
|
+
const [agent, sessionID] = agentAndSessionIDFromSecret(agentSecret);
|
|
426
271
|
const node = new LocalNode(agent.agentSecret, sessionID, Crypto);
|
|
427
272
|
|
|
428
|
-
const
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
const { secret: keySecret, id: keyID } = coValue.getCurrentReadKey();
|
|
439
|
-
|
|
440
|
-
assert(keySecret);
|
|
441
|
-
|
|
442
|
-
const encrypted = Crypto.encryptForTransaction(
|
|
443
|
-
[{ hello: "world" }],
|
|
444
|
-
keySecret,
|
|
445
|
-
{
|
|
446
|
-
in: coValue.id,
|
|
447
|
-
tx: coValue.nextTransactionID(),
|
|
273
|
+
const fixtures = {
|
|
274
|
+
id: "co_zWwrEiushQLvbkWd6Z3L8WxTU1r",
|
|
275
|
+
signature:
|
|
276
|
+
"signature_z3ktW7wxMnW7VYExCGZv4Ug2UJSW3ag6zLDiP8GpZThzif6veJt7JipYpUgshhuGbgHtLcWywWSWysV7hChxFypDt",
|
|
277
|
+
decrypted:
|
|
278
|
+
'[{"after":"start","op":"app","value":"co_zMphsnYN6GU8nn2HDY5suvyGufY"}]',
|
|
279
|
+
key: {
|
|
280
|
+
secret: "keySecret_z3dU66SsyQkkGKpNCJW6NX74MnfVGHUyY7r85b4M8X88L",
|
|
281
|
+
id: "key_z5XUAHyoqUV9zXWvMK",
|
|
448
282
|
},
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
283
|
+
transaction: {
|
|
284
|
+
privacy: "private",
|
|
285
|
+
madeAt: 0,
|
|
286
|
+
encryptedChanges:
|
|
287
|
+
"encrypted_UNAxqdUSGRZ2rzuLU99AFPKCe2C0HwsTzMWQreXZqLr6RpWrSMa-5lwgwIev7xPHTgZFq5UyUgMFrO9zlHJHJGgjJcDzFihY=" as any,
|
|
288
|
+
keyUsed: "key_z5XUAHyoqUV9zXWvMK",
|
|
289
|
+
},
|
|
290
|
+
session:
|
|
291
|
+
"sealer_z5yhsCCe2XwLTZC4254mUoMASshm3Diq49JrefPpjTktp/signer_z7gVGDpNz9qUtsRxAkHMuu4DYdtVVCG4XELTKPYdoYLPr_session_z9mDP8FoonSA",
|
|
292
|
+
} as const;
|
|
458
293
|
|
|
459
|
-
const
|
|
460
|
-
|
|
461
|
-
validTransaction,
|
|
462
|
-
]);
|
|
294
|
+
const group = node.createGroup();
|
|
295
|
+
const map = group.createMap();
|
|
463
296
|
|
|
464
|
-
|
|
465
|
-
.tryAddTransactions(
|
|
466
|
-
node.currentSessionID,
|
|
467
|
-
[validTransaction],
|
|
468
|
-
expectedNewHash1,
|
|
469
|
-
Crypto.sign(agent.currentSignerSecret(), expectedNewHash1),
|
|
470
|
-
"immediate",
|
|
471
|
-
)
|
|
472
|
-
._unsafeUnwrap();
|
|
297
|
+
map.set("hello", "world");
|
|
473
298
|
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
encrypt(
|
|
477
|
-
textEncoder.encode('{"invalid": json}'),
|
|
478
|
-
keySecret,
|
|
479
|
-
textEncoder.encode(
|
|
480
|
-
stableStringify({
|
|
481
|
-
in: coValue.id,
|
|
482
|
-
tx: coValue.nextTransactionID(),
|
|
483
|
-
}),
|
|
484
|
-
),
|
|
485
|
-
),
|
|
486
|
-
)}`;
|
|
487
|
-
|
|
488
|
-
// Create an invalid private transaction with malformed JSON after decryption
|
|
489
|
-
const invalidTransaction: Transaction = {
|
|
490
|
-
privacy: "private",
|
|
491
|
-
madeAt: Date.now() + 1,
|
|
492
|
-
keyUsed: keyID,
|
|
493
|
-
encryptedChanges: brokenChange as any,
|
|
494
|
-
};
|
|
495
|
-
|
|
496
|
-
const { expectedNewHash: expectedNewHash2 } =
|
|
497
|
-
coValue.verified.expectedNewHashAfter(node.currentSessionID, [
|
|
498
|
-
invalidTransaction,
|
|
499
|
-
]);
|
|
500
|
-
|
|
501
|
-
coValue
|
|
299
|
+
// This should fail silently, because the encryptedChanges will be outputted as gibberish
|
|
300
|
+
map.core
|
|
502
301
|
.tryAddTransactions(
|
|
503
|
-
|
|
504
|
-
[
|
|
505
|
-
|
|
506
|
-
|
|
302
|
+
fixtures.session,
|
|
303
|
+
[fixtures.transaction],
|
|
304
|
+
undefined,
|
|
305
|
+
fixtures.signature,
|
|
507
306
|
"immediate",
|
|
508
307
|
)
|
|
509
308
|
._unsafeUnwrap();
|
|
510
309
|
|
|
511
|
-
// Get valid transactions - should
|
|
512
|
-
const validTransactions =
|
|
513
|
-
ignorePrivateTransactions: false,
|
|
514
|
-
});
|
|
310
|
+
// Get valid transactions - should only include the valid one
|
|
311
|
+
const validTransactions = map.core.getValidTransactions();
|
|
515
312
|
|
|
516
|
-
|
|
517
|
-
// we just verify that the method doesn't crash and handles the invalid JSON gracefully
|
|
518
|
-
expect(validTransactions).toBeDefined();
|
|
519
|
-
expect(Array.isArray(validTransactions)).toBe(true);
|
|
520
|
-
expect(validTransactions.length).toBe(1);
|
|
521
|
-
expect(validTransactions[0]?.changes).toEqual([{ hello: "world" }]);
|
|
313
|
+
expect(validTransactions).toHaveLength(1);
|
|
522
314
|
});
|
|
523
315
|
|
|
524
316
|
describe("markErrored and isErroredInPeer", () => {
|