shogun-core 3.1.0 → 3.2.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 (109) hide show
  1. package/dist/browser/_e6ae.shogun-core.js +14 -0
  2. package/dist/browser/_e6ae.shogun-core.js.map +1 -0
  3. package/dist/browser/shogun-core.js +1685 -6
  4. package/dist/browser/shogun-core.js.map +1 -1
  5. package/dist/ship/examples/messenger-cli.js +632 -0
  6. package/dist/ship/implementation/SHIP_01.js +803 -0
  7. package/dist/ship/interfaces/ISHIP_01.js +71 -0
  8. package/dist/{gundb → src/gundb}/db.js +2 -2
  9. package/dist/{index.js → src/index.js} +7 -2
  10. package/dist/types/ship/examples/messenger-cli.d.ts +31 -0
  11. package/dist/types/ship/implementation/SHIP_01.d.ts +108 -0
  12. package/dist/types/ship/interfaces/ISHIP_01.d.ts +305 -0
  13. package/dist/types/{index.d.ts → src/index.d.ts} +4 -1
  14. package/package.json +2 -1
  15. /package/dist/{config → src/config}/simplified-config.js +0 -0
  16. /package/dist/{core.js → src/core.js} +0 -0
  17. /package/dist/{examples → src/examples}/api-test.js +0 -0
  18. /package/dist/{examples → src/examples}/simple-api-test.js +0 -0
  19. /package/dist/{gundb → src/gundb}/api.js +0 -0
  20. /package/dist/{gundb → src/gundb}/crypto.js +0 -0
  21. /package/dist/{gundb → src/gundb}/derive.js +0 -0
  22. /package/dist/{gundb → src/gundb}/errors.js +0 -0
  23. /package/dist/{gundb → src/gundb}/index.js +0 -0
  24. /package/dist/{gundb → src/gundb}/rxjs.js +0 -0
  25. /package/dist/{gundb → src/gundb}/types.js +0 -0
  26. /package/dist/{interfaces → src/interfaces}/common.js +0 -0
  27. /package/dist/{interfaces → src/interfaces}/events.js +0 -0
  28. /package/dist/{interfaces → src/interfaces}/plugin.js +0 -0
  29. /package/dist/{interfaces → src/interfaces}/shogun.js +0 -0
  30. /package/dist/{managers → src/managers}/AuthManager.js +0 -0
  31. /package/dist/{managers → src/managers}/CoreInitializer.js +0 -0
  32. /package/dist/{managers → src/managers}/EventManager.js +0 -0
  33. /package/dist/{managers → src/managers}/PluginManager.js +0 -0
  34. /package/dist/{migration-test.js → src/migration-test.js} +0 -0
  35. /package/dist/{plugins → src/plugins}/base.js +0 -0
  36. /package/dist/{plugins → src/plugins}/index.js +0 -0
  37. /package/dist/{plugins → src/plugins}/nostr/index.js +0 -0
  38. /package/dist/{plugins → src/plugins}/nostr/nostrConnector.js +0 -0
  39. /package/dist/{plugins → src/plugins}/nostr/nostrConnectorPlugin.js +0 -0
  40. /package/dist/{plugins → src/plugins}/nostr/nostrSigner.js +0 -0
  41. /package/dist/{plugins → src/plugins}/nostr/types.js +0 -0
  42. /package/dist/{plugins → src/plugins}/oauth/index.js +0 -0
  43. /package/dist/{plugins → src/plugins}/oauth/oauthConnector.js +0 -0
  44. /package/dist/{plugins → src/plugins}/oauth/oauthPlugin.js +0 -0
  45. /package/dist/{plugins → src/plugins}/oauth/types.js +0 -0
  46. /package/dist/{plugins → src/plugins}/web3/index.js +0 -0
  47. /package/dist/{plugins → src/plugins}/web3/types.js +0 -0
  48. /package/dist/{plugins → src/plugins}/web3/web3Connector.js +0 -0
  49. /package/dist/{plugins → src/plugins}/web3/web3ConnectorPlugin.js +0 -0
  50. /package/dist/{plugins → src/plugins}/web3/web3Signer.js +0 -0
  51. /package/dist/{plugins → src/plugins}/webauthn/index.js +0 -0
  52. /package/dist/{plugins → src/plugins}/webauthn/types.js +0 -0
  53. /package/dist/{plugins → src/plugins}/webauthn/webauthn.js +0 -0
  54. /package/dist/{plugins → src/plugins}/webauthn/webauthnPlugin.js +0 -0
  55. /package/dist/{plugins → src/plugins}/webauthn/webauthnSigner.js +0 -0
  56. /package/dist/{storage → src/storage}/storage.js +0 -0
  57. /package/dist/{types → src/types}/events.js +0 -0
  58. /package/dist/{types → src/types}/shogun.js +0 -0
  59. /package/dist/{utils → src/utils}/errorHandler.js +0 -0
  60. /package/dist/{utils → src/utils}/eventEmitter.js +0 -0
  61. /package/dist/{utils → src/utils}/validation.js +0 -0
  62. /package/dist/types/{config → src/config}/simplified-config.d.ts +0 -0
  63. /package/dist/types/{core.d.ts → src/core.d.ts} +0 -0
  64. /package/dist/types/{examples → src/examples}/api-test.d.ts +0 -0
  65. /package/dist/types/{examples → src/examples}/simple-api-test.d.ts +0 -0
  66. /package/dist/types/{gundb → src/gundb}/api.d.ts +0 -0
  67. /package/dist/types/{gundb → src/gundb}/crypto.d.ts +0 -0
  68. /package/dist/types/{gundb → src/gundb}/db.d.ts +0 -0
  69. /package/dist/types/{gundb → src/gundb}/derive.d.ts +0 -0
  70. /package/dist/types/{gundb → src/gundb}/errors.d.ts +0 -0
  71. /package/dist/types/{gundb → src/gundb}/index.d.ts +0 -0
  72. /package/dist/types/{gundb → src/gundb}/rxjs.d.ts +0 -0
  73. /package/dist/types/{gundb → src/gundb}/types.d.ts +0 -0
  74. /package/dist/types/{interfaces → src/interfaces}/common.d.ts +0 -0
  75. /package/dist/types/{interfaces → src/interfaces}/events.d.ts +0 -0
  76. /package/dist/types/{interfaces → src/interfaces}/plugin.d.ts +0 -0
  77. /package/dist/types/{interfaces → src/interfaces}/shogun.d.ts +0 -0
  78. /package/dist/types/{managers → src/managers}/AuthManager.d.ts +0 -0
  79. /package/dist/types/{managers → src/managers}/CoreInitializer.d.ts +0 -0
  80. /package/dist/types/{managers → src/managers}/EventManager.d.ts +0 -0
  81. /package/dist/types/{managers → src/managers}/PluginManager.d.ts +0 -0
  82. /package/dist/types/{migration-test.d.ts → src/migration-test.d.ts} +0 -0
  83. /package/dist/types/{plugins → src/plugins}/base.d.ts +0 -0
  84. /package/dist/types/{plugins → src/plugins}/index.d.ts +0 -0
  85. /package/dist/types/{plugins → src/plugins}/nostr/index.d.ts +0 -0
  86. /package/dist/types/{plugins → src/plugins}/nostr/nostrConnector.d.ts +0 -0
  87. /package/dist/types/{plugins → src/plugins}/nostr/nostrConnectorPlugin.d.ts +0 -0
  88. /package/dist/types/{plugins → src/plugins}/nostr/nostrSigner.d.ts +0 -0
  89. /package/dist/types/{plugins → src/plugins}/nostr/types.d.ts +0 -0
  90. /package/dist/types/{plugins → src/plugins}/oauth/index.d.ts +0 -0
  91. /package/dist/types/{plugins → src/plugins}/oauth/oauthConnector.d.ts +0 -0
  92. /package/dist/types/{plugins → src/plugins}/oauth/oauthPlugin.d.ts +0 -0
  93. /package/dist/types/{plugins → src/plugins}/oauth/types.d.ts +0 -0
  94. /package/dist/types/{plugins → src/plugins}/web3/index.d.ts +0 -0
  95. /package/dist/types/{plugins → src/plugins}/web3/types.d.ts +0 -0
  96. /package/dist/types/{plugins → src/plugins}/web3/web3Connector.d.ts +0 -0
  97. /package/dist/types/{plugins → src/plugins}/web3/web3ConnectorPlugin.d.ts +0 -0
  98. /package/dist/types/{plugins → src/plugins}/web3/web3Signer.d.ts +0 -0
  99. /package/dist/types/{plugins → src/plugins}/webauthn/index.d.ts +0 -0
  100. /package/dist/types/{plugins → src/plugins}/webauthn/types.d.ts +0 -0
  101. /package/dist/types/{plugins → src/plugins}/webauthn/webauthn.d.ts +0 -0
  102. /package/dist/types/{plugins → src/plugins}/webauthn/webauthnPlugin.d.ts +0 -0
  103. /package/dist/types/{plugins → src/plugins}/webauthn/webauthnSigner.d.ts +0 -0
  104. /package/dist/types/{storage → src/storage}/storage.d.ts +0 -0
  105. /package/dist/types/{types → src/types}/events.d.ts +0 -0
  106. /package/dist/types/{types → src/types}/shogun.d.ts +0 -0
  107. /package/dist/types/{utils → src/utils}/errorHandler.d.ts +0 -0
  108. /package/dist/types/{utils → src/utils}/eventEmitter.d.ts +0 -0
  109. /package/dist/types/{utils → src/utils}/validation.d.ts +0 -0
@@ -98485,6 +98485,1463 @@ module.exports = function whichTypedArray(value) {
98485
98485
  };
98486
98486
 
98487
98487
 
98488
+ /***/ }),
98489
+
98490
+ /***/ "./ship/examples/messenger-cli.ts":
98491
+ /*!****************************************!*\
98492
+ !*** ./ship/examples/messenger-cli.ts ***!
98493
+ \****************************************/
98494
+ /***/ ((__unused_webpack_module, exports, __webpack_require__) => {
98495
+
98496
+ "use strict";
98497
+ /* provided dependency */ var process = __webpack_require__(/*! process/browser */ "./node_modules/process/browser.js");
98498
+ /* provided dependency */ var Buffer = __webpack_require__(/*! buffer */ "./node_modules/buffer/index.js")["Buffer"];
98499
+ //#!/usr/bin/env node
98500
+
98501
+ /**
98502
+ * Shogun Chat - CLI Interface
98503
+ *
98504
+ * End-to-end encrypted decentralized chat
98505
+ * Simple and functional CLI interface
98506
+ */
98507
+ Object.defineProperty(exports, "__esModule", ({ value: true }));
98508
+ exports.MessengerCLI = void 0;
98509
+ const SHIP_01_1 = __webpack_require__(/*! ../implementation/SHIP_01 */ "./ship/implementation/SHIP_01.ts");
98510
+ // Only import readline in Node.js environment
98511
+ let readline;
98512
+ try {
98513
+ if (false) // removed by dead control flow
98514
+ {}
98515
+ }
98516
+ catch (e) {
98517
+ // Browser environment - readline not available
98518
+ }
98519
+ // ============================================================================
98520
+ // COLORS
98521
+ // ============================================================================
98522
+ const colors = {
98523
+ reset: "\x1b[0m",
98524
+ bold: "\x1b[1m",
98525
+ dim: "\x1b[2m",
98526
+ red: "\x1b[31m",
98527
+ green: "\x1b[32m",
98528
+ yellow: "\x1b[33m",
98529
+ blue: "\x1b[34m",
98530
+ magenta: "\x1b[35m",
98531
+ cyan: "\x1b[36m",
98532
+ white: "\x1b[37m",
98533
+ gray: "\x1b[90m",
98534
+ };
98535
+ const c = (color, text) => `${colors[color]}${text}${colors.reset}`;
98536
+ // ============================================================================
98537
+ // CHAT CLI
98538
+ // ============================================================================
98539
+ class MessengerCLI {
98540
+ constructor() {
98541
+ this.currentUser = "";
98542
+ this.recipient = "";
98543
+ this.derivedAddress = "";
98544
+ this.isAuthenticated = false;
98545
+ // Initialize app in all environments (needed for TypeScript)
98546
+ this.app = new SHIP_01_1.SHIP_01({
98547
+ gunOptions: {
98548
+ peers: [
98549
+ "https://v5g5jseqhgkp43lppgregcfbvi.srv.us/gun",
98550
+ "https://relay.shogun-eco.xyz/gun",
98551
+ "https://peer.wallie.io/gun",
98552
+ ],
98553
+ radisk: false,
98554
+ localStorage: false,
98555
+ multicast: false, // Disabilita multicast per evitare blocchi
98556
+ wire: false,
98557
+ axe: false,
98558
+ },
98559
+ });
98560
+ // Don't initialize readline in browser environment
98561
+ if (true) {
98562
+ console.warn('MessengerCLI is designed for Node.js CLI usage only');
98563
+ return;
98564
+ }
98565
+ // removed by dead control flow
98566
+
98567
+ // removed by dead control flow
98568
+
98569
+ }
98570
+ // ========================================================================
98571
+ // SETUP
98572
+ // ========================================================================
98573
+ setupHandlers() {
98574
+ this.rl.on("line", async (line) => {
98575
+ const input = line.trim();
98576
+ if (!input) {
98577
+ this.rl.prompt();
98578
+ return;
98579
+ }
98580
+ if (input.startsWith("/")) {
98581
+ await this.handleCommand(input);
98582
+ }
98583
+ else {
98584
+ await this.sendMessage(input);
98585
+ }
98586
+ this.rl.prompt();
98587
+ });
98588
+ this.rl.on("close", () => {
98589
+ console.log("\n" + c("yellow", "👋 Arrivederci!"));
98590
+ process.exit(0);
98591
+ });
98592
+ // Ctrl+C handler
98593
+ process.on("SIGINT", () => {
98594
+ this.rl.close();
98595
+ });
98596
+ }
98597
+ // ========================================================================
98598
+ // UTILITIES
98599
+ // ========================================================================
98600
+ async withTimeout(promise, timeoutMs, errorMessage) {
98601
+ return Promise.race([
98602
+ promise,
98603
+ new Promise((_, reject) => setTimeout(() => reject(new Error(errorMessage)), timeoutMs)),
98604
+ ]);
98605
+ }
98606
+ // ========================================================================
98607
+ // AUTH
98608
+ // ========================================================================
98609
+ async login(username, password) {
98610
+ console.log(c("cyan", "🔐 Login in corso..."));
98611
+ // Loading indicator
98612
+ const loadingInterval = setInterval(() => {
98613
+ process.stdout.write(c("gray", "."));
98614
+ }, 500);
98615
+ try {
98616
+ // Prova login con timeout
98617
+ let result = await this.withTimeout(this.app.login(username, password), 15000, "Login timeout - verifica connessione ai peers");
98618
+ clearInterval(loadingInterval);
98619
+ console.log(""); // Nuova linea dopo i dots
98620
+ // Se fallisce, prova signup
98621
+ if (!result.success) {
98622
+ console.log(c("yellow", "📝 Utente non trovato, creazione in corso..."));
98623
+ const signupResult = await this.app.signup(username, password);
98624
+ if (signupResult.success) {
98625
+ // Aspetta un momento per evitare race condition
98626
+ await new Promise((resolve) => setTimeout(resolve, 1000));
98627
+ // Riprova login
98628
+ result = await this.app.login(username, password);
98629
+ }
98630
+ else {
98631
+ console.log(c("red", `❌ Signup fallito: ${signupResult.error}`));
98632
+ return false;
98633
+ }
98634
+ }
98635
+ if (result.success) {
98636
+ this.currentUser = username;
98637
+ this.derivedAddress = result.derivedAddress || "";
98638
+ this.isAuthenticated = true;
98639
+ console.log("");
98640
+ console.log(c("green", "✅ Login effettuato!"));
98641
+ console.log(c("gray", ` Username: ${c("bold", username)}`));
98642
+ console.log(c("gray", ` Public Key: ${result.userPub?.substring(0, 40)}...`));
98643
+ console.log(c("gray", ` Derived Address: ${c("cyan", result.derivedAddress || "")}`));
98644
+ console.log("");
98645
+ console.log(c("yellow", "📢 Pubblicazione chiave pubblica..."));
98646
+ await this.app.publishPublicKey();
98647
+ // Aspetta che la chiave sia sincronizzata
98648
+ await new Promise((resolve) => setTimeout(resolve, 1000));
98649
+ console.log(c("green", "✅ Chiave pubblicata su GunDB"));
98650
+ console.log("");
98651
+ // Ascolta messaggi
98652
+ await this.app.listenForMessages((msg) => {
98653
+ this.onMessageReceived(msg);
98654
+ });
98655
+ console.log(c("cyan", "💬 Chat pronta! Scrivi /help per i comandi disponibili"));
98656
+ console.log("");
98657
+ return true;
98658
+ }
98659
+ else {
98660
+ console.log(c("red", `❌ Login fallito: ${result.error}`));
98661
+ return false;
98662
+ }
98663
+ }
98664
+ catch (error) {
98665
+ clearInterval(loadingInterval);
98666
+ console.log("");
98667
+ console.log(c("red", `❌ Errore: ${error.message}`));
98668
+ return false;
98669
+ }
98670
+ finally {
98671
+ clearInterval(loadingInterval);
98672
+ }
98673
+ }
98674
+ // ========================================================================
98675
+ // MESSAGING
98676
+ // ========================================================================
98677
+ async sendMessage(content) {
98678
+ if (!this.isAuthenticated) {
98679
+ console.log(c("red", "❌ Non autenticato. Usa /login"));
98680
+ return;
98681
+ }
98682
+ if (!this.recipient) {
98683
+ console.log(c("yellow", "⚠️ Nessun destinatario. Usa /to <username>"));
98684
+ return;
98685
+ }
98686
+ try {
98687
+ const result = await this.app.sendMessage(this.recipient, content);
98688
+ if (result.success) {
98689
+ const time = new Date().toLocaleTimeString();
98690
+ console.log(c("gray", `[${time}]`) +
98691
+ " " +
98692
+ c("green", `${this.currentUser}:`) +
98693
+ " " +
98694
+ content);
98695
+ }
98696
+ else {
98697
+ console.log(c("red", `❌ Errore invio: ${result.error}`));
98698
+ }
98699
+ }
98700
+ catch (error) {
98701
+ console.log(c("red", `❌ Errore: ${error.message}`));
98702
+ }
98703
+ }
98704
+ onMessageReceived(message) {
98705
+ const time = new Date(message.timestamp).toLocaleTimeString();
98706
+ const fromUser = message.from.substring(0, 10) + "...";
98707
+ console.log("");
98708
+ console.log(c("cyan", "📨 Nuovo messaggio!"));
98709
+ console.log(c("gray", `[${time}]`) +
98710
+ " " +
98711
+ c("cyan", `${fromUser}:`) +
98712
+ " " +
98713
+ message.content);
98714
+ console.log("");
98715
+ this.rl.prompt();
98716
+ }
98717
+ // ========================================================================
98718
+ // KEY PAIR MANAGEMENT
98719
+ // ========================================================================
98720
+ async exportKeyPair() {
98721
+ try {
98722
+ // Ottieni il SEA pair completo
98723
+ const seaPair = this.app["shogun"].db.gun.user()?._?.sea;
98724
+ if (!seaPair) {
98725
+ console.log(c("red", "❌ Impossibile accedere al SEA pair"));
98726
+ return;
98727
+ }
98728
+ // Crea export object
98729
+ const exportData = {
98730
+ pub: seaPair.pub,
98731
+ priv: seaPair.priv,
98732
+ epub: seaPair.epub,
98733
+ epriv: seaPair.epriv,
98734
+ alias: this.currentUser,
98735
+ exportedAt: Date.now()
98736
+ };
98737
+ // Converti in base64 per facilità di copia
98738
+ const jsonString = JSON.stringify(exportData);
98739
+ const base64 = Buffer.from(jsonString).toString('base64');
98740
+ console.log("");
98741
+ console.log(c("green", "✅ KEY PAIR ESPORTATO"));
98742
+ console.log(c("yellow", "═".repeat(60)));
98743
+ console.log("");
98744
+ console.log(c("bold", "🔑 SEA PAIR (Base64):"));
98745
+ console.log("");
98746
+ console.log(c("cyan", base64));
98747
+ console.log("");
98748
+ console.log(c("yellow", "═".repeat(60)));
98749
+ console.log("");
98750
+ console.log(c("gray", "💾 SALVA QUESTO KEY PAIR IN UN LUOGO SICURO!"));
98751
+ console.log(c("gray", " Puoi usarlo per:"));
98752
+ console.log(c("gray", " - Fare login: /login-pair <keypair>"));
98753
+ console.log(c("gray", " - Importare: /import <keypair>"));
98754
+ console.log(c("gray", " - Backup della tua identità"));
98755
+ console.log("");
98756
+ console.log(c("red", "⚠️ NON CONDIVIDERE MAI QUESTO KEY PAIR!"));
98757
+ console.log(c("red", " Contiene le tue chiavi private!"));
98758
+ console.log("");
98759
+ // Salva anche su file (opzionale)
98760
+ const fs = await __webpack_require__.e(/*! import() */ "_e6ae").then(__webpack_require__.t.bind(__webpack_require__, /*! fs */ "?e6ae", 23));
98761
+ const filename = `shogun-keypair-${this.currentUser}-${Date.now()}.txt`;
98762
+ fs.writeFileSync(filename, base64);
98763
+ console.log(c("green", `💾 Key pair salvato anche in: ${filename}`));
98764
+ console.log("");
98765
+ }
98766
+ catch (error) {
98767
+ console.log(c("red", `❌ Errore export: ${error.message}`));
98768
+ }
98769
+ }
98770
+ async importKeyPair(base64KeyPair) {
98771
+ try {
98772
+ // Decodifica da base64
98773
+ const jsonString = Buffer.from(base64KeyPair, 'base64').toString('utf-8');
98774
+ const keyPairData = JSON.parse(jsonString);
98775
+ // Verifica che abbia tutti i campi necessari
98776
+ if (!keyPairData.pub || !keyPairData.priv || !keyPairData.epub || !keyPairData.epriv) {
98777
+ console.log(c("red", "❌ Key pair invalido. Mancano campi obbligatori."));
98778
+ return;
98779
+ }
98780
+ console.log(c("cyan", "📥 Key pair importato con successo!"));
98781
+ console.log(c("gray", ` Utente: ${keyPairData.alias || 'unknown'}`));
98782
+ console.log(c("gray", ` Public Key: ${keyPairData.pub.substring(0, 30)}...`));
98783
+ console.log("");
98784
+ console.log(c("yellow", "💡 Usa /login-pair <keypair> per fare login"));
98785
+ console.log("");
98786
+ }
98787
+ catch (error) {
98788
+ console.log(c("red", `❌ Errore import: ${error.message}`));
98789
+ console.log(c("gray", " Verifica che il key pair sia valido"));
98790
+ }
98791
+ }
98792
+ async loginWithPair(base64KeyPair) {
98793
+ console.log(c("cyan", "🔐 Login con key pair..."));
98794
+ const loadingInterval = setInterval(() => {
98795
+ process.stdout.write(c("gray", "."));
98796
+ }, 500);
98797
+ try {
98798
+ // Decodifica key pair
98799
+ const jsonString = Buffer.from(base64KeyPair, 'base64').toString('utf-8');
98800
+ const keyPairData = JSON.parse(jsonString);
98801
+ // Verifica validità
98802
+ if (!keyPairData.pub || !keyPairData.priv || !keyPairData.epub || !keyPairData.epriv) {
98803
+ throw new Error("Key pair invalido");
98804
+ }
98805
+ // Crea SEA pair object
98806
+ const seaPair = {
98807
+ pub: keyPairData.pub,
98808
+ priv: keyPairData.priv,
98809
+ epub: keyPairData.epub,
98810
+ epriv: keyPairData.epriv
98811
+ };
98812
+ // Login con pair
98813
+ const result = await this.withTimeout(this.app["shogun"].loginWithPair(seaPair), 15000, "Login timeout");
98814
+ clearInterval(loadingInterval);
98815
+ console.log("");
98816
+ if (result.success) {
98817
+ this.currentUser = keyPairData.alias || result.username || 'unknown';
98818
+ this.derivedAddress = await this.app.deriveEthereumAddress(seaPair.pub);
98819
+ this.isAuthenticated = true;
98820
+ console.log("");
98821
+ console.log(c("green", "✅ Login con key pair effettuato!"));
98822
+ console.log(c("gray", ` Username: ${c("bold", this.currentUser)}`));
98823
+ console.log(c("gray", ` Public Key: ${seaPair.pub.substring(0, 40)}...`));
98824
+ console.log(c("gray", ` Derived Address: ${c("cyan", this.derivedAddress)}`));
98825
+ console.log("");
98826
+ console.log(c("yellow", "📢 Pubblicazione chiave pubblica..."));
98827
+ await this.app.publishPublicKey();
98828
+ await new Promise((resolve) => setTimeout(resolve, 1000));
98829
+ console.log(c("green", "✅ Chiave pubblicata su GunDB"));
98830
+ console.log("");
98831
+ // Ascolta messaggi
98832
+ await this.app.listenForMessages((msg) => {
98833
+ this.onMessageReceived(msg);
98834
+ });
98835
+ console.log(c("cyan", "💬 Chat pronta!"));
98836
+ console.log("");
98837
+ this.updatePrompt();
98838
+ }
98839
+ else {
98840
+ console.log(c("red", `❌ Login fallito: ${result.error}`));
98841
+ }
98842
+ }
98843
+ catch (error) {
98844
+ clearInterval(loadingInterval);
98845
+ console.log("");
98846
+ console.log(c("red", `❌ Errore: ${error.message}`));
98847
+ }
98848
+ finally {
98849
+ clearInterval(loadingInterval);
98850
+ }
98851
+ }
98852
+ async wipeAllMessages() {
98853
+ console.log("");
98854
+ console.log(c("yellow", "⚠️ ATTENZIONE: Stai per cancellare TUTTI i messaggi dal nodo GunDB"));
98855
+ console.log(c("yellow", " Questa operazione è IRREVERSIBILE!"));
98856
+ console.log("");
98857
+ // Conferma
98858
+ this.rl.question(c("red", "Sei sicuro? Scrivi 'CONFERMA' per procedere: "), (answer) => {
98859
+ if (answer.trim() === "CONFERMA") {
98860
+ console.log(c("yellow", "🗑️ Cancellazione messaggi in corso..."));
98861
+ // Ottieni tutti i messaggi
98862
+ this.app["shogun"].db.gun.get("messages").once((allMessages) => {
98863
+ if (allMessages && typeof allMessages === 'object') {
98864
+ let count = 0;
98865
+ // Cancella ogni messaggio
98866
+ for (const [messageId, data] of Object.entries(allMessages)) {
98867
+ if (typeof data === "object" && data !== null && messageId !== '_') {
98868
+ this.app["shogun"].db.gun.get("messages").get(messageId).put(null);
98869
+ count++;
98870
+ }
98871
+ }
98872
+ console.log(c("green", `✅ ${count} messaggi cancellati dal nodo GunDB`));
98873
+ }
98874
+ else {
98875
+ console.log(c("gray", "ℹ️ Nessun messaggio da cancellare"));
98876
+ }
98877
+ console.log("");
98878
+ this.rl.prompt();
98879
+ });
98880
+ }
98881
+ else {
98882
+ console.log(c("gray", "❌ Cancellazione annullata"));
98883
+ console.log("");
98884
+ this.rl.prompt();
98885
+ }
98886
+ });
98887
+ }
98888
+ // ========================================================================
98889
+ // COMMANDS
98890
+ // ========================================================================
98891
+ async handleCommand(cmd) {
98892
+ const parts = cmd.split(" ");
98893
+ const command = parts[0].toLowerCase();
98894
+ const args = parts.slice(1);
98895
+ switch (command) {
98896
+ case "/login":
98897
+ if (args.length >= 2) {
98898
+ const [username, password] = args;
98899
+ await this.login(username, password);
98900
+ this.updatePrompt();
98901
+ }
98902
+ else {
98903
+ console.log(c("yellow", "⚠️ Uso: /login <username> <password>"));
98904
+ }
98905
+ break;
98906
+ case "/to":
98907
+ case "/chat":
98908
+ if (!this.isAuthenticated) {
98909
+ console.log(c("red", "❌ Prima fai login: /login <username> <password>"));
98910
+ break;
98911
+ }
98912
+ if (args[0]) {
98913
+ this.recipient = args[0];
98914
+ console.log(c("cyan", `💬 Chattando con ${c("bold", this.recipient)}`));
98915
+ // Carica storico
98916
+ const history = await this.app.getMessageHistory(this.recipient);
98917
+ if (history.length > 0) {
98918
+ console.log(c("gray", `\n📚 Storico conversazione (${history.length} messaggi):\n`));
98919
+ history.forEach((msg, i) => {
98920
+ const time = new Date(msg.timestamp).toLocaleTimeString();
98921
+ const isMe = msg.from === this.currentUser;
98922
+ const from = isMe ? this.currentUser : this.recipient;
98923
+ const color = isMe ? "green" : "cyan";
98924
+ console.log(c("gray", `[${time}]`) +
98925
+ " " +
98926
+ c(color, `${from}:`) +
98927
+ " " +
98928
+ msg.content);
98929
+ });
98930
+ console.log("");
98931
+ }
98932
+ this.updatePrompt();
98933
+ }
98934
+ else {
98935
+ console.log(c("yellow", "⚠️ Uso: /to <username>"));
98936
+ }
98937
+ break;
98938
+ case "/help":
98939
+ this.showHelp();
98940
+ break;
98941
+ case "/clear":
98942
+ console.clear();
98943
+ this.showHeader();
98944
+ break;
98945
+ case "/status":
98946
+ this.showStatus();
98947
+ break;
98948
+ case "/logout":
98949
+ this.app.logout();
98950
+ this.isAuthenticated = false;
98951
+ this.currentUser = "";
98952
+ this.recipient = "";
98953
+ console.log(c("yellow", "👋 Disconnesso"));
98954
+ this.updatePrompt();
98955
+ break;
98956
+ case "/export":
98957
+ case "/backup":
98958
+ if (!this.isAuthenticated) {
98959
+ console.log(c("red", "❌ Prima fai login"));
98960
+ break;
98961
+ }
98962
+ await this.exportKeyPair();
98963
+ break;
98964
+ case "/import":
98965
+ case "/restore":
98966
+ if (args[0]) {
98967
+ await this.importKeyPair(args[0]);
98968
+ }
98969
+ else {
98970
+ console.log(c("yellow", "⚠️ Uso: /import <keypair-json-base64>"));
98971
+ }
98972
+ break;
98973
+ case "/login-pair":
98974
+ if (args[0]) {
98975
+ await this.loginWithPair(args[0]);
98976
+ }
98977
+ else {
98978
+ console.log(c("yellow", "⚠️ Uso: /login-pair <keypair-json-base64>"));
98979
+ }
98980
+ break;
98981
+ case "/wipe":
98982
+ case "/delete-all":
98983
+ if (!this.isAuthenticated) {
98984
+ console.log(c("red", "❌ Prima fai login"));
98985
+ break;
98986
+ }
98987
+ await this.wipeAllMessages();
98988
+ break;
98989
+ case "/exit":
98990
+ case "/quit":
98991
+ this.rl.close();
98992
+ break;
98993
+ default:
98994
+ console.log(c("red", `❌ Comando sconosciuto: ${command}`));
98995
+ console.log(c("gray", " Scrivi /help per aiuto"));
98996
+ }
98997
+ }
98998
+ showHelp() {
98999
+ console.log("");
99000
+ console.log(c("bold", c("cyan", "📖 COMANDI DISPONIBILI")));
99001
+ console.log("");
99002
+ console.log(c("bold", "AUTENTICAZIONE:"));
99003
+ console.log(" " + c("bold", "/login <user> <pass>") + " - Login/Signup con password");
99004
+ console.log(" " + c("bold", "/login-pair <keypair>") + " - Login con SEA key pair");
99005
+ console.log("");
99006
+ console.log(c("bold", "MESSAGGISTICA:"));
99007
+ console.log(" " + c("bold", "/to <username>") + " - Inizia chat con un utente");
99008
+ console.log("");
99009
+ console.log(c("bold", "KEY MANAGEMENT:"));
99010
+ console.log(" " + c("bold", "/export") + " - Esporta il tuo key pair (backup)");
99011
+ console.log(" " + c("bold", "/import <keypair>") + " - Mostra info su key pair");
99012
+ console.log("");
99013
+ console.log(c("bold", "UTILITÀ:"));
99014
+ console.log(" " + c("bold", "/help") + " - Mostra questo aiuto");
99015
+ console.log(" " + c("bold", "/status") + " - Mostra stato connessione");
99016
+ console.log(" " + c("bold", "/clear") + " - Pulisci schermo");
99017
+ console.log(" " + c("bold", "/wipe") + " - Cancella TUTTI i messaggi (⚠️)");
99018
+ console.log(" " + c("bold", "/logout") + " - Disconnetti");
99019
+ console.log(" " + c("bold", "/exit") + " - Esci dall'app");
99020
+ console.log("");
99021
+ console.log(c("bold", c("green", "🔐 SICUREZZA")));
99022
+ console.log("");
99023
+ console.log(" ✅ Crittografia end-to-end (ECDH + AES-GCM)");
99024
+ console.log(" ✅ Storage decentralizzato P2P (GunDB)");
99025
+ console.log(" ✅ Nessun server può leggere i messaggi");
99026
+ console.log(" ✅ Key pair portabile (export/import)");
99027
+ console.log(" ✅ Zero costi, completamente gratis");
99028
+ console.log("");
99029
+ console.log(c("bold", c("yellow", "💡 ESEMPI")));
99030
+ console.log("");
99031
+ console.log(" " + c("gray", "# Login normale"));
99032
+ console.log(" " + c("gray", "/login alice password123"));
99033
+ console.log("");
99034
+ console.log(" " + c("gray", "# Export key pair (backup)"));
99035
+ console.log(" " + c("gray", "/export"));
99036
+ console.log("");
99037
+ console.log(" " + c("gray", "# Login con key pair (no password)"));
99038
+ console.log(" " + c("gray", "/login-pair eyJwdWIiOiIuLi4ifQ=="));
99039
+ console.log("");
99040
+ console.log(" " + c("gray", "# Chattare"));
99041
+ console.log(" " + c("gray", "/to bob"));
99042
+ console.log(" " + c("gray", "Ciao Bob! Come stai?"));
99043
+ console.log("");
99044
+ }
99045
+ showStatus() {
99046
+ console.log("");
99047
+ console.log(c("bold", c("cyan", "📊 STATO SISTEMA")));
99048
+ console.log("");
99049
+ console.log(" " + c("gray", "Utente:") + " " + c("green", this.currentUser));
99050
+ console.log(" " +
99051
+ c("gray", "Destinatario:") +
99052
+ " " +
99053
+ c("yellow", this.recipient || "(nessuno)"));
99054
+ console.log(" " + c("gray", "Address:") + " " + c("cyan", this.derivedAddress));
99055
+ console.log(" " +
99056
+ c("gray", "Autenticato:") +
99057
+ " " +
99058
+ (this.isAuthenticated ? c("green", "✅ Sì") : c("red", "❌ No")));
99059
+ console.log("");
99060
+ }
99061
+ showHeader() {
99062
+ console.log("");
99063
+ console.log(c("bold", c("cyan", "═══════════════════════════════════════════════════════")));
99064
+ console.log(c("bold", c("cyan", " 🗡️ SHOGUN CHAT - Decentralized E2E Messaging")));
99065
+ console.log(c("bold", c("cyan", "═══════════════════════════════════════════════════════")));
99066
+ console.log("");
99067
+ console.log(c("gray", " Powered by Shogun Core + GunDB"));
99068
+ console.log(c("gray", " Zero-cost encrypted messaging over P2P network"));
99069
+ console.log("");
99070
+ }
99071
+ updatePrompt() {
99072
+ let prompt = "";
99073
+ if (this.recipient) {
99074
+ prompt =
99075
+ c("green", `[${this.currentUser}]`) +
99076
+ c("white", " → ") +
99077
+ c("yellow", this.recipient) +
99078
+ c("green", " ➤ ");
99079
+ }
99080
+ else if (this.currentUser) {
99081
+ prompt = c("green", `[${this.currentUser}]`) + c("green", " ➤ ");
99082
+ }
99083
+ else {
99084
+ prompt = c("gray", "➤ ");
99085
+ }
99086
+ this.rl.setPrompt(prompt);
99087
+ }
99088
+ // ========================================================================
99089
+ // START
99090
+ // ========================================================================
99091
+ async start() {
99092
+ this.showHeader();
99093
+ const args = process.argv.slice(2);
99094
+ if (args.length >= 2) {
99095
+ // Auto-login
99096
+ const [username, password] = args;
99097
+ const success = await this.login(username, password);
99098
+ if (success) {
99099
+ this.updatePrompt();
99100
+ this.rl.prompt();
99101
+ }
99102
+ else {
99103
+ console.log(c("red", "❌ Auto-login fallito"));
99104
+ this.rl.close();
99105
+ }
99106
+ }
99107
+ else {
99108
+ // Login manuale
99109
+ console.log(c("cyan", "💡 Comandi disponibili:"));
99110
+ console.log(c("yellow", " /login <username> <password>") +
99111
+ c("gray", " - Login o crea account"));
99112
+ console.log(c("yellow", " /help") +
99113
+ c("gray", " - Mostra tutti i comandi"));
99114
+ console.log("");
99115
+ console.log(c("gray", " Oppure avvia con: yarn chat <username> <password>"));
99116
+ console.log("");
99117
+ this.updatePrompt();
99118
+ this.rl.prompt();
99119
+ }
99120
+ }
99121
+ }
99122
+ exports.MessengerCLI = MessengerCLI;
99123
+ // ============================================================================
99124
+ // MAIN
99125
+ // ============================================================================
99126
+ const cli = new MessengerCLI();
99127
+ cli.start().catch(console.error);
99128
+
99129
+
99130
+ /***/ }),
99131
+
99132
+ /***/ "./ship/implementation/SHIP_01.ts":
99133
+ /*!****************************************!*\
99134
+ !*** ./ship/implementation/SHIP_01.ts ***!
99135
+ \****************************************/
99136
+ /***/ (function(module, exports, __webpack_require__) {
99137
+
99138
+ "use strict";
99139
+ /* module decorator */ module = __webpack_require__.nmd(module);
99140
+
99141
+ /**
99142
+ * Esempio Pratico: Messaggistica Decentralizzata con Shogun Core
99143
+ *
99144
+ * Questo esempio mostra come creare un sistema di messaggistica sicuro usando:
99145
+ * - Shogun Core per autenticazione (username/password)
99146
+ * - GunDB per storage decentralizzato P2P
99147
+ * - SEA (Security, Encryption, Authorization) per crittografia
99148
+ *
99149
+ * Vantaggi:
99150
+ * ✅ Completamente decentralizzato (no server centrale)
99151
+ * ✅ Zero costi (no blockchain, no gas fees)
99152
+ * ✅ Real-time messaging
99153
+ * ✅ Offline-first
99154
+ * ✅ End-to-end encryption
99155
+ *
99156
+ * Note sull'ERC7627:
99157
+ * L'EIP era un template concettuale. Questo esempio implementa
99158
+ * solo la parte GunDB/Shogun Core senza interazione blockchain.
99159
+ * La funzione deriveEthereumAddress() rimane come utility per derivare
99160
+ * un address Ethereum dalla chiave GunDB se necessario in futuro.
99161
+ */
99162
+ var __importDefault = (this && this.__importDefault) || function (mod) {
99163
+ return (mod && mod.__esModule) ? mod : { "default": mod };
99164
+ };
99165
+ Object.defineProperty(exports, "__esModule", ({ value: true }));
99166
+ exports.SHIP_01 = void 0;
99167
+ const core_1 = __webpack_require__(/*! ../../src/core */ "./src/core.ts");
99168
+ const ethers_1 = __webpack_require__(/*! ethers */ "./node_modules/ethers/lib.commonjs/index.js");
99169
+ const derive_1 = __importDefault(__webpack_require__(/*! ../../src/gundb/derive */ "./src/gundb/derive.ts"));
99170
+ // ============================================================================
99171
+ // 1. SETUP: Inizializzazione del Sistema Completo
99172
+ // ============================================================================
99173
+ /**
99174
+ * Classe per messaggistica sicura con Shogun Core
99175
+ * Implementa l'interfaccia ISHIP_01
99176
+ * Usa solo GunDB per storage decentralizzato (no blockchain)
99177
+ */
99178
+ class SHIP_01 {
99179
+ constructor(shogunConfig) {
99180
+ // Inizializza Shogun Core
99181
+ this.shogun = new core_1.ShogunCore(shogunConfig);
99182
+ }
99183
+ // ========================================================================
99184
+ // 2. AUTENTICAZIONE: Username e Password
99185
+ // ========================================================================
99186
+ /**
99187
+ * Registra un nuovo utente
99188
+ */
99189
+ async signup(username, password) {
99190
+ try {
99191
+ // Registra con Shogun Core (crea SEA pair automaticamente)
99192
+ const signupResult = await this.shogun.signUp(username, password);
99193
+ if (!signupResult.success) {
99194
+ return {
99195
+ success: false,
99196
+ error: signupResult.error || "Signup failed"
99197
+ };
99198
+ }
99199
+ console.log("✅ Utente registrato");
99200
+ console.log(` Username: ${username}`);
99201
+ console.log(` GunDB Public Key: ${signupResult.pub}`);
99202
+ // Opzionale: deriva address Ethereum dalla chiave GunDB
99203
+ const derivedAddress = signupResult.pub
99204
+ ? await this.deriveEthereumAddress(signupResult.pub)
99205
+ : undefined;
99206
+ if (derivedAddress) {
99207
+ console.log(` Derived Address: ${derivedAddress}`);
99208
+ }
99209
+ return {
99210
+ success: true,
99211
+ userPub: signupResult.pub,
99212
+ derivedAddress
99213
+ };
99214
+ }
99215
+ catch (error) {
99216
+ return {
99217
+ success: false,
99218
+ error: error.message
99219
+ };
99220
+ }
99221
+ }
99222
+ /**
99223
+ * Login con username e password
99224
+ */
99225
+ async login(username, password) {
99226
+ try {
99227
+ // Login con Shogun Core
99228
+ const loginResult = await this.shogun.login(username, password);
99229
+ if (!loginResult.success) {
99230
+ return {
99231
+ success: false,
99232
+ error: loginResult.error || "Login failed"
99233
+ };
99234
+ }
99235
+ console.log("✅ Login effettuato");
99236
+ console.log(` Username: ${username}`);
99237
+ console.log(` GunDB Public Key: ${loginResult.userPub}`);
99238
+ // Opzionale: deriva address Ethereum dalla chiave GunDB
99239
+ const derivedAddress = loginResult.userPub
99240
+ ? await this.deriveEthereumAddress(loginResult.userPub)
99241
+ : undefined;
99242
+ if (derivedAddress) {
99243
+ console.log(` Derived Address: ${derivedAddress}`);
99244
+ }
99245
+ return {
99246
+ success: true,
99247
+ userPub: loginResult.userPub,
99248
+ derivedAddress
99249
+ };
99250
+ }
99251
+ catch (error) {
99252
+ return {
99253
+ success: false,
99254
+ error: error.message
99255
+ };
99256
+ }
99257
+ }
99258
+ /**
99259
+ * Login con SEA Key Pair
99260
+ *
99261
+ * Autenticazione diretta usando un key pair esportato.
99262
+ * Utile per:
99263
+ * - Recupero account senza password
99264
+ * - Portabilità tra dispositivi
99265
+ * - Backup dell'identità
99266
+ */
99267
+ async loginWithPair(seaPair) {
99268
+ try {
99269
+ console.log("🔐 Login con key pair...");
99270
+ // Autentica con GunDB usando il pair
99271
+ const authResult = await new Promise((resolve) => {
99272
+ this.shogun.db.gun.user().auth(seaPair, (ack) => {
99273
+ if (ack.err) {
99274
+ resolve({
99275
+ success: false,
99276
+ error: ack.err,
99277
+ });
99278
+ }
99279
+ else {
99280
+ resolve({
99281
+ success: true,
99282
+ userPub: seaPair.pub,
99283
+ });
99284
+ }
99285
+ });
99286
+ });
99287
+ if (!authResult.success) {
99288
+ console.log("❌ Login fallito:", authResult.error);
99289
+ return authResult;
99290
+ }
99291
+ // Opzionale: deriva address Ethereum dalla chiave GunDB
99292
+ const derivedAddress = await this.deriveEthereumAddress(seaPair.pub);
99293
+ console.log("✅ Login effettuato");
99294
+ console.log(` GunDB Public Key: ${seaPair.pub}`);
99295
+ console.log(` Derived Address: ${derivedAddress}`);
99296
+ return {
99297
+ success: true,
99298
+ userPub: authResult.userPub,
99299
+ derivedAddress
99300
+ };
99301
+ }
99302
+ catch (error) {
99303
+ console.error("❌ Errore login con pair:", error);
99304
+ return {
99305
+ success: false,
99306
+ error: error instanceof Error ? error.message : "Unknown error",
99307
+ };
99308
+ }
99309
+ }
99310
+ /**
99311
+ * Logout
99312
+ */
99313
+ logout() {
99314
+ this.shogun.logout();
99315
+ console.log("👋 Logout effettuato");
99316
+ }
99317
+ /**
99318
+ * Verifica se l'utente è autenticato
99319
+ */
99320
+ isLoggedIn() {
99321
+ return this.shogun.isLoggedIn();
99322
+ }
99323
+ // ========================================================================
99324
+ // 3. GESTIONE CHIAVI PUBBLICHE: Salva su GunDB
99325
+ // ========================================================================
99326
+ /**
99327
+ * Salva la chiave pubblica dell'utente su GunDB
99328
+ * Questo permette ad altri di trovare la tua chiave per criptare messaggi
99329
+ */
99330
+ async publishPublicKey() {
99331
+ try {
99332
+ if (!this.isLoggedIn()) {
99333
+ return { success: false, error: "Not logged in" };
99334
+ }
99335
+ // Ottieni il SEA pair dell'utente corrente
99336
+ const currentUser = this.shogun.db.user;
99337
+ if (!currentUser || !currentUser.is) {
99338
+ return { success: false, error: "No user session" };
99339
+ }
99340
+ // Salva chiave pubblica sul nodo globale usando il userPub come chiave
99341
+ // Questo permette ad altri di trovarla facilmente
99342
+ const userPub = currentUser.is.pub;
99343
+ await this.shogun.db.gun.get(userPub).put({
99344
+ pub: currentUser.is.pub,
99345
+ epub: currentUser.is.epub,
99346
+ algorithm: "ECDSA",
99347
+ timestamp: Date.now().toString()
99348
+ }).then();
99349
+ console.log(`📝 Chiave pubblica pubblicata su GunDB`);
99350
+ return { success: true };
99351
+ }
99352
+ catch (error) {
99353
+ console.error("❌ Errore pubblicazione chiave:", error);
99354
+ return { success: false, error: error.message };
99355
+ }
99356
+ }
99357
+ // ========================================================================
99358
+ // 4. INVIO MESSAGGI: Solo GunDB
99359
+ // ========================================================================
99360
+ /**
99361
+ * Invia un messaggio crittografato a un altro utente
99362
+ */
99363
+ async sendMessage(recipientUsername, message) {
99364
+ try {
99365
+ if (!this.isLoggedIn()) {
99366
+ return { success: false, error: "Not logged in" };
99367
+ }
99368
+ const currentUser = this.shogun.db.user;
99369
+ if (!currentUser || !currentUser.is) {
99370
+ return { success: false, error: "No user session" };
99371
+ }
99372
+ // 1. Ottieni la chiave pubblica del destinatario
99373
+ const recipientKey = await this.getRecipientPublicKey(recipientUsername);
99374
+ if (!recipientKey) {
99375
+ return {
99376
+ success: false,
99377
+ error: `Recipient ${recipientUsername} has not published their public key`
99378
+ };
99379
+ }
99380
+ // 2. Ottieni il SEA pair completo (include chiavi private)
99381
+ const senderPair = this.shogun.db.gun.user()?._?.sea;
99382
+ if (!senderPair) {
99383
+ return { success: false, error: "Cannot access SEA pair" };
99384
+ }
99385
+ // 3. Cripta il messaggio usando SEA.secret + SEA.encrypt (ECDH)
99386
+ const encryptedMessage = await this.shogun.db.crypto.encFor(message, senderPair, // sender pair completo
99387
+ { epub: recipientKey.epub } // recipient public encryption key
99388
+ );
99389
+ // 4. Genera ID messaggio
99390
+ const messageId = this.generateMessageId();
99391
+ const senderPub = currentUser.is.pub;
99392
+ // 5. Salva messaggio crittografato su GunDB
99393
+ const messageData = {
99394
+ from: senderPub,
99395
+ to: recipientUsername,
99396
+ content: encryptedMessage, // Contenuto crittografato!
99397
+ timestamp: Date.now().toString(),
99398
+ messageId: messageId
99399
+ };
99400
+ // Salva sul nodo globale 'messages' per permettere il listener
99401
+ await this.shogun.db.gun.get('messages').get(messageId).put(messageData).then();
99402
+ console.log(`✅ Messaggio salvato: ${messageId}`);
99403
+ return {
99404
+ success: true,
99405
+ messageId: messageId
99406
+ };
99407
+ }
99408
+ catch (error) {
99409
+ return {
99410
+ success: false,
99411
+ error: error.message
99412
+ };
99413
+ }
99414
+ }
99415
+ /**
99416
+ * Ottiene la chiave pubblica di un utente da GunDB
99417
+ */
99418
+ async getRecipientPublicKey(username) {
99419
+ try {
99420
+ // Prima trova l'utente dal username
99421
+ const userData = await this.shogun.db.getUserByAlias(username);
99422
+ if (!userData || !userData.userPub) {
99423
+ console.error(`❌ User ${username} not found`);
99424
+ return null;
99425
+ }
99426
+ const userPub = userData.userPub;
99427
+ // Le chiavi sono salvate direttamente sul nodo userPub
99428
+ const publicKeyData = await this.shogun.db.gun.get(userPub).then();
99429
+ if (publicKeyData && publicKeyData.epub && publicKeyData.pub) {
99430
+ return {
99431
+ pub: publicKeyData.pub,
99432
+ epub: publicKeyData.epub
99433
+ };
99434
+ }
99435
+ return null;
99436
+ }
99437
+ catch (error) {
99438
+ console.error("❌ Errore recupero chiave pubblica:", error);
99439
+ return null;
99440
+ }
99441
+ }
99442
+ // ========================================================================
99443
+ // 5. RICEZIONE MESSAGGI: Ascolta GunDB in real-time
99444
+ // ========================================================================
99445
+ /**
99446
+ * Ascolta messaggi crittografati in arrivo su GunDB
99447
+ */
99448
+ async listenForMessages(onMessage) {
99449
+ if (!this.isLoggedIn()) {
99450
+ console.error("❌ Non autenticato");
99451
+ return;
99452
+ }
99453
+ const currentUser = this.shogun.db.user;
99454
+ if (!currentUser || !currentUser.is) {
99455
+ console.error("❌ Nessuna sessione utente");
99456
+ return;
99457
+ }
99458
+ const userPub = currentUser.is.pub;
99459
+ // Ottieni username dell'utente corrente
99460
+ const username = currentUser.is.alias;
99461
+ // Set per tracciare messaggi già ricevuti (evita duplicati)
99462
+ const receivedMessages = new Set();
99463
+ // Ascolta messaggi in tempo reale su GunDB
99464
+ this.shogun.db.gun
99465
+ .get(`messages`)
99466
+ .map()
99467
+ .on(async (data, key) => {
99468
+ // Filtra solo i messaggi destinati a questo utente (per username)
99469
+ if (data && data.to === username && data.from && data.content && data.messageId) {
99470
+ // Evita duplicati (GunDB può emettere più volte)
99471
+ if (receivedMessages.has(data.messageId)) {
99472
+ return;
99473
+ }
99474
+ receivedMessages.add(data.messageId);
99475
+ try {
99476
+ // Decripta il messaggio
99477
+ const decryptedContent = await this.decryptMessage(data.content, data.from);
99478
+ onMessage({
99479
+ from: data.from,
99480
+ content: decryptedContent,
99481
+ timestamp: parseInt(data.timestamp)
99482
+ });
99483
+ }
99484
+ catch (error) {
99485
+ console.error("❌ Errore decrittazione messaggio:", error);
99486
+ }
99487
+ }
99488
+ });
99489
+ console.log(`👂 In ascolto di messaggi per ${username} (${userPub.substring(0, 10)}...)`);
99490
+ }
99491
+ /**
99492
+ * Decripta un messaggio usando SEA.secret + SEA.decrypt (ECDH)
99493
+ */
99494
+ async decryptMessage(encryptedContent, senderPub) {
99495
+ // Ottieni il SEA pair completo del destinatario (noi)
99496
+ const receiverPair = this.shogun.db.gun.user()?._?.sea;
99497
+ if (!receiverPair) {
99498
+ throw new Error("Cannot access SEA pair");
99499
+ }
99500
+ // Ottieni epub del mittente
99501
+ const senderKey = await this.getPublicKeyByPub(senderPub);
99502
+ if (!senderKey) {
99503
+ throw new Error("Sender public key not found");
99504
+ }
99505
+ // Decripta usando SEA.secret + SEA.decrypt (ECDH)
99506
+ const decrypted = await this.shogun.db.crypto.decFrom(encryptedContent, { epub: senderKey.epub }, // sender's public encryption key
99507
+ receiverPair // receiver's pair completo
99508
+ );
99509
+ return decrypted;
99510
+ }
99511
+ /**
99512
+ * Ottiene la chiave pubblica di un utente dalla sua pub key
99513
+ */
99514
+ async getPublicKeyByPub(userPub) {
99515
+ try {
99516
+ // Le chiavi sono salvate direttamente sul nodo userPub
99517
+ const publicKeyData = await this.shogun.db.gun.get(userPub).then();
99518
+ if (publicKeyData && publicKeyData.epub && publicKeyData.pub) {
99519
+ return {
99520
+ pub: publicKeyData.pub,
99521
+ epub: publicKeyData.epub
99522
+ };
99523
+ }
99524
+ return null;
99525
+ }
99526
+ catch (error) {
99527
+ console.error("❌ Errore recupero chiave:", error);
99528
+ return null;
99529
+ }
99530
+ }
99531
+ // ========================================================================
99532
+ // 6. RECUPERO STORICO: Query messaggi passati
99533
+ // ========================================================================
99534
+ /**
99535
+ * Recupera lo storico dei messaggi crittografati con un utente
99536
+ */
99537
+ async getMessageHistory(withUsername) {
99538
+ if (!this.isLoggedIn()) {
99539
+ console.error("❌ Non autenticato");
99540
+ return [];
99541
+ }
99542
+ const currentUser = this.shogun.db.user;
99543
+ if (!currentUser || !currentUser.is) {
99544
+ console.error("❌ Nessuna sessione utente");
99545
+ return [];
99546
+ }
99547
+ const userPub = currentUser.is.pub;
99548
+ const username = currentUser.is.alias;
99549
+ const allMessages = [];
99550
+ // Ottieni il userPub dell'altro utente
99551
+ const otherUserData = await this.shogun.db.getUserByAlias(withUsername);
99552
+ const otherUserPub = otherUserData?.userPub;
99553
+ // Recupera tutti i messaggi dal nodo 'messages' e filtra
99554
+ const allMessagesNode = await this.shogun.db.gun.get('messages').then();
99555
+ if (allMessagesNode) {
99556
+ for (const [messageId, data] of Object.entries(allMessagesNode)) {
99557
+ if (typeof data === 'object' && data !== null) {
99558
+ const msgData = data;
99559
+ // Filtra messaggi tra questo utente e withUsername
99560
+ // Messaggi inviati da me a loro
99561
+ const isSentToTarget = msgData.from === userPub && msgData.to === withUsername;
99562
+ // Messaggi ricevuti da loro
99563
+ const isReceivedFromTarget = msgData.to === username &&
99564
+ (msgData.from === otherUserPub ||
99565
+ msgData.from);
99566
+ if ((isSentToTarget || isReceivedFromTarget) && msgData.content && msgData.messageId) {
99567
+ try {
99568
+ // Decripta ogni messaggio
99569
+ const decryptedContent = await this.decryptMessage(msgData.content, msgData.from);
99570
+ allMessages.push({
99571
+ from: msgData.from,
99572
+ to: msgData.to,
99573
+ content: decryptedContent,
99574
+ timestamp: parseInt(msgData.timestamp)
99575
+ });
99576
+ }
99577
+ catch (error) {
99578
+ console.error(`❌ Errore decrittazione messaggio ${messageId}:`, error);
99579
+ // Salta messaggi che non possono essere decriptati
99580
+ }
99581
+ }
99582
+ }
99583
+ }
99584
+ }
99585
+ // Ordina per timestamp
99586
+ return allMessages.sort((a, b) => a.timestamp - b.timestamp);
99587
+ }
99588
+ // ========================================================================
99589
+ // 7. UTILITY FUNCTIONS
99590
+ // ========================================================================
99591
+ /**
99592
+ * Converte la chiave pubblica di GunDB in address Ethereum
99593
+ * Usa la chiave privata SEA come seed per derivazione deterministica
99594
+ *
99595
+ * Questo garantisce che:
99596
+ * - Stesso SEA pair → stesso address Ethereum
99597
+ * - Derivazione cryptografica sicura
99598
+ * - Identità unificata tra GunDB e blockchain
99599
+ */
99600
+ async deriveEthereumAddress(publicKey) {
99601
+ try {
99602
+ // Ottieni il SEA pair completo
99603
+ const seaPair = this.shogun.db.gun.user()?._?.sea;
99604
+ if (!seaPair || !seaPair.priv) {
99605
+ throw new Error("Cannot access SEA pair");
99606
+ }
99607
+ // Usa la chiave privata SEA come seed per derive
99608
+ // Questo è MOLTO più sicuro e deterministico del username!
99609
+ const derived = await (0, derive_1.default)(seaPair.priv, null, {
99610
+ includeSecp256k1Ethereum: true,
99611
+ includeP256: false,
99612
+ includeSecp256k1Bitcoin: false
99613
+ });
99614
+ return derived.secp256k1Ethereum.address;
99615
+ }
99616
+ catch (error) {
99617
+ console.error("❌ Errore derivazione address:", error);
99618
+ // Fallback: hash della chiave pubblica
99619
+ const fallbackKey = publicKey || "unknown";
99620
+ const hash = ethers_1.ethers.keccak256(ethers_1.ethers.toUtf8Bytes(fallbackKey));
99621
+ return ethers_1.ethers.getAddress('0x' + hash.slice(-40));
99622
+ }
99623
+ }
99624
+ /**
99625
+ * Genera ID messaggio univoco
99626
+ */
99627
+ generateMessageId() {
99628
+ return ethers_1.ethers.hexlify(ethers_1.ethers.randomBytes(16));
99629
+ }
99630
+ }
99631
+ exports.SHIP_01 = SHIP_01;
99632
+ // ============================================================================
99633
+ // 8. ESEMPIO D'USO COMPLETO
99634
+ // ============================================================================
99635
+ // async function main() {
99636
+ // console.log("🚀 Secure Messaging App - Shogun Core + GunDB\n");
99637
+ // // 1. Inizializza il sistema
99638
+ // const app = new SHIP_01({
99639
+ // gunOptions: {
99640
+ // peers: ["https://relay.shogun-eco.xyz/gun","https://v5g5jseqhgkp43lppgregcfbvi.srv.us/gun","https://peer.wallie.io/gun"],
99641
+ // radisk: false,
99642
+ // localStorage:false,
99643
+ // }
99644
+ // });
99645
+ // // 2. Signup (prima volta)
99646
+ // console.log("📝 Registrazione nuovo utente...");
99647
+ // const signupResult = await app.signup("alice", "password123");
99648
+ // if (!signupResult.success) {
99649
+ // console.log("ℹ️ Utente già esistente, procedo con login");
99650
+ // } else {
99651
+ // console.log("✅ Utente registrato!");
99652
+ // console.log(` Username: alice`);
99653
+ // console.log(` Public Key: ${signupResult.userPub}`);
99654
+ // console.log(` Derived Address: ${signupResult.derivedAddress}\n`);
99655
+ // }
99656
+ // // 3. Login
99657
+ // console.log("🔐 Login...");
99658
+ // const loginResult = await app.login("alice", "password123");
99659
+ // if (!loginResult.success) {
99660
+ // console.error("❌ Login fallito:", loginResult.error);
99661
+ // return;
99662
+ // }
99663
+ // console.log("✅ Login effettuato!");
99664
+ // console.log(` - Autenticazione: Shogun Core (Username/Password)`);
99665
+ // console.log(` - Storage: GunDB decentralizzato P2P\n`);
99666
+ // // 4. Pubblica chiave pubblica
99667
+ // console.log("📢 Pubblicazione chiave pubblica...");
99668
+ // await app.publishPublicKey();
99669
+ // // 5. Ascolta messaggi in arrivo
99670
+ // console.log("\n👂 In ascolto di messaggi...\n");
99671
+ // await app.listenForMessages((message) => {
99672
+ // console.log(`📨 Nuovo messaggio da ${message.from.substring(0, 10)}...:`);
99673
+ // console.log(` Contenuto: ${message.content}`);
99674
+ // console.log(` Timestamp: ${new Date(message.timestamp).toLocaleString()}\n`);
99675
+ // });
99676
+ // // 6. Invia un messaggio
99677
+ // const recipientUsername = "bob";
99678
+ // console.log(`📤 Invio messaggio a ${recipientUsername}...`);
99679
+ // const result = await app.sendMessage(
99680
+ // recipientUsername,
99681
+ // "Hello Bob! This is a secure message using Shogun Core"
99682
+ // );
99683
+ // if (result.success) {
99684
+ // console.log("✅ Messaggio inviato!");
99685
+ // console.log(` Message ID: ${result.messageId}`);
99686
+ // console.log(` Storage: GunDB P2P (gratis!)`);
99687
+ // }
99688
+ // // 7. Recupera storico conversazione
99689
+ // console.log("\n📚 Recupero storico messaggi...");
99690
+ // const history = await app.getMessageHistory(recipientUsername);
99691
+ // console.log(`\n💬 Conversazione con ${recipientUsername} (${history.length} messaggi):`);
99692
+ // history.forEach((msg, i) => {
99693
+ // const isMe = msg.from === loginResult.userPub;
99694
+ // console.log(`${i + 1}. ${isMe ? 'Tu' : 'Loro'}: ${msg.content}`);
99695
+ // });
99696
+ // }
99697
+ // ============================================================================
99698
+ // 9. VANTAGGI DELL'ARCHITETTURA
99699
+ // ============================================================================
99700
+ /**
99701
+ * VANTAGGI DI QUESTA ARCHITETTURA:
99702
+ *
99703
+ * 1. SEMPLICITÀ:
99704
+ * - Solo username/password (nessun wallet necessario)
99705
+ * - Nessun gas fee o transazioni blockchain
99706
+ * - Setup in pochi secondi
99707
+ *
99708
+ * 2. DECENTRALIZZAZIONE COMPLETA:
99709
+ * - Storage P2P su GunDB
99710
+ * - Nessun server centrale
99711
+ * - Censorship resistant
99712
+ * - User sovereignty
99713
+ *
99714
+ * 3. COSTI ZERO:
99715
+ * - Nessun costo per messaggi
99716
+ * - Nessun costo per storage
99717
+ * - Completamente gratis
99718
+ *
99719
+ * 4. END-TO-END ENCRYPTION:
99720
+ * - Messaggi crittografati con ECDH (Elliptic Curve Diffie-Hellman)
99721
+ * - SEA.secret deriva shared secret da epub (encryption public key)
99722
+ * - SEA.encrypt cripta con AES-GCM
99723
+ * - Solo mittente e destinatario possono leggere i messaggi
99724
+ * - Nessun server o relay può leggere il contenuto
99725
+ *
99726
+ * 5. IDENTITÀ DECENTRALIZZATA:
99727
+ * - Chiave pubblica GunDB come identità
99728
+ * - Può essere derivata in address Ethereum se necessario
99729
+ * - Portabile tra diverse applicazioni
99730
+ *
99731
+ * 6. REAL-TIME:
99732
+ * - Messaggi in tempo reale
99733
+ * - Sincronizzazione automatica
99734
+ * - Listener reattivi
99735
+ *
99736
+ * 7. OFFLINE-FIRST:
99737
+ * - Funziona anche offline
99738
+ * - Sincronizzazione automatica al riconnect
99739
+ * - GunDB gestisce conflitti automaticamente
99740
+ *
99741
+ * COME FUNZIONA LA CRITTOGRAFIA:
99742
+ *
99743
+ * 1. SETUP - Ogni utente ha un SEA pair:
99744
+ * - pub: chiave pubblica di signing
99745
+ * - priv: chiave privata di signing
99746
+ * - epub: chiave pubblica di encryption (per ECDH)
99747
+ * - epriv: chiave privata di encryption (per ECDH)
99748
+ *
99749
+ * 2. PUBBLICAZIONE CHIAVI:
99750
+ * - Ogni utente pubblica il suo epub su GunDB
99751
+ * - Altri possono trovarlo per criptare messaggi
99752
+ *
99753
+ * 3. INVIO MESSAGGIO (Alice → Bob):
99754
+ * a) Alice ottiene l'epub di Bob da GunDB
99755
+ * b) SEA.secret(bob.epub, alice.pair) → shared_secret (ECDH)
99756
+ * c) SEA.encrypt(message, shared_secret) → encrypted_message
99757
+ * d) Alice salva encrypted_message su GunDB
99758
+ *
99759
+ * 4. RICEZIONE MESSAGGIO (Bob riceve):
99760
+ * a) Bob legge encrypted_message da GunDB
99761
+ * b) Bob ottiene l'epub di Alice
99762
+ * c) SEA.secret(alice.epub, bob.pair) → shared_secret (stesso!)
99763
+ * d) SEA.decrypt(encrypted_message, shared_secret) → message
99764
+ *
99765
+ * 5. SICUREZZA:
99766
+ * - Shared secret derivato con ECDH (mai trasmesso)
99767
+ * - Solo Alice e Bob possono derivare lo stesso secret
99768
+ * - Messaggi crittografati con AES-256-GCM
99769
+ * - Forward secrecy se chiavi sono ruotate
99770
+ *
99771
+ * Esempio tecnico:
99772
+ * Alice.epub + Bob.epriv → shared_secret_AB
99773
+ * Bob.epub + Alice.epriv → shared_secret_AB (stesso!)
99774
+ *
99775
+ * Vantaggi:
99776
+ * ✅ End-to-end encryption
99777
+ * ✅ Perfect forward secrecy (con key rotation)
99778
+ * ✅ Nessun server può leggere i messaggi
99779
+ * ✅ Standard crittografico (ECDH + AES-GCM)
99780
+ * ✅ Una sola chiave privata da gestire
99781
+ * ✅ Address Ethereum derivabile (interoperabilità)
99782
+ */
99783
+ // ============================================================================
99784
+ // 10. TEST COMPLETO: Alice e Bob si scambiano messaggi
99785
+ // ============================================================================
99786
+ /**
99787
+ * Test completo che simula Alice e Bob che si scambiano messaggi CRITTOGRAFATI
99788
+ *
99789
+ * CRITTOGRAFIA END-TO-END:
99790
+ * - Ogni messaggio è crittografato con ECDH (Elliptic Curve Diffie-Hellman)
99791
+ * - Solo mittente e destinatario possono leggere i messaggi
99792
+ * - I relay GunDB vedono solo dati crittografati
99793
+ *
99794
+ * FLOW:
99795
+ * 1. Alice e Bob pubblicano le loro chiavi pubbliche (epub)
99796
+ * 2. Alice vuole inviare a Bob:
99797
+ * - Ottiene bob.epub da GunDB
99798
+ * - SEA.secret(bob.epub, alice.pair) → shared_secret
99799
+ * - SEA.encrypt(message, shared_secret) → encrypted
99800
+ * - Salva encrypted su GunDB
99801
+ * 3. Bob riceve:
99802
+ * - Legge encrypted da GunDB
99803
+ * - Ottiene alice.epub
99804
+ * - SEA.secret(alice.epub, bob.pair) → shared_secret (stesso!)
99805
+ * - SEA.decrypt(encrypted, shared_secret) → message
99806
+ */
99807
+ async function testAliceAndBob() {
99808
+ console.log("🧪 TEST: Alice e Bob - Conversazione Crittografata E2E\n");
99809
+ console.log("=".repeat(60));
99810
+ // Setup Alice
99811
+ console.log("\n👩 ALICE - Setup");
99812
+ console.log("-".repeat(60));
99813
+ const alice = new SHIP_01({
99814
+ gunOptions: {
99815
+ peers: ["https://peer.wallie.io/gun"],
99816
+ radisk: true,
99817
+ },
99818
+ });
99819
+ // Alice signup/login
99820
+ await alice.signup("alice", "password123");
99821
+ const aliceLogin = await alice.login("alice", "password123");
99822
+ if (!aliceLogin.success) {
99823
+ console.error("❌ Alice login failed");
99824
+ return;
99825
+ }
99826
+ await alice.publishPublicKey();
99827
+ // Aspetta che la chiave sia sincronizzata
99828
+ await new Promise(resolve => setTimeout(resolve, 1000));
99829
+ // Setup Bob
99830
+ console.log("\n👨 BOB - Setup");
99831
+ console.log("-".repeat(60));
99832
+ const bob = new SHIP_01({
99833
+ gunOptions: {
99834
+ peers: ["https://peer.wallie.io/gun"],
99835
+ radisk: true
99836
+ },
99837
+ });
99838
+ // Bob signup/login
99839
+ await bob.signup("bob", "password456");
99840
+ const bobLogin = await bob.login("bob", "password456");
99841
+ if (!bobLogin.success) {
99842
+ console.error("❌ Bob login failed");
99843
+ return;
99844
+ }
99845
+ await bob.publishPublicKey();
99846
+ // Aspetta che la chiave sia sincronizzata
99847
+ await new Promise(resolve => setTimeout(resolve, 1000));
99848
+ console.log("\n" + "=".repeat(60));
99849
+ console.log("💬 CONVERSAZIONE");
99850
+ console.log("=".repeat(60));
99851
+ // Alice e Bob ascoltano messaggi
99852
+ let aliceMessages = [];
99853
+ let bobMessages = [];
99854
+ await alice.listenForMessages((msg) => {
99855
+ aliceMessages.push(msg);
99856
+ console.log(`\n[Alice riceve] 📨`);
99857
+ console.log(` Da: ${msg.from.substring(0, 10)}...`);
99858
+ console.log(` Messaggio: "${msg.content}"`);
99859
+ console.log(` Timestamp: ${new Date(msg.timestamp).toLocaleTimeString()}`);
99860
+ });
99861
+ await bob.listenForMessages((msg) => {
99862
+ bobMessages.push(msg);
99863
+ console.log(`\n[Bob riceve] 📨`);
99864
+ console.log(` Da: ${msg.from.substring(0, 10)}...`);
99865
+ console.log(` Messaggio: "${msg.content}"`);
99866
+ console.log(` Timestamp: ${new Date(msg.timestamp).toLocaleTimeString()}`);
99867
+ });
99868
+ // Aspetta che i listener siano pronti
99869
+ await new Promise(resolve => setTimeout(resolve, 2000));
99870
+ // Alice invia messaggio a Bob
99871
+ console.log("\n[Alice invia] 📤");
99872
+ const msg1 = await alice.sendMessage("bob", "Ciao Bob! Come stai? 👋");
99873
+ console.log(` ✅ Inviato: "${msg1.messageId}"`);
99874
+ // Aspetta che Bob riceva
99875
+ await new Promise(resolve => setTimeout(resolve, 2000));
99876
+ // Bob risponde ad Alice
99877
+ console.log("\n[Bob invia] 📤");
99878
+ const msg2 = await bob.sendMessage("alice", "Ciao Alice! Tutto bene, grazie! Tu? 😊");
99879
+ console.log(` ✅ Inviato: "${msg2.messageId}"`);
99880
+ // Aspetta che Alice riceva
99881
+ await new Promise(resolve => setTimeout(resolve, 2000));
99882
+ // Alice risponde
99883
+ console.log("\n[Alice invia] 📤");
99884
+ const msg3 = await alice.sendMessage("bob", "Anch'io benissimo! Questo sistema di messaggistica è fantastico! 🚀");
99885
+ console.log(` ✅ Inviato: "${msg3.messageId}"`);
99886
+ // Aspetta che Bob riceva
99887
+ await new Promise(resolve => setTimeout(resolve, 2000));
99888
+ // Bob conclude
99889
+ console.log("\n[Bob invia] 📤");
99890
+ const msg4 = await bob.sendMessage("alice", "Vero! Zero costi, decentralizzato e veloce! 💪");
99891
+ console.log(` ✅ Inviato: "${msg4.messageId}"`);
99892
+ // Aspetta finale
99893
+ await new Promise(resolve => setTimeout(resolve, 3000));
99894
+ // Mostra statistiche
99895
+ console.log("\n" + "=".repeat(60));
99896
+ console.log("📊 STATISTICHE FINALI");
99897
+ console.log("=".repeat(60));
99898
+ console.log(`\n👩 Alice:`);
99899
+ console.log(` - Messaggi inviati: 2`);
99900
+ console.log(` - Messaggi ricevuti: ${aliceMessages.length}`);
99901
+ console.log(` - Public Key: ${aliceLogin.userPub?.substring(0, 20)}...`);
99902
+ console.log(` - Derived Address: ${aliceLogin.derivedAddress}`);
99903
+ console.log(`\n👨 Bob:`);
99904
+ console.log(` - Messaggi inviati: 2`);
99905
+ console.log(` - Messaggi ricevuti: ${bobMessages.length}`);
99906
+ console.log(` - Public Key: ${bobLogin.userPub?.substring(0, 20)}...`);
99907
+ console.log(` - Derived Address: ${bobLogin.derivedAddress}`);
99908
+ // Recupera storico
99909
+ console.log("\n" + "=".repeat(60));
99910
+ console.log("📚 STORICO CONVERSAZIONE");
99911
+ console.log("=".repeat(60));
99912
+ const aliceHistory = await alice.getMessageHistory("bob");
99913
+ console.log(`\n👩 Storico di Alice con Bob (${aliceHistory.length} messaggi):`);
99914
+ aliceHistory.forEach((msg, i) => {
99915
+ const sender = msg.from === aliceLogin.userPub ? "Alice" : "Bob";
99916
+ console.log(` ${i + 1}. [${sender}]: ${msg.content}`);
99917
+ });
99918
+ const bobHistory = await bob.getMessageHistory("alice");
99919
+ console.log(`\n👨 Storico di Bob con Alice (${bobHistory.length} messaggi):`);
99920
+ bobHistory.forEach((msg, i) => {
99921
+ const sender = msg.from === bobLogin.userPub ? "Bob" : "Alice";
99922
+ console.log(` ${i + 1}. [${sender}]: ${msg.content}`);
99923
+ });
99924
+ // Riepilogo finale
99925
+ console.log("\n" + "=".repeat(60));
99926
+ console.log("✅ TEST COMPLETATO CON SUCCESSO!");
99927
+ console.log("=".repeat(60));
99928
+ console.log("\n📝 Riepilogo:");
99929
+ console.log(" ✅ 2 utenti registrati (Alice, Bob)");
99930
+ console.log(" ✅ 4 messaggi scambiati");
99931
+ console.log(" ✅ Messaggi ricevuti in real-time");
99932
+ console.log(" ✅ Storico recuperato correttamente");
99933
+ console.log(" ✅ Storage: GunDB P2P (gratis!)");
99934
+ console.log(" ✅ Costi: $0.00");
99935
+ console.log("\n🎉 Sistema di messaggistica decentralizzato funzionante!\n");
99936
+ }
99937
+ // Esegui esempio o test
99938
+ if (__webpack_require__.c[__webpack_require__.s] === module) {
99939
+ // Scegli quale eseguire decommentando una delle due righe:
99940
+ // main().catch(console.error); // Esempio singolo utente
99941
+ testAliceAndBob().catch(console.error); // Test completo Alice & Bob
99942
+ }
99943
+
99944
+
98488
99945
  /***/ }),
98489
99946
 
98490
99947
  /***/ "./src/config/simplified-config.ts":
@@ -101230,8 +102687,8 @@ class DataBase {
101230
102687
  username: username,
101231
102688
  userPub: userPub,
101232
102689
  epub: epub,
101233
- registeredAt: Date.now(),
101234
- lastSeen: Date.now(),
102690
+ registeredAt: Date.now().toString(),
102691
+ lastSeen: Date.now().toString(),
101235
102692
  };
101236
102693
  const ack = await this.node
101237
102694
  .get("users")
@@ -102820,7 +104277,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
102820
104277
  return (mod && mod.__esModule) ? mod : { "default": mod };
102821
104278
  };
102822
104279
  Object.defineProperty(exports, "__esModule", ({ value: true }));
102823
- exports.autoQuickStart = exports.AutoQuickStart = exports.createSimpleAPI = exports.quickStart = exports.QuickStart = exports.SimpleGunAPI = exports.DataBase = exports.GunErrors = exports.derive = exports.crypto = exports.RxJS = exports.SEA = exports.ShogunCore = exports.Gun = void 0;
104280
+ exports.autoQuickStart = exports.AutoQuickStart = exports.createSimpleAPI = exports.quickStart = exports.QuickStart = exports.SimpleGunAPI = exports.DataBase = exports.GunErrors = exports.derive = exports.crypto = exports.RxJS = exports.SEA = exports.ShogunCore = exports.Gun = exports.MessengerCLI = exports.SHIP_01 = void 0;
102824
104281
  const core_1 = __webpack_require__(/*! ./core */ "./src/core.ts");
102825
104282
  Object.defineProperty(exports, "ShogunCore", ({ enumerable: true, get: function () { return core_1.ShogunCore; } }));
102826
104283
  const db_1 = __webpack_require__(/*! ./gundb/db */ "./src/gundb/db.ts");
@@ -102844,8 +104301,13 @@ exports.Gun = db_3.default;
102844
104301
  __exportStar(__webpack_require__(/*! ./utils/errorHandler */ "./src/utils/errorHandler.ts"), exports);
102845
104302
  __exportStar(__webpack_require__(/*! ./plugins */ "./src/plugins/index.ts"), exports);
102846
104303
  __exportStar(__webpack_require__(/*! ./interfaces/shogun */ "./src/interfaces/shogun.ts"), exports);
102847
- // Export simplified configuration
102848
104304
  __exportStar(__webpack_require__(/*! ./config/simplified-config */ "./src/config/simplified-config.ts"), exports);
104305
+ var SHIP_01_1 = __webpack_require__(/*! ../ship/implementation/SHIP_01 */ "./ship/implementation/SHIP_01.ts");
104306
+ Object.defineProperty(exports, "SHIP_01", ({ enumerable: true, get: function () { return SHIP_01_1.SHIP_01; } }));
104307
+ // Export MessengerCLI only in Node.js environment (not browser)
104308
+ // This prevents "readline is not a function" errors in browser builds
104309
+ var messenger_cli_1 = __webpack_require__(/*! ../ship/examples/messenger-cli */ "./ship/examples/messenger-cli.ts");
104310
+ Object.defineProperty(exports, "MessengerCLI", ({ enumerable: true, get: function () { return messenger_cli_1.MessengerCLI; } }));
102849
104311
 
102850
104312
 
102851
104313
  /***/ }),
@@ -109640,7 +111102,43 @@ function generateDeterministicPassword(salt) {
109640
111102
  /******/ return module.exports;
109641
111103
  /******/ }
109642
111104
  /******/
111105
+ /******/ // expose the modules object (__webpack_modules__)
111106
+ /******/ __webpack_require__.m = __webpack_modules__;
111107
+ /******/
111108
+ /******/ // expose the module cache
111109
+ /******/ __webpack_require__.c = __webpack_module_cache__;
111110
+ /******/
109643
111111
  /************************************************************************/
111112
+ /******/ /* webpack/runtime/create fake namespace object */
111113
+ /******/ (() => {
111114
+ /******/ var getProto = Object.getPrototypeOf ? (obj) => (Object.getPrototypeOf(obj)) : (obj) => (obj.__proto__);
111115
+ /******/ var leafPrototypes;
111116
+ /******/ // create a fake namespace object
111117
+ /******/ // mode & 1: value is a module id, require it
111118
+ /******/ // mode & 2: merge all properties of value into the ns
111119
+ /******/ // mode & 4: return value when already ns object
111120
+ /******/ // mode & 16: return value when it's Promise-like
111121
+ /******/ // mode & 8|1: behave like require
111122
+ /******/ __webpack_require__.t = function(value, mode) {
111123
+ /******/ if(mode & 1) value = this(value);
111124
+ /******/ if(mode & 8) return value;
111125
+ /******/ if(typeof value === 'object' && value) {
111126
+ /******/ if((mode & 4) && value.__esModule) return value;
111127
+ /******/ if((mode & 16) && typeof value.then === 'function') return value;
111128
+ /******/ }
111129
+ /******/ var ns = Object.create(null);
111130
+ /******/ __webpack_require__.r(ns);
111131
+ /******/ var def = {};
111132
+ /******/ leafPrototypes = leafPrototypes || [null, getProto({}), getProto([]), getProto(getProto)];
111133
+ /******/ for(var current = mode & 2 && value; (typeof current == 'object' || typeof current == 'function') && !~leafPrototypes.indexOf(current); current = getProto(current)) {
111134
+ /******/ Object.getOwnPropertyNames(current).forEach((key) => (def[key] = () => (value[key])));
111135
+ /******/ }
111136
+ /******/ def['default'] = () => (value);
111137
+ /******/ __webpack_require__.d(ns, def);
111138
+ /******/ return ns;
111139
+ /******/ };
111140
+ /******/ })();
111141
+ /******/
109644
111142
  /******/ /* webpack/runtime/define property getters */
109645
111143
  /******/ (() => {
109646
111144
  /******/ // define getter functions for harmony exports
@@ -109653,6 +111151,28 @@ function generateDeterministicPassword(salt) {
109653
111151
  /******/ };
109654
111152
  /******/ })();
109655
111153
  /******/
111154
+ /******/ /* webpack/runtime/ensure chunk */
111155
+ /******/ (() => {
111156
+ /******/ __webpack_require__.f = {};
111157
+ /******/ // This file contains only the entry chunk.
111158
+ /******/ // The chunk loading function for additional chunks
111159
+ /******/ __webpack_require__.e = (chunkId) => {
111160
+ /******/ return Promise.all(Object.keys(__webpack_require__.f).reduce((promises, key) => {
111161
+ /******/ __webpack_require__.f[key](chunkId, promises);
111162
+ /******/ return promises;
111163
+ /******/ }, []));
111164
+ /******/ };
111165
+ /******/ })();
111166
+ /******/
111167
+ /******/ /* webpack/runtime/get javascript chunk filename */
111168
+ /******/ (() => {
111169
+ /******/ // This function allow to reference async chunks
111170
+ /******/ __webpack_require__.u = (chunkId) => {
111171
+ /******/ // return url for filenames based on template
111172
+ /******/ return "" + chunkId + ".shogun-core.js";
111173
+ /******/ };
111174
+ /******/ })();
111175
+ /******/
109656
111176
  /******/ /* webpack/runtime/global */
109657
111177
  /******/ (() => {
109658
111178
  /******/ __webpack_require__.g = (function() {
@@ -109670,6 +111190,52 @@ function generateDeterministicPassword(salt) {
109670
111190
  /******/ __webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop))
109671
111191
  /******/ })();
109672
111192
  /******/
111193
+ /******/ /* webpack/runtime/load script */
111194
+ /******/ (() => {
111195
+ /******/ var inProgress = {};
111196
+ /******/ var dataWebpackPrefix = "ShogunCore:";
111197
+ /******/ // loadScript function to load a script via script tag
111198
+ /******/ __webpack_require__.l = (url, done, key, chunkId) => {
111199
+ /******/ if(inProgress[url]) { inProgress[url].push(done); return; }
111200
+ /******/ var script, needAttach;
111201
+ /******/ if(key !== undefined) {
111202
+ /******/ var scripts = document.getElementsByTagName("script");
111203
+ /******/ for(var i = 0; i < scripts.length; i++) {
111204
+ /******/ var s = scripts[i];
111205
+ /******/ if(s.getAttribute("src") == url || s.getAttribute("data-webpack") == dataWebpackPrefix + key) { script = s; break; }
111206
+ /******/ }
111207
+ /******/ }
111208
+ /******/ if(!script) {
111209
+ /******/ needAttach = true;
111210
+ /******/ script = document.createElement('script');
111211
+ /******/
111212
+ /******/ script.charset = 'utf-8';
111213
+ /******/ script.timeout = 120;
111214
+ /******/ if (__webpack_require__.nc) {
111215
+ /******/ script.setAttribute("nonce", __webpack_require__.nc);
111216
+ /******/ }
111217
+ /******/ script.setAttribute("data-webpack", dataWebpackPrefix + key);
111218
+ /******/
111219
+ /******/ script.src = url;
111220
+ /******/ }
111221
+ /******/ inProgress[url] = [done];
111222
+ /******/ var onScriptComplete = (prev, event) => {
111223
+ /******/ // avoid mem leaks in IE.
111224
+ /******/ script.onerror = script.onload = null;
111225
+ /******/ clearTimeout(timeout);
111226
+ /******/ var doneFns = inProgress[url];
111227
+ /******/ delete inProgress[url];
111228
+ /******/ script.parentNode && script.parentNode.removeChild(script);
111229
+ /******/ doneFns && doneFns.forEach((fn) => (fn(event)));
111230
+ /******/ if(prev) return prev(event);
111231
+ /******/ }
111232
+ /******/ var timeout = setTimeout(onScriptComplete.bind(null, undefined, { type: 'timeout', target: script }), 120000);
111233
+ /******/ script.onerror = onScriptComplete.bind(null, script.onerror);
111234
+ /******/ script.onload = onScriptComplete.bind(null, script.onload);
111235
+ /******/ needAttach && document.head.appendChild(script);
111236
+ /******/ };
111237
+ /******/ })();
111238
+ /******/
109673
111239
  /******/ /* webpack/runtime/make namespace object */
109674
111240
  /******/ (() => {
109675
111241
  /******/ // define __esModule on exports
@@ -109690,12 +111256,125 @@ function generateDeterministicPassword(salt) {
109690
111256
  /******/ };
109691
111257
  /******/ })();
109692
111258
  /******/
111259
+ /******/ /* webpack/runtime/publicPath */
111260
+ /******/ (() => {
111261
+ /******/ var scriptUrl;
111262
+ /******/ if (__webpack_require__.g.importScripts) scriptUrl = __webpack_require__.g.location + "";
111263
+ /******/ var document = __webpack_require__.g.document;
111264
+ /******/ if (!scriptUrl && document) {
111265
+ /******/ if (document.currentScript && document.currentScript.tagName.toUpperCase() === 'SCRIPT')
111266
+ /******/ scriptUrl = document.currentScript.src;
111267
+ /******/ if (!scriptUrl) {
111268
+ /******/ var scripts = document.getElementsByTagName("script");
111269
+ /******/ if(scripts.length) {
111270
+ /******/ var i = scripts.length - 1;
111271
+ /******/ while (i > -1 && (!scriptUrl || !/^http(s?):/.test(scriptUrl))) scriptUrl = scripts[i--].src;
111272
+ /******/ }
111273
+ /******/ }
111274
+ /******/ }
111275
+ /******/ // When supporting browsers where an automatic publicPath is not supported you must specify an output.publicPath manually via configuration
111276
+ /******/ // or pass an empty string ("") and set the __webpack_public_path__ variable from your code to use your own logic.
111277
+ /******/ if (!scriptUrl) throw new Error("Automatic publicPath is not supported in this browser");
111278
+ /******/ scriptUrl = scriptUrl.replace(/^blob:/, "").replace(/#.*$/, "").replace(/\?.*$/, "").replace(/\/[^\/]+$/, "/");
111279
+ /******/ __webpack_require__.p = scriptUrl;
111280
+ /******/ })();
111281
+ /******/
111282
+ /******/ /* webpack/runtime/jsonp chunk loading */
111283
+ /******/ (() => {
111284
+ /******/ // no baseURI
111285
+ /******/
111286
+ /******/ // object to store loaded and loading chunks
111287
+ /******/ // undefined = chunk not loaded, null = chunk preloaded/prefetched
111288
+ /******/ // [resolve, reject, Promise] = chunk loading, 0 = chunk loaded
111289
+ /******/ var installedChunks = {
111290
+ /******/ "main": 0
111291
+ /******/ };
111292
+ /******/
111293
+ /******/ __webpack_require__.f.j = (chunkId, promises) => {
111294
+ /******/ // JSONP chunk loading for javascript
111295
+ /******/ var installedChunkData = __webpack_require__.o(installedChunks, chunkId) ? installedChunks[chunkId] : undefined;
111296
+ /******/ if(installedChunkData !== 0) { // 0 means "already installed".
111297
+ /******/
111298
+ /******/ // a Promise means "currently loading".
111299
+ /******/ if(installedChunkData) {
111300
+ /******/ promises.push(installedChunkData[2]);
111301
+ /******/ } else {
111302
+ /******/ if(true) { // all chunks have JS
111303
+ /******/ // setup Promise in chunk cache
111304
+ /******/ var promise = new Promise((resolve, reject) => (installedChunkData = installedChunks[chunkId] = [resolve, reject]));
111305
+ /******/ promises.push(installedChunkData[2] = promise);
111306
+ /******/
111307
+ /******/ // start chunk loading
111308
+ /******/ var url = __webpack_require__.p + __webpack_require__.u(chunkId);
111309
+ /******/ // create error before stack unwound to get useful stacktrace later
111310
+ /******/ var error = new Error();
111311
+ /******/ var loadingEnded = (event) => {
111312
+ /******/ if(__webpack_require__.o(installedChunks, chunkId)) {
111313
+ /******/ installedChunkData = installedChunks[chunkId];
111314
+ /******/ if(installedChunkData !== 0) installedChunks[chunkId] = undefined;
111315
+ /******/ if(installedChunkData) {
111316
+ /******/ var errorType = event && (event.type === 'load' ? 'missing' : event.type);
111317
+ /******/ var realSrc = event && event.target && event.target.src;
111318
+ /******/ error.message = 'Loading chunk ' + chunkId + ' failed.\n(' + errorType + ': ' + realSrc + ')';
111319
+ /******/ error.name = 'ChunkLoadError';
111320
+ /******/ error.type = errorType;
111321
+ /******/ error.request = realSrc;
111322
+ /******/ installedChunkData[1](error);
111323
+ /******/ }
111324
+ /******/ }
111325
+ /******/ };
111326
+ /******/ __webpack_require__.l(url, loadingEnded, "chunk-" + chunkId, chunkId);
111327
+ /******/ }
111328
+ /******/ }
111329
+ /******/ }
111330
+ /******/ };
111331
+ /******/
111332
+ /******/ // no prefetching
111333
+ /******/
111334
+ /******/ // no preloaded
111335
+ /******/
111336
+ /******/ // no HMR
111337
+ /******/
111338
+ /******/ // no HMR manifest
111339
+ /******/
111340
+ /******/ // no on chunks loaded
111341
+ /******/
111342
+ /******/ // install a JSONP callback for chunk loading
111343
+ /******/ var webpackJsonpCallback = (parentChunkLoadingFunction, data) => {
111344
+ /******/ var [chunkIds, moreModules, runtime] = data;
111345
+ /******/ // add "moreModules" to the modules object,
111346
+ /******/ // then flag all "chunkIds" as loaded and fire callback
111347
+ /******/ var moduleId, chunkId, i = 0;
111348
+ /******/ if(chunkIds.some((id) => (installedChunks[id] !== 0))) {
111349
+ /******/ for(moduleId in moreModules) {
111350
+ /******/ if(__webpack_require__.o(moreModules, moduleId)) {
111351
+ /******/ __webpack_require__.m[moduleId] = moreModules[moduleId];
111352
+ /******/ }
111353
+ /******/ }
111354
+ /******/ if(runtime) var result = runtime(__webpack_require__);
111355
+ /******/ }
111356
+ /******/ if(parentChunkLoadingFunction) parentChunkLoadingFunction(data);
111357
+ /******/ for(;i < chunkIds.length; i++) {
111358
+ /******/ chunkId = chunkIds[i];
111359
+ /******/ if(__webpack_require__.o(installedChunks, chunkId) && installedChunks[chunkId]) {
111360
+ /******/ installedChunks[chunkId][0]();
111361
+ /******/ }
111362
+ /******/ installedChunks[chunkId] = 0;
111363
+ /******/ }
111364
+ /******/
111365
+ /******/ }
111366
+ /******/
111367
+ /******/ var chunkLoadingGlobal = this["webpackChunkShogunCore"] = this["webpackChunkShogunCore"] || [];
111368
+ /******/ chunkLoadingGlobal.forEach(webpackJsonpCallback.bind(null, 0));
111369
+ /******/ chunkLoadingGlobal.push = webpackJsonpCallback.bind(null, chunkLoadingGlobal.push.bind(chunkLoadingGlobal));
111370
+ /******/ })();
111371
+ /******/
109693
111372
  /************************************************************************/
109694
111373
  /******/
111374
+ /******/ // module cache are used so entry inlining is disabled
109695
111375
  /******/ // startup
109696
111376
  /******/ // Load entry module and return exports
109697
- /******/ // This entry module is referenced by other modules so it can't be inlined
109698
- /******/ var __webpack_exports__ = __webpack_require__("./src/index.ts");
111377
+ /******/ var __webpack_exports__ = __webpack_require__(__webpack_require__.s = "./src/index.ts");
109699
111378
  /******/
109700
111379
  /******/ return __webpack_exports__;
109701
111380
  /******/ })()