shogun-core 3.3.1 → 3.3.2

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 (147) hide show
  1. package/dist/ship/examples/ephemeral-cli.js +234 -0
  2. package/dist/ship/examples/identity-cli.js +503 -0
  3. package/dist/ship/examples/messenger-cli.js +745 -0
  4. package/dist/ship/examples/stealth-cli.js +433 -0
  5. package/dist/ship/examples/storage-cli.js +615 -0
  6. package/dist/ship/examples/vault-cli.js +444 -0
  7. package/dist/ship/examples/wallet-cli.js +767 -0
  8. package/dist/ship/implementation/SHIP_00.js +478 -0
  9. package/dist/ship/implementation/SHIP_01.js +433 -0
  10. package/dist/ship/implementation/SHIP_02.js +1366 -0
  11. package/dist/ship/implementation/SHIP_03.js +855 -0
  12. package/dist/ship/implementation/SHIP_04.js +589 -0
  13. package/dist/ship/implementation/SHIP_05.js +1064 -0
  14. package/dist/ship/implementation/SHIP_06.js +350 -0
  15. package/dist/ship/implementation/SHIP_07.js +635 -0
  16. package/dist/ship/index.js +17 -0
  17. package/dist/ship/interfaces/ISHIP_00.js +135 -0
  18. package/dist/ship/interfaces/ISHIP_01.js +128 -0
  19. package/dist/ship/interfaces/ISHIP_02.js +57 -0
  20. package/dist/ship/interfaces/ISHIP_03.js +61 -0
  21. package/dist/ship/interfaces/ISHIP_04.js +62 -0
  22. package/dist/ship/interfaces/ISHIP_05.js +59 -0
  23. package/dist/ship/interfaces/ISHIP_06.js +144 -0
  24. package/dist/ship/interfaces/ISHIP_07.js +194 -0
  25. package/dist/types/ship/examples/ephemeral-cli.d.ts +13 -0
  26. package/dist/types/ship/examples/identity-cli.d.ts +40 -0
  27. package/dist/types/ship/examples/messenger-cli.d.ts +37 -0
  28. package/dist/types/ship/examples/stealth-cli.d.ts +31 -0
  29. package/dist/types/ship/examples/storage-cli.d.ts +48 -0
  30. package/dist/types/ship/examples/vault-cli.d.ts +13 -0
  31. package/dist/types/ship/examples/wallet-cli.d.ts +131 -0
  32. package/dist/types/ship/implementation/SHIP_00.d.ts +113 -0
  33. package/dist/types/ship/implementation/SHIP_01.d.ts +80 -0
  34. package/dist/types/ship/implementation/SHIP_02.d.ts +297 -0
  35. package/dist/types/ship/implementation/SHIP_03.d.ts +127 -0
  36. package/dist/types/ship/implementation/SHIP_04.d.ts +76 -0
  37. package/dist/types/ship/implementation/SHIP_05.d.ts +70 -0
  38. package/dist/types/ship/implementation/SHIP_06.d.ts +66 -0
  39. package/dist/types/ship/implementation/SHIP_07.d.ts +101 -0
  40. package/dist/types/ship/index.d.ts +14 -0
  41. package/dist/types/ship/interfaces/ISHIP_00.d.ts +410 -0
  42. package/dist/types/ship/interfaces/ISHIP_01.d.ts +343 -0
  43. package/dist/types/ship/interfaces/ISHIP_02.d.ts +470 -0
  44. package/dist/types/ship/interfaces/ISHIP_03.d.ts +295 -0
  45. package/dist/types/ship/interfaces/ISHIP_04.d.ts +245 -0
  46. package/dist/types/ship/interfaces/ISHIP_05.d.ts +234 -0
  47. package/dist/types/ship/interfaces/ISHIP_06.d.ts +370 -0
  48. package/dist/types/ship/interfaces/ISHIP_07.d.ts +522 -0
  49. package/package.json +1 -1
  50. /package/dist/{config → src/config}/simplified-config.js +0 -0
  51. /package/dist/{core.js → src/core.js} +0 -0
  52. /package/dist/{examples → src/examples}/api-test.js +0 -0
  53. /package/dist/{examples → src/examples}/simple-api-test.js +0 -0
  54. /package/dist/{gundb → src/gundb}/api.js +0 -0
  55. /package/dist/{gundb → src/gundb}/crypto.js +0 -0
  56. /package/dist/{gundb → src/gundb}/db.js +0 -0
  57. /package/dist/{gundb → src/gundb}/derive.js +0 -0
  58. /package/dist/{gundb → src/gundb}/errors.js +0 -0
  59. /package/dist/{gundb → src/gundb}/index.js +0 -0
  60. /package/dist/{gundb → src/gundb}/rxjs.js +0 -0
  61. /package/dist/{gundb → src/gundb}/types.js +0 -0
  62. /package/dist/{index.js → src/index.js} +0 -0
  63. /package/dist/{interfaces → src/interfaces}/common.js +0 -0
  64. /package/dist/{interfaces → src/interfaces}/events.js +0 -0
  65. /package/dist/{interfaces → src/interfaces}/plugin.js +0 -0
  66. /package/dist/{interfaces → src/interfaces}/shogun.js +0 -0
  67. /package/dist/{managers → src/managers}/AuthManager.js +0 -0
  68. /package/dist/{managers → src/managers}/CoreInitializer.js +0 -0
  69. /package/dist/{managers → src/managers}/EventManager.js +0 -0
  70. /package/dist/{managers → src/managers}/PluginManager.js +0 -0
  71. /package/dist/{migration-test.js → src/migration-test.js} +0 -0
  72. /package/dist/{plugins → src/plugins}/base.js +0 -0
  73. /package/dist/{plugins → src/plugins}/index.js +0 -0
  74. /package/dist/{plugins → src/plugins}/nostr/index.js +0 -0
  75. /package/dist/{plugins → src/plugins}/nostr/nostrConnector.js +0 -0
  76. /package/dist/{plugins → src/plugins}/nostr/nostrConnectorPlugin.js +0 -0
  77. /package/dist/{plugins → src/plugins}/nostr/nostrSigner.js +0 -0
  78. /package/dist/{plugins → src/plugins}/nostr/types.js +0 -0
  79. /package/dist/{plugins → src/plugins}/oauth/index.js +0 -0
  80. /package/dist/{plugins → src/plugins}/oauth/oauthConnector.js +0 -0
  81. /package/dist/{plugins → src/plugins}/oauth/oauthPlugin.js +0 -0
  82. /package/dist/{plugins → src/plugins}/oauth/types.js +0 -0
  83. /package/dist/{plugins → src/plugins}/web3/index.js +0 -0
  84. /package/dist/{plugins → src/plugins}/web3/types.js +0 -0
  85. /package/dist/{plugins → src/plugins}/web3/web3Connector.js +0 -0
  86. /package/dist/{plugins → src/plugins}/web3/web3ConnectorPlugin.js +0 -0
  87. /package/dist/{plugins → src/plugins}/web3/web3Signer.js +0 -0
  88. /package/dist/{plugins → src/plugins}/webauthn/index.js +0 -0
  89. /package/dist/{plugins → src/plugins}/webauthn/types.js +0 -0
  90. /package/dist/{plugins → src/plugins}/webauthn/webauthn.js +0 -0
  91. /package/dist/{plugins → src/plugins}/webauthn/webauthnPlugin.js +0 -0
  92. /package/dist/{plugins → src/plugins}/webauthn/webauthnSigner.js +0 -0
  93. /package/dist/{storage → src/storage}/storage.js +0 -0
  94. /package/dist/{types → src/types}/events.js +0 -0
  95. /package/dist/{types → src/types}/shogun.js +0 -0
  96. /package/dist/{utils → src/utils}/errorHandler.js +0 -0
  97. /package/dist/{utils → src/utils}/eventEmitter.js +0 -0
  98. /package/dist/{utils → src/utils}/validation.js +0 -0
  99. /package/dist/types/{config → src/config}/simplified-config.d.ts +0 -0
  100. /package/dist/types/{core.d.ts → src/core.d.ts} +0 -0
  101. /package/dist/types/{examples → src/examples}/api-test.d.ts +0 -0
  102. /package/dist/types/{examples → src/examples}/simple-api-test.d.ts +0 -0
  103. /package/dist/types/{gundb → src/gundb}/api.d.ts +0 -0
  104. /package/dist/types/{gundb → src/gundb}/crypto.d.ts +0 -0
  105. /package/dist/types/{gundb → src/gundb}/db.d.ts +0 -0
  106. /package/dist/types/{gundb → src/gundb}/derive.d.ts +0 -0
  107. /package/dist/types/{gundb → src/gundb}/errors.d.ts +0 -0
  108. /package/dist/types/{gundb → src/gundb}/index.d.ts +0 -0
  109. /package/dist/types/{gundb → src/gundb}/rxjs.d.ts +0 -0
  110. /package/dist/types/{gundb → src/gundb}/types.d.ts +0 -0
  111. /package/dist/types/{index.d.ts → src/index.d.ts} +0 -0
  112. /package/dist/types/{interfaces → src/interfaces}/common.d.ts +0 -0
  113. /package/dist/types/{interfaces → src/interfaces}/events.d.ts +0 -0
  114. /package/dist/types/{interfaces → src/interfaces}/plugin.d.ts +0 -0
  115. /package/dist/types/{interfaces → src/interfaces}/shogun.d.ts +0 -0
  116. /package/dist/types/{managers → src/managers}/AuthManager.d.ts +0 -0
  117. /package/dist/types/{managers → src/managers}/CoreInitializer.d.ts +0 -0
  118. /package/dist/types/{managers → src/managers}/EventManager.d.ts +0 -0
  119. /package/dist/types/{managers → src/managers}/PluginManager.d.ts +0 -0
  120. /package/dist/types/{migration-test.d.ts → src/migration-test.d.ts} +0 -0
  121. /package/dist/types/{plugins → src/plugins}/base.d.ts +0 -0
  122. /package/dist/types/{plugins → src/plugins}/index.d.ts +0 -0
  123. /package/dist/types/{plugins → src/plugins}/nostr/index.d.ts +0 -0
  124. /package/dist/types/{plugins → src/plugins}/nostr/nostrConnector.d.ts +0 -0
  125. /package/dist/types/{plugins → src/plugins}/nostr/nostrConnectorPlugin.d.ts +0 -0
  126. /package/dist/types/{plugins → src/plugins}/nostr/nostrSigner.d.ts +0 -0
  127. /package/dist/types/{plugins → src/plugins}/nostr/types.d.ts +0 -0
  128. /package/dist/types/{plugins → src/plugins}/oauth/index.d.ts +0 -0
  129. /package/dist/types/{plugins → src/plugins}/oauth/oauthConnector.d.ts +0 -0
  130. /package/dist/types/{plugins → src/plugins}/oauth/oauthPlugin.d.ts +0 -0
  131. /package/dist/types/{plugins → src/plugins}/oauth/types.d.ts +0 -0
  132. /package/dist/types/{plugins → src/plugins}/web3/index.d.ts +0 -0
  133. /package/dist/types/{plugins → src/plugins}/web3/types.d.ts +0 -0
  134. /package/dist/types/{plugins → src/plugins}/web3/web3Connector.d.ts +0 -0
  135. /package/dist/types/{plugins → src/plugins}/web3/web3ConnectorPlugin.d.ts +0 -0
  136. /package/dist/types/{plugins → src/plugins}/web3/web3Signer.d.ts +0 -0
  137. /package/dist/types/{plugins → src/plugins}/webauthn/index.d.ts +0 -0
  138. /package/dist/types/{plugins → src/plugins}/webauthn/types.d.ts +0 -0
  139. /package/dist/types/{plugins → src/plugins}/webauthn/webauthn.d.ts +0 -0
  140. /package/dist/types/{plugins → src/plugins}/webauthn/webauthnPlugin.d.ts +0 -0
  141. /package/dist/types/{plugins → src/plugins}/webauthn/webauthnSigner.d.ts +0 -0
  142. /package/dist/types/{storage → src/storage}/storage.d.ts +0 -0
  143. /package/dist/types/{types → src/types}/events.d.ts +0 -0
  144. /package/dist/types/{types → src/types}/shogun.d.ts +0 -0
  145. /package/dist/types/{utils → src/utils}/errorHandler.d.ts +0 -0
  146. /package/dist/types/{utils → src/utils}/eventEmitter.d.ts +0 -0
  147. /package/dist/types/{utils → src/utils}/validation.d.ts +0 -0
@@ -0,0 +1,433 @@
1
+ "use strict";
2
+ /**
3
+ * SHIP-01: Decentralized Encrypted Messaging Implementation
4
+ *
5
+ * Messaggistica decentralizzata E2E che dipende da SHIP-00 per l'identità.
6
+ *
7
+ * Dipendenze:
8
+ * - SHIP-00 (Identity & Authentication) - per gestione utenti e chiavi
9
+ * - GunDB - per storage decentralizzato P2P
10
+ * - SEA - per crittografia ECDH + AES-GCM
11
+ *
12
+ * Vantaggi dell'architettura modulare:
13
+ * ✅ Separazione delle responsabilità (Identity vs Messaging)
14
+ * ✅ Riusabilità di SHIP-00 in altre applicazioni
15
+ * ✅ Testing più semplice e isolato
16
+ * ✅ Manutenibilità migliorata
17
+ */
18
+ Object.defineProperty(exports, "__esModule", { value: true });
19
+ exports.SHIP_01 = void 0;
20
+ const ethers_1 = require("ethers");
21
+ // ============================================================================
22
+ // IMPLEMENTATION
23
+ // ============================================================================
24
+ /**
25
+ * SHIP-01 Reference Implementation
26
+ *
27
+ * Questa implementazione dipende da ISHIP_00 per tutte le operazioni di identità.
28
+ * Si concentra esclusivamente sulla logica di messaggistica.
29
+ */
30
+ class SHIP_01 {
31
+ /**
32
+ * Constructor
33
+ * @param identity ISHIP_00 instance for identity operations
34
+ */
35
+ constructor(identity) {
36
+ if (!identity.isLoggedIn()) {
37
+ throw new Error("User must be authenticated via SHIP-00 before using SHIP-01");
38
+ }
39
+ this.identity = identity;
40
+ console.log("✅ SHIP-01 initialized with authenticated identity");
41
+ }
42
+ /**
43
+ * Get identity provider
44
+ */
45
+ getIdentity() {
46
+ return this.identity;
47
+ }
48
+ // ========================================================================
49
+ // MESSAGING - Send
50
+ // ========================================================================
51
+ /**
52
+ * Send encrypted message to a user
53
+ * Uses identity provider (SHIP-00) to get keys
54
+ */
55
+ async sendMessage(recipientUsername, message) {
56
+ try {
57
+ // Verify authentication
58
+ if (!this.identity.isLoggedIn()) {
59
+ return { success: false, error: "Not authenticated" };
60
+ }
61
+ // 1. Get recipient's public key from SHIP-00
62
+ const recipientKey = await this.identity.getPublicKey(recipientUsername);
63
+ if (!recipientKey) {
64
+ return {
65
+ success: false,
66
+ error: `Recipient ${recipientUsername} has not published their public key`,
67
+ };
68
+ }
69
+ // 2. Get sender's key pair from SHIP-00
70
+ const senderPair = this.identity.getKeyPair();
71
+ if (!senderPair) {
72
+ return { success: false, error: "Cannot access sender key pair" };
73
+ }
74
+ // 3. Get current user from SHIP-00
75
+ const currentUser = this.identity.getCurrentUser();
76
+ if (!currentUser) {
77
+ return { success: false, error: "No current user" };
78
+ }
79
+ // 4. Access GunDB through identity provider
80
+ const shogun = this.identity.getShogun();
81
+ if (!shogun || !shogun.db) {
82
+ return { success: false, error: "Cannot access ShogunCore" };
83
+ }
84
+ const gun = shogun.db.gun;
85
+ const crypto = shogun.db.crypto;
86
+ if (!gun || !crypto) {
87
+ return { success: false, error: "Cannot access GunDB or crypto" };
88
+ }
89
+ // 5. Encrypt message using ECDH
90
+ const encryptedMessage = await crypto.encFor(message, senderPair, { epub: recipientKey.epub });
91
+ // 6. Generate message ID
92
+ const messageId = this.generateMessageId();
93
+ // 7. Save encrypted message on GunDB
94
+ const messageData = {
95
+ from: currentUser.pub,
96
+ to: recipientUsername,
97
+ content: encryptedMessage,
98
+ timestamp: Date.now().toString(),
99
+ messageId: messageId,
100
+ };
101
+ await gun
102
+ .get(SHIP_01.NODES.MESSAGES)
103
+ .get(messageId)
104
+ .put(messageData)
105
+ .then();
106
+ console.log(`✅ Message sent: ${messageId}`);
107
+ return {
108
+ success: true,
109
+ messageId: messageId,
110
+ };
111
+ }
112
+ catch (error) {
113
+ console.error("❌ Error sending message:", error);
114
+ return {
115
+ success: false,
116
+ error: error.message,
117
+ };
118
+ }
119
+ }
120
+ // ========================================================================
121
+ // MESSAGING - Listen
122
+ // ========================================================================
123
+ /**
124
+ * Listen for incoming encrypted messages
125
+ * Uses identity provider (SHIP-00) to decrypt messages
126
+ */
127
+ async listenForMessages(onMessage) {
128
+ if (!this.identity.isLoggedIn()) {
129
+ console.error("❌ Not authenticated");
130
+ return;
131
+ }
132
+ // Get current user from SHIP-00
133
+ const currentUser = this.identity.getCurrentUser();
134
+ if (!currentUser || !currentUser.alias) {
135
+ console.error("❌ No current user");
136
+ return;
137
+ }
138
+ const username = currentUser.alias;
139
+ // Access GunDB
140
+ const shogun = this.identity.getShogun();
141
+ const gun = shogun?.db?.gun;
142
+ if (!gun) {
143
+ console.error("❌ Cannot access GunDB");
144
+ return;
145
+ }
146
+ // Track received messages to avoid duplicates
147
+ const receivedMessages = new Set();
148
+ // Listen for messages in real-time
149
+ gun
150
+ .get(SHIP_01.NODES.MESSAGES)
151
+ .map()
152
+ .on(async (data, key) => {
153
+ // Filter messages for this user
154
+ if (data &&
155
+ data.to === username &&
156
+ data.from &&
157
+ data.content &&
158
+ data.messageId) {
159
+ // Avoid duplicates
160
+ if (receivedMessages.has(data.messageId)) {
161
+ return;
162
+ }
163
+ receivedMessages.add(data.messageId);
164
+ try {
165
+ // Decrypt message using SHIP-00
166
+ const decryptedContent = await this.decryptMessage(data.content, data.from);
167
+ onMessage({
168
+ from: data.from,
169
+ content: decryptedContent,
170
+ timestamp: parseInt(data.timestamp),
171
+ });
172
+ }
173
+ catch (error) {
174
+ console.error("❌ Error decrypting message:", error);
175
+ }
176
+ }
177
+ });
178
+ console.log(`👂 Listening for messages to ${username}...`);
179
+ }
180
+ // ========================================================================
181
+ // MESSAGING - History
182
+ // ========================================================================
183
+ /**
184
+ * Get message history with a user
185
+ * Uses identity provider (SHIP-00) to decrypt messages
186
+ */
187
+ async getMessageHistory(withUsername) {
188
+ if (!this.identity.isLoggedIn()) {
189
+ console.error("❌ Not authenticated");
190
+ return [];
191
+ }
192
+ // Get current user from SHIP-00
193
+ const currentUser = this.identity.getCurrentUser();
194
+ if (!currentUser || !currentUser.alias) {
195
+ console.error("❌ No current user");
196
+ return [];
197
+ }
198
+ const username = currentUser.alias;
199
+ const userPub = currentUser.pub;
200
+ // Get other user's public key from SHIP-00
201
+ const otherUserData = await this.identity.getUserByAlias(withUsername);
202
+ const otherUserPub = otherUserData?.userPub;
203
+ // Access GunDB
204
+ const shogun = this.identity.getShogun();
205
+ const gun = shogun?.db?.gun;
206
+ if (!gun) {
207
+ console.error("❌ Cannot access GunDB");
208
+ return [];
209
+ }
210
+ // Get all messages and filter
211
+ return new Promise((resolve) => {
212
+ const messages = [];
213
+ gun
214
+ .get(SHIP_01.NODES.MESSAGES)
215
+ .map()
216
+ .once(async (msgData, messageId) => {
217
+ // Skip metadata
218
+ if (!msgData || typeof msgData !== "object" || messageId === "_") {
219
+ return;
220
+ }
221
+ try {
222
+ // Check if message is part of this conversation
223
+ const isSentToTarget = msgData.from === userPub &&
224
+ (msgData.to === withUsername || msgData.to === otherUserPub);
225
+ const isReceivedFromTarget = (msgData.to === username || msgData.to === userPub) &&
226
+ msgData.from === otherUserPub;
227
+ if (isSentToTarget || isReceivedFromTarget) {
228
+ // Decrypt message
229
+ const decryptedContent = await this.decryptMessage(msgData.content, msgData.from);
230
+ messages.push({
231
+ from: msgData.from,
232
+ to: msgData.to,
233
+ content: decryptedContent,
234
+ timestamp: parseInt(msgData.timestamp),
235
+ });
236
+ }
237
+ }
238
+ catch (error) {
239
+ // Silent error - message couldn't be decrypted
240
+ }
241
+ });
242
+ // Wait for GunDB to return all messages, then resolve
243
+ setTimeout(() => {
244
+ const sorted = messages.sort((a, b) => a.timestamp - b.timestamp);
245
+ resolve(sorted);
246
+ }, 2000);
247
+ });
248
+ }
249
+ // ========================================================================
250
+ // PRIVATE HELPERS
251
+ // ========================================================================
252
+ /**
253
+ * Decrypt a message using ECDH
254
+ * Uses identity provider (SHIP-00) to get keys
255
+ */
256
+ async decryptMessage(encryptedContent, senderPub) {
257
+ // Get receiver's key pair from SHIP-00
258
+ const receiverPair = this.identity.getKeyPair();
259
+ if (!receiverPair) {
260
+ throw new Error("Cannot access receiver key pair");
261
+ }
262
+ // Get sender's public key
263
+ const senderKeyData = await this.getPublicKeyByPub(senderPub);
264
+ if (!senderKeyData) {
265
+ throw new Error("Sender public key not found");
266
+ }
267
+ // Access crypto
268
+ const shogun = this.identity.getShogun();
269
+ const crypto = shogun?.db?.crypto;
270
+ if (!crypto) {
271
+ throw new Error("Cannot access crypto");
272
+ }
273
+ // Decrypt using ECDH
274
+ const decrypted = await crypto.decFrom(encryptedContent, { epub: senderKeyData.epub }, receiverPair);
275
+ return decrypted;
276
+ }
277
+ /**
278
+ * Get public key by pub key
279
+ * Uses identity provider internally
280
+ */
281
+ async getPublicKeyByPub(userPub) {
282
+ try {
283
+ // Access GunDB
284
+ const shogun = this.identity.getShogun();
285
+ const gun = shogun?.db?.gun;
286
+ if (!gun) {
287
+ return null;
288
+ }
289
+ const publicKeyData = await 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("❌ Error getting public key:", error);
300
+ return null;
301
+ }
302
+ }
303
+ /**
304
+ * Generate unique message ID
305
+ */
306
+ generateMessageId() {
307
+ return ethers_1.ethers.hexlify(ethers_1.ethers.randomBytes(16));
308
+ }
309
+ // ========================================================================
310
+ // TOKEN-BASED MESSAGING (Channels/Groups)
311
+ // ========================================================================
312
+ /**
313
+ * Send message encrypted with shared token/password
314
+ * Useful for group chats, channels, broadcast messages
315
+ */
316
+ async sendMessageWithToken(token, message, channel) {
317
+ try {
318
+ // Verify authentication
319
+ if (!this.identity.isLoggedIn()) {
320
+ return { success: false, error: "Not authenticated" };
321
+ }
322
+ // Get current user
323
+ const currentUser = this.identity.getCurrentUser();
324
+ if (!currentUser) {
325
+ return { success: false, error: "No current user" };
326
+ }
327
+ // Access crypto and GunDB
328
+ const shogun = this.identity.getShogun();
329
+ const crypto = shogun?.db?.crypto;
330
+ const gun = shogun?.db?.gun;
331
+ if (!crypto || !gun) {
332
+ return { success: false, error: "Cannot access crypto or GunDB" };
333
+ }
334
+ // Hash token for key derivation (more secure)
335
+ const hashedToken = await crypto.hashText(token);
336
+ // Encrypt message with hashed token
337
+ const encryptedMessage = await crypto.encrypt(message, hashedToken);
338
+ // Generate message ID
339
+ const messageId = this.generateMessageId();
340
+ // Save encrypted message
341
+ const messageData = {
342
+ from: currentUser.pub,
343
+ content: encryptedMessage,
344
+ channel: channel || "default",
345
+ timestamp: Date.now().toString(),
346
+ messageId: messageId,
347
+ type: "token", // Mark as token-encrypted
348
+ };
349
+ await gun
350
+ .get(SHIP_01.NODES.TOKEN_MESSAGES)
351
+ .get(messageId)
352
+ .put(messageData)
353
+ .then();
354
+ console.log(`✅ Token message sent: ${messageId} (channel: ${channel || "default"})`);
355
+ return {
356
+ success: true,
357
+ messageId: messageId,
358
+ };
359
+ }
360
+ catch (error) {
361
+ console.error("❌ Error sending token message:", error);
362
+ return {
363
+ success: false,
364
+ error: error.message,
365
+ };
366
+ }
367
+ }
368
+ /**
369
+ * Listen for token-encrypted messages
370
+ * Automatically decrypts with provided token
371
+ */
372
+ async listenForTokenMessages(token, onMessage, channel) {
373
+ if (!this.identity.isLoggedIn()) {
374
+ console.error("❌ Not authenticated");
375
+ return;
376
+ }
377
+ // Access GunDB and crypto
378
+ const shogun = this.identity.getShogun();
379
+ const gun = shogun?.db?.gun;
380
+ const crypto = shogun?.db?.crypto;
381
+ if (!gun || !crypto) {
382
+ console.error("❌ Cannot access GunDB or crypto");
383
+ return;
384
+ }
385
+ // Hash token for decryption
386
+ const hashedToken = await crypto.hashText(token);
387
+ // Track received messages to avoid duplicates
388
+ const receivedMessages = new Set();
389
+ // Listen for token messages in real-time
390
+ gun
391
+ .get(SHIP_01.NODES.TOKEN_MESSAGES)
392
+ .map()
393
+ .on(async (data, key) => {
394
+ // Filter by channel if specified
395
+ if (channel && data?.channel !== channel) {
396
+ return;
397
+ }
398
+ // Validate data
399
+ if (data &&
400
+ data.type === "token" &&
401
+ data.from &&
402
+ data.content &&
403
+ data.messageId) {
404
+ // Avoid duplicates
405
+ if (receivedMessages.has(data.messageId)) {
406
+ return;
407
+ }
408
+ receivedMessages.add(data.messageId);
409
+ try {
410
+ // Decrypt message with hashed token
411
+ const decryptedContent = await crypto.decrypt(data.content, hashedToken);
412
+ onMessage({
413
+ from: data.from,
414
+ content: decryptedContent,
415
+ channel: data.channel,
416
+ timestamp: parseInt(data.timestamp),
417
+ });
418
+ }
419
+ catch (error) {
420
+ // Silently skip messages that can't be decrypted
421
+ // (wrong token or corrupted data)
422
+ }
423
+ }
424
+ });
425
+ console.log(`👂 Listening for token messages (channel: ${channel || "all"})...`);
426
+ }
427
+ }
428
+ exports.SHIP_01 = SHIP_01;
429
+ // GunDB Node Names for messaging
430
+ SHIP_01.NODES = {
431
+ MESSAGES: "messages",
432
+ TOKEN_MESSAGES: "token_messages", // Token-encrypted messages (channels/groups)
433
+ };