cojson 0.17.9 → 0.17.11
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 +18 -0
- package/dist/coValueCore/SessionMap.d.ts +45 -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 +10 -4
- package/dist/coValueCore/coValueCore.d.ts.map +1 -1
- package/dist/coValueCore/coValueCore.js +55 -68
- package/dist/coValueCore/coValueCore.js.map +1 -1
- package/dist/coValueCore/verifiedState.d.ts +15 -19
- package/dist/coValueCore/verifiedState.d.ts.map +1 -1
- package/dist/coValueCore/verifiedState.js +24 -87
- 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/coValues/group.d.ts.map +1 -1
- package/dist/coValues/group.js +6 -2
- package/dist/coValues/group.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 +115 -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/permissions.d.ts +17 -1
- package/dist/permissions.d.ts.map +1 -1
- package/dist/permissions.js.map +1 -1
- package/dist/sync.d.ts.map +1 -1
- package/dist/sync.js +55 -49
- 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 +102 -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/group.addMember.test.js +6 -11
- package/dist/tests/group.addMember.test.js.map +1 -1
- package/dist/tests/sync.load.test.js +40 -1
- package/dist/tests/sync.load.test.js.map +1 -1
- package/dist/tests/sync.test.js +1 -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 +229 -0
- package/src/coValueCore/coValueCore.ts +106 -121
- package/src/coValueCore/verifiedState.ts +61 -132
- package/src/coValues/account.ts +28 -4
- package/src/coValues/group.ts +10 -2
- package/src/crypto/PureJSCrypto.ts +206 -2
- package/src/crypto/WasmCrypto.ts +95 -4
- package/src/crypto/crypto.ts +38 -1
- package/src/localNode.ts +18 -10
- package/src/permissions.ts +17 -1
- package/src/sync.ts +63 -59
- package/src/tests/PureJSCrypto.test.ts +153 -0
- package/src/tests/WasmCrypto.test.ts +128 -0
- package/src/tests/coValueCore.test.ts +81 -293
- package/src/tests/coreWasm.test.ts +142 -0
- package/src/tests/group.addMember.test.ts +69 -63
- package/src/tests/sync.load.test.ts +52 -0
- package/src/tests/sync.test.ts +0 -2
- package/src/tests/testUtils.ts +9 -1
|
@@ -0,0 +1,128 @@
|
|
|
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
|
+
"signature_z12345678",
|
|
117
|
+
true,
|
|
118
|
+
);
|
|
119
|
+
|
|
120
|
+
const content =
|
|
121
|
+
mapInOtherSession.core.verified.newContentSince(undefined)?.[0];
|
|
122
|
+
assert(content);
|
|
123
|
+
|
|
124
|
+
client.node.syncManager.handleNewContent(content, "storage");
|
|
125
|
+
|
|
126
|
+
expect(map.get("count")).toEqual(0);
|
|
127
|
+
});
|
|
128
|
+
});
|
|
@@ -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,51 @@ 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
|
-
privacy: "trusting",
|
|
144
|
-
madeAt: Date.now(),
|
|
145
|
-
changes: stableStringify([
|
|
146
|
-
{
|
|
147
|
-
hello: "wrong",
|
|
148
|
-
},
|
|
149
|
-
]),
|
|
150
|
-
},
|
|
151
|
-
],
|
|
78
|
+
[transaction],
|
|
79
|
+
signature,
|
|
152
80
|
);
|
|
153
81
|
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
.tryAddTransactions(
|
|
157
|
-
node.currentSessionID,
|
|
158
|
-
[transaction],
|
|
159
|
-
expectedNewHash,
|
|
160
|
-
Crypto.sign(agent.currentSignerSecret(), expectedNewHash),
|
|
161
|
-
"immediate",
|
|
162
|
-
)
|
|
163
|
-
._unsafeUnwrapErr({ withStackTrace: true });
|
|
82
|
+
expect(result.isErr()).toBe(true);
|
|
83
|
+
expect(newEntry.getValidSortedTransactions().length).toBe(0);
|
|
164
84
|
});
|
|
165
85
|
|
|
166
86
|
test("New transactions in a group correctly update owned values, including subscriptions", async () => {
|
|
167
87
|
const [agent, sessionID] = randomAgentAndSessionID();
|
|
168
88
|
const node = new LocalNode(agent.agentSecret, sessionID, Crypto);
|
|
169
89
|
|
|
170
|
-
const
|
|
90
|
+
const timeBeforeEdit = Date.now() - 1000;
|
|
91
|
+
const dateNowMock = vi
|
|
92
|
+
.spyOn(Date, "now")
|
|
93
|
+
.mockImplementation(() => timeBeforeEdit);
|
|
171
94
|
|
|
172
|
-
const
|
|
95
|
+
const group = node.createGroup();
|
|
173
96
|
|
|
174
97
|
await new Promise((resolve) => setTimeout(resolve, 10));
|
|
175
98
|
|
|
@@ -179,49 +102,31 @@ test("New transactions in a group correctly update owned values, including subsc
|
|
|
179
102
|
|
|
180
103
|
const listener = vi.fn();
|
|
181
104
|
|
|
182
|
-
map.subscribe(
|
|
105
|
+
map.subscribe((map) => {
|
|
106
|
+
listener(map.get("hello"));
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
expect(listener).toHaveBeenLastCalledWith("world");
|
|
183
110
|
|
|
184
|
-
expect(
|
|
111
|
+
expect(map.core.getValidSortedTransactions().length).toBe(1);
|
|
112
|
+
expect(group.get(agent.id)).toBe("admin");
|
|
185
113
|
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
madeAt: timeBeforeEdit,
|
|
189
|
-
changes: stableStringify([
|
|
114
|
+
group.core.makeTransaction(
|
|
115
|
+
[
|
|
190
116
|
{
|
|
191
117
|
op: "set",
|
|
192
118
|
key: agent.id,
|
|
193
119
|
value: "revoked",
|
|
194
|
-
}
|
|
195
|
-
]
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
const { expectedNewHash } = group.core.verified.expectedNewHashAfter(
|
|
199
|
-
sessionID,
|
|
200
|
-
[resignationThatWeJustLearnedAbout],
|
|
201
|
-
);
|
|
202
|
-
|
|
203
|
-
const signature = Crypto.sign(
|
|
204
|
-
node.getCurrentAgent().currentSignerSecret(),
|
|
205
|
-
expectedNewHash,
|
|
120
|
+
},
|
|
121
|
+
],
|
|
122
|
+
"trusting",
|
|
206
123
|
);
|
|
207
124
|
|
|
208
|
-
expect(
|
|
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);
|
|
125
|
+
expect(group.get(agent.id)).toBe("revoked");
|
|
126
|
+
dateNowMock.mockReset();
|
|
224
127
|
|
|
128
|
+
expect(listener).toHaveBeenCalledTimes(2);
|
|
129
|
+
expect(listener).toHaveBeenLastCalledWith(undefined);
|
|
225
130
|
expect(map.core.getValidSortedTransactions().length).toBe(0);
|
|
226
131
|
});
|
|
227
132
|
|
|
@@ -359,166 +264,49 @@ test("listeners are notified even if the previous listener threw an error", asyn
|
|
|
359
264
|
errorLog.mockRestore();
|
|
360
265
|
});
|
|
361
266
|
|
|
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
267
|
test("getValidTransactions should skip private transactions with invalid JSON", () => {
|
|
425
|
-
const [agent, sessionID] =
|
|
268
|
+
const [agent, sessionID] = agentAndSessionIDFromSecret(agentSecret);
|
|
426
269
|
const node = new LocalNode(agent.agentSecret, sessionID, Crypto);
|
|
427
270
|
|
|
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(),
|
|
271
|
+
const fixtures = {
|
|
272
|
+
id: "co_zWwrEiushQLvbkWd6Z3L8WxTU1r",
|
|
273
|
+
signature:
|
|
274
|
+
"signature_z3ktW7wxMnW7VYExCGZv4Ug2UJSW3ag6zLDiP8GpZThzif6veJt7JipYpUgshhuGbgHtLcWywWSWysV7hChxFypDt",
|
|
275
|
+
decrypted:
|
|
276
|
+
'[{"after":"start","op":"app","value":"co_zMphsnYN6GU8nn2HDY5suvyGufY"}]',
|
|
277
|
+
key: {
|
|
278
|
+
secret: "keySecret_z3dU66SsyQkkGKpNCJW6NX74MnfVGHUyY7r85b4M8X88L",
|
|
279
|
+
id: "key_z5XUAHyoqUV9zXWvMK",
|
|
448
280
|
},
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
281
|
+
transaction: {
|
|
282
|
+
privacy: "private",
|
|
283
|
+
madeAt: 0,
|
|
284
|
+
encryptedChanges:
|
|
285
|
+
"encrypted_UNAxqdUSGRZ2rzuLU99AFPKCe2C0HwsTzMWQreXZqLr6RpWrSMa-5lwgwIev7xPHTgZFq5UyUgMFrO9zlHJHJGgjJcDzFihY=" as any,
|
|
286
|
+
keyUsed: "key_z5XUAHyoqUV9zXWvMK",
|
|
287
|
+
},
|
|
288
|
+
session:
|
|
289
|
+
"sealer_z5yhsCCe2XwLTZC4254mUoMASshm3Diq49JrefPpjTktp/signer_z7gVGDpNz9qUtsRxAkHMuu4DYdtVVCG4XELTKPYdoYLPr_session_z9mDP8FoonSA",
|
|
290
|
+
} as const;
|
|
458
291
|
|
|
459
|
-
const
|
|
460
|
-
|
|
461
|
-
validTransaction,
|
|
462
|
-
]);
|
|
292
|
+
const group = node.createGroup();
|
|
293
|
+
const map = group.createMap();
|
|
463
294
|
|
|
464
|
-
|
|
465
|
-
.tryAddTransactions(
|
|
466
|
-
node.currentSessionID,
|
|
467
|
-
[validTransaction],
|
|
468
|
-
expectedNewHash1,
|
|
469
|
-
Crypto.sign(agent.currentSignerSecret(), expectedNewHash1),
|
|
470
|
-
"immediate",
|
|
471
|
-
)
|
|
472
|
-
._unsafeUnwrap();
|
|
295
|
+
map.set("hello", "world");
|
|
473
296
|
|
|
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
|
|
297
|
+
// This should fail silently, because the encryptedChanges will be outputted as gibberish
|
|
298
|
+
map.core
|
|
502
299
|
.tryAddTransactions(
|
|
503
|
-
|
|
504
|
-
[
|
|
505
|
-
|
|
506
|
-
Crypto.sign(agent.currentSignerSecret(), expectedNewHash2),
|
|
507
|
-
"immediate",
|
|
300
|
+
fixtures.session,
|
|
301
|
+
[fixtures.transaction],
|
|
302
|
+
fixtures.signature,
|
|
508
303
|
)
|
|
509
304
|
._unsafeUnwrap();
|
|
510
305
|
|
|
511
|
-
// Get valid transactions - should
|
|
512
|
-
const validTransactions =
|
|
513
|
-
ignorePrivateTransactions: false,
|
|
514
|
-
});
|
|
306
|
+
// Get valid transactions - should only include the valid one
|
|
307
|
+
const validTransactions = map.core.getValidTransactions();
|
|
515
308
|
|
|
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" }]);
|
|
309
|
+
expect(validTransactions).toHaveLength(1);
|
|
522
310
|
});
|
|
523
311
|
|
|
524
312
|
describe("markErrored and isErroredInPeer", () => {
|