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.
- package/dist/ship/examples/ephemeral-cli.js +234 -0
- package/dist/ship/examples/identity-cli.js +503 -0
- package/dist/ship/examples/messenger-cli.js +745 -0
- package/dist/ship/examples/stealth-cli.js +433 -0
- package/dist/ship/examples/storage-cli.js +615 -0
- package/dist/ship/examples/vault-cli.js +444 -0
- package/dist/ship/examples/wallet-cli.js +767 -0
- package/dist/ship/implementation/SHIP_00.js +478 -0
- package/dist/ship/implementation/SHIP_01.js +433 -0
- package/dist/ship/implementation/SHIP_02.js +1366 -0
- package/dist/ship/implementation/SHIP_03.js +855 -0
- package/dist/ship/implementation/SHIP_04.js +589 -0
- package/dist/ship/implementation/SHIP_05.js +1064 -0
- package/dist/ship/implementation/SHIP_06.js +350 -0
- package/dist/ship/implementation/SHIP_07.js +635 -0
- package/dist/ship/index.js +17 -0
- package/dist/ship/interfaces/ISHIP_00.js +135 -0
- package/dist/ship/interfaces/ISHIP_01.js +128 -0
- package/dist/ship/interfaces/ISHIP_02.js +57 -0
- package/dist/ship/interfaces/ISHIP_03.js +61 -0
- package/dist/ship/interfaces/ISHIP_04.js +62 -0
- package/dist/ship/interfaces/ISHIP_05.js +59 -0
- package/dist/ship/interfaces/ISHIP_06.js +144 -0
- package/dist/ship/interfaces/ISHIP_07.js +194 -0
- package/dist/types/ship/examples/ephemeral-cli.d.ts +13 -0
- package/dist/types/ship/examples/identity-cli.d.ts +40 -0
- package/dist/types/ship/examples/messenger-cli.d.ts +37 -0
- package/dist/types/ship/examples/stealth-cli.d.ts +31 -0
- package/dist/types/ship/examples/storage-cli.d.ts +48 -0
- package/dist/types/ship/examples/vault-cli.d.ts +13 -0
- package/dist/types/ship/examples/wallet-cli.d.ts +131 -0
- package/dist/types/ship/implementation/SHIP_00.d.ts +113 -0
- package/dist/types/ship/implementation/SHIP_01.d.ts +80 -0
- package/dist/types/ship/implementation/SHIP_02.d.ts +297 -0
- package/dist/types/ship/implementation/SHIP_03.d.ts +127 -0
- package/dist/types/ship/implementation/SHIP_04.d.ts +76 -0
- package/dist/types/ship/implementation/SHIP_05.d.ts +70 -0
- package/dist/types/ship/implementation/SHIP_06.d.ts +66 -0
- package/dist/types/ship/implementation/SHIP_07.d.ts +101 -0
- package/dist/types/ship/index.d.ts +14 -0
- package/dist/types/ship/interfaces/ISHIP_00.d.ts +410 -0
- package/dist/types/ship/interfaces/ISHIP_01.d.ts +343 -0
- package/dist/types/ship/interfaces/ISHIP_02.d.ts +470 -0
- package/dist/types/ship/interfaces/ISHIP_03.d.ts +295 -0
- package/dist/types/ship/interfaces/ISHIP_04.d.ts +245 -0
- package/dist/types/ship/interfaces/ISHIP_05.d.ts +234 -0
- package/dist/types/ship/interfaces/ISHIP_06.d.ts +370 -0
- package/dist/types/ship/interfaces/ISHIP_07.d.ts +522 -0
- package/package.json +1 -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}/db.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/{index.js → src/index.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/{index.d.ts → src/index.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,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
|
+
};
|