shogun-core 5.2.2 → 6.0.0

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 (43) hide show
  1. package/README.md +123 -20
  2. package/dist/browser/shogun-core.js +1134 -493
  3. package/dist/browser/shogun-core.js.map +1 -1
  4. package/dist/config/simplified-config.js +108 -40
  5. package/dist/crypto/mls.js +34 -15
  6. package/dist/crypto/sframe.js +13 -11
  7. package/dist/examples/auth-test.js +263 -59
  8. package/dist/examples/crypto-identity-example.js +55 -21
  9. package/dist/examples/mls-3-member-test.js +97 -0
  10. package/dist/examples/mls-multi-member.js +153 -0
  11. package/dist/examples/mls-sframe-test.js +14 -11
  12. package/dist/examples/mls-simple-test.js +58 -0
  13. package/dist/examples/shogun-core-example.js +90 -0
  14. package/dist/examples/zkproof-credentials-example.js +9 -5
  15. package/dist/examples/zkproof-example.js +14 -10
  16. package/dist/gundb/api.js +17 -16
  17. package/dist/gundb/db.js +769 -328
  18. package/dist/index.js +4 -4
  19. package/dist/managers/CoreInitializer.js +21 -15
  20. package/dist/managers/CryptoIdentityManager.js +79 -32
  21. package/dist/plugins/zkproof/zkCredentials.js +4 -1
  22. package/dist/types/config/simplified-config.d.ts +64 -3
  23. package/dist/types/crypto/sframe.d.ts +4 -0
  24. package/dist/types/examples/mls-3-member-test.d.ts +6 -0
  25. package/dist/types/examples/mls-multi-member.d.ts +6 -0
  26. package/dist/types/examples/mls-simple-test.d.ts +6 -0
  27. package/dist/types/examples/shogun-core-example.d.ts +8 -0
  28. package/dist/types/gundb/api.d.ts +6 -13
  29. package/dist/types/gundb/db.d.ts +84 -41
  30. package/dist/types/index.d.ts +4 -2
  31. package/dist/types/interfaces/shogun.d.ts +1 -2
  32. package/dist/types/managers/CryptoIdentityManager.d.ts +2 -1
  33. package/package.json +11 -8
  34. package/dist/examples/mls-advanced-example.js +0 -294
  35. package/dist/examples/quick-auth-test.js +0 -61
  36. package/dist/examples/simple-api-test.js +0 -114
  37. package/dist/examples/simple-crypto-identity-example.js +0 -84
  38. package/dist/examples/timeout-test.js +0 -227
  39. package/dist/types/examples/mls-advanced-example.d.ts +0 -53
  40. package/dist/types/examples/quick-auth-test.d.ts +0 -8
  41. package/dist/types/examples/simple-api-test.d.ts +0 -10
  42. package/dist/types/examples/simple-crypto-identity-example.d.ts +0 -6
  43. package/dist/types/examples/timeout-test.d.ts +0 -8
@@ -2,31 +2,94 @@
2
2
  /**
3
3
  * Simplified configuration options to reduce complexity
4
4
  * Provides sensible defaults and easy-to-use presets
5
+ *
6
+ * NOTE: This file is deprecated. ShogunCore now requires an existing Gun instance.
7
+ * Use the examples in the examples/ directory for proper usage.
5
8
  */
9
+ var __importDefault = (this && this.__importDefault) || function (mod) {
10
+ return (mod && mod.__esModule) ? mod : { "default": mod };
11
+ };
6
12
  Object.defineProperty(exports, "__esModule", { value: true });
7
- exports.QuickConfig = exports.ConfigHelpers = exports.ShogunConfigBuilder = exports.ShogunPresets = void 0;
13
+ exports.QuickConfig = exports.ConfigHelpers = exports.ShogunConfigBuilder = exports.ShogunPresets = exports.GunInstanceHelpers = void 0;
14
+ const gun_1 = __importDefault(require("gun/gun"));
15
+ require("gun/lib/then");
16
+ require("gun/lib/radix");
17
+ require("gun/lib/radisk");
18
+ require("gun/lib/store");
19
+ require("gun/lib/rindexed");
20
+ require("gun/lib/webrtc");
21
+ /**
22
+ * Helper functions to create Gun instances with common configurations
23
+ * These functions create Gun instances that can be passed to ShogunCore
24
+ */
25
+ exports.GunInstanceHelpers = {
26
+ /**
27
+ * Create a minimal Gun instance for simple apps
28
+ */
29
+ minimal: () => (0, gun_1.default)({
30
+ peers: ["https://shogunnode.scobrudot.dev/gun"],
31
+ localStorage: true,
32
+ }),
33
+ /**
34
+ * Create a development Gun instance with local storage
35
+ */
36
+ development: () => (0, gun_1.default)({
37
+ peers: ["https://shogunnode.scobrudot.dev/gun"],
38
+ localStorage: true,
39
+ radisk: false,
40
+ }),
41
+ /**
42
+ * Create a production Gun instance with multiple peers
43
+ */
44
+ production: (customPeers) => (0, gun_1.default)({
45
+ peers: customPeers || [
46
+ "https://shogunnode.scobrudot.dev/gun",
47
+ "https://peer.wallie.io/gun",
48
+ ],
49
+ localStorage: true,
50
+ radisk: true,
51
+ }),
52
+ /**
53
+ * Create an offline-first Gun instance
54
+ */
55
+ offline: () => (0, gun_1.default)({
56
+ peers: [],
57
+ localStorage: true,
58
+ radisk: true,
59
+ }),
60
+ /**
61
+ * Create a Gun instance for Web3-enabled apps
62
+ */
63
+ web3: () => (0, gun_1.default)({
64
+ peers: ["https://shogunnode.scobrudot.dev/gun"],
65
+ localStorage: true,
66
+ }),
67
+ /**
68
+ * Create a Gun instance for WebAuthn-enabled apps
69
+ */
70
+ webauthn: () => (0, gun_1.default)({
71
+ peers: ["https://shogunnode.scobrudot.dev/gun"],
72
+ localStorage: true,
73
+ }),
74
+ };
8
75
  /**
9
76
  * Preset configurations for common use cases
77
+ * @deprecated Use GunInstanceHelpers to create Gun instances and pass them to ShogunCore
10
78
  */
11
79
  exports.ShogunPresets = {
12
80
  /**
13
81
  * Minimal configuration for simple apps
82
+ * @deprecated Use GunInstanceHelpers.minimal() instead
14
83
  */
15
84
  minimal: () => ({
16
- gunOptions: {
17
- peers: ["https://relay.shogun-eco.xyz/gun"],
18
- localStorage: true,
19
- },
85
+ gunInstance: exports.GunInstanceHelpers.minimal(),
20
86
  }),
21
87
  /**
22
88
  * Development configuration with local storage
89
+ * @deprecated Use GunInstanceHelpers.development() instead
23
90
  */
24
91
  development: () => ({
25
- gunOptions: {
26
- peers: ["https://relay.shogun-eco.xyz/gun"],
27
- localStorage: true,
28
- radisk: false,
29
- },
92
+ gunInstance: exports.GunInstanceHelpers.development(),
30
93
  timeouts: {
31
94
  login: 5000,
32
95
  signup: 5000,
@@ -35,16 +98,10 @@ exports.ShogunPresets = {
35
98
  }),
36
99
  /**
37
100
  * Production configuration with multiple peers
101
+ * @deprecated Use GunInstanceHelpers.production() instead
38
102
  */
39
103
  production: (customPeers) => ({
40
- gunOptions: {
41
- peers: customPeers || [
42
- "https://relay.shogun-eco.xyz/gun",
43
- "https://peer.wallie.io/gun",
44
- ],
45
- localStorage: true,
46
- radisk: true,
47
- },
104
+ gunInstance: exports.GunInstanceHelpers.production(customPeers),
48
105
  timeouts: {
49
106
  login: 10000,
50
107
  signup: 10000,
@@ -53,62 +110,59 @@ exports.ShogunPresets = {
53
110
  }),
54
111
  /**
55
112
  * Offline-first configuration
113
+ * @deprecated Use GunInstanceHelpers.offline() instead
56
114
  */
57
115
  offline: () => ({
58
- gunOptions: {
59
- peers: [],
60
- localStorage: true,
61
- radisk: true,
62
- },
116
+ gunInstance: exports.GunInstanceHelpers.offline(),
63
117
  }),
64
118
  /**
65
119
  * Web3-enabled configuration
120
+ * @deprecated Use GunInstanceHelpers.web3() instead
66
121
  */
67
122
  web3: () => ({
68
- gunOptions: {
69
- peers: ["https://relay.shogun-eco.xyz/gun"],
70
- localStorage: true,
71
- },
123
+ gunInstance: exports.GunInstanceHelpers.web3(),
72
124
  web3: {
73
125
  enabled: true,
74
126
  },
75
127
  }),
76
128
  /**
77
129
  * WebAuthn-enabled configuration
130
+ * @deprecated Use GunInstanceHelpers.webauthn() instead
78
131
  */
79
132
  webauthn: () => ({
80
- gunOptions: {
81
- peers: ["https://relay.shogun-eco.xyz/gun"],
82
- localStorage: true,
83
- },
133
+ gunInstance: exports.GunInstanceHelpers.webauthn(),
84
134
  webauthn: {
85
135
  enabled: true,
86
136
  rpName: "My Shogun App",
87
- rpId: window.location.hostname,
137
+ rpId: typeof window !== "undefined" ? window.location.hostname : "localhost",
88
138
  },
89
139
  }),
90
140
  };
91
141
  /**
92
142
  * Configuration builder for custom setups
143
+ * @deprecated Use GunInstanceHelpers to create Gun instances and pass them to ShogunCore
93
144
  */
94
145
  class ShogunConfigBuilder {
95
146
  constructor() {
96
147
  this.config = {};
148
+ this.gunOptions = {};
97
149
  }
98
150
  /**
99
- * Set Gun options
151
+ * Set Gun options (deprecated - use GunInstanceHelpers instead)
152
+ * @deprecated Use GunInstanceHelpers to create Gun instances
100
153
  */
101
- gunOptions(options) {
102
- this.config.gunOptions = { ...this.config.gunOptions, ...options };
154
+ setGunOptions(options) {
155
+ this.gunOptions = { ...this.gunOptions, ...options };
103
156
  return this;
104
157
  }
105
158
  /**
106
- * Add peers
159
+ * Add peers (deprecated - use GunInstanceHelpers instead)
160
+ * @deprecated Use GunInstanceHelpers to create Gun instances
107
161
  */
108
162
  peers(peerList) {
109
- this.config.gunOptions = {
110
- ...this.config.gunOptions,
111
- peers: [...(this.config.gunOptions?.peers || []), ...peerList],
163
+ this.gunOptions = {
164
+ ...this.gunOptions,
165
+ peers: [...(this.gunOptions?.peers || []), ...peerList],
112
166
  };
113
167
  return this;
114
168
  }
@@ -146,18 +200,24 @@ class ShogunConfigBuilder {
146
200
  }
147
201
  /**
148
202
  * Build the final configuration
203
+ * @deprecated Use GunInstanceHelpers to create Gun instances and pass them to ShogunCore
149
204
  */
150
205
  build() {
151
- return this.config;
206
+ return {
207
+ ...this.config,
208
+ gunInstance: (0, gun_1.default)(this.gunOptions),
209
+ };
152
210
  }
153
211
  }
154
212
  exports.ShogunConfigBuilder = ShogunConfigBuilder;
155
213
  /**
156
214
  * Helper functions for common configuration patterns
215
+ * @deprecated Use GunInstanceHelpers to create Gun instances and pass them to ShogunCore
157
216
  */
158
217
  exports.ConfigHelpers = {
159
218
  /**
160
219
  * Create a configuration for a specific environment
220
+ * @deprecated Use GunInstanceHelpers instead
161
221
  */
162
222
  forEnvironment(env) {
163
223
  switch (env) {
@@ -173,12 +233,14 @@ exports.ConfigHelpers = {
173
233
  },
174
234
  /**
175
235
  * Create a configuration with custom peers
236
+ * @deprecated Use GunInstanceHelpers.production(peers) instead
176
237
  */
177
238
  withPeers(peers) {
178
239
  return exports.ShogunPresets.production(peers);
179
240
  },
180
241
  /**
181
242
  * Create a configuration for a specific use case
243
+ * @deprecated Use GunInstanceHelpers instead
182
244
  */
183
245
  forUseCase(useCase) {
184
246
  const baseConfig = exports.ShogunPresets.production();
@@ -211,26 +273,32 @@ exports.ConfigHelpers = {
211
273
  };
212
274
  /**
213
275
  * Quick configuration functions
276
+ * @deprecated Use GunInstanceHelpers to create Gun instances and pass them to ShogunCore
214
277
  */
215
278
  exports.QuickConfig = {
216
279
  /**
217
280
  * Minimal setup for quick testing
281
+ * @deprecated Use GunInstanceHelpers.minimal() instead
218
282
  */
219
283
  test: () => exports.ShogunPresets.minimal(),
220
284
  /**
221
285
  * Standard setup for most apps
286
+ * @deprecated Use GunInstanceHelpers.production() instead
222
287
  */
223
288
  standard: () => exports.ShogunPresets.production(),
224
289
  /**
225
290
  * Setup with WebAuthn for secure apps
291
+ * @deprecated Use GunInstanceHelpers.webauthn() instead
226
292
  */
227
293
  secure: () => exports.ShogunPresets.webauthn(),
228
294
  /**
229
295
  * Setup with Web3 for crypto apps
296
+ * @deprecated Use GunInstanceHelpers.web3() instead
230
297
  */
231
298
  crypto: () => exports.ShogunPresets.web3(),
232
299
  /**
233
300
  * Offline setup for local development
301
+ * @deprecated Use GunInstanceHelpers.offline() instead
234
302
  */
235
303
  local: () => exports.ShogunPresets.offline(),
236
304
  };
@@ -141,7 +141,9 @@ class MLSManager {
141
141
  console.group("🔍 [MLS Debug] Commit Structure");
142
142
  console.log("commitResult keys:", Object.keys(commitResult));
143
143
  console.log("commit:", commitResult.commit);
144
- console.log("commit.privateMessage:", commitResult.commit?.privateMessage);
144
+ if (commitResult.commit?.wireformat === "mls_private_message") {
145
+ console.log("commit.privateMessage:", commitResult.commit.privateMessage);
146
+ }
145
147
  console.groupEnd();
146
148
  // RFC 9420 Section 11.2: Commit Distribution
147
149
  // ⚠️ IMPORTANT: The returned commit MUST be sent to all existing group members
@@ -205,8 +207,8 @@ class MLSManager {
205
207
  else {
206
208
  console.log(` Node ${i}:`, {
207
209
  type: typeof node,
208
- isObject: typeof node === "object",
209
- hasNodeType: node && typeof node === "object" && "nodeType" in node,
210
+ isObject: typeof node === "object" && node !== null,
211
+ hasNodeType: typeof node === "object" && node !== null && "nodeType" in node,
210
212
  nodeType: node?.nodeType,
211
213
  keys: node && typeof node === "object"
212
214
  ? Object.keys(node).slice(0, 5)
@@ -283,10 +285,11 @@ class MLSManager {
283
285
  }
284
286
  // Decode the message
285
287
  const decoded = (0, ts_mls_1.decodeMlsMessage)(envelope.ciphertext, 0);
286
- if (!decoded) {
288
+ if (!decoded || decoded.length === 0) {
289
+ // Changed from 0n to 0 to fix type error
287
290
  throw new Error("Failed to decode message");
288
291
  }
289
- const [decodedMessage] = decoded;
292
+ const decodedMessage = decoded[0];
290
293
  if (decodedMessage.wireformat !== "mls_private_message") {
291
294
  throw new Error("Expected private message");
292
295
  }
@@ -392,7 +395,7 @@ class MLSManager {
392
395
  }
393
396
  catch (error) {
394
397
  console.error("❌ [MLS] Failed to process commit:", error);
395
- console.error("❌ [MLS Debug] Error details:", error instanceof Error ? error.stack : "No stack trace");
398
+ console.error("❌ [MLS Debug] Error details:", error instanceof Error ? error.stack : String(error));
396
399
  console.error("❌ [MLS Debug] Error message:", error instanceof Error ? error.message : String(error));
397
400
  throw new Error(`Commit processing failed: ${error instanceof Error ? error.message : String(error)}`);
398
401
  }
@@ -412,7 +415,7 @@ class MLSManager {
412
415
  const removeProposals = memberIndices.map((index) => ({
413
416
  proposalType: "remove",
414
417
  remove: {
415
- removed: index, // ts-mls expects number, not BigInt
418
+ removed: index, // Changed from BigInt(index) to number
416
419
  },
417
420
  }));
418
421
  // Create commit with remove proposals
@@ -420,11 +423,21 @@ class MLSManager {
420
423
  // Update group state
421
424
  this.groups.set(groupId, commitResult.newState);
422
425
  // Encode the commit
423
- const encodedCommit = (0, ts_mls_1.encodeMlsMessage)({
424
- publicMessage: commitResult.publicMessage,
425
- wireformat: "mls_public_message",
426
- version: "mls10",
427
- });
426
+ let encodedCommit;
427
+ if (commitResult.commit &&
428
+ commitResult.commit.wireformat === "mls_public_message") {
429
+ encodedCommit = (0, ts_mls_1.encodeMlsMessage)({
430
+ publicMessage: commitResult.commit
431
+ .publicMessage,
432
+ wireformat: "mls_public_message",
433
+ version: "mls10",
434
+ });
435
+ }
436
+ else {
437
+ // Fallback or error handling if not a public message
438
+ // For now, we'll assume it should be public for remove operation.
439
+ throw new Error("Commit result does not contain a public message for encoding.");
440
+ }
428
441
  console.log("✅ [MLS] Members removed");
429
442
  return encodedCommit;
430
443
  }
@@ -517,9 +530,15 @@ class MLSManager {
517
530
  const node = state.ratchetTree[i];
518
531
  if (node &&
519
532
  node.nodeType === "leaf" &&
520
- node.leaf?.credential) {
521
- const identity = new TextDecoder().decode(node.leaf.credential.identity);
522
- members.push(identity);
533
+ node.leaf.credential) {
534
+ const credential = node.leaf.credential;
535
+ if (credential.credentialType === "basic" && credential.identity) {
536
+ const identity = new TextDecoder().decode(credential.identity);
537
+ members.push(identity);
538
+ }
539
+ else {
540
+ console.warn("Skipping credential without basic identity:", credential);
541
+ }
523
542
  }
524
543
  }
525
544
  }
@@ -110,6 +110,13 @@ class SFrameManager {
110
110
  throw new Error(`SFrame key derivation failed: ${error instanceof Error ? error.message : String(error)}`);
111
111
  }
112
112
  }
113
+ /**
114
+ * Set a shared SFrame key (e.g., from another member)
115
+ */
116
+ async setSharedKey(sframeKey) {
117
+ this.keys.set(sframeKey.keyId, sframeKey);
118
+ console.log(`✅ [SFrame] Shared key ${sframeKey.keyId} set.`);
119
+ }
113
120
  /**
114
121
  * Set the active encryption key
115
122
  */
@@ -155,11 +162,9 @@ class SFrameManager {
155
162
  tagLength: 128, // 128-bit authentication tag
156
163
  }, sframeKey.key, frameData);
157
164
  // RFC 9605: SFrame format = header + ciphertext (IV is derived, not transmitted)
158
- // Note: We include IV for now for simplicity, but RFC specifies deriving it from counter
159
- const encrypted = new Uint8Array(header.length + iv.length + ciphertext.byteLength);
165
+ const encrypted = new Uint8Array(header.length + ciphertext.byteLength);
160
166
  encrypted.set(header, 0);
161
- encrypted.set(iv, header.length);
162
- encrypted.set(new Uint8Array(ciphertext), header.length + iv.length);
167
+ encrypted.set(new Uint8Array(ciphertext), header.length);
163
168
  // Increment frame counter
164
169
  this.frameCounter++;
165
170
  return encrypted;
@@ -184,20 +189,17 @@ class SFrameManager {
184
189
  if (!sframeKey) {
185
190
  throw new Error(`SFrame key ${keyId} not found`);
186
191
  }
187
- // Extract IV (12 bytes after header)
188
- const iv = encryptedFrame.slice(5, 17);
189
- // RFC 9605: Verify IV derivation (optional check for debugging)
190
- // Reconstruct expected IV from frame count and salt
192
+ // RFC 9605: IV is derived from frame count and salt (not transmitted)
191
193
  const counterBytes = new Uint8Array(12);
192
194
  const counterView = new DataView(counterBytes.buffer);
193
195
  counterView.setUint32(4, Math.floor(frameCount / 0x100000000), false);
194
196
  counterView.setUint32(8, frameCount & 0xffffffff, false);
195
- const expectedIV = new Uint8Array(12);
197
+ const iv = new Uint8Array(12);
196
198
  for (let i = 0; i < 12; i++) {
197
- expectedIV[i] = sframeKey.salt[i] ^ counterBytes[i];
199
+ iv[i] = sframeKey.salt[i] ^ counterBytes[i];
198
200
  }
199
201
  // Extract ciphertext (rest of the data)
200
- const ciphertext = encryptedFrame.slice(17);
202
+ const ciphertext = encryptedFrame.slice(header.length);
201
203
  // Decrypt the frame with header authentication (RFC 9605 Section 4.3)
202
204
  const plaintext = await crypto.subtle.decrypt({
203
205
  name: "AES-GCM",