cojson 0.0.11 → 0.0.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/README.md +2 -2
- package/dist/account.d.ts +57 -0
- package/dist/account.js +76 -0
- package/dist/account.js.map +1 -0
- package/dist/account.test.d.ts +1 -0
- package/dist/account.test.js +40 -0
- package/dist/account.test.js.map +1 -0
- package/dist/coValue.d.ts +17 -36
- package/dist/coValue.js +53 -117
- package/dist/coValue.js.map +1 -1
- package/dist/coValue.test.js +16 -16
- package/dist/coValue.test.js.map +1 -1
- package/dist/contentType.d.ts +9 -9
- package/dist/contentType.js.map +1 -1
- package/dist/contentType.test.js +13 -17
- package/dist/contentType.test.js.map +1 -1
- package/dist/contentTypes/coList.d.ts +3 -3
- package/dist/contentTypes/coList.js.map +1 -1
- package/dist/contentTypes/coMap.d.ts +31 -21
- package/dist/contentTypes/coMap.js +28 -0
- package/dist/contentTypes/coMap.js.map +1 -1
- package/dist/contentTypes/coStream.d.ts +3 -3
- package/dist/contentTypes/coStream.js.map +1 -1
- package/dist/contentTypes/static.d.ts +4 -4
- package/dist/contentTypes/static.js.map +1 -1
- package/dist/crypto.d.ts +45 -39
- package/dist/crypto.js +68 -49
- package/dist/crypto.js.map +1 -1
- package/dist/crypto.test.js +45 -49
- package/dist/crypto.test.js.map +1 -1
- package/dist/ids.d.ts +5 -3
- package/dist/ids.js +3 -1
- package/dist/ids.js.map +1 -1
- package/dist/index.d.ts +12 -14
- package/dist/index.js +6 -8
- package/dist/index.js.map +1 -1
- package/dist/jsonValue.d.ts +2 -2
- package/dist/node.d.ts +25 -15
- package/dist/node.js +88 -33
- package/dist/node.js.map +1 -1
- package/dist/permissions.d.ts +27 -33
- package/dist/permissions.js +55 -47
- package/dist/permissions.js.map +1 -1
- package/dist/permissions.test.js +231 -314
- package/dist/permissions.test.js.map +1 -1
- package/dist/sync.d.ts +27 -30
- package/dist/sync.js +68 -64
- package/dist/sync.js.map +1 -1
- package/dist/sync.test.js +181 -305
- package/dist/sync.test.js.map +1 -1
- package/dist/testUtils.d.ts +37 -0
- package/dist/testUtils.js +157 -0
- package/dist/testUtils.js.map +1 -0
- package/package.json +1 -1
- package/src/account.test.ts +67 -0
- package/src/account.ts +152 -0
- package/src/coValue.test.ts +17 -31
- package/src/coValue.ts +98 -185
- package/src/contentType.test.ts +18 -45
- package/src/contentType.ts +15 -13
- package/src/contentTypes/coList.ts +4 -4
- package/src/contentTypes/coMap.ts +55 -29
- package/src/contentTypes/coStream.ts +4 -4
- package/src/contentTypes/static.ts +5 -5
- package/src/crypto.test.ts +53 -59
- package/src/crypto.ts +123 -95
- package/src/ids.ts +9 -3
- package/src/index.ts +14 -25
- package/src/jsonValue.ts +2 -2
- package/src/node.ts +189 -61
- package/src/permissions.test.ts +370 -404
- package/src/permissions.ts +126 -109
- package/src/sync.test.ts +262 -440
- package/src/sync.ts +96 -101
- package/src/testUtils.ts +229 -0
package/src/contentType.test.ts
CHANGED
|
@@ -1,25 +1,16 @@
|
|
|
1
|
-
import {
|
|
2
|
-
agentIDfromSessionID,
|
|
3
|
-
getAgent,
|
|
4
|
-
getAgentID,
|
|
5
|
-
newRandomAgentCredential,
|
|
6
|
-
newRandomSessionID,
|
|
7
|
-
} from './coValue.js';
|
|
1
|
+
import { accountOrAgentIDfromSessionID } from "./coValue.js";
|
|
8
2
|
import { createdNowUnique } from "./crypto.js";
|
|
9
3
|
import { LocalNode } from "./node.js";
|
|
4
|
+
import { randomAnonymousAccountAndSessionID } from "./testUtils.js";
|
|
10
5
|
|
|
11
6
|
test("Empty COJSON Map works", () => {
|
|
12
|
-
const
|
|
13
|
-
const node = new LocalNode(
|
|
14
|
-
agentCredential,
|
|
15
|
-
newRandomSessionID(getAgentID(getAgent(agentCredential)))
|
|
16
|
-
);
|
|
7
|
+
const node = new LocalNode(...randomAnonymousAccountAndSessionID());
|
|
17
8
|
|
|
18
9
|
const coValue = node.createCoValue({
|
|
19
10
|
type: "comap",
|
|
20
11
|
ruleset: { type: "unsafeAllowAll" },
|
|
21
12
|
meta: null,
|
|
22
|
-
...createdNowUnique()
|
|
13
|
+
...createdNowUnique(),
|
|
23
14
|
});
|
|
24
15
|
|
|
25
16
|
const content = coValue.getCurrentContent();
|
|
@@ -34,17 +25,13 @@ test("Empty COJSON Map works", () => {
|
|
|
34
25
|
});
|
|
35
26
|
|
|
36
27
|
test("Can insert and delete Map entries in edit()", () => {
|
|
37
|
-
const
|
|
38
|
-
const node = new LocalNode(
|
|
39
|
-
agentCredential,
|
|
40
|
-
newRandomSessionID(getAgentID(getAgent(agentCredential)))
|
|
41
|
-
);
|
|
28
|
+
const node = new LocalNode(...randomAnonymousAccountAndSessionID());
|
|
42
29
|
|
|
43
30
|
const coValue = node.createCoValue({
|
|
44
31
|
type: "comap",
|
|
45
32
|
ruleset: { type: "unsafeAllowAll" },
|
|
46
33
|
meta: null,
|
|
47
|
-
...createdNowUnique()
|
|
34
|
+
...createdNowUnique(),
|
|
48
35
|
});
|
|
49
36
|
|
|
50
37
|
const content = coValue.getCurrentContent();
|
|
@@ -67,17 +54,13 @@ test("Can insert and delete Map entries in edit()", () => {
|
|
|
67
54
|
});
|
|
68
55
|
|
|
69
56
|
test("Can get map entry values at different points in time", () => {
|
|
70
|
-
const
|
|
71
|
-
const node = new LocalNode(
|
|
72
|
-
agentCredential,
|
|
73
|
-
newRandomSessionID(getAgentID(getAgent(agentCredential)))
|
|
74
|
-
);
|
|
57
|
+
const node = new LocalNode(...randomAnonymousAccountAndSessionID());
|
|
75
58
|
|
|
76
59
|
const coValue = node.createCoValue({
|
|
77
60
|
type: "comap",
|
|
78
61
|
ruleset: { type: "unsafeAllowAll" },
|
|
79
62
|
meta: null,
|
|
80
|
-
...createdNowUnique()
|
|
63
|
+
...createdNowUnique(),
|
|
81
64
|
});
|
|
82
65
|
|
|
83
66
|
const content = coValue.getCurrentContent();
|
|
@@ -90,13 +73,13 @@ test("Can get map entry values at different points in time", () => {
|
|
|
90
73
|
|
|
91
74
|
content.edit((editable) => {
|
|
92
75
|
const beforeA = Date.now();
|
|
93
|
-
while(Date.now() < beforeA + 10){}
|
|
76
|
+
while (Date.now() < beforeA + 10) {}
|
|
94
77
|
editable.set("hello", "A", "trusting");
|
|
95
78
|
const beforeB = Date.now();
|
|
96
|
-
while(Date.now() < beforeB + 10){}
|
|
79
|
+
while (Date.now() < beforeB + 10) {}
|
|
97
80
|
editable.set("hello", "B", "trusting");
|
|
98
81
|
const beforeC = Date.now();
|
|
99
|
-
while(Date.now() < beforeC + 10){}
|
|
82
|
+
while (Date.now() < beforeC + 10) {}
|
|
100
83
|
editable.set("hello", "C", "trusting");
|
|
101
84
|
expect(editable.get("hello")).toEqual("C");
|
|
102
85
|
expect(editable.getAtTime("hello", Date.now())).toEqual("C");
|
|
@@ -107,17 +90,13 @@ test("Can get map entry values at different points in time", () => {
|
|
|
107
90
|
});
|
|
108
91
|
|
|
109
92
|
test("Can get all historic values of key", () => {
|
|
110
|
-
const
|
|
111
|
-
const node = new LocalNode(
|
|
112
|
-
agentCredential,
|
|
113
|
-
newRandomSessionID(getAgentID(getAgent(agentCredential)))
|
|
114
|
-
);
|
|
93
|
+
const node = new LocalNode(...randomAnonymousAccountAndSessionID());
|
|
115
94
|
|
|
116
95
|
const coValue = node.createCoValue({
|
|
117
96
|
type: "comap",
|
|
118
97
|
ruleset: { type: "unsafeAllowAll" },
|
|
119
98
|
meta: null,
|
|
120
|
-
...createdNowUnique()
|
|
99
|
+
...createdNowUnique(),
|
|
121
100
|
});
|
|
122
101
|
|
|
123
102
|
const content = coValue.getCurrentContent();
|
|
@@ -137,9 +116,7 @@ test("Can get all historic values of key", () => {
|
|
|
137
116
|
const txDel = editable.getLastTxID("hello");
|
|
138
117
|
editable.set("hello", "C", "trusting");
|
|
139
118
|
const txC = editable.getLastTxID("hello");
|
|
140
|
-
expect(
|
|
141
|
-
editable.getHistory("hello")
|
|
142
|
-
).toEqual([
|
|
119
|
+
expect(editable.getHistory("hello")).toEqual([
|
|
143
120
|
{
|
|
144
121
|
txID: txA,
|
|
145
122
|
value: "A",
|
|
@@ -165,17 +142,13 @@ test("Can get all historic values of key", () => {
|
|
|
165
142
|
});
|
|
166
143
|
|
|
167
144
|
test("Can get last tx ID for a key", () => {
|
|
168
|
-
const
|
|
169
|
-
const node = new LocalNode(
|
|
170
|
-
agentCredential,
|
|
171
|
-
newRandomSessionID(getAgentID(getAgent(agentCredential)))
|
|
172
|
-
);
|
|
145
|
+
const node = new LocalNode(...randomAnonymousAccountAndSessionID());
|
|
173
146
|
|
|
174
147
|
const coValue = node.createCoValue({
|
|
175
148
|
type: "comap",
|
|
176
149
|
ruleset: { type: "unsafeAllowAll" },
|
|
177
150
|
meta: null,
|
|
178
|
-
...createdNowUnique()
|
|
151
|
+
...createdNowUnique(),
|
|
179
152
|
});
|
|
180
153
|
|
|
181
154
|
const content = coValue.getCurrentContent();
|
|
@@ -190,8 +163,8 @@ test("Can get last tx ID for a key", () => {
|
|
|
190
163
|
expect(editable.getLastTxID("hello")).toEqual(undefined);
|
|
191
164
|
editable.set("hello", "A", "trusting");
|
|
192
165
|
const sessionID = editable.getLastTxID("hello")?.sessionID;
|
|
193
|
-
expect(sessionID &&
|
|
194
|
-
|
|
166
|
+
expect(sessionID && accountOrAgentIDfromSessionID(sessionID)).toEqual(
|
|
167
|
+
node.account.id
|
|
195
168
|
);
|
|
196
169
|
expect(editable.getLastTxID("hello")?.txIndex).toEqual(0);
|
|
197
170
|
editable.set("hello", "B", "trusting");
|
package/src/contentType.ts
CHANGED
|
@@ -1,24 +1,26 @@
|
|
|
1
|
-
import { JsonValue } from
|
|
2
|
-
import {
|
|
3
|
-
import { CoMap } from
|
|
4
|
-
import { CoStream } from
|
|
5
|
-
import { Static } from
|
|
6
|
-
import { CoList } from
|
|
1
|
+
import { JsonObject, JsonValue } from "./jsonValue.js";
|
|
2
|
+
import { RawCoID } from "./ids.js";
|
|
3
|
+
import { CoMap } from "./contentTypes/coMap.js";
|
|
4
|
+
import { CoStream } from "./contentTypes/coStream.js";
|
|
5
|
+
import { Static } from "./contentTypes/static.js";
|
|
6
|
+
import { CoList } from "./contentTypes/coList.js";
|
|
7
7
|
|
|
8
|
-
export type
|
|
8
|
+
export type CoID<T extends ContentType> = RawCoID & {
|
|
9
9
|
readonly __type: T;
|
|
10
10
|
};
|
|
11
11
|
|
|
12
12
|
export type ContentType =
|
|
13
|
-
| CoMap<{[key: string]: JsonValue},
|
|
14
|
-
| CoList<JsonValue,
|
|
15
|
-
| CoStream<JsonValue,
|
|
16
|
-
| Static<
|
|
13
|
+
| CoMap<{ [key: string]: JsonValue }, JsonObject | null>
|
|
14
|
+
| CoList<JsonValue, JsonObject | null>
|
|
15
|
+
| CoStream<JsonValue, JsonObject | null>
|
|
16
|
+
| Static<JsonObject>;
|
|
17
17
|
|
|
18
|
-
export function expectMap(
|
|
18
|
+
export function expectMap(
|
|
19
|
+
content: ContentType
|
|
20
|
+
): CoMap<{ [key: string]: string }, JsonObject | null> {
|
|
19
21
|
if (content.type !== "comap") {
|
|
20
22
|
throw new Error("Expected map");
|
|
21
23
|
}
|
|
22
24
|
|
|
23
|
-
return content as CoMap<{ [key: string]: string },
|
|
25
|
+
return content as CoMap<{ [key: string]: string }, JsonObject | null>;
|
|
24
26
|
}
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
import { JsonObject, JsonValue } from '../jsonValue.js';
|
|
2
|
-
import {
|
|
2
|
+
import { CoID } from '../contentType.js';
|
|
3
3
|
import { CoValue } from '../coValue.js';
|
|
4
4
|
|
|
5
|
-
export class CoList<T extends JsonValue, Meta extends
|
|
6
|
-
id:
|
|
5
|
+
export class CoList<T extends JsonValue, Meta extends JsonObject | null = null> {
|
|
6
|
+
id: CoID<CoList<T, Meta>>;
|
|
7
7
|
type = "colist" as const;
|
|
8
8
|
coValue: CoValue;
|
|
9
9
|
|
|
10
10
|
constructor(coValue: CoValue) {
|
|
11
|
-
this.id = coValue.id as
|
|
11
|
+
this.id = coValue.id as CoID<CoList<T, Meta>>;
|
|
12
12
|
this.coValue = coValue;
|
|
13
13
|
}
|
|
14
14
|
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { JsonObject, JsonValue } from '../jsonValue.js';
|
|
2
2
|
import { TransactionID } from '../ids.js';
|
|
3
|
-
import {
|
|
4
|
-
import { CoValue } from '../coValue.js';
|
|
3
|
+
import { CoID } from '../contentType.js';
|
|
4
|
+
import { CoValue, accountOrAgentIDfromSessionID } from '../coValue.js';
|
|
5
|
+
import { AccountID, isAccountID } from '../account.js';
|
|
5
6
|
|
|
6
7
|
type MapOp<K extends string, V extends JsonValue> = {
|
|
7
8
|
txID: TransactionID;
|
|
@@ -20,24 +21,25 @@ export type MapOpPayload<K extends string, V extends JsonValue> = {
|
|
|
20
21
|
key: K;
|
|
21
22
|
};
|
|
22
23
|
|
|
24
|
+
export type MapK<M extends { [key: string]: JsonValue; }> = keyof M & string;
|
|
25
|
+
export type MapV<M extends { [key: string]: JsonValue; }> = M[MapK<M>];
|
|
26
|
+
export type MapM<M extends { [key: string]: JsonValue; }> = {
|
|
27
|
+
[KK in MapK<M>]: M[KK];
|
|
28
|
+
}
|
|
29
|
+
|
|
23
30
|
export class CoMap<
|
|
24
31
|
M extends { [key: string]: JsonValue; },
|
|
25
|
-
Meta extends
|
|
26
|
-
K extends string = keyof M & string,
|
|
27
|
-
V extends JsonValue = M[K],
|
|
28
|
-
MM extends { [key: string]: JsonValue; } = {
|
|
29
|
-
[KK in K]: M[KK];
|
|
30
|
-
}
|
|
32
|
+
Meta extends JsonObject | null = null,
|
|
31
33
|
> {
|
|
32
|
-
id:
|
|
34
|
+
id: CoID<CoMap<MapM<M>, Meta>>;
|
|
33
35
|
coValue: CoValue;
|
|
34
36
|
type = "comap" as const;
|
|
35
37
|
ops: {
|
|
36
|
-
[KK in
|
|
38
|
+
[KK in MapK<M>]?: MapOp<KK, M[KK]>[];
|
|
37
39
|
};
|
|
38
40
|
|
|
39
41
|
constructor(coValue: CoValue) {
|
|
40
|
-
this.id = coValue.id as
|
|
42
|
+
this.id = coValue.id as CoID<CoMap<MapM<M>, Meta>>;
|
|
41
43
|
this.coValue = coValue;
|
|
42
44
|
this.ops = {};
|
|
43
45
|
|
|
@@ -51,7 +53,7 @@ export class CoMap<
|
|
|
51
53
|
for (const [changeIdx, changeUntyped] of (
|
|
52
54
|
changes
|
|
53
55
|
).entries()) {
|
|
54
|
-
const change = changeUntyped as MapOpPayload<
|
|
56
|
+
const change = changeUntyped as MapOpPayload<MapK<M>, MapV<M>>;
|
|
55
57
|
let entries = this.ops[change.key];
|
|
56
58
|
if (!entries) {
|
|
57
59
|
entries = [];
|
|
@@ -61,17 +63,17 @@ export class CoMap<
|
|
|
61
63
|
txID,
|
|
62
64
|
madeAt,
|
|
63
65
|
changeIdx,
|
|
64
|
-
...(change as MapOpPayload<
|
|
66
|
+
...(change as MapOpPayload<MapK<M>, MapV<M>>),
|
|
65
67
|
});
|
|
66
68
|
}
|
|
67
69
|
}
|
|
68
70
|
}
|
|
69
71
|
|
|
70
|
-
keys():
|
|
71
|
-
return Object.keys(this.ops) as
|
|
72
|
+
keys(): MapK<M>[] {
|
|
73
|
+
return Object.keys(this.ops) as MapK<M>[];
|
|
72
74
|
}
|
|
73
75
|
|
|
74
|
-
get<
|
|
76
|
+
get<K extends MapK<M>>(key: K): M[K] | undefined {
|
|
75
77
|
const ops = this.ops[key];
|
|
76
78
|
if (!ops) {
|
|
77
79
|
return undefined;
|
|
@@ -86,7 +88,7 @@ export class CoMap<
|
|
|
86
88
|
}
|
|
87
89
|
}
|
|
88
90
|
|
|
89
|
-
getAtTime<
|
|
91
|
+
getAtTime<K extends MapK<M>>(key: K, time: number): M[K] | undefined {
|
|
90
92
|
const ops = this.ops[key];
|
|
91
93
|
if (!ops) {
|
|
92
94
|
return undefined;
|
|
@@ -105,7 +107,20 @@ export class CoMap<
|
|
|
105
107
|
}
|
|
106
108
|
}
|
|
107
109
|
|
|
108
|
-
|
|
110
|
+
getLastEditor<K extends MapK<M>>(key: K): AccountID | undefined {
|
|
111
|
+
const tx = this.getLastTxID(key);
|
|
112
|
+
if (!tx) {
|
|
113
|
+
return undefined;
|
|
114
|
+
}
|
|
115
|
+
const accountID = accountOrAgentIDfromSessionID(tx.sessionID);
|
|
116
|
+
if (isAccountID(accountID)) {
|
|
117
|
+
return accountID;
|
|
118
|
+
} else {
|
|
119
|
+
return undefined;
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
getLastTxID<K extends MapK<M>>(key: K): TransactionID | undefined {
|
|
109
124
|
const ops = this.ops[key];
|
|
110
125
|
if (!ops) {
|
|
111
126
|
return undefined;
|
|
@@ -116,13 +131,28 @@ export class CoMap<
|
|
|
116
131
|
return lastEntry.txID;
|
|
117
132
|
}
|
|
118
133
|
|
|
119
|
-
|
|
134
|
+
getLastEntry<K extends MapK<M>>(key: K): { at: number; txID: TransactionID; value: M[K]; } | undefined {
|
|
135
|
+
const ops = this.ops[key];
|
|
136
|
+
if (!ops) {
|
|
137
|
+
return undefined;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
const lastEntry = ops[ops.length - 1]!;
|
|
141
|
+
|
|
142
|
+
if (lastEntry.op === "delete") {
|
|
143
|
+
return undefined;
|
|
144
|
+
} else {
|
|
145
|
+
return { at: lastEntry.madeAt, txID: lastEntry.txID, value: lastEntry.value };
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
getHistory<K extends MapK<M>>(key: K): { at: number; txID: TransactionID; value: M[K] | undefined; }[] {
|
|
120
150
|
const ops = this.ops[key];
|
|
121
151
|
if (!ops) {
|
|
122
152
|
return [];
|
|
123
153
|
}
|
|
124
154
|
|
|
125
|
-
const history: { at: number; txID: TransactionID; value: M[
|
|
155
|
+
const history: { at: number; txID: TransactionID; value: M[K] | undefined; }[] = [];
|
|
126
156
|
|
|
127
157
|
for (const op of ops) {
|
|
128
158
|
if (op.op === "delete") {
|
|
@@ -163,14 +193,10 @@ export class CoMap<
|
|
|
163
193
|
|
|
164
194
|
export class WriteableCoMap<
|
|
165
195
|
M extends { [key: string]: JsonValue; },
|
|
166
|
-
Meta extends
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
[KK in K]: M[KK];
|
|
171
|
-
}
|
|
172
|
-
> extends CoMap<M, Meta, K, V, MM> {
|
|
173
|
-
set<KK extends K>(key: KK, value: M[KK], privacy: "private" | "trusting" = "private"): void {
|
|
196
|
+
Meta extends JsonObject | null = null,
|
|
197
|
+
|
|
198
|
+
> extends CoMap<M, Meta> {
|
|
199
|
+
set<K extends MapK<M>>(key: K, value: M[K], privacy: "private" | "trusting" = "private"): void {
|
|
174
200
|
this.coValue.makeTransaction([
|
|
175
201
|
{
|
|
176
202
|
op: "insert",
|
|
@@ -182,7 +208,7 @@ export class WriteableCoMap<
|
|
|
182
208
|
this.fillOpsFromCoValue();
|
|
183
209
|
}
|
|
184
210
|
|
|
185
|
-
delete(key:
|
|
211
|
+
delete(key: MapK<M>, privacy: "private" | "trusting" = "private"): void {
|
|
186
212
|
this.coValue.makeTransaction([
|
|
187
213
|
{
|
|
188
214
|
op: "delete",
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
import { JsonObject, JsonValue } from '../jsonValue.js';
|
|
2
|
-
import {
|
|
2
|
+
import { CoID } from '../contentType.js';
|
|
3
3
|
import { CoValue } from '../coValue.js';
|
|
4
4
|
|
|
5
|
-
export class CoStream<T extends JsonValue, Meta extends
|
|
6
|
-
id:
|
|
5
|
+
export class CoStream<T extends JsonValue, Meta extends JsonObject | null = null> {
|
|
6
|
+
id: CoID<CoStream<T, Meta>>;
|
|
7
7
|
type = "costream" as const;
|
|
8
8
|
coValue: CoValue;
|
|
9
9
|
|
|
10
10
|
constructor(coValue: CoValue) {
|
|
11
|
-
this.id = coValue.id as
|
|
11
|
+
this.id = coValue.id as CoID<CoStream<T, Meta>>;
|
|
12
12
|
this.coValue = coValue;
|
|
13
13
|
}
|
|
14
14
|
|
|
@@ -1,14 +1,14 @@
|
|
|
1
|
-
import { JsonObject
|
|
2
|
-
import {
|
|
1
|
+
import { JsonObject } from '../jsonValue.js';
|
|
2
|
+
import { CoID } from '../contentType.js';
|
|
3
3
|
import { CoValue } from '../coValue.js';
|
|
4
4
|
|
|
5
|
-
export class Static<T extends
|
|
6
|
-
id:
|
|
5
|
+
export class Static<T extends JsonObject> {
|
|
6
|
+
id: CoID<Static<T>>;
|
|
7
7
|
type = "static" as const;
|
|
8
8
|
coValue: CoValue;
|
|
9
9
|
|
|
10
10
|
constructor(coValue: CoValue) {
|
|
11
|
-
this.id = coValue.id as
|
|
11
|
+
this.id = coValue.id as CoID<Static<T>>;
|
|
12
12
|
this.coValue = coValue;
|
|
13
13
|
}
|
|
14
14
|
|
package/src/crypto.test.ts
CHANGED
|
@@ -1,19 +1,19 @@
|
|
|
1
1
|
import {
|
|
2
|
-
|
|
3
|
-
|
|
2
|
+
getSealerID,
|
|
3
|
+
getSignerID,
|
|
4
4
|
secureHash,
|
|
5
|
-
|
|
6
|
-
|
|
5
|
+
newRandomSealer,
|
|
6
|
+
newRandomSigner,
|
|
7
7
|
seal,
|
|
8
8
|
sign,
|
|
9
|
-
|
|
9
|
+
unseal,
|
|
10
10
|
verify,
|
|
11
11
|
shortHash,
|
|
12
12
|
newRandomKeySecret,
|
|
13
13
|
encryptForTransaction,
|
|
14
14
|
decryptForTransaction,
|
|
15
|
-
|
|
16
|
-
|
|
15
|
+
encryptKeySecret,
|
|
16
|
+
decryptKeySecret,
|
|
17
17
|
} from './crypto.js';
|
|
18
18
|
import { base58, base64url } from "@scure/base";
|
|
19
19
|
import { x25519 } from "@noble/curves/ed25519";
|
|
@@ -23,69 +23,63 @@ import stableStringify from "fast-json-stable-stringify";
|
|
|
23
23
|
|
|
24
24
|
test("Signatures round-trip and use stable stringify", () => {
|
|
25
25
|
const data = { b: "world", a: "hello" };
|
|
26
|
-
const
|
|
27
|
-
const signature = sign(
|
|
26
|
+
const signer = newRandomSigner();
|
|
27
|
+
const signature = sign(signer, data);
|
|
28
28
|
|
|
29
29
|
expect(signature).toMatch(/^signature_z/);
|
|
30
30
|
expect(
|
|
31
|
-
verify(signature, { a: "hello", b: "world" },
|
|
31
|
+
verify(signature, { a: "hello", b: "world" }, getSignerID(signer))
|
|
32
32
|
).toBe(true);
|
|
33
33
|
});
|
|
34
34
|
|
|
35
35
|
test("Invalid signatures don't verify", () => {
|
|
36
36
|
const data = { b: "world", a: "hello" };
|
|
37
|
-
const
|
|
38
|
-
const
|
|
39
|
-
const wrongSignature = sign(
|
|
37
|
+
const signer = newRandomSigner();
|
|
38
|
+
const signer2 = newRandomSigner();
|
|
39
|
+
const wrongSignature = sign(signer2, data);
|
|
40
40
|
|
|
41
|
-
expect(verify(wrongSignature, data,
|
|
41
|
+
expect(verify(wrongSignature, data, getSignerID(signer))).toBe(false);
|
|
42
42
|
});
|
|
43
43
|
|
|
44
|
-
test("
|
|
44
|
+
test("encrypting round-trips, but invalid receiver can't unseal", () => {
|
|
45
45
|
const data = { b: "world", a: "hello" };
|
|
46
|
-
const sender =
|
|
47
|
-
const
|
|
48
|
-
const
|
|
49
|
-
const recipient3 = newRandomRecipient();
|
|
46
|
+
const sender = newRandomSealer();
|
|
47
|
+
const sealer = newRandomSealer();
|
|
48
|
+
const wrongSealer = newRandomSealer();
|
|
50
49
|
|
|
51
50
|
const nOnceMaterial = {
|
|
52
51
|
in: "co_zTEST",
|
|
53
|
-
tx: { sessionID: "
|
|
52
|
+
tx: { sessionID: "co_zTEST_session_zTEST", txIndex: 0 },
|
|
54
53
|
} as const;
|
|
55
54
|
|
|
56
55
|
const sealed = seal(
|
|
57
56
|
data,
|
|
58
57
|
sender,
|
|
59
|
-
|
|
58
|
+
getSealerID(sealer),
|
|
60
59
|
nOnceMaterial
|
|
61
60
|
);
|
|
62
61
|
|
|
63
|
-
expect(sealed[getRecipientID(recipient1)]).toMatch(/^sealed_U/);
|
|
64
|
-
expect(sealed[getRecipientID(recipient2)]).toMatch(/^sealed_U/);
|
|
65
62
|
expect(
|
|
66
|
-
|
|
63
|
+
unseal(sealed, sealer, getSealerID(sender), nOnceMaterial)
|
|
67
64
|
).toEqual(data);
|
|
68
65
|
expect(
|
|
69
|
-
|
|
70
|
-
).
|
|
71
|
-
expect(
|
|
72
|
-
openAs(sealed, recipient3, getRecipientID(sender), nOnceMaterial)
|
|
73
|
-
).toBeUndefined();
|
|
66
|
+
() => unseal(sealed, wrongSealer, getSealerID(sender), nOnceMaterial)
|
|
67
|
+
).toThrow(/Wrong tag/);
|
|
74
68
|
|
|
75
|
-
// trying with wrong
|
|
69
|
+
// trying with wrong sealer secret, by hand
|
|
76
70
|
const nOnce = blake3(
|
|
77
71
|
new TextEncoder().encode(stableStringify(nOnceMaterial))
|
|
78
72
|
).slice(0, 24);
|
|
79
|
-
const
|
|
80
|
-
|
|
73
|
+
const sealer3priv = base58.decode(
|
|
74
|
+
wrongSealer.substring("sealerSecret_z".length)
|
|
81
75
|
);
|
|
82
76
|
const senderPub = base58.decode(
|
|
83
|
-
|
|
77
|
+
getSealerID(sender).substring("sealer_z".length)
|
|
84
78
|
);
|
|
85
79
|
const sealedBytes = base64url.decode(
|
|
86
|
-
sealed
|
|
80
|
+
sealed.substring("sealed_U".length)
|
|
87
81
|
);
|
|
88
|
-
const sharedSecret = x25519.getSharedSecret(
|
|
82
|
+
const sharedSecret = x25519.getSharedSecret(sealer3priv, senderPub);
|
|
89
83
|
|
|
90
84
|
expect(() => {
|
|
91
85
|
const _ = xsalsa20_poly1305(sharedSecret, nOnce).decrypt(sealedBytes);
|
|
@@ -107,22 +101,22 @@ test("Encryption for transactions round-trips", () => {
|
|
|
107
101
|
|
|
108
102
|
const encrypted1 = encryptForTransaction({ a: "hello" }, secret, {
|
|
109
103
|
in: "co_zTEST",
|
|
110
|
-
tx: { sessionID: "
|
|
104
|
+
tx: { sessionID: "co_zTEST_session_zTEST", txIndex: 0 },
|
|
111
105
|
});
|
|
112
106
|
|
|
113
107
|
const encrypted2 = encryptForTransaction({ b: "world" }, secret, {
|
|
114
108
|
in: "co_zTEST",
|
|
115
|
-
tx: { sessionID: "
|
|
109
|
+
tx: { sessionID: "co_zTEST_session_zTEST", txIndex: 1 },
|
|
116
110
|
});
|
|
117
111
|
|
|
118
112
|
const decrypted1 = decryptForTransaction(encrypted1, secret, {
|
|
119
113
|
in: "co_zTEST",
|
|
120
|
-
tx: { sessionID: "
|
|
114
|
+
tx: { sessionID: "co_zTEST_session_zTEST", txIndex: 0 },
|
|
121
115
|
});
|
|
122
116
|
|
|
123
117
|
const decrypted2 = decryptForTransaction(encrypted2, secret, {
|
|
124
118
|
in: "co_zTEST",
|
|
125
|
-
tx: { sessionID: "
|
|
119
|
+
tx: { sessionID: "co_zTEST_session_zTEST", txIndex: 1 },
|
|
126
120
|
});
|
|
127
121
|
|
|
128
122
|
expect([decrypted1, decrypted2]).toEqual([{ a: "hello" }, { b: "world" }]);
|
|
@@ -134,56 +128,56 @@ test("Encryption for transactions doesn't decrypt with a wrong key", () => {
|
|
|
134
128
|
|
|
135
129
|
const encrypted1 = encryptForTransaction({ a: "hello" }, secret, {
|
|
136
130
|
in: "co_zTEST",
|
|
137
|
-
tx: { sessionID: "
|
|
131
|
+
tx: { sessionID: "co_zTEST_session_zTEST", txIndex: 0 },
|
|
138
132
|
});
|
|
139
133
|
|
|
140
134
|
const encrypted2 = encryptForTransaction({ b: "world" }, secret, {
|
|
141
135
|
in: "co_zTEST",
|
|
142
|
-
tx: { sessionID: "
|
|
136
|
+
tx: { sessionID: "co_zTEST_session_zTEST", txIndex: 1 },
|
|
143
137
|
});
|
|
144
138
|
|
|
145
139
|
const decrypted1 = decryptForTransaction(encrypted1, secret2, {
|
|
146
140
|
in: "co_zTEST",
|
|
147
|
-
tx: { sessionID: "
|
|
141
|
+
tx: { sessionID: "co_zTEST_session_zTEST", txIndex: 0 },
|
|
148
142
|
});
|
|
149
143
|
|
|
150
144
|
const decrypted2 = decryptForTransaction(encrypted2, secret2, {
|
|
151
145
|
in: "co_zTEST",
|
|
152
|
-
tx: { sessionID: "
|
|
146
|
+
tx: { sessionID: "co_zTEST_session_zTEST", txIndex: 1 },
|
|
153
147
|
});
|
|
154
148
|
|
|
155
149
|
expect([decrypted1, decrypted2]).toEqual([undefined, undefined]);
|
|
156
150
|
});
|
|
157
151
|
|
|
158
152
|
test("Encryption of keySecrets round-trips", () => {
|
|
159
|
-
const
|
|
160
|
-
const
|
|
153
|
+
const toEncrypt = newRandomKeySecret();
|
|
154
|
+
const encrypting = newRandomKeySecret();
|
|
161
155
|
|
|
162
156
|
const keys = {
|
|
163
|
-
|
|
164
|
-
|
|
157
|
+
toEncrypt,
|
|
158
|
+
encrypting,
|
|
165
159
|
};
|
|
166
160
|
|
|
167
|
-
const
|
|
161
|
+
const encrypted = encryptKeySecret(keys);
|
|
168
162
|
|
|
169
|
-
const
|
|
163
|
+
const decrypted = decryptKeySecret(encrypted, encrypting.secret);
|
|
170
164
|
|
|
171
|
-
expect(
|
|
165
|
+
expect(decrypted).toEqual(toEncrypt.secret);
|
|
172
166
|
});
|
|
173
167
|
|
|
174
|
-
test("Encryption of keySecrets doesn't
|
|
175
|
-
const
|
|
176
|
-
const
|
|
177
|
-
const
|
|
168
|
+
test("Encryption of keySecrets doesn't decrypt with a wrong key", () => {
|
|
169
|
+
const toEncrypt = newRandomKeySecret();
|
|
170
|
+
const encrypting = newRandomKeySecret();
|
|
171
|
+
const encryptingWrong = newRandomKeySecret();
|
|
178
172
|
|
|
179
173
|
const keys = {
|
|
180
|
-
|
|
181
|
-
|
|
174
|
+
toEncrypt,
|
|
175
|
+
encrypting,
|
|
182
176
|
};
|
|
183
177
|
|
|
184
|
-
const
|
|
178
|
+
const encrypted = encryptKeySecret(keys);
|
|
185
179
|
|
|
186
|
-
const
|
|
180
|
+
const decrypted = decryptKeySecret(encrypted, encryptingWrong.secret);
|
|
187
181
|
|
|
188
|
-
expect(
|
|
182
|
+
expect(decrypted).toBeUndefined();
|
|
189
183
|
});
|