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.
- package/dist/browser/_e6ae.shogun-core.js +14 -0
- package/dist/browser/_e6ae.shogun-core.js.map +1 -0
- package/dist/browser/shogun-core.js +1685 -6
- package/dist/browser/shogun-core.js.map +1 -1
- package/dist/ship/examples/messenger-cli.js +632 -0
- package/dist/ship/implementation/SHIP_01.js +803 -0
- package/dist/ship/interfaces/ISHIP_01.js +71 -0
- package/dist/{gundb → src/gundb}/db.js +2 -2
- package/dist/{index.js → src/index.js} +7 -2
- package/dist/types/ship/examples/messenger-cli.d.ts +31 -0
- package/dist/types/ship/implementation/SHIP_01.d.ts +108 -0
- package/dist/types/ship/interfaces/ISHIP_01.d.ts +305 -0
- package/dist/types/{index.d.ts → src/index.d.ts} +4 -1
- package/package.json +2 -1
- /package/dist/{config → src/config}/simplified-config.js +0 -0
- /package/dist/{core.js → src/core.js} +0 -0
- /package/dist/{examples → src/examples}/api-test.js +0 -0
- /package/dist/{examples → src/examples}/simple-api-test.js +0 -0
- /package/dist/{gundb → src/gundb}/api.js +0 -0
- /package/dist/{gundb → src/gundb}/crypto.js +0 -0
- /package/dist/{gundb → src/gundb}/derive.js +0 -0
- /package/dist/{gundb → src/gundb}/errors.js +0 -0
- /package/dist/{gundb → src/gundb}/index.js +0 -0
- /package/dist/{gundb → src/gundb}/rxjs.js +0 -0
- /package/dist/{gundb → src/gundb}/types.js +0 -0
- /package/dist/{interfaces → src/interfaces}/common.js +0 -0
- /package/dist/{interfaces → src/interfaces}/events.js +0 -0
- /package/dist/{interfaces → src/interfaces}/plugin.js +0 -0
- /package/dist/{interfaces → src/interfaces}/shogun.js +0 -0
- /package/dist/{managers → src/managers}/AuthManager.js +0 -0
- /package/dist/{managers → src/managers}/CoreInitializer.js +0 -0
- /package/dist/{managers → src/managers}/EventManager.js +0 -0
- /package/dist/{managers → src/managers}/PluginManager.js +0 -0
- /package/dist/{migration-test.js → src/migration-test.js} +0 -0
- /package/dist/{plugins → src/plugins}/base.js +0 -0
- /package/dist/{plugins → src/plugins}/index.js +0 -0
- /package/dist/{plugins → src/plugins}/nostr/index.js +0 -0
- /package/dist/{plugins → src/plugins}/nostr/nostrConnector.js +0 -0
- /package/dist/{plugins → src/plugins}/nostr/nostrConnectorPlugin.js +0 -0
- /package/dist/{plugins → src/plugins}/nostr/nostrSigner.js +0 -0
- /package/dist/{plugins → src/plugins}/nostr/types.js +0 -0
- /package/dist/{plugins → src/plugins}/oauth/index.js +0 -0
- /package/dist/{plugins → src/plugins}/oauth/oauthConnector.js +0 -0
- /package/dist/{plugins → src/plugins}/oauth/oauthPlugin.js +0 -0
- /package/dist/{plugins → src/plugins}/oauth/types.js +0 -0
- /package/dist/{plugins → src/plugins}/web3/index.js +0 -0
- /package/dist/{plugins → src/plugins}/web3/types.js +0 -0
- /package/dist/{plugins → src/plugins}/web3/web3Connector.js +0 -0
- /package/dist/{plugins → src/plugins}/web3/web3ConnectorPlugin.js +0 -0
- /package/dist/{plugins → src/plugins}/web3/web3Signer.js +0 -0
- /package/dist/{plugins → src/plugins}/webauthn/index.js +0 -0
- /package/dist/{plugins → src/plugins}/webauthn/types.js +0 -0
- /package/dist/{plugins → src/plugins}/webauthn/webauthn.js +0 -0
- /package/dist/{plugins → src/plugins}/webauthn/webauthnPlugin.js +0 -0
- /package/dist/{plugins → src/plugins}/webauthn/webauthnSigner.js +0 -0
- /package/dist/{storage → src/storage}/storage.js +0 -0
- /package/dist/{types → src/types}/events.js +0 -0
- /package/dist/{types → src/types}/shogun.js +0 -0
- /package/dist/{utils → src/utils}/errorHandler.js +0 -0
- /package/dist/{utils → src/utils}/eventEmitter.js +0 -0
- /package/dist/{utils → src/utils}/validation.js +0 -0
- /package/dist/types/{config → src/config}/simplified-config.d.ts +0 -0
- /package/dist/types/{core.d.ts → src/core.d.ts} +0 -0
- /package/dist/types/{examples → src/examples}/api-test.d.ts +0 -0
- /package/dist/types/{examples → src/examples}/simple-api-test.d.ts +0 -0
- /package/dist/types/{gundb → src/gundb}/api.d.ts +0 -0
- /package/dist/types/{gundb → src/gundb}/crypto.d.ts +0 -0
- /package/dist/types/{gundb → src/gundb}/db.d.ts +0 -0
- /package/dist/types/{gundb → src/gundb}/derive.d.ts +0 -0
- /package/dist/types/{gundb → src/gundb}/errors.d.ts +0 -0
- /package/dist/types/{gundb → src/gundb}/index.d.ts +0 -0
- /package/dist/types/{gundb → src/gundb}/rxjs.d.ts +0 -0
- /package/dist/types/{gundb → src/gundb}/types.d.ts +0 -0
- /package/dist/types/{interfaces → src/interfaces}/common.d.ts +0 -0
- /package/dist/types/{interfaces → src/interfaces}/events.d.ts +0 -0
- /package/dist/types/{interfaces → src/interfaces}/plugin.d.ts +0 -0
- /package/dist/types/{interfaces → src/interfaces}/shogun.d.ts +0 -0
- /package/dist/types/{managers → src/managers}/AuthManager.d.ts +0 -0
- /package/dist/types/{managers → src/managers}/CoreInitializer.d.ts +0 -0
- /package/dist/types/{managers → src/managers}/EventManager.d.ts +0 -0
- /package/dist/types/{managers → src/managers}/PluginManager.d.ts +0 -0
- /package/dist/types/{migration-test.d.ts → src/migration-test.d.ts} +0 -0
- /package/dist/types/{plugins → src/plugins}/base.d.ts +0 -0
- /package/dist/types/{plugins → src/plugins}/index.d.ts +0 -0
- /package/dist/types/{plugins → src/plugins}/nostr/index.d.ts +0 -0
- /package/dist/types/{plugins → src/plugins}/nostr/nostrConnector.d.ts +0 -0
- /package/dist/types/{plugins → src/plugins}/nostr/nostrConnectorPlugin.d.ts +0 -0
- /package/dist/types/{plugins → src/plugins}/nostr/nostrSigner.d.ts +0 -0
- /package/dist/types/{plugins → src/plugins}/nostr/types.d.ts +0 -0
- /package/dist/types/{plugins → src/plugins}/oauth/index.d.ts +0 -0
- /package/dist/types/{plugins → src/plugins}/oauth/oauthConnector.d.ts +0 -0
- /package/dist/types/{plugins → src/plugins}/oauth/oauthPlugin.d.ts +0 -0
- /package/dist/types/{plugins → src/plugins}/oauth/types.d.ts +0 -0
- /package/dist/types/{plugins → src/plugins}/web3/index.d.ts +0 -0
- /package/dist/types/{plugins → src/plugins}/web3/types.d.ts +0 -0
- /package/dist/types/{plugins → src/plugins}/web3/web3Connector.d.ts +0 -0
- /package/dist/types/{plugins → src/plugins}/web3/web3ConnectorPlugin.d.ts +0 -0
- /package/dist/types/{plugins → src/plugins}/web3/web3Signer.d.ts +0 -0
- /package/dist/types/{plugins → src/plugins}/webauthn/index.d.ts +0 -0
- /package/dist/types/{plugins → src/plugins}/webauthn/types.d.ts +0 -0
- /package/dist/types/{plugins → src/plugins}/webauthn/webauthn.d.ts +0 -0
- /package/dist/types/{plugins → src/plugins}/webauthn/webauthnPlugin.d.ts +0 -0
- /package/dist/types/{plugins → src/plugins}/webauthn/webauthnSigner.d.ts +0 -0
- /package/dist/types/{storage → src/storage}/storage.d.ts +0 -0
- /package/dist/types/{types → src/types}/events.d.ts +0 -0
- /package/dist/types/{types → src/types}/shogun.d.ts +0 -0
- /package/dist/types/{utils → src/utils}/errorHandler.d.ts +0 -0
- /package/dist/types/{utils → src/utils}/eventEmitter.d.ts +0 -0
- /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
|
+
}
|