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
@@ -0,0 +1,803 @@
1
+ "use strict";
2
+ /**
3
+ * Esempio Pratico: Messaggistica Decentralizzata con Shogun Core
4
+ *
5
+ * Questo esempio mostra come creare un sistema di messaggistica sicuro usando:
6
+ * - Shogun Core per autenticazione (username/password)
7
+ * - GunDB per storage decentralizzato P2P
8
+ * - SEA (Security, Encryption, Authorization) per crittografia
9
+ *
10
+ * Vantaggi:
11
+ * ✅ Completamente decentralizzato (no server centrale)
12
+ * ✅ Zero costi (no blockchain, no gas fees)
13
+ * ✅ Real-time messaging
14
+ * ✅ Offline-first
15
+ * ✅ End-to-end encryption
16
+ *
17
+ * Note sull'ERC7627:
18
+ * L'EIP era un template concettuale. Questo esempio implementa
19
+ * solo la parte GunDB/Shogun Core senza interazione blockchain.
20
+ * La funzione deriveEthereumAddress() rimane come utility per derivare
21
+ * un address Ethereum dalla chiave GunDB se necessario in futuro.
22
+ */
23
+ var __importDefault = (this && this.__importDefault) || function (mod) {
24
+ return (mod && mod.__esModule) ? mod : { "default": mod };
25
+ };
26
+ Object.defineProperty(exports, "__esModule", { value: true });
27
+ exports.SHIP_01 = void 0;
28
+ const core_1 = require("../../src/core");
29
+ const ethers_1 = require("ethers");
30
+ const derive_1 = __importDefault(require("../../src/gundb/derive"));
31
+ // ============================================================================
32
+ // 1. SETUP: Inizializzazione del Sistema Completo
33
+ // ============================================================================
34
+ /**
35
+ * Classe per messaggistica sicura con Shogun Core
36
+ * Implementa l'interfaccia ISHIP_01
37
+ * Usa solo GunDB per storage decentralizzato (no blockchain)
38
+ */
39
+ class SHIP_01 {
40
+ constructor(shogunConfig) {
41
+ // Inizializza Shogun Core
42
+ this.shogun = new core_1.ShogunCore(shogunConfig);
43
+ }
44
+ // ========================================================================
45
+ // 2. AUTENTICAZIONE: Username e Password
46
+ // ========================================================================
47
+ /**
48
+ * Registra un nuovo utente
49
+ */
50
+ async signup(username, password) {
51
+ try {
52
+ // Registra con Shogun Core (crea SEA pair automaticamente)
53
+ const signupResult = await this.shogun.signUp(username, password);
54
+ if (!signupResult.success) {
55
+ return {
56
+ success: false,
57
+ error: signupResult.error || "Signup failed"
58
+ };
59
+ }
60
+ console.log("✅ Utente registrato");
61
+ console.log(` Username: ${username}`);
62
+ console.log(` GunDB Public Key: ${signupResult.pub}`);
63
+ // Opzionale: deriva address Ethereum dalla chiave GunDB
64
+ const derivedAddress = signupResult.pub
65
+ ? await this.deriveEthereumAddress(signupResult.pub)
66
+ : undefined;
67
+ if (derivedAddress) {
68
+ console.log(` Derived Address: ${derivedAddress}`);
69
+ }
70
+ return {
71
+ success: true,
72
+ userPub: signupResult.pub,
73
+ derivedAddress
74
+ };
75
+ }
76
+ catch (error) {
77
+ return {
78
+ success: false,
79
+ error: error.message
80
+ };
81
+ }
82
+ }
83
+ /**
84
+ * Login con username e password
85
+ */
86
+ async login(username, password) {
87
+ try {
88
+ // Login con Shogun Core
89
+ const loginResult = await this.shogun.login(username, password);
90
+ if (!loginResult.success) {
91
+ return {
92
+ success: false,
93
+ error: loginResult.error || "Login failed"
94
+ };
95
+ }
96
+ console.log("✅ Login effettuato");
97
+ console.log(` Username: ${username}`);
98
+ console.log(` GunDB Public Key: ${loginResult.userPub}`);
99
+ // Opzionale: deriva address Ethereum dalla chiave GunDB
100
+ const derivedAddress = loginResult.userPub
101
+ ? await this.deriveEthereumAddress(loginResult.userPub)
102
+ : undefined;
103
+ if (derivedAddress) {
104
+ console.log(` Derived Address: ${derivedAddress}`);
105
+ }
106
+ return {
107
+ success: true,
108
+ userPub: loginResult.userPub,
109
+ derivedAddress
110
+ };
111
+ }
112
+ catch (error) {
113
+ return {
114
+ success: false,
115
+ error: error.message
116
+ };
117
+ }
118
+ }
119
+ /**
120
+ * Login con SEA Key Pair
121
+ *
122
+ * Autenticazione diretta usando un key pair esportato.
123
+ * Utile per:
124
+ * - Recupero account senza password
125
+ * - Portabilità tra dispositivi
126
+ * - Backup dell'identità
127
+ */
128
+ async loginWithPair(seaPair) {
129
+ try {
130
+ console.log("🔐 Login con key pair...");
131
+ // Autentica con GunDB usando il pair
132
+ const authResult = await new Promise((resolve) => {
133
+ this.shogun.db.gun.user().auth(seaPair, (ack) => {
134
+ if (ack.err) {
135
+ resolve({
136
+ success: false,
137
+ error: ack.err,
138
+ });
139
+ }
140
+ else {
141
+ resolve({
142
+ success: true,
143
+ userPub: seaPair.pub,
144
+ });
145
+ }
146
+ });
147
+ });
148
+ if (!authResult.success) {
149
+ console.log("❌ Login fallito:", authResult.error);
150
+ return authResult;
151
+ }
152
+ // Opzionale: deriva address Ethereum dalla chiave GunDB
153
+ const derivedAddress = await this.deriveEthereumAddress(seaPair.pub);
154
+ console.log("✅ Login effettuato");
155
+ console.log(` GunDB Public Key: ${seaPair.pub}`);
156
+ console.log(` Derived Address: ${derivedAddress}`);
157
+ return {
158
+ success: true,
159
+ userPub: authResult.userPub,
160
+ derivedAddress
161
+ };
162
+ }
163
+ catch (error) {
164
+ console.error("❌ Errore login con pair:", error);
165
+ return {
166
+ success: false,
167
+ error: error instanceof Error ? error.message : "Unknown error",
168
+ };
169
+ }
170
+ }
171
+ /**
172
+ * Logout
173
+ */
174
+ logout() {
175
+ this.shogun.logout();
176
+ console.log("👋 Logout effettuato");
177
+ }
178
+ /**
179
+ * Verifica se l'utente è autenticato
180
+ */
181
+ isLoggedIn() {
182
+ return this.shogun.isLoggedIn();
183
+ }
184
+ // ========================================================================
185
+ // 3. GESTIONE CHIAVI PUBBLICHE: Salva su GunDB
186
+ // ========================================================================
187
+ /**
188
+ * Salva la chiave pubblica dell'utente su GunDB
189
+ * Questo permette ad altri di trovare la tua chiave per criptare messaggi
190
+ */
191
+ async publishPublicKey() {
192
+ try {
193
+ if (!this.isLoggedIn()) {
194
+ return { success: false, error: "Not logged in" };
195
+ }
196
+ // Ottieni il SEA pair dell'utente corrente
197
+ const currentUser = this.shogun.db.user;
198
+ if (!currentUser || !currentUser.is) {
199
+ return { success: false, error: "No user session" };
200
+ }
201
+ // Salva chiave pubblica sul nodo globale usando il userPub come chiave
202
+ // Questo permette ad altri di trovarla facilmente
203
+ const userPub = currentUser.is.pub;
204
+ await this.shogun.db.gun.get(userPub).put({
205
+ pub: currentUser.is.pub,
206
+ epub: currentUser.is.epub,
207
+ algorithm: "ECDSA",
208
+ timestamp: Date.now().toString()
209
+ }).then();
210
+ console.log(`📝 Chiave pubblica pubblicata su GunDB`);
211
+ return { success: true };
212
+ }
213
+ catch (error) {
214
+ console.error("❌ Errore pubblicazione chiave:", error);
215
+ return { success: false, error: error.message };
216
+ }
217
+ }
218
+ // ========================================================================
219
+ // 4. INVIO MESSAGGI: Solo GunDB
220
+ // ========================================================================
221
+ /**
222
+ * Invia un messaggio crittografato a un altro utente
223
+ */
224
+ async sendMessage(recipientUsername, message) {
225
+ try {
226
+ if (!this.isLoggedIn()) {
227
+ return { success: false, error: "Not logged in" };
228
+ }
229
+ const currentUser = this.shogun.db.user;
230
+ if (!currentUser || !currentUser.is) {
231
+ return { success: false, error: "No user session" };
232
+ }
233
+ // 1. Ottieni la chiave pubblica del destinatario
234
+ const recipientKey = await this.getRecipientPublicKey(recipientUsername);
235
+ if (!recipientKey) {
236
+ return {
237
+ success: false,
238
+ error: `Recipient ${recipientUsername} has not published their public key`
239
+ };
240
+ }
241
+ // 2. Ottieni il SEA pair completo (include chiavi private)
242
+ const senderPair = this.shogun.db.gun.user()?._?.sea;
243
+ if (!senderPair) {
244
+ return { success: false, error: "Cannot access SEA pair" };
245
+ }
246
+ // 3. Cripta il messaggio usando SEA.secret + SEA.encrypt (ECDH)
247
+ const encryptedMessage = await this.shogun.db.crypto.encFor(message, senderPair, // sender pair completo
248
+ { epub: recipientKey.epub } // recipient public encryption key
249
+ );
250
+ // 4. Genera ID messaggio
251
+ const messageId = this.generateMessageId();
252
+ const senderPub = currentUser.is.pub;
253
+ // 5. Salva messaggio crittografato su GunDB
254
+ const messageData = {
255
+ from: senderPub,
256
+ to: recipientUsername,
257
+ content: encryptedMessage, // Contenuto crittografato!
258
+ timestamp: Date.now().toString(),
259
+ messageId: messageId
260
+ };
261
+ // Salva sul nodo globale 'messages' per permettere il listener
262
+ await this.shogun.db.gun.get('messages').get(messageId).put(messageData).then();
263
+ console.log(`✅ Messaggio salvato: ${messageId}`);
264
+ return {
265
+ success: true,
266
+ messageId: messageId
267
+ };
268
+ }
269
+ catch (error) {
270
+ return {
271
+ success: false,
272
+ error: error.message
273
+ };
274
+ }
275
+ }
276
+ /**
277
+ * Ottiene la chiave pubblica di un utente da GunDB
278
+ */
279
+ async getRecipientPublicKey(username) {
280
+ try {
281
+ // Prima trova l'utente dal username
282
+ const userData = await this.shogun.db.getUserByAlias(username);
283
+ if (!userData || !userData.userPub) {
284
+ console.error(`❌ User ${username} not found`);
285
+ return null;
286
+ }
287
+ const userPub = userData.userPub;
288
+ // Le chiavi sono salvate direttamente sul nodo userPub
289
+ const publicKeyData = await this.shogun.db.gun.get(userPub).then();
290
+ if (publicKeyData && publicKeyData.epub && publicKeyData.pub) {
291
+ return {
292
+ pub: publicKeyData.pub,
293
+ epub: publicKeyData.epub
294
+ };
295
+ }
296
+ return null;
297
+ }
298
+ catch (error) {
299
+ console.error("❌ Errore recupero chiave pubblica:", error);
300
+ return null;
301
+ }
302
+ }
303
+ // ========================================================================
304
+ // 5. RICEZIONE MESSAGGI: Ascolta GunDB in real-time
305
+ // ========================================================================
306
+ /**
307
+ * Ascolta messaggi crittografati in arrivo su GunDB
308
+ */
309
+ async listenForMessages(onMessage) {
310
+ if (!this.isLoggedIn()) {
311
+ console.error("❌ Non autenticato");
312
+ return;
313
+ }
314
+ const currentUser = this.shogun.db.user;
315
+ if (!currentUser || !currentUser.is) {
316
+ console.error("❌ Nessuna sessione utente");
317
+ return;
318
+ }
319
+ const userPub = currentUser.is.pub;
320
+ // Ottieni username dell'utente corrente
321
+ const username = currentUser.is.alias;
322
+ // Set per tracciare messaggi già ricevuti (evita duplicati)
323
+ const receivedMessages = new Set();
324
+ // Ascolta messaggi in tempo reale su GunDB
325
+ this.shogun.db.gun
326
+ .get(`messages`)
327
+ .map()
328
+ .on(async (data, key) => {
329
+ // Filtra solo i messaggi destinati a questo utente (per username)
330
+ if (data && data.to === username && data.from && data.content && data.messageId) {
331
+ // Evita duplicati (GunDB può emettere più volte)
332
+ if (receivedMessages.has(data.messageId)) {
333
+ return;
334
+ }
335
+ receivedMessages.add(data.messageId);
336
+ try {
337
+ // Decripta il messaggio
338
+ const decryptedContent = await this.decryptMessage(data.content, data.from);
339
+ onMessage({
340
+ from: data.from,
341
+ content: decryptedContent,
342
+ timestamp: parseInt(data.timestamp)
343
+ });
344
+ }
345
+ catch (error) {
346
+ console.error("❌ Errore decrittazione messaggio:", error);
347
+ }
348
+ }
349
+ });
350
+ console.log(`👂 In ascolto di messaggi per ${username} (${userPub.substring(0, 10)}...)`);
351
+ }
352
+ /**
353
+ * Decripta un messaggio usando SEA.secret + SEA.decrypt (ECDH)
354
+ */
355
+ async decryptMessage(encryptedContent, senderPub) {
356
+ // Ottieni il SEA pair completo del destinatario (noi)
357
+ const receiverPair = this.shogun.db.gun.user()?._?.sea;
358
+ if (!receiverPair) {
359
+ throw new Error("Cannot access SEA pair");
360
+ }
361
+ // Ottieni epub del mittente
362
+ const senderKey = await this.getPublicKeyByPub(senderPub);
363
+ if (!senderKey) {
364
+ throw new Error("Sender public key not found");
365
+ }
366
+ // Decripta usando SEA.secret + SEA.decrypt (ECDH)
367
+ const decrypted = await this.shogun.db.crypto.decFrom(encryptedContent, { epub: senderKey.epub }, // sender's public encryption key
368
+ receiverPair // receiver's pair completo
369
+ );
370
+ return decrypted;
371
+ }
372
+ /**
373
+ * Ottiene la chiave pubblica di un utente dalla sua pub key
374
+ */
375
+ async getPublicKeyByPub(userPub) {
376
+ try {
377
+ // Le chiavi sono salvate direttamente sul nodo userPub
378
+ const publicKeyData = await this.shogun.db.gun.get(userPub).then();
379
+ if (publicKeyData && publicKeyData.epub && publicKeyData.pub) {
380
+ return {
381
+ pub: publicKeyData.pub,
382
+ epub: publicKeyData.epub
383
+ };
384
+ }
385
+ return null;
386
+ }
387
+ catch (error) {
388
+ console.error("❌ Errore recupero chiave:", error);
389
+ return null;
390
+ }
391
+ }
392
+ // ========================================================================
393
+ // 6. RECUPERO STORICO: Query messaggi passati
394
+ // ========================================================================
395
+ /**
396
+ * Recupera lo storico dei messaggi crittografati con un utente
397
+ */
398
+ async getMessageHistory(withUsername) {
399
+ if (!this.isLoggedIn()) {
400
+ console.error("❌ Non autenticato");
401
+ return [];
402
+ }
403
+ const currentUser = this.shogun.db.user;
404
+ if (!currentUser || !currentUser.is) {
405
+ console.error("❌ Nessuna sessione utente");
406
+ return [];
407
+ }
408
+ const userPub = currentUser.is.pub;
409
+ const username = currentUser.is.alias;
410
+ const allMessages = [];
411
+ // Ottieni il userPub dell'altro utente
412
+ const otherUserData = await this.shogun.db.getUserByAlias(withUsername);
413
+ const otherUserPub = otherUserData?.userPub;
414
+ // Recupera tutti i messaggi dal nodo 'messages' e filtra
415
+ const allMessagesNode = await this.shogun.db.gun.get('messages').then();
416
+ if (allMessagesNode) {
417
+ for (const [messageId, data] of Object.entries(allMessagesNode)) {
418
+ if (typeof data === 'object' && data !== null) {
419
+ const msgData = data;
420
+ // Filtra messaggi tra questo utente e withUsername
421
+ // Messaggi inviati da me a loro
422
+ const isSentToTarget = msgData.from === userPub && msgData.to === withUsername;
423
+ // Messaggi ricevuti da loro
424
+ const isReceivedFromTarget = msgData.to === username &&
425
+ (msgData.from === otherUserPub ||
426
+ msgData.from);
427
+ if ((isSentToTarget || isReceivedFromTarget) && msgData.content && msgData.messageId) {
428
+ try {
429
+ // Decripta ogni messaggio
430
+ const decryptedContent = await this.decryptMessage(msgData.content, msgData.from);
431
+ allMessages.push({
432
+ from: msgData.from,
433
+ to: msgData.to,
434
+ content: decryptedContent,
435
+ timestamp: parseInt(msgData.timestamp)
436
+ });
437
+ }
438
+ catch (error) {
439
+ console.error(`❌ Errore decrittazione messaggio ${messageId}:`, error);
440
+ // Salta messaggi che non possono essere decriptati
441
+ }
442
+ }
443
+ }
444
+ }
445
+ }
446
+ // Ordina per timestamp
447
+ return allMessages.sort((a, b) => a.timestamp - b.timestamp);
448
+ }
449
+ // ========================================================================
450
+ // 7. UTILITY FUNCTIONS
451
+ // ========================================================================
452
+ /**
453
+ * Converte la chiave pubblica di GunDB in address Ethereum
454
+ * Usa la chiave privata SEA come seed per derivazione deterministica
455
+ *
456
+ * Questo garantisce che:
457
+ * - Stesso SEA pair → stesso address Ethereum
458
+ * - Derivazione cryptografica sicura
459
+ * - Identità unificata tra GunDB e blockchain
460
+ */
461
+ async deriveEthereumAddress(publicKey) {
462
+ try {
463
+ // Ottieni il SEA pair completo
464
+ const seaPair = this.shogun.db.gun.user()?._?.sea;
465
+ if (!seaPair || !seaPair.priv) {
466
+ throw new Error("Cannot access SEA pair");
467
+ }
468
+ // Usa la chiave privata SEA come seed per derive
469
+ // Questo è MOLTO più sicuro e deterministico del username!
470
+ const derived = await (0, derive_1.default)(seaPair.priv, null, {
471
+ includeSecp256k1Ethereum: true,
472
+ includeP256: false,
473
+ includeSecp256k1Bitcoin: false
474
+ });
475
+ return derived.secp256k1Ethereum.address;
476
+ }
477
+ catch (error) {
478
+ console.error("❌ Errore derivazione address:", error);
479
+ // Fallback: hash della chiave pubblica
480
+ const fallbackKey = publicKey || "unknown";
481
+ const hash = ethers_1.ethers.keccak256(ethers_1.ethers.toUtf8Bytes(fallbackKey));
482
+ return ethers_1.ethers.getAddress('0x' + hash.slice(-40));
483
+ }
484
+ }
485
+ /**
486
+ * Genera ID messaggio univoco
487
+ */
488
+ generateMessageId() {
489
+ return ethers_1.ethers.hexlify(ethers_1.ethers.randomBytes(16));
490
+ }
491
+ }
492
+ exports.SHIP_01 = SHIP_01;
493
+ // ============================================================================
494
+ // 8. ESEMPIO D'USO COMPLETO
495
+ // ============================================================================
496
+ // async function main() {
497
+ // console.log("🚀 Secure Messaging App - Shogun Core + GunDB\n");
498
+ // // 1. Inizializza il sistema
499
+ // const app = new SHIP_01({
500
+ // gunOptions: {
501
+ // peers: ["https://relay.shogun-eco.xyz/gun","https://v5g5jseqhgkp43lppgregcfbvi.srv.us/gun","https://peer.wallie.io/gun"],
502
+ // radisk: false,
503
+ // localStorage:false,
504
+ // }
505
+ // });
506
+ // // 2. Signup (prima volta)
507
+ // console.log("📝 Registrazione nuovo utente...");
508
+ // const signupResult = await app.signup("alice", "password123");
509
+ // if (!signupResult.success) {
510
+ // console.log("ℹ️ Utente già esistente, procedo con login");
511
+ // } else {
512
+ // console.log("✅ Utente registrato!");
513
+ // console.log(` Username: alice`);
514
+ // console.log(` Public Key: ${signupResult.userPub}`);
515
+ // console.log(` Derived Address: ${signupResult.derivedAddress}\n`);
516
+ // }
517
+ // // 3. Login
518
+ // console.log("🔐 Login...");
519
+ // const loginResult = await app.login("alice", "password123");
520
+ // if (!loginResult.success) {
521
+ // console.error("❌ Login fallito:", loginResult.error);
522
+ // return;
523
+ // }
524
+ // console.log("✅ Login effettuato!");
525
+ // console.log(` - Autenticazione: Shogun Core (Username/Password)`);
526
+ // console.log(` - Storage: GunDB decentralizzato P2P\n`);
527
+ // // 4. Pubblica chiave pubblica
528
+ // console.log("📢 Pubblicazione chiave pubblica...");
529
+ // await app.publishPublicKey();
530
+ // // 5. Ascolta messaggi in arrivo
531
+ // console.log("\n👂 In ascolto di messaggi...\n");
532
+ // await app.listenForMessages((message) => {
533
+ // console.log(`📨 Nuovo messaggio da ${message.from.substring(0, 10)}...:`);
534
+ // console.log(` Contenuto: ${message.content}`);
535
+ // console.log(` Timestamp: ${new Date(message.timestamp).toLocaleString()}\n`);
536
+ // });
537
+ // // 6. Invia un messaggio
538
+ // const recipientUsername = "bob";
539
+ // console.log(`📤 Invio messaggio a ${recipientUsername}...`);
540
+ // const result = await app.sendMessage(
541
+ // recipientUsername,
542
+ // "Hello Bob! This is a secure message using Shogun Core"
543
+ // );
544
+ // if (result.success) {
545
+ // console.log("✅ Messaggio inviato!");
546
+ // console.log(` Message ID: ${result.messageId}`);
547
+ // console.log(` Storage: GunDB P2P (gratis!)`);
548
+ // }
549
+ // // 7. Recupera storico conversazione
550
+ // console.log("\n📚 Recupero storico messaggi...");
551
+ // const history = await app.getMessageHistory(recipientUsername);
552
+ // console.log(`\n💬 Conversazione con ${recipientUsername} (${history.length} messaggi):`);
553
+ // history.forEach((msg, i) => {
554
+ // const isMe = msg.from === loginResult.userPub;
555
+ // console.log(`${i + 1}. ${isMe ? 'Tu' : 'Loro'}: ${msg.content}`);
556
+ // });
557
+ // }
558
+ // ============================================================================
559
+ // 9. VANTAGGI DELL'ARCHITETTURA
560
+ // ============================================================================
561
+ /**
562
+ * VANTAGGI DI QUESTA ARCHITETTURA:
563
+ *
564
+ * 1. SEMPLICITÀ:
565
+ * - Solo username/password (nessun wallet necessario)
566
+ * - Nessun gas fee o transazioni blockchain
567
+ * - Setup in pochi secondi
568
+ *
569
+ * 2. DECENTRALIZZAZIONE COMPLETA:
570
+ * - Storage P2P su GunDB
571
+ * - Nessun server centrale
572
+ * - Censorship resistant
573
+ * - User sovereignty
574
+ *
575
+ * 3. COSTI ZERO:
576
+ * - Nessun costo per messaggi
577
+ * - Nessun costo per storage
578
+ * - Completamente gratis
579
+ *
580
+ * 4. END-TO-END ENCRYPTION:
581
+ * - Messaggi crittografati con ECDH (Elliptic Curve Diffie-Hellman)
582
+ * - SEA.secret deriva shared secret da epub (encryption public key)
583
+ * - SEA.encrypt cripta con AES-GCM
584
+ * - Solo mittente e destinatario possono leggere i messaggi
585
+ * - Nessun server o relay può leggere il contenuto
586
+ *
587
+ * 5. IDENTITÀ DECENTRALIZZATA:
588
+ * - Chiave pubblica GunDB come identità
589
+ * - Può essere derivata in address Ethereum se necessario
590
+ * - Portabile tra diverse applicazioni
591
+ *
592
+ * 6. REAL-TIME:
593
+ * - Messaggi in tempo reale
594
+ * - Sincronizzazione automatica
595
+ * - Listener reattivi
596
+ *
597
+ * 7. OFFLINE-FIRST:
598
+ * - Funziona anche offline
599
+ * - Sincronizzazione automatica al riconnect
600
+ * - GunDB gestisce conflitti automaticamente
601
+ *
602
+ * COME FUNZIONA LA CRITTOGRAFIA:
603
+ *
604
+ * 1. SETUP - Ogni utente ha un SEA pair:
605
+ * - pub: chiave pubblica di signing
606
+ * - priv: chiave privata di signing
607
+ * - epub: chiave pubblica di encryption (per ECDH)
608
+ * - epriv: chiave privata di encryption (per ECDH)
609
+ *
610
+ * 2. PUBBLICAZIONE CHIAVI:
611
+ * - Ogni utente pubblica il suo epub su GunDB
612
+ * - Altri possono trovarlo per criptare messaggi
613
+ *
614
+ * 3. INVIO MESSAGGIO (Alice → Bob):
615
+ * a) Alice ottiene l'epub di Bob da GunDB
616
+ * b) SEA.secret(bob.epub, alice.pair) → shared_secret (ECDH)
617
+ * c) SEA.encrypt(message, shared_secret) → encrypted_message
618
+ * d) Alice salva encrypted_message su GunDB
619
+ *
620
+ * 4. RICEZIONE MESSAGGIO (Bob riceve):
621
+ * a) Bob legge encrypted_message da GunDB
622
+ * b) Bob ottiene l'epub di Alice
623
+ * c) SEA.secret(alice.epub, bob.pair) → shared_secret (stesso!)
624
+ * d) SEA.decrypt(encrypted_message, shared_secret) → message
625
+ *
626
+ * 5. SICUREZZA:
627
+ * - Shared secret derivato con ECDH (mai trasmesso)
628
+ * - Solo Alice e Bob possono derivare lo stesso secret
629
+ * - Messaggi crittografati con AES-256-GCM
630
+ * - Forward secrecy se chiavi sono ruotate
631
+ *
632
+ * Esempio tecnico:
633
+ * Alice.epub + Bob.epriv → shared_secret_AB
634
+ * Bob.epub + Alice.epriv → shared_secret_AB (stesso!)
635
+ *
636
+ * Vantaggi:
637
+ * ✅ End-to-end encryption
638
+ * ✅ Perfect forward secrecy (con key rotation)
639
+ * ✅ Nessun server può leggere i messaggi
640
+ * ✅ Standard crittografico (ECDH + AES-GCM)
641
+ * ✅ Una sola chiave privata da gestire
642
+ * ✅ Address Ethereum derivabile (interoperabilità)
643
+ */
644
+ // ============================================================================
645
+ // 10. TEST COMPLETO: Alice e Bob si scambiano messaggi
646
+ // ============================================================================
647
+ /**
648
+ * Test completo che simula Alice e Bob che si scambiano messaggi CRITTOGRAFATI
649
+ *
650
+ * CRITTOGRAFIA END-TO-END:
651
+ * - Ogni messaggio è crittografato con ECDH (Elliptic Curve Diffie-Hellman)
652
+ * - Solo mittente e destinatario possono leggere i messaggi
653
+ * - I relay GunDB vedono solo dati crittografati
654
+ *
655
+ * FLOW:
656
+ * 1. Alice e Bob pubblicano le loro chiavi pubbliche (epub)
657
+ * 2. Alice vuole inviare a Bob:
658
+ * - Ottiene bob.epub da GunDB
659
+ * - SEA.secret(bob.epub, alice.pair) → shared_secret
660
+ * - SEA.encrypt(message, shared_secret) → encrypted
661
+ * - Salva encrypted su GunDB
662
+ * 3. Bob riceve:
663
+ * - Legge encrypted da GunDB
664
+ * - Ottiene alice.epub
665
+ * - SEA.secret(alice.epub, bob.pair) → shared_secret (stesso!)
666
+ * - SEA.decrypt(encrypted, shared_secret) → message
667
+ */
668
+ async function testAliceAndBob() {
669
+ console.log("🧪 TEST: Alice e Bob - Conversazione Crittografata E2E\n");
670
+ console.log("=".repeat(60));
671
+ // Setup Alice
672
+ console.log("\n👩 ALICE - Setup");
673
+ console.log("-".repeat(60));
674
+ const alice = new SHIP_01({
675
+ gunOptions: {
676
+ peers: ["https://peer.wallie.io/gun"],
677
+ radisk: true,
678
+ },
679
+ });
680
+ // Alice signup/login
681
+ await alice.signup("alice", "password123");
682
+ const aliceLogin = await alice.login("alice", "password123");
683
+ if (!aliceLogin.success) {
684
+ console.error("❌ Alice login failed");
685
+ return;
686
+ }
687
+ await alice.publishPublicKey();
688
+ // Aspetta che la chiave sia sincronizzata
689
+ await new Promise(resolve => setTimeout(resolve, 1000));
690
+ // Setup Bob
691
+ console.log("\n👨 BOB - Setup");
692
+ console.log("-".repeat(60));
693
+ const bob = new SHIP_01({
694
+ gunOptions: {
695
+ peers: ["https://peer.wallie.io/gun"],
696
+ radisk: true
697
+ },
698
+ });
699
+ // Bob signup/login
700
+ await bob.signup("bob", "password456");
701
+ const bobLogin = await bob.login("bob", "password456");
702
+ if (!bobLogin.success) {
703
+ console.error("❌ Bob login failed");
704
+ return;
705
+ }
706
+ await bob.publishPublicKey();
707
+ // Aspetta che la chiave sia sincronizzata
708
+ await new Promise(resolve => setTimeout(resolve, 1000));
709
+ console.log("\n" + "=".repeat(60));
710
+ console.log("💬 CONVERSAZIONE");
711
+ console.log("=".repeat(60));
712
+ // Alice e Bob ascoltano messaggi
713
+ let aliceMessages = [];
714
+ let bobMessages = [];
715
+ await alice.listenForMessages((msg) => {
716
+ aliceMessages.push(msg);
717
+ console.log(`\n[Alice riceve] 📨`);
718
+ console.log(` Da: ${msg.from.substring(0, 10)}...`);
719
+ console.log(` Messaggio: "${msg.content}"`);
720
+ console.log(` Timestamp: ${new Date(msg.timestamp).toLocaleTimeString()}`);
721
+ });
722
+ await bob.listenForMessages((msg) => {
723
+ bobMessages.push(msg);
724
+ console.log(`\n[Bob riceve] 📨`);
725
+ console.log(` Da: ${msg.from.substring(0, 10)}...`);
726
+ console.log(` Messaggio: "${msg.content}"`);
727
+ console.log(` Timestamp: ${new Date(msg.timestamp).toLocaleTimeString()}`);
728
+ });
729
+ // Aspetta che i listener siano pronti
730
+ await new Promise(resolve => setTimeout(resolve, 2000));
731
+ // Alice invia messaggio a Bob
732
+ console.log("\n[Alice invia] 📤");
733
+ const msg1 = await alice.sendMessage("bob", "Ciao Bob! Come stai? 👋");
734
+ console.log(` ✅ Inviato: "${msg1.messageId}"`);
735
+ // Aspetta che Bob riceva
736
+ await new Promise(resolve => setTimeout(resolve, 2000));
737
+ // Bob risponde ad Alice
738
+ console.log("\n[Bob invia] 📤");
739
+ const msg2 = await bob.sendMessage("alice", "Ciao Alice! Tutto bene, grazie! Tu? 😊");
740
+ console.log(` ✅ Inviato: "${msg2.messageId}"`);
741
+ // Aspetta che Alice riceva
742
+ await new Promise(resolve => setTimeout(resolve, 2000));
743
+ // Alice risponde
744
+ console.log("\n[Alice invia] 📤");
745
+ const msg3 = await alice.sendMessage("bob", "Anch'io benissimo! Questo sistema di messaggistica è fantastico! 🚀");
746
+ console.log(` ✅ Inviato: "${msg3.messageId}"`);
747
+ // Aspetta che Bob riceva
748
+ await new Promise(resolve => setTimeout(resolve, 2000));
749
+ // Bob conclude
750
+ console.log("\n[Bob invia] 📤");
751
+ const msg4 = await bob.sendMessage("alice", "Vero! Zero costi, decentralizzato e veloce! 💪");
752
+ console.log(` ✅ Inviato: "${msg4.messageId}"`);
753
+ // Aspetta finale
754
+ await new Promise(resolve => setTimeout(resolve, 3000));
755
+ // Mostra statistiche
756
+ console.log("\n" + "=".repeat(60));
757
+ console.log("📊 STATISTICHE FINALI");
758
+ console.log("=".repeat(60));
759
+ console.log(`\n👩 Alice:`);
760
+ console.log(` - Messaggi inviati: 2`);
761
+ console.log(` - Messaggi ricevuti: ${aliceMessages.length}`);
762
+ console.log(` - Public Key: ${aliceLogin.userPub?.substring(0, 20)}...`);
763
+ console.log(` - Derived Address: ${aliceLogin.derivedAddress}`);
764
+ console.log(`\n👨 Bob:`);
765
+ console.log(` - Messaggi inviati: 2`);
766
+ console.log(` - Messaggi ricevuti: ${bobMessages.length}`);
767
+ console.log(` - Public Key: ${bobLogin.userPub?.substring(0, 20)}...`);
768
+ console.log(` - Derived Address: ${bobLogin.derivedAddress}`);
769
+ // Recupera storico
770
+ console.log("\n" + "=".repeat(60));
771
+ console.log("📚 STORICO CONVERSAZIONE");
772
+ console.log("=".repeat(60));
773
+ const aliceHistory = await alice.getMessageHistory("bob");
774
+ console.log(`\n👩 Storico di Alice con Bob (${aliceHistory.length} messaggi):`);
775
+ aliceHistory.forEach((msg, i) => {
776
+ const sender = msg.from === aliceLogin.userPub ? "Alice" : "Bob";
777
+ console.log(` ${i + 1}. [${sender}]: ${msg.content}`);
778
+ });
779
+ const bobHistory = await bob.getMessageHistory("alice");
780
+ console.log(`\n👨 Storico di Bob con Alice (${bobHistory.length} messaggi):`);
781
+ bobHistory.forEach((msg, i) => {
782
+ const sender = msg.from === bobLogin.userPub ? "Bob" : "Alice";
783
+ console.log(` ${i + 1}. [${sender}]: ${msg.content}`);
784
+ });
785
+ // Riepilogo finale
786
+ console.log("\n" + "=".repeat(60));
787
+ console.log("✅ TEST COMPLETATO CON SUCCESSO!");
788
+ console.log("=".repeat(60));
789
+ console.log("\n📝 Riepilogo:");
790
+ console.log(" ✅ 2 utenti registrati (Alice, Bob)");
791
+ console.log(" ✅ 4 messaggi scambiati");
792
+ console.log(" ✅ Messaggi ricevuti in real-time");
793
+ console.log(" ✅ Storico recuperato correttamente");
794
+ console.log(" ✅ Storage: GunDB P2P (gratis!)");
795
+ console.log(" ✅ Costi: $0.00");
796
+ console.log("\n🎉 Sistema di messaggistica decentralizzato funzionante!\n");
797
+ }
798
+ // Esegui esempio o test
799
+ if (require.main === module) {
800
+ // Scegli quale eseguire decommentando una delle due righe:
801
+ // main().catch(console.error); // Esempio singolo utente
802
+ testAliceAndBob().catch(console.error); // Test completo Alice & Bob
803
+ }