shogun-core 3.2.3 → 3.3.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 (32) hide show
  1. package/README.md +12 -0
  2. package/dist/browser/shogun-core.js +108102 -43579
  3. package/dist/browser/shogun-core.js.map +1 -1
  4. package/dist/ship/examples/messenger-cli.js +171 -55
  5. package/dist/ship/examples/wallet-cli.js +767 -0
  6. package/dist/ship/implementation/SHIP_00.js +478 -0
  7. package/dist/ship/implementation/SHIP_01.js +275 -492
  8. package/dist/ship/implementation/SHIP_02.js +1366 -0
  9. package/dist/ship/implementation/SHIP_03.js +855 -0
  10. package/dist/ship/interfaces/ISHIP_00.js +135 -0
  11. package/dist/ship/interfaces/ISHIP_01.js +81 -24
  12. package/dist/ship/interfaces/ISHIP_02.js +57 -0
  13. package/dist/ship/interfaces/ISHIP_03.js +61 -0
  14. package/dist/src/gundb/db.js +55 -11
  15. package/dist/src/index.js +10 -2
  16. package/dist/src/managers/CoreInitializer.js +41 -13
  17. package/dist/src/storage/storage.js +22 -9
  18. package/dist/types/ship/examples/messenger-cli.d.ts +7 -1
  19. package/dist/types/ship/examples/wallet-cli.d.ts +131 -0
  20. package/dist/types/ship/implementation/SHIP_00.d.ts +113 -0
  21. package/dist/types/ship/implementation/SHIP_01.d.ts +44 -77
  22. package/dist/types/ship/implementation/SHIP_02.d.ts +297 -0
  23. package/dist/types/ship/implementation/SHIP_03.d.ts +127 -0
  24. package/dist/types/ship/interfaces/ISHIP_00.d.ts +410 -0
  25. package/dist/types/ship/interfaces/ISHIP_01.d.ts +157 -119
  26. package/dist/types/ship/interfaces/ISHIP_02.d.ts +470 -0
  27. package/dist/types/ship/interfaces/ISHIP_03.d.ts +295 -0
  28. package/dist/types/src/gundb/db.d.ts +10 -3
  29. package/dist/types/src/index.d.ts +7 -0
  30. package/dist/types/src/interfaces/shogun.d.ts +2 -0
  31. package/dist/types/src/storage/storage.d.ts +2 -1
  32. package/package.json +22 -9
@@ -0,0 +1,478 @@
1
+ "use strict";
2
+ /**
3
+ * SHIP-00: Decentralized Identity & Authentication Implementation
4
+ *
5
+ * Foundation layer for the Shogun ecosystem.
6
+ * Provides identity and authentication services for all other SHIPs.
7
+ *
8
+ * Based on:
9
+ * - Shogun Core API (see ../API.md)
10
+ * - GunDB for P2P identity storage
11
+ * - SEA for cryptographic operations
12
+ * - shogun-derive for address derivation
13
+ *
14
+ * Features:
15
+ * ✅ Username/password authentication
16
+ * ✅ SEA key pair management
17
+ * ✅ Public key publication and discovery
18
+ * ✅ User registry and lookup
19
+ * ✅ Blockchain address derivation
20
+ * ✅ Multi-device support (export/import)
21
+ */
22
+ var __importDefault = (this && this.__importDefault) || function (mod) {
23
+ return (mod && mod.__esModule) ? mod : { "default": mod };
24
+ };
25
+ Object.defineProperty(exports, "__esModule", { value: true });
26
+ exports.SHIP_00 = void 0;
27
+ const core_1 = require("../../src/core");
28
+ const ethers_1 = require("ethers");
29
+ const derive_1 = __importDefault(require("../../src/gundb/derive"));
30
+ // ============================================================================
31
+ // IMPLEMENTATION
32
+ // ============================================================================
33
+ /**
34
+ * SHIP-00 Reference Implementation
35
+ *
36
+ * Uses Shogun Core as the underlying implementation.
37
+ * This class wraps Shogun Core APIs to provide the ISHIP_00 standard interface.
38
+ */
39
+ class SHIP_00 {
40
+ constructor(shogunConfig) {
41
+ // Initialize Shogun Core with provided config
42
+ this.shogun = new core_1.ShogunCore(shogunConfig);
43
+ }
44
+ // ========================================================================
45
+ // AUTHENTICATION
46
+ // ========================================================================
47
+ /**
48
+ * Register new user
49
+ * Uses Shogun Core signUp method (see API.md)
50
+ */
51
+ async signup(username, password) {
52
+ try {
53
+ // Use Shogun Core signUp (API.md line 315-327)
54
+ const signupResult = await this.shogun.signUp(username, password);
55
+ if (!signupResult.success) {
56
+ return {
57
+ success: false,
58
+ error: signupResult.error || "Signup failed",
59
+ };
60
+ }
61
+ console.log("✅ User registered");
62
+ console.log(` Username: ${username}`);
63
+ console.log(` GunDB Public Key: ${signupResult.pub}`);
64
+ // Derive Ethereum address using shogun-derive
65
+ const derivedAddress = signupResult.pub
66
+ ? await this.deriveEthereumAddress(signupResult.pub)
67
+ : undefined;
68
+ if (derivedAddress) {
69
+ console.log(` Derived Address: ${derivedAddress}`);
70
+ }
71
+ return {
72
+ success: true,
73
+ userPub: signupResult.pub,
74
+ username: username,
75
+ derivedAddress,
76
+ };
77
+ }
78
+ catch (error) {
79
+ return {
80
+ success: false,
81
+ error: error.message,
82
+ };
83
+ }
84
+ }
85
+ /**
86
+ * Login with username and password
87
+ * Uses Shogun Core login method (see API.md)
88
+ */
89
+ async login(username, password) {
90
+ try {
91
+ // Use Shogun Core login (API.md line 309-317)
92
+ const loginResult = await this.shogun.login(username, password);
93
+ if (!loginResult.success) {
94
+ return {
95
+ success: false,
96
+ error: loginResult.error || "Login failed",
97
+ };
98
+ }
99
+ console.log("✅ Login successful");
100
+ console.log(` Username: ${username}`);
101
+ console.log(` GunDB Public Key: ${loginResult.userPub}`);
102
+ // Derive Ethereum address
103
+ const derivedAddress = loginResult.userPub
104
+ ? await this.deriveEthereumAddress(loginResult.userPub)
105
+ : undefined;
106
+ if (derivedAddress) {
107
+ console.log(` Derived Address: ${derivedAddress}`);
108
+ }
109
+ return {
110
+ success: true,
111
+ userPub: loginResult.userPub,
112
+ username: username,
113
+ derivedAddress,
114
+ };
115
+ }
116
+ catch (error) {
117
+ return {
118
+ success: false,
119
+ error: error.message,
120
+ };
121
+ }
122
+ }
123
+ /**
124
+ * Login with SEA Key Pair
125
+ * Uses Shogun Core loginWithPair method (see API.md)
126
+ */
127
+ async loginWithPair(seaPair) {
128
+ try {
129
+ console.log("🔐 Login with key pair...");
130
+ // Use Shogun Core loginWithPair (API.md line 324)
131
+ const authResult = await this.shogun.loginWithPair(seaPair);
132
+ if (!authResult.success) {
133
+ console.log("❌ Login failed:", authResult.error);
134
+ return {
135
+ success: false,
136
+ error: authResult.error || "Login with pair failed",
137
+ };
138
+ }
139
+ // Derive Ethereum address
140
+ const derivedAddress = await this.deriveEthereumAddress(seaPair.pub);
141
+ console.log("✅ Login successful");
142
+ console.log(` GunDB Public Key: ${seaPair.pub}`);
143
+ console.log(` Derived Address: ${derivedAddress}`);
144
+ return {
145
+ success: true,
146
+ userPub: authResult.userPub,
147
+ username: authResult.username,
148
+ derivedAddress,
149
+ };
150
+ }
151
+ catch (error) {
152
+ console.error("❌ Error login with pair:", error);
153
+ return {
154
+ success: false,
155
+ error: error instanceof Error ? error.message : "Unknown error",
156
+ };
157
+ }
158
+ }
159
+ /**
160
+ * Logout
161
+ * Uses Shogun Core logout method (see API.md line 325)
162
+ */
163
+ logout() {
164
+ this.shogun.logout();
165
+ console.log("👋 Logout successful");
166
+ }
167
+ /**
168
+ * Check if user is logged in
169
+ * Uses Shogun Core isLoggedIn method (see API.md line 326)
170
+ */
171
+ isLoggedIn() {
172
+ return this.shogun.isLoggedIn();
173
+ }
174
+ // ========================================================================
175
+ // CORE ACCESS
176
+ // ========================================================================
177
+ /**
178
+ * Get underlying ShogunCore instance
179
+ * Provides access to Gun, SEA, and crypto utilities
180
+ */
181
+ getShogun() {
182
+ return this.shogun;
183
+ }
184
+ // ========================================================================
185
+ // KEY MANAGEMENT
186
+ // ========================================================================
187
+ /**
188
+ * Publish public key on GunDB
189
+ * Makes user's public key discoverable by others
190
+ */
191
+ async publishPublicKey() {
192
+ try {
193
+ if (!this.isLoggedIn()) {
194
+ return { success: false, error: "Not logged in" };
195
+ }
196
+ // Get current user from DataBase (API.md line 374)
197
+ const currentUser = this.shogun.db.user;
198
+ if (!currentUser || !currentUser.is) {
199
+ return { success: false, error: "No user session" };
200
+ }
201
+ const userPub = currentUser.is.pub;
202
+ // Save public key to GunDB for discovery
203
+ // Using Gun operations (API.md line 399-406)
204
+ await this.shogun.db.gun
205
+ .get(userPub)
206
+ .put({
207
+ pub: currentUser.is.pub,
208
+ epub: currentUser.is.epub,
209
+ algorithm: "ECDSA",
210
+ timestamp: Date.now().toString(),
211
+ })
212
+ .then();
213
+ console.log(`📝 Public key published on GunDB`);
214
+ return { success: true };
215
+ }
216
+ catch (error) {
217
+ console.error("❌ Error publishing key:", error);
218
+ return { success: false, error: error.message };
219
+ }
220
+ }
221
+ /**
222
+ * Export current user's SEA key pair
223
+ * For backup and multi-device usage
224
+ * Uses Shogun Core exportPair method (see API.md line 354)
225
+ */
226
+ exportKeyPair() {
227
+ try {
228
+ if (!this.isLoggedIn()) {
229
+ console.warn("Cannot export key pair: user not logged in");
230
+ return null;
231
+ }
232
+ // Access SEA pair from Gun user node
233
+ const seaPair = this.shogun.db.gun.user()?._?.sea;
234
+ if (!seaPair) {
235
+ console.warn("Cannot access SEA pair");
236
+ return null;
237
+ }
238
+ return {
239
+ pub: seaPair.pub,
240
+ priv: seaPair.priv,
241
+ epub: seaPair.epub,
242
+ epriv: seaPair.epriv,
243
+ };
244
+ }
245
+ catch (error) {
246
+ console.error("❌ Error exporting key pair:", error);
247
+ return null;
248
+ }
249
+ }
250
+ /**
251
+ * Get current user's key pair
252
+ * Alias for exportKeyPair()
253
+ */
254
+ getKeyPair() {
255
+ return this.exportKeyPair();
256
+ }
257
+ // ========================================================================
258
+ // USER DISCOVERY
259
+ // ========================================================================
260
+ /**
261
+ * Get user information by username
262
+ * Uses Shogun Core getUserByAlias method (see API.md line 1141-1148)
263
+ */
264
+ async getUserByAlias(username) {
265
+ try {
266
+ // Use DataBase getUserByAlias (API.md line 1141)
267
+ const userData = await this.shogun.db.getUserByAlias(username);
268
+ if (!userData) {
269
+ return null;
270
+ }
271
+ return {
272
+ userPub: userData.userPub || "",
273
+ username: userData.username,
274
+ epub: userData.epub || "",
275
+ registeredAt: userData.registeredAt,
276
+ lastSeen: userData.lastSeen,
277
+ };
278
+ }
279
+ catch (error) {
280
+ console.error("❌ Error getting user by alias:", error);
281
+ return null;
282
+ }
283
+ }
284
+ /**
285
+ * Get user information by public key
286
+ * Uses Shogun Core getUserDataByPub method (see API.md line 1150-1152)
287
+ */
288
+ async getUserByPub(userPub) {
289
+ try {
290
+ const userData = await this.shogun.db.getUserDataByPub(userPub);
291
+ if (!userData) {
292
+ return null;
293
+ }
294
+ return {
295
+ userPub: userPub,
296
+ username: userData.username,
297
+ epub: userData.epub || "",
298
+ registeredAt: userData.registeredAt,
299
+ lastSeen: userData.lastSeen,
300
+ };
301
+ }
302
+ catch (error) {
303
+ console.error("❌ Error getting user by pub:", error);
304
+ return null;
305
+ }
306
+ }
307
+ /**
308
+ * Check if user exists
309
+ * Uses SimpleGunAPI userExists method (see API.md line 188)
310
+ */
311
+ async userExists(username) {
312
+ try {
313
+ const userData = await this.getUserByAlias(username);
314
+ return userData !== null;
315
+ }
316
+ catch (error) {
317
+ console.error("❌ Error checking user existence:", error);
318
+ return false;
319
+ }
320
+ }
321
+ /**
322
+ * Get public key by username
323
+ */
324
+ async getPublicKey(username) {
325
+ try {
326
+ // Get user data first
327
+ const userData = await this.getUserByAlias(username);
328
+ if (!userData || !userData.userPub) {
329
+ console.error(`❌ User ${username} not found`);
330
+ return null;
331
+ }
332
+ const userPub = userData.userPub;
333
+ // Get published public key data
334
+ const publicKeyData = await this.shogun.db.gun.get(userPub).then();
335
+ if (publicKeyData && publicKeyData.epub && publicKeyData.pub) {
336
+ return {
337
+ pub: publicKeyData.pub,
338
+ epub: publicKeyData.epub,
339
+ algorithm: publicKeyData.algorithm,
340
+ timestamp: publicKeyData.timestamp,
341
+ };
342
+ }
343
+ return null;
344
+ }
345
+ catch (error) {
346
+ console.error("❌ Error getting public key:", error);
347
+ return null;
348
+ }
349
+ }
350
+ // ========================================================================
351
+ // IDENTITY
352
+ // ========================================================================
353
+ /**
354
+ * Get current authenticated user info
355
+ * Uses Shogun Core getCurrentUser method (see API.md line 429)
356
+ */
357
+ getCurrentUser() {
358
+ try {
359
+ if (!this.isLoggedIn()) {
360
+ return null;
361
+ }
362
+ // Use DataBase getCurrentUser (API.md line 429)
363
+ const currentUser = this.shogun.db.getCurrentUser();
364
+ if (!currentUser) {
365
+ return null;
366
+ }
367
+ return {
368
+ pub: currentUser.pub,
369
+ alias: currentUser.alias,
370
+ epub: currentUser.epub,
371
+ };
372
+ }
373
+ catch (error) {
374
+ console.error("❌ Error getting current user:", error);
375
+ return null;
376
+ }
377
+ }
378
+ /**
379
+ * Derive Ethereum address from SEA keypair
380
+ * Uses shogun-derive package for deterministic derivation
381
+ */
382
+ async deriveEthereumAddress(publicKey) {
383
+ try {
384
+ // Get SEA pair
385
+ const seaPair = this.shogun.db.gun.user()?._?.sea;
386
+ if (!seaPair || !seaPair.priv) {
387
+ throw new Error("Cannot access SEA pair");
388
+ }
389
+ // Use shogun-derive for deterministic address derivation
390
+ const derived = await (0, derive_1.default)(seaPair.priv, null, {
391
+ includeSecp256k1Ethereum: true,
392
+ includeP256: false,
393
+ includeSecp256k1Bitcoin: false,
394
+ });
395
+ return derived.secp256k1Ethereum.address;
396
+ }
397
+ catch (error) {
398
+ console.error("❌ Error deriving address:", error);
399
+ // Fallback: hash of public key
400
+ const fallbackKey = publicKey || "unknown";
401
+ const hash = ethers_1.ethers.keccak256(ethers_1.ethers.toUtf8Bytes(fallbackKey));
402
+ return ethers_1.ethers.getAddress("0x" + hash.slice(-40));
403
+ }
404
+ }
405
+ }
406
+ exports.SHIP_00 = SHIP_00;
407
+ // GunDB Node Names for identity storage
408
+ // Note: Most operations use ShogunCore API which manages nodes internally
409
+ // These are reference names for direct Gun access when needed
410
+ SHIP_00.NODES = {
411
+ USERS: "users", // User registry
412
+ PUBLIC_KEYS: "publicKeys", // Public key directory
413
+ REGISTRY: "registry", // User alias → pub mapping
414
+ };
415
+ // ============================================================================
416
+ // EXAMPLE & TESTING
417
+ // ============================================================================
418
+ /**
419
+ * Example usage of SHIP-00
420
+ */
421
+ async function exampleUsage() {
422
+ console.log("🧪 SHIP-00 Example: Identity Management\n");
423
+ console.log("=".repeat(60));
424
+ // Initialize
425
+ const identity = new SHIP_00({
426
+ gunOptions: {
427
+ peers: ["https://peer.wallie.io/gun"],
428
+ radisk: true,
429
+ },
430
+ });
431
+ // Signup
432
+ console.log("\n📝 SIGNUP");
433
+ console.log("-".repeat(60));
434
+ const signupResult = await identity.signup("alice", "password123");
435
+ if (signupResult.success) {
436
+ console.log("✅ Signup successful");
437
+ console.log(` Username: ${signupResult.username}`);
438
+ console.log(` Public Key: ${signupResult.userPub?.substring(0, 40)}...`);
439
+ console.log(` Ethereum Address: ${signupResult.derivedAddress}`);
440
+ }
441
+ // Publish public key
442
+ console.log("\n📢 PUBLISH PUBLIC KEY");
443
+ console.log("-".repeat(60));
444
+ await identity.publishPublicKey();
445
+ // Export key pair
446
+ console.log("\n💾 EXPORT KEY PAIR");
447
+ console.log("-".repeat(60));
448
+ const keyPair = identity.exportKeyPair();
449
+ if (keyPair) {
450
+ const backup = Buffer.from(JSON.stringify(keyPair)).toString('base64');
451
+ console.log("✅ Key pair exported (base64)");
452
+ console.log(` Length: ${backup.length} characters`);
453
+ }
454
+ // Current user
455
+ console.log("\n👤 CURRENT USER");
456
+ console.log("-".repeat(60));
457
+ const currentUser = identity.getCurrentUser();
458
+ console.log("Current user:", currentUser?.alias);
459
+ console.log("Public key:", currentUser?.pub.substring(0, 40) + "...");
460
+ // User discovery
461
+ console.log("\n🔍 USER DISCOVERY");
462
+ console.log("-".repeat(60));
463
+ const exists = await identity.userExists("alice");
464
+ console.log("Alice exists:", exists);
465
+ const aliceData = await identity.getUserByAlias("alice");
466
+ console.log("Alice data:", aliceData?.username);
467
+ // Logout
468
+ console.log("\n👋 LOGOUT");
469
+ console.log("-".repeat(60));
470
+ identity.logout();
471
+ console.log("Logged out successfully");
472
+ console.log("\n" + "=".repeat(60));
473
+ console.log("✅ SHIP-00 Example Complete!\n");
474
+ }
475
+ // Run example if executed directly
476
+ if (require.main === module) {
477
+ exampleUsage().catch(console.error);
478
+ }