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.
Files changed (75) hide show
  1. package/README.md +2 -2
  2. package/dist/account.d.ts +57 -0
  3. package/dist/account.js +76 -0
  4. package/dist/account.js.map +1 -0
  5. package/dist/account.test.d.ts +1 -0
  6. package/dist/account.test.js +40 -0
  7. package/dist/account.test.js.map +1 -0
  8. package/dist/coValue.d.ts +16 -35
  9. package/dist/coValue.js +49 -112
  10. package/dist/coValue.js.map +1 -1
  11. package/dist/coValue.test.js +16 -16
  12. package/dist/coValue.test.js.map +1 -1
  13. package/dist/contentType.d.ts +9 -9
  14. package/dist/contentType.js.map +1 -1
  15. package/dist/contentType.test.js +13 -17
  16. package/dist/contentType.test.js.map +1 -1
  17. package/dist/contentTypes/coList.d.ts +3 -3
  18. package/dist/contentTypes/coList.js.map +1 -1
  19. package/dist/contentTypes/coMap.d.ts +31 -21
  20. package/dist/contentTypes/coMap.js +28 -0
  21. package/dist/contentTypes/coMap.js.map +1 -1
  22. package/dist/contentTypes/coStream.d.ts +3 -3
  23. package/dist/contentTypes/coStream.js.map +1 -1
  24. package/dist/contentTypes/static.d.ts +4 -4
  25. package/dist/contentTypes/static.js.map +1 -1
  26. package/dist/crypto.d.ts +45 -39
  27. package/dist/crypto.js +68 -49
  28. package/dist/crypto.js.map +1 -1
  29. package/dist/crypto.test.js +45 -49
  30. package/dist/crypto.test.js.map +1 -1
  31. package/dist/ids.d.ts +5 -3
  32. package/dist/ids.js +3 -1
  33. package/dist/ids.js.map +1 -1
  34. package/dist/index.d.ts +12 -14
  35. package/dist/index.js +6 -8
  36. package/dist/index.js.map +1 -1
  37. package/dist/jsonValue.d.ts +2 -2
  38. package/dist/node.d.ts +25 -15
  39. package/dist/node.js +88 -33
  40. package/dist/node.js.map +1 -1
  41. package/dist/permissions.d.ts +27 -33
  42. package/dist/permissions.js +55 -47
  43. package/dist/permissions.js.map +1 -1
  44. package/dist/permissions.test.js +231 -314
  45. package/dist/permissions.test.js.map +1 -1
  46. package/dist/sync.d.ts +26 -28
  47. package/dist/sync.js +81 -67
  48. package/dist/sync.js.map +1 -1
  49. package/dist/sync.test.js +194 -293
  50. package/dist/sync.test.js.map +1 -1
  51. package/dist/testUtils.d.ts +37 -0
  52. package/dist/testUtils.js +157 -0
  53. package/dist/testUtils.js.map +1 -0
  54. package/package.json +1 -1
  55. package/src/account.test.ts +67 -0
  56. package/src/account.ts +152 -0
  57. package/src/coValue.test.ts +17 -31
  58. package/src/coValue.ts +93 -179
  59. package/src/contentType.test.ts +18 -45
  60. package/src/contentType.ts +15 -13
  61. package/src/contentTypes/coList.ts +4 -4
  62. package/src/contentTypes/coMap.ts +55 -29
  63. package/src/contentTypes/coStream.ts +4 -4
  64. package/src/contentTypes/static.ts +5 -5
  65. package/src/crypto.test.ts +53 -59
  66. package/src/crypto.ts +123 -95
  67. package/src/ids.ts +9 -3
  68. package/src/index.ts +14 -25
  69. package/src/jsonValue.ts +2 -2
  70. package/src/node.ts +189 -61
  71. package/src/permissions.test.ts +370 -404
  72. package/src/permissions.ts +126 -109
  73. package/src/sync.test.ts +284 -426
  74. package/src/sync.ts +115 -105
  75. 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 { RawCoValueID, TransactionID } from './ids.js';
8
+ import { AgentID, RawCoID, TransactionID } from './ids.js';
9
9
 
10
- export type SignatorySecret = `signatorySecret_z${string}`;
11
- export type SignatoryID = `signatory_z${string}`;
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 RecipientSecret = `recipientSecret_z${string}`;
15
- export type RecipientID = `recipient_z${string}`;
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 newRandomSignatory(): SignatorySecret {
22
- return `signatorySecret_z${base58.encode(
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 signatorySecretToBytes(secret: SignatorySecret): Uint8Array {
28
- return base58.decode(secret.substring("signatorySecret_z".length));
29
+ export function signerSecretToBytes(secret: SignerSecret): Uint8Array {
30
+ return base58.decode(secret.substring("signerSecret_z".length));
29
31
  }
30
32
 
31
- export function signatorySecretFromBytes(bytes: Uint8Array): SignatorySecret {
32
- return `signatorySecret_z${base58.encode(bytes)}`;
33
+ export function signerSecretFromBytes(bytes: Uint8Array): SignerSecret {
34
+ return `signerSecret_z${base58.encode(bytes)}`;
33
35
  }
34
36
 
35
- export function getSignatoryID(secret: SignatorySecret): SignatoryID {
36
- return `signatory_z${base58.encode(
37
+ export function getSignerID(secret: SignerSecret): SignerID {
38
+ return `signer_z${base58.encode(
37
39
  ed25519.getPublicKey(
38
- base58.decode(secret.substring("signatorySecret_z".length))
40
+ base58.decode(secret.substring("signerSecret_z".length))
39
41
  )
40
42
  )}`;
41
43
  }
42
44
 
43
- export function sign(secret: SignatorySecret, message: JsonValue): Signature {
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("signatorySecret_z".length))
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: SignatoryID
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("signatory_z".length))
61
+ base58.decode(id.substring("signer_z".length))
60
62
  );
61
63
  }
62
64
 
63
- export function newRandomRecipient(): RecipientSecret {
64
- return `recipientSecret_z${base58.encode(x25519.utils.randomPrivateKey())}`;
65
+ export function newRandomSealer(): SealerSecret {
66
+ return `sealerSecret_z${base58.encode(x25519.utils.randomPrivateKey())}`;
65
67
  }
66
68
 
67
- export function recipientSecretToBytes(secret: RecipientSecret): Uint8Array {
68
- return base58.decode(secret.substring("recipientSecret_z".length));
69
+ export function sealerSecretToBytes(secret: SealerSecret): Uint8Array {
70
+ return base58.decode(secret.substring("sealerSecret_z".length));
69
71
  }
70
72
 
71
- export function recipientSecretFromBytes(bytes: Uint8Array): RecipientSecret {
72
- return `recipientSecret_z${base58.encode(bytes)}`;
73
+ export function sealerSecretFromBytes(bytes: Uint8Array): SealerSecret {
74
+ return `sealerSecret_z${base58.encode(bytes)}`;
73
75
  }
74
76
 
75
- export function getRecipientID(secret: RecipientSecret): RecipientID {
76
- return `recipient_z${base58.encode(
77
+ export function getSealerID(secret: SealerSecret): SealerID {
78
+ return `sealer_z${base58.encode(
77
79
  x25519.getPublicKey(
78
- base58.decode(secret.substring("recipientSecret_z".length))
80
+ base58.decode(secret.substring("sealerSecret_z".length))
79
81
  )
80
82
  )}`;
81
83
  }
82
84
 
83
- export type SealedSet<T> = {
84
- [recipient: RecipientID]: Sealed<T>;
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: RecipientSecret,
90
- to: Set<RecipientID>,
91
- nOnceMaterial: { in: RawCoValueID; tx: TransactionID }
92
- ): SealedSet<T> {
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 recipientsSorted = Array.from(to).sort();
98
- const recipientPubs = recipientsSorted.map((recipient) => {
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("recipientSecret_z".length)
143
+ from.substring("sealerSecret_z".length)
103
144
  );
104
145
 
105
146
  const plaintext = textEncoder.encode(stableStringify(message));
106
147
 
107
- const sealedSet: SealedSet<T> = {};
108
-
109
- for (let i = 0; i < recipientsSorted.length; i++) {
110
- const recipient = recipientsSorted[i]!;
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
- sealedSet[recipient] = `sealed_U${base64url.encode(
121
- sealedBytes
122
- )}` as Sealed<T>;
123
- }
153
+ const sealedBytes = xsalsa20_poly1305(sharedSecret, nOnce).encrypt(
154
+ plaintext
155
+ );
124
156
 
125
- return sealedSet;
157
+ return `sealed_U${base64url.encode(
158
+ sealedBytes
159
+ )}` as Sealed<T>
126
160
  }
127
161
 
128
- export function openAs<T extends JsonValue>(
129
- sealedSet: SealedSet<T>,
130
- recipient: RecipientSecret,
131
- from: RecipientID,
132
- nOnceMaterial: { in: RawCoValueID; tx: TransactionID }
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 recipientPriv = base58.decode(
139
- recipient.substring("recipientSecret_z".length)
172
+ const sealerPriv = base58.decode(
173
+ sealer.substring("sealerSecret_z".length)
140
174
  );
141
175
 
142
- const senderPub = base58.decode(from.substring("recipient_z".length));
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(recipientPriv, senderPub);
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: RawCoValueID; tx: TransactionID }
239
- ): Encrypted<T, { in: RawCoValueID; tx: TransactionID }> {
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 sealKeySecret(keys: {
244
- toSeal: { id: KeyID; secret: KeySecret };
245
- sealing: { id: KeyID; secret: KeySecret };
271
+ export function encryptKeySecret(keys: {
272
+ toEncrypt: { id: KeyID; secret: KeySecret };
273
+ encrypting: { id: KeyID; secret: KeySecret };
246
274
  }): {
247
- sealed: KeyID;
248
- sealing: KeyID;
249
- encrypted: Encrypted<KeySecret, { sealed: KeyID; sealing: KeyID }>;
275
+ encryptedID: KeyID;
276
+ encryptingID: KeyID;
277
+ encrypted: Encrypted<KeySecret, { encryptedID: KeyID; encryptingID: KeyID }>;
250
278
  } {
251
279
  const nOnceMaterial = {
252
- sealed: keys.toSeal.id,
253
- sealing: keys.sealing.id,
280
+ encryptedID: keys.toEncrypt.id,
281
+ encryptingID: keys.encrypting.id,
254
282
  };
255
283
 
256
284
  return {
257
- sealed: keys.toSeal.id,
258
- sealing: keys.sealing.id,
285
+ encryptedID: keys.toEncrypt.id,
286
+ encryptingID: keys.encrypting.id,
259
287
  encrypted: encrypt(
260
- keys.toSeal.secret,
261
- keys.sealing.secret,
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: RawCoValueID; tx: TransactionID }>,
320
+ encrypted: Encrypted<T, { in: RawCoID; tx: TransactionID }>,
293
321
  keySecret: KeySecret,
294
- nOnceMaterial: { in: RawCoValueID; tx: TransactionID }
322
+ nOnceMaterial: { in: RawCoID; tx: TransactionID }
295
323
  ): T | undefined {
296
324
  return decrypt(encrypted, keySecret, nOnceMaterial);
297
325
  }
298
326
 
299
- export function unsealKeySecret(
300
- sealedInfo: {
301
- sealed: KeyID;
302
- sealing: KeyID;
303
- encrypted: Encrypted<KeySecret, { sealed: KeyID; sealing: KeyID }>;
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
- sealed: sealedInfo.sealed,
309
- sealing: sealedInfo.sealing,
336
+ encryptedID: encryptedInfo.encryptedID,
337
+ encryptingID: encryptedInfo.encryptingID,
310
338
  };
311
339
 
312
- return decrypt(sealedInfo.encrypted, sealingSecret, nOnceMaterial);
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
- export type RawCoValueID = `co_z${string}` | `co_${string}_z${string}`;
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 = `co_agent${string}_z${string}`;
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 = `${AgentID}_session_z${string}`;
13
+ export type SessionID = `${AccountIDOrAgentID}_session_z${string}`;
package/src/index.ts CHANGED
@@ -1,29 +1,19 @@
1
- import {
2
- CoValue,
3
- agentCredentialFromBytes,
4
- agentCredentialToBytes,
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 { AgentCredential } from './coValue.js';
14
- import type { AgentID, SessionID } from './ids.js';
15
- import type { CoValueID, ContentType } from './contentType.js';
16
- import type { JsonValue } from './jsonValue.js';
17
- import type { SyncMessage } from './sync.js';
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
- agentCredentialToBytes,
23
- agentCredentialFromBytes,
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
- CoValueID,
37
- AgentCredential,
26
+ CoID,
27
+ AgentSecret,
38
28
  SessionID,
39
- AgentID,
40
- SyncMessage
29
+ SyncMessage,
41
30
  };
package/src/jsonValue.ts CHANGED
@@ -1,6 +1,6 @@
1
- import { CoValueID, ContentType } from './contentType.js';
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 | CoValueID<ContentType>;
4
+ export type JsonValue = JsonAtom | JsonArray | JsonObject | CoID<ContentType>;
5
5
  export type JsonArray = JsonValue[];
6
6
  export type JsonObject = { [key: string]: JsonValue; };