cojson 0.0.10 → 0.0.12
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 +16 -35
- package/dist/coValue.js +49 -112
- 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 +26 -28
- package/dist/sync.js +81 -67
- package/dist/sync.js.map +1 -1
- package/dist/sync.test.js +194 -293
- 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 +93 -179
- 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 +284 -426
- package/src/sync.ts +115 -105
- package/src/testUtils.ts +229 -0
package/src/crypto.ts
CHANGED
|
@@ -5,45 +5,47 @@ import { base58, base64url } from "@scure/base";
|
|
|
5
5
|
import stableStringify from "fast-json-stable-stringify";
|
|
6
6
|
import { blake3 } from "@noble/hashes/blake3";
|
|
7
7
|
import { randomBytes } from "@noble/ciphers/webcrypto/utils";
|
|
8
|
-
import {
|
|
8
|
+
import { AgentID, RawCoID, TransactionID } from './ids.js';
|
|
9
9
|
|
|
10
|
-
export type
|
|
11
|
-
export type
|
|
10
|
+
export type SignerSecret = `signerSecret_z${string}`;
|
|
11
|
+
export type SignerID = `signer_z${string}`;
|
|
12
12
|
export type Signature = `signature_z${string}`;
|
|
13
13
|
|
|
14
|
-
export type
|
|
15
|
-
export type
|
|
14
|
+
export type SealerSecret = `sealerSecret_z${string}`;
|
|
15
|
+
export type SealerID = `sealer_z${string}`;
|
|
16
16
|
export type Sealed<T> = `sealed_U${string}` & { __type: T };
|
|
17
17
|
|
|
18
|
+
export type AgentSecret = `${SealerSecret}/${SignerSecret}`;
|
|
19
|
+
|
|
18
20
|
const textEncoder = new TextEncoder();
|
|
19
21
|
const textDecoder = new TextDecoder();
|
|
20
22
|
|
|
21
|
-
export function
|
|
22
|
-
return `
|
|
23
|
+
export function newRandomSigner(): SignerSecret {
|
|
24
|
+
return `signerSecret_z${base58.encode(
|
|
23
25
|
ed25519.utils.randomPrivateKey()
|
|
24
26
|
)}`;
|
|
25
27
|
}
|
|
26
28
|
|
|
27
|
-
export function
|
|
28
|
-
return base58.decode(secret.substring("
|
|
29
|
+
export function signerSecretToBytes(secret: SignerSecret): Uint8Array {
|
|
30
|
+
return base58.decode(secret.substring("signerSecret_z".length));
|
|
29
31
|
}
|
|
30
32
|
|
|
31
|
-
export function
|
|
32
|
-
return `
|
|
33
|
+
export function signerSecretFromBytes(bytes: Uint8Array): SignerSecret {
|
|
34
|
+
return `signerSecret_z${base58.encode(bytes)}`;
|
|
33
35
|
}
|
|
34
36
|
|
|
35
|
-
export function
|
|
36
|
-
return `
|
|
37
|
+
export function getSignerID(secret: SignerSecret): SignerID {
|
|
38
|
+
return `signer_z${base58.encode(
|
|
37
39
|
ed25519.getPublicKey(
|
|
38
|
-
base58.decode(secret.substring("
|
|
40
|
+
base58.decode(secret.substring("signerSecret_z".length))
|
|
39
41
|
)
|
|
40
42
|
)}`;
|
|
41
43
|
}
|
|
42
44
|
|
|
43
|
-
export function sign(secret:
|
|
45
|
+
export function sign(secret: SignerSecret, message: JsonValue): Signature {
|
|
44
46
|
const signature = ed25519.sign(
|
|
45
47
|
textEncoder.encode(stableStringify(message)),
|
|
46
|
-
base58.decode(secret.substring("
|
|
48
|
+
base58.decode(secret.substring("signerSecret_z".length))
|
|
47
49
|
);
|
|
48
50
|
return `signature_z${base58.encode(signature)}`;
|
|
49
51
|
}
|
|
@@ -51,105 +53,131 @@ export function sign(secret: SignatorySecret, message: JsonValue): Signature {
|
|
|
51
53
|
export function verify(
|
|
52
54
|
signature: Signature,
|
|
53
55
|
message: JsonValue,
|
|
54
|
-
id:
|
|
56
|
+
id: SignerID
|
|
55
57
|
): boolean {
|
|
56
58
|
return ed25519.verify(
|
|
57
59
|
base58.decode(signature.substring("signature_z".length)),
|
|
58
60
|
textEncoder.encode(stableStringify(message)),
|
|
59
|
-
base58.decode(id.substring("
|
|
61
|
+
base58.decode(id.substring("signer_z".length))
|
|
60
62
|
);
|
|
61
63
|
}
|
|
62
64
|
|
|
63
|
-
export function
|
|
64
|
-
return `
|
|
65
|
+
export function newRandomSealer(): SealerSecret {
|
|
66
|
+
return `sealerSecret_z${base58.encode(x25519.utils.randomPrivateKey())}`;
|
|
65
67
|
}
|
|
66
68
|
|
|
67
|
-
export function
|
|
68
|
-
return base58.decode(secret.substring("
|
|
69
|
+
export function sealerSecretToBytes(secret: SealerSecret): Uint8Array {
|
|
70
|
+
return base58.decode(secret.substring("sealerSecret_z".length));
|
|
69
71
|
}
|
|
70
72
|
|
|
71
|
-
export function
|
|
72
|
-
return `
|
|
73
|
+
export function sealerSecretFromBytes(bytes: Uint8Array): SealerSecret {
|
|
74
|
+
return `sealerSecret_z${base58.encode(bytes)}`;
|
|
73
75
|
}
|
|
74
76
|
|
|
75
|
-
export function
|
|
76
|
-
return `
|
|
77
|
+
export function getSealerID(secret: SealerSecret): SealerID {
|
|
78
|
+
return `sealer_z${base58.encode(
|
|
77
79
|
x25519.getPublicKey(
|
|
78
|
-
base58.decode(secret.substring("
|
|
80
|
+
base58.decode(secret.substring("sealerSecret_z".length))
|
|
79
81
|
)
|
|
80
82
|
)}`;
|
|
81
83
|
}
|
|
82
84
|
|
|
83
|
-
export
|
|
84
|
-
|
|
85
|
-
}
|
|
85
|
+
export function newRandomAgentSecret(): AgentSecret {
|
|
86
|
+
return `${newRandomSealer()}/${newRandomSigner()}`;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
export function agentSecretToBytes(secret: AgentSecret): Uint8Array {
|
|
90
|
+
const [sealerSecret, signerSecret] = secret.split("/");
|
|
91
|
+
return new Uint8Array([
|
|
92
|
+
...sealerSecretToBytes(sealerSecret as SealerSecret),
|
|
93
|
+
...signerSecretToBytes(signerSecret as SignerSecret),
|
|
94
|
+
]);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
export function agentSecretFromBytes(bytes: Uint8Array): AgentSecret {
|
|
98
|
+
const sealerSecret = sealerSecretFromBytes(
|
|
99
|
+
bytes.slice(0, 32)
|
|
100
|
+
);
|
|
101
|
+
const signerSecret = signerSecretFromBytes(
|
|
102
|
+
bytes.slice(32)
|
|
103
|
+
);
|
|
104
|
+
return `${sealerSecret}/${signerSecret}`;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
export function getAgentID(secret: AgentSecret): AgentID {
|
|
108
|
+
const [sealerSecret, signerSecret] = secret.split("/");
|
|
109
|
+
return `${getSealerID(
|
|
110
|
+
sealerSecret as SealerSecret
|
|
111
|
+
)}/${getSignerID(signerSecret as SignerSecret)}`;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
export function getAgentSignerID(agentId: AgentID): SignerID {
|
|
115
|
+
return agentId.split("/")[1] as SignerID;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
export function getAgentSignerSecret(agentSecret: AgentSecret): SignerSecret {
|
|
119
|
+
return agentSecret.split("/")[1] as SignerSecret;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
export function getAgentSealerID(agentId: AgentID): SealerID {
|
|
123
|
+
return agentId.split("/")[0] as SealerID;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
export function getAgentSealerSecret(agentSecret: AgentSecret): SealerSecret {
|
|
127
|
+
return agentSecret.split("/")[0] as SealerSecret;
|
|
128
|
+
}
|
|
86
129
|
|
|
87
130
|
export function seal<T extends JsonValue>(
|
|
88
131
|
message: T,
|
|
89
|
-
from:
|
|
90
|
-
to:
|
|
91
|
-
nOnceMaterial: { in:
|
|
92
|
-
):
|
|
132
|
+
from: SealerSecret,
|
|
133
|
+
to: SealerID,
|
|
134
|
+
nOnceMaterial: { in: RawCoID; tx: TransactionID }
|
|
135
|
+
): Sealed<T> {
|
|
93
136
|
const nOnce = blake3(
|
|
94
137
|
textEncoder.encode(stableStringify(nOnceMaterial))
|
|
95
138
|
).slice(0, 24);
|
|
96
139
|
|
|
97
|
-
const
|
|
98
|
-
|
|
99
|
-
return base58.decode(recipient.substring("recipient_z".length));
|
|
100
|
-
});
|
|
140
|
+
const sealerPub = base58.decode(to.substring("sealer_z".length));
|
|
141
|
+
|
|
101
142
|
const senderPriv = base58.decode(
|
|
102
|
-
from.substring("
|
|
143
|
+
from.substring("sealerSecret_z".length)
|
|
103
144
|
);
|
|
104
145
|
|
|
105
146
|
const plaintext = textEncoder.encode(stableStringify(message));
|
|
106
147
|
|
|
107
|
-
const
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
const sharedSecret = x25519.getSharedSecret(
|
|
112
|
-
senderPriv,
|
|
113
|
-
recipientPubs[i]!
|
|
114
|
-
);
|
|
115
|
-
|
|
116
|
-
const sealedBytes = xsalsa20_poly1305(sharedSecret, nOnce).encrypt(
|
|
117
|
-
plaintext
|
|
118
|
-
);
|
|
148
|
+
const sharedSecret = x25519.getSharedSecret(
|
|
149
|
+
senderPriv,
|
|
150
|
+
sealerPub
|
|
151
|
+
);
|
|
119
152
|
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
}
|
|
153
|
+
const sealedBytes = xsalsa20_poly1305(sharedSecret, nOnce).encrypt(
|
|
154
|
+
plaintext
|
|
155
|
+
);
|
|
124
156
|
|
|
125
|
-
return
|
|
157
|
+
return `sealed_U${base64url.encode(
|
|
158
|
+
sealedBytes
|
|
159
|
+
)}` as Sealed<T>
|
|
126
160
|
}
|
|
127
161
|
|
|
128
|
-
export function
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
from:
|
|
132
|
-
nOnceMaterial: { in:
|
|
162
|
+
export function unseal<T extends JsonValue>(
|
|
163
|
+
sealed: Sealed<T>,
|
|
164
|
+
sealer: SealerSecret,
|
|
165
|
+
from: SealerID,
|
|
166
|
+
nOnceMaterial: { in: RawCoID; tx: TransactionID }
|
|
133
167
|
): T | undefined {
|
|
134
168
|
const nOnce = blake3(
|
|
135
169
|
textEncoder.encode(stableStringify(nOnceMaterial))
|
|
136
170
|
).slice(0, 24);
|
|
137
171
|
|
|
138
|
-
const
|
|
139
|
-
|
|
172
|
+
const sealerPriv = base58.decode(
|
|
173
|
+
sealer.substring("sealerSecret_z".length)
|
|
140
174
|
);
|
|
141
175
|
|
|
142
|
-
const senderPub = base58.decode(from.substring("
|
|
143
|
-
|
|
144
|
-
const sealed = sealedSet[getRecipientID(recipient)];
|
|
145
|
-
|
|
146
|
-
if (!sealed) {
|
|
147
|
-
return undefined;
|
|
148
|
-
}
|
|
176
|
+
const senderPub = base58.decode(from.substring("sealer_z".length));
|
|
149
177
|
|
|
150
178
|
const sealedBytes = base64url.decode(sealed.substring("sealed_U".length));
|
|
151
179
|
|
|
152
|
-
const sharedSecret = x25519.getSharedSecret(
|
|
180
|
+
const sharedSecret = x25519.getSharedSecret(sealerPriv, senderPub);
|
|
153
181
|
|
|
154
182
|
const plaintext = xsalsa20_poly1305(sharedSecret, nOnce).decrypt(
|
|
155
183
|
sealedBytes
|
|
@@ -235,30 +263,30 @@ function encrypt<T extends JsonValue, N extends JsonValue>(
|
|
|
235
263
|
export function encryptForTransaction<T extends JsonValue>(
|
|
236
264
|
value: T,
|
|
237
265
|
keySecret: KeySecret,
|
|
238
|
-
nOnceMaterial: { in:
|
|
239
|
-
): Encrypted<T, { in:
|
|
266
|
+
nOnceMaterial: { in: RawCoID; tx: TransactionID }
|
|
267
|
+
): Encrypted<T, { in: RawCoID; tx: TransactionID }> {
|
|
240
268
|
return encrypt(value, keySecret, nOnceMaterial);
|
|
241
269
|
}
|
|
242
270
|
|
|
243
|
-
export function
|
|
244
|
-
|
|
245
|
-
|
|
271
|
+
export function encryptKeySecret(keys: {
|
|
272
|
+
toEncrypt: { id: KeyID; secret: KeySecret };
|
|
273
|
+
encrypting: { id: KeyID; secret: KeySecret };
|
|
246
274
|
}): {
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
encrypted: Encrypted<KeySecret, {
|
|
275
|
+
encryptedID: KeyID;
|
|
276
|
+
encryptingID: KeyID;
|
|
277
|
+
encrypted: Encrypted<KeySecret, { encryptedID: KeyID; encryptingID: KeyID }>;
|
|
250
278
|
} {
|
|
251
279
|
const nOnceMaterial = {
|
|
252
|
-
|
|
253
|
-
|
|
280
|
+
encryptedID: keys.toEncrypt.id,
|
|
281
|
+
encryptingID: keys.encrypting.id,
|
|
254
282
|
};
|
|
255
283
|
|
|
256
284
|
return {
|
|
257
|
-
|
|
258
|
-
|
|
285
|
+
encryptedID: keys.toEncrypt.id,
|
|
286
|
+
encryptingID: keys.encrypting.id,
|
|
259
287
|
encrypted: encrypt(
|
|
260
|
-
keys.
|
|
261
|
-
keys.
|
|
288
|
+
keys.toEncrypt.secret,
|
|
289
|
+
keys.encrypting.secret,
|
|
262
290
|
nOnceMaterial
|
|
263
291
|
),
|
|
264
292
|
};
|
|
@@ -289,27 +317,27 @@ function decrypt<T extends JsonValue, N extends JsonValue>(
|
|
|
289
317
|
}
|
|
290
318
|
|
|
291
319
|
export function decryptForTransaction<T extends JsonValue>(
|
|
292
|
-
encrypted: Encrypted<T, { in:
|
|
320
|
+
encrypted: Encrypted<T, { in: RawCoID; tx: TransactionID }>,
|
|
293
321
|
keySecret: KeySecret,
|
|
294
|
-
nOnceMaterial: { in:
|
|
322
|
+
nOnceMaterial: { in: RawCoID; tx: TransactionID }
|
|
295
323
|
): T | undefined {
|
|
296
324
|
return decrypt(encrypted, keySecret, nOnceMaterial);
|
|
297
325
|
}
|
|
298
326
|
|
|
299
|
-
export function
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
encrypted: Encrypted<KeySecret, {
|
|
327
|
+
export function decryptKeySecret(
|
|
328
|
+
encryptedInfo: {
|
|
329
|
+
encryptedID: KeyID;
|
|
330
|
+
encryptingID: KeyID;
|
|
331
|
+
encrypted: Encrypted<KeySecret, { encryptedID: KeyID; encryptingID: KeyID }>;
|
|
304
332
|
},
|
|
305
333
|
sealingSecret: KeySecret
|
|
306
334
|
): KeySecret | undefined {
|
|
307
335
|
const nOnceMaterial = {
|
|
308
|
-
|
|
309
|
-
|
|
336
|
+
encryptedID: encryptedInfo.encryptedID,
|
|
337
|
+
encryptingID: encryptedInfo.encryptingID,
|
|
310
338
|
};
|
|
311
339
|
|
|
312
|
-
return decrypt(
|
|
340
|
+
return decrypt(encryptedInfo.encrypted, sealingSecret, nOnceMaterial);
|
|
313
341
|
}
|
|
314
342
|
|
|
315
343
|
export function uniquenessForHeader(): `z${string}` {
|
package/src/ids.ts
CHANGED
|
@@ -1,7 +1,13 @@
|
|
|
1
|
-
|
|
1
|
+
import { AccountIDOrAgentID } from './account.js';
|
|
2
|
+
|
|
3
|
+
export type RawCoID = `co_z${string}`;
|
|
2
4
|
|
|
3
5
|
export type TransactionID = { sessionID: SessionID; txIndex: number };
|
|
4
6
|
|
|
5
|
-
export type AgentID = `
|
|
7
|
+
export type AgentID = `sealer_z${string}/signer_z${string}`;
|
|
8
|
+
|
|
9
|
+
export function isAgentID(id: string): id is AgentID {
|
|
10
|
+
return typeof id === "string" && id.startsWith("sealer_") && id.includes("/signer_");
|
|
11
|
+
}
|
|
6
12
|
|
|
7
|
-
export type SessionID = `${
|
|
13
|
+
export type SessionID = `${AccountIDOrAgentID}_session_z${string}`;
|
package/src/index.ts
CHANGED
|
@@ -1,29 +1,19 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
getAgent,
|
|
6
|
-
getAgentID,
|
|
7
|
-
newRandomAgentCredential,
|
|
8
|
-
newRandomSessionID,
|
|
9
|
-
} from './coValue.js';
|
|
10
|
-
import { LocalNode } from './node.js';
|
|
11
|
-
import { CoMap } from './contentTypes/coMap.js';
|
|
1
|
+
import { CoValue, newRandomSessionID } from "./coValue.js";
|
|
2
|
+
import { LocalNode } from "./node.js";
|
|
3
|
+
import { CoMap } from "./contentTypes/coMap.js";
|
|
4
|
+
import { agentSecretFromBytes, agentSecretToBytes } from "./crypto.js";
|
|
12
5
|
|
|
13
|
-
import type {
|
|
14
|
-
import type {
|
|
15
|
-
import type {
|
|
16
|
-
import type {
|
|
17
|
-
import type {
|
|
6
|
+
import type { SessionID } from "./ids.js";
|
|
7
|
+
import type { CoID, ContentType } from "./contentType.js";
|
|
8
|
+
import type { JsonValue } from "./jsonValue.js";
|
|
9
|
+
import type { SyncMessage } from "./sync.js";
|
|
10
|
+
import type { AgentSecret } from "./crypto.js";
|
|
18
11
|
|
|
19
12
|
type Value = JsonValue | ContentType;
|
|
20
13
|
|
|
21
14
|
const internals = {
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
getAgent,
|
|
25
|
-
getAgentID,
|
|
26
|
-
newRandomAgentCredential,
|
|
15
|
+
agentSecretFromBytes,
|
|
16
|
+
agentSecretToBytes,
|
|
27
17
|
newRandomSessionID,
|
|
28
18
|
};
|
|
29
19
|
|
|
@@ -33,9 +23,8 @@ export type {
|
|
|
33
23
|
Value,
|
|
34
24
|
JsonValue,
|
|
35
25
|
ContentType,
|
|
36
|
-
|
|
37
|
-
|
|
26
|
+
CoID,
|
|
27
|
+
AgentSecret,
|
|
38
28
|
SessionID,
|
|
39
|
-
|
|
40
|
-
SyncMessage
|
|
29
|
+
SyncMessage,
|
|
41
30
|
};
|
package/src/jsonValue.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { CoID, ContentType } from './contentType.js';
|
|
2
2
|
|
|
3
3
|
export type JsonAtom = string | number | boolean | null;
|
|
4
|
-
export type JsonValue = JsonAtom | JsonArray | JsonObject |
|
|
4
|
+
export type JsonValue = JsonAtom | JsonArray | JsonObject | CoID<ContentType>;
|
|
5
5
|
export type JsonArray = JsonValue[];
|
|
6
6
|
export type JsonObject = { [key: string]: JsonValue; };
|