shogun-core 3.2.3 → 3.3.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/README.md +12 -0
- package/dist/browser/shogun-core.js +108102 -43579
- package/dist/browser/shogun-core.js.map +1 -1
- package/dist/ship/examples/messenger-cli.js +171 -55
- 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 +275 -492
- package/dist/ship/implementation/SHIP_02.js +1366 -0
- package/dist/ship/implementation/SHIP_03.js +855 -0
- package/dist/ship/interfaces/ISHIP_00.js +135 -0
- package/dist/ship/interfaces/ISHIP_01.js +81 -24
- package/dist/ship/interfaces/ISHIP_02.js +57 -0
- package/dist/ship/interfaces/ISHIP_03.js +61 -0
- package/dist/src/gundb/db.js +55 -11
- package/dist/src/index.js +10 -2
- package/dist/src/managers/CoreInitializer.js +41 -13
- package/dist/src/storage/storage.js +22 -9
- package/dist/types/ship/examples/messenger-cli.d.ts +7 -1
- 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 +44 -77
- 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/interfaces/ISHIP_00.d.ts +410 -0
- package/dist/types/ship/interfaces/ISHIP_01.d.ts +157 -119
- 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/src/gundb/db.d.ts +10 -3
- package/dist/types/src/index.d.ts +7 -0
- package/dist/types/src/interfaces/shogun.d.ts +2 -0
- package/dist/types/src/storage/storage.d.ts +2 -1
- package/package.json +22 -9
|
@@ -3,51 +3,30 @@
|
|
|
3
3
|
*
|
|
4
4
|
* @title ISHIP_01 - Decentralized Encrypted Messaging
|
|
5
5
|
* @notice Interface for decentralized encrypted messaging on GunDB
|
|
6
|
+
* @dev This interface depends on ISHIP_00 for identity and authentication
|
|
6
7
|
*
|
|
7
8
|
* ## Abstract
|
|
8
9
|
*
|
|
9
10
|
* This standard defines an interface for decentralized messaging that allows:
|
|
10
|
-
* - Username/password authentication
|
|
11
|
-
* - Public key publication on GunDB
|
|
12
11
|
* - End-to-end encrypted message sending (ECDH)
|
|
13
12
|
* - Real-time message reception
|
|
14
13
|
* - Decentralized message history
|
|
15
14
|
*
|
|
15
|
+
* ## Dependencies
|
|
16
|
+
*
|
|
17
|
+
* - ISHIP_00: Identity and authentication layer
|
|
18
|
+
* - GunDB: P2P storage
|
|
19
|
+
* - SEA: Cryptography (ECDH + AES-GCM)
|
|
20
|
+
*
|
|
16
21
|
* ## Specification
|
|
17
22
|
*
|
|
18
23
|
* Based on:
|
|
24
|
+
* - SHIP-00 for identity management
|
|
19
25
|
* - GunDB for P2P storage
|
|
20
26
|
* - SEA (Security, Encryption, Authorization) for cryptography
|
|
21
27
|
* - ECDH (Elliptic Curve Diffie-Hellman) for key agreement
|
|
22
28
|
*/
|
|
23
|
-
|
|
24
|
-
* @notice Authentication result
|
|
25
|
-
*/
|
|
26
|
-
export interface AuthResult {
|
|
27
|
-
success: boolean;
|
|
28
|
-
userPub?: string;
|
|
29
|
-
derivedAddress?: string;
|
|
30
|
-
error?: string;
|
|
31
|
-
}
|
|
32
|
-
/**
|
|
33
|
-
* @notice Signup result
|
|
34
|
-
*/
|
|
35
|
-
export interface SignupResult {
|
|
36
|
-
success: boolean;
|
|
37
|
-
userPub?: string;
|
|
38
|
-
derivedAddress?: string;
|
|
39
|
-
error?: string;
|
|
40
|
-
}
|
|
41
|
-
/**
|
|
42
|
-
* @notice Message structure
|
|
43
|
-
*/
|
|
44
|
-
export interface Message {
|
|
45
|
-
from: string;
|
|
46
|
-
to: string;
|
|
47
|
-
content: string;
|
|
48
|
-
timestamp: string;
|
|
49
|
-
messageId: string;
|
|
50
|
-
}
|
|
29
|
+
import type { ISHIP_00 } from "./ISHIP_00";
|
|
51
30
|
/**
|
|
52
31
|
* @notice Decrypted message structure (for UI)
|
|
53
32
|
*/
|
|
@@ -57,61 +36,50 @@ export interface DecryptedMessage {
|
|
|
57
36
|
timestamp: number;
|
|
58
37
|
}
|
|
59
38
|
/**
|
|
60
|
-
* @notice
|
|
39
|
+
* @notice Message history entry
|
|
61
40
|
*/
|
|
62
|
-
export interface
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
timestamp:
|
|
41
|
+
export interface MessageHistoryEntry {
|
|
42
|
+
from: string;
|
|
43
|
+
to: string;
|
|
44
|
+
content: string;
|
|
45
|
+
timestamp: number;
|
|
67
46
|
}
|
|
68
47
|
/**
|
|
69
|
-
* @notice
|
|
48
|
+
* @notice Send message result
|
|
70
49
|
*/
|
|
71
|
-
export interface
|
|
50
|
+
export interface SendMessageResult {
|
|
72
51
|
success: boolean;
|
|
52
|
+
messageId?: string;
|
|
73
53
|
error?: string;
|
|
74
54
|
}
|
|
75
55
|
/**
|
|
76
|
-
* @notice
|
|
56
|
+
* @notice Token-encrypted message (for channels/groups)
|
|
77
57
|
*/
|
|
78
|
-
export interface
|
|
79
|
-
|
|
58
|
+
export interface TokenMessage {
|
|
59
|
+
content: string;
|
|
60
|
+
from: string;
|
|
61
|
+
channel?: string;
|
|
62
|
+
timestamp: number;
|
|
80
63
|
}
|
|
81
64
|
/**
|
|
82
65
|
* @title ISHIP_01 - Decentralized Messaging
|
|
83
66
|
* @notice Main interface for the messaging system
|
|
67
|
+
* @dev Depends on ISHIP_00 for all identity operations
|
|
68
|
+
*
|
|
69
|
+
* Constructor pattern:
|
|
70
|
+
* ```typescript
|
|
71
|
+
* class MessagingApp implements ISHIP_01 {
|
|
72
|
+
* constructor(private identity: ISHIP_00) {}
|
|
73
|
+
* }
|
|
74
|
+
* ```
|
|
84
75
|
*/
|
|
85
76
|
export interface ISHIP_01 {
|
|
86
77
|
/**
|
|
87
|
-
* @notice
|
|
88
|
-
* @
|
|
89
|
-
* @
|
|
90
|
-
* @return Result with userPub and derivedAddress
|
|
91
|
-
*/
|
|
92
|
-
signup(username: string, password: string): Promise<SignupResult>;
|
|
93
|
-
/**
|
|
94
|
-
* @notice Login with username and password
|
|
95
|
-
* @param username Username
|
|
96
|
-
* @param password Password
|
|
97
|
-
* @return Result with userPub and derivedAddress
|
|
98
|
-
*/
|
|
99
|
-
login(username: string, password: string): Promise<AuthResult>;
|
|
100
|
-
/**
|
|
101
|
-
* @notice Logout current user
|
|
78
|
+
* @notice Get the identity provider
|
|
79
|
+
* @dev Returns the ISHIP_00 instance used for identity operations
|
|
80
|
+
* @return Identity provider instance
|
|
102
81
|
*/
|
|
103
|
-
|
|
104
|
-
/**
|
|
105
|
-
* @notice Check if user is authenticated
|
|
106
|
-
* @return True if authenticated
|
|
107
|
-
*/
|
|
108
|
-
isLoggedIn(): boolean;
|
|
109
|
-
/**
|
|
110
|
-
* @notice Publish public key on GunDB
|
|
111
|
-
* @dev Allows others to find your key to encrypt messages
|
|
112
|
-
* @return Operation result
|
|
113
|
-
*/
|
|
114
|
-
publishPublicKey(): Promise<OperationResult>;
|
|
82
|
+
getIdentity(): ISHIP_00;
|
|
115
83
|
/**
|
|
116
84
|
* @notice Send encrypted message
|
|
117
85
|
* @dev Uses ECDH to derive shared secret, then AES-GCM for encryption
|
|
@@ -119,8 +87,12 @@ export interface ISHIP_01 {
|
|
|
119
87
|
* @param message Plain text message content
|
|
120
88
|
* @return Result with messageId
|
|
121
89
|
*
|
|
90
|
+
* Prerequisites:
|
|
91
|
+
* - User must be authenticated (via ISHIP_00)
|
|
92
|
+
* - Recipient must have published their public key
|
|
93
|
+
*
|
|
122
94
|
* Flow:
|
|
123
|
-
* 1.
|
|
95
|
+
* 1. Get recipient's epub from identity provider
|
|
124
96
|
* 2. SEA.secret(recipient.epub, sender.pair) → shared_secret
|
|
125
97
|
* 3. SEA.encrypt(message, shared_secret) → encrypted
|
|
126
98
|
* 4. Save encrypted on GunDB
|
|
@@ -131,9 +103,12 @@ export interface ISHIP_01 {
|
|
|
131
103
|
* @dev Automatically decrypts received messages
|
|
132
104
|
* @param onMessage Callback called for each message
|
|
133
105
|
*
|
|
106
|
+
* Prerequisites:
|
|
107
|
+
* - User must be authenticated (via ISHIP_00)
|
|
108
|
+
*
|
|
134
109
|
* Decryption flow:
|
|
135
110
|
* 1. Receive encrypted message from GunDB
|
|
136
|
-
* 2. Retrieve sender's epub
|
|
111
|
+
* 2. Retrieve sender's epub from identity provider
|
|
137
112
|
* 3. SEA.secret(sender.epub, receiver.pair) → shared_secret
|
|
138
113
|
* 4. SEA.decrypt(encrypted, shared_secret) → message
|
|
139
114
|
* 5. Call callback with decrypted message
|
|
@@ -144,44 +119,56 @@ export interface ISHIP_01 {
|
|
|
144
119
|
* @dev Decrypts all messages in history
|
|
145
120
|
* @param withUsername Username of the other user
|
|
146
121
|
* @return Array of decrypted messages sorted by timestamp
|
|
122
|
+
*
|
|
123
|
+
* Prerequisites:
|
|
124
|
+
* - User must be authenticated (via ISHIP_00)
|
|
147
125
|
*/
|
|
148
|
-
getMessageHistory(withUsername: string): Promise<
|
|
149
|
-
from: string;
|
|
150
|
-
to: string;
|
|
151
|
-
content: string;
|
|
152
|
-
timestamp: number;
|
|
153
|
-
}>>;
|
|
154
|
-
}
|
|
155
|
-
/**
|
|
156
|
-
* @notice Interface for GunDB → Ethereum identity conversion
|
|
157
|
-
*/
|
|
158
|
-
export interface IAddressDerivation {
|
|
126
|
+
getMessageHistory(withUsername: string): Promise<MessageHistoryEntry[]>;
|
|
159
127
|
/**
|
|
160
|
-
* @notice
|
|
161
|
-
* @
|
|
162
|
-
* @
|
|
128
|
+
* @notice Send message encrypted with a shared token/password
|
|
129
|
+
* @dev Uses symmetric encryption with provided token
|
|
130
|
+
* @param token Shared secret/password for encryption
|
|
131
|
+
* @param message Plain text message content
|
|
132
|
+
* @param channel Optional channel name for organization
|
|
133
|
+
* @return Result with messageId
|
|
134
|
+
*
|
|
135
|
+
* Use cases:
|
|
136
|
+
* - Group chats with shared password
|
|
137
|
+
* - Broadcast channels
|
|
138
|
+
* - Private communities
|
|
139
|
+
*
|
|
140
|
+
* Flow:
|
|
141
|
+
* 1. Hash token for key derivation
|
|
142
|
+
* 2. SEA.encrypt(message, hashedToken) → encrypted
|
|
143
|
+
* 3. Save encrypted on GunDB with channel tag
|
|
144
|
+
*/
|
|
145
|
+
sendMessageWithToken(token: string, message: string, channel?: string): Promise<SendMessageResult>;
|
|
146
|
+
/**
|
|
147
|
+
* @notice Listen for token-encrypted messages
|
|
148
|
+
* @dev Automatically decrypts received messages with provided token
|
|
149
|
+
* @param token Shared secret/password for decryption
|
|
150
|
+
* @param onMessage Callback called for each message
|
|
151
|
+
* @param channel Optional channel filter
|
|
163
152
|
*
|
|
164
|
-
*
|
|
165
|
-
*
|
|
166
|
-
*
|
|
167
|
-
*
|
|
168
|
-
*
|
|
169
|
-
*
|
|
153
|
+
* Prerequisites:
|
|
154
|
+
* - User must be authenticated (via ISHIP_00)
|
|
155
|
+
*
|
|
156
|
+
* Decryption flow:
|
|
157
|
+
* 1. Receive encrypted message from GunDB
|
|
158
|
+
* 2. Hash token
|
|
159
|
+
* 3. SEA.decrypt(encrypted, hashedToken) → message
|
|
160
|
+
* 4. Call callback with decrypted message
|
|
170
161
|
*/
|
|
171
|
-
|
|
162
|
+
listenForTokenMessages(token: string, onMessage: (message: TokenMessage) => void, channel?: string): Promise<void>;
|
|
172
163
|
}
|
|
173
164
|
/**
|
|
174
165
|
* @notice Messaging system configuration
|
|
175
166
|
*/
|
|
176
167
|
export interface MessagingConfig {
|
|
177
168
|
/**
|
|
178
|
-
* @notice
|
|
179
|
-
*/
|
|
180
|
-
peers: string[];
|
|
181
|
-
/**
|
|
182
|
-
* @notice Application scope
|
|
169
|
+
* @notice Identity provider (SHIP-00 instance)
|
|
183
170
|
*/
|
|
184
|
-
|
|
171
|
+
identity: ISHIP_00;
|
|
185
172
|
/**
|
|
186
173
|
* @notice Operation timeout (ms)
|
|
187
174
|
*/
|
|
@@ -260,46 +247,97 @@ export interface ISEACrypto {
|
|
|
260
247
|
hashText(text: string): Promise<string>;
|
|
261
248
|
}
|
|
262
249
|
/**
|
|
263
|
-
* Example of how to implement ISHIP_01
|
|
250
|
+
* Example of how to implement ISHIP_01 with ISHIP_00 dependency
|
|
264
251
|
*
|
|
265
252
|
* ```typescript
|
|
266
|
-
*
|
|
267
|
-
*
|
|
253
|
+
* import { ISHIP_00 } from './ISHIP_00';
|
|
254
|
+
* import { ISHIP_01, DecryptedMessage, SendMessageResult } from './ISHIP_01';
|
|
268
255
|
*
|
|
269
|
-
*
|
|
270
|
-
*
|
|
256
|
+
* class SecureMessagingApp implements ISHIP_01 {
|
|
257
|
+
* constructor(private identity: ISHIP_00) {
|
|
258
|
+
* // Verify identity is authenticated
|
|
259
|
+
* if (!identity.isLoggedIn()) {
|
|
260
|
+
* throw new Error('User must be authenticated');
|
|
261
|
+
* }
|
|
271
262
|
* }
|
|
272
263
|
*
|
|
273
|
-
*
|
|
274
|
-
*
|
|
275
|
-
* return {
|
|
276
|
-
* success: result.success,
|
|
277
|
-
* userPub: result.pub,
|
|
278
|
-
* derivedAddress: this.pubKeyToAddress(result.pub || "")
|
|
279
|
-
* };
|
|
264
|
+
* getIdentity(): ISHIP_00 {
|
|
265
|
+
* return this.identity;
|
|
280
266
|
* }
|
|
281
267
|
*
|
|
282
268
|
* async sendMessage(recipientUsername: string, message: string): Promise<SendMessageResult> {
|
|
283
|
-
* // 1. Get recipient's
|
|
284
|
-
* const recipientKey = await this.
|
|
269
|
+
* // 1. Get recipient's public key from identity provider
|
|
270
|
+
* const recipientKey = await this.identity.getPublicKey(recipientUsername);
|
|
271
|
+
* if (!recipientKey) {
|
|
272
|
+
* return { success: false, error: 'Recipient not found' };
|
|
273
|
+
* }
|
|
285
274
|
*
|
|
286
|
-
* // 2.
|
|
287
|
-
* const
|
|
275
|
+
* // 2. Get sender's key pair from identity provider
|
|
276
|
+
* const senderPair = this.identity.getKeyPair();
|
|
277
|
+
* if (!senderPair) {
|
|
278
|
+
* return { success: false, error: 'Not authenticated' };
|
|
279
|
+
* }
|
|
280
|
+
*
|
|
281
|
+
* // 3. Encrypt with ECDH
|
|
282
|
+
* const encrypted = await crypto.encFor(
|
|
288
283
|
* message,
|
|
289
|
-
*
|
|
290
|
-
* { epub: recipientKey.epub }
|
|
284
|
+
* senderPair,
|
|
285
|
+
* { epub: recipientKey.epub }
|
|
291
286
|
* );
|
|
292
287
|
*
|
|
293
|
-
* //
|
|
294
|
-
*
|
|
288
|
+
* // 4. Save to GunDB
|
|
289
|
+
* const messageId = generateId();
|
|
290
|
+
* await gun.get('messages').get(messageId).put({
|
|
295
291
|
* content: encrypted,
|
|
296
|
-
* from:
|
|
292
|
+
* from: senderPair.pub,
|
|
297
293
|
* to: recipientUsername,
|
|
298
294
|
* timestamp: Date.now().toString()
|
|
299
295
|
* });
|
|
300
296
|
*
|
|
301
|
-
* return { success: true, messageId
|
|
297
|
+
* return { success: true, messageId };
|
|
298
|
+
* }
|
|
299
|
+
*
|
|
300
|
+
* async listenForMessages(onMessage: (message: DecryptedMessage) => void): Promise<void> {
|
|
301
|
+
* const currentUser = this.identity.getCurrentUser();
|
|
302
|
+
* if (!currentUser) {
|
|
303
|
+
* throw new Error('Not authenticated');
|
|
304
|
+
* }
|
|
305
|
+
*
|
|
306
|
+
* gun.get('messages').map().on(async (data, key) => {
|
|
307
|
+
* if (data && data.to === currentUser.alias) {
|
|
308
|
+
* // Decrypt message
|
|
309
|
+
* const senderKey = await this.identity.getPublicKey(data.from);
|
|
310
|
+
* const receiverPair = this.identity.getKeyPair();
|
|
311
|
+
*
|
|
312
|
+
* if (senderKey && receiverPair) {
|
|
313
|
+
* const decrypted = await crypto.decFrom(
|
|
314
|
+
* data.content,
|
|
315
|
+
* { epub: senderKey.epub },
|
|
316
|
+
* receiverPair
|
|
317
|
+
* );
|
|
318
|
+
*
|
|
319
|
+
* onMessage({
|
|
320
|
+
* from: data.from,
|
|
321
|
+
* content: decrypted,
|
|
322
|
+
* timestamp: parseInt(data.timestamp)
|
|
323
|
+
* });
|
|
324
|
+
* }
|
|
325
|
+
* }
|
|
326
|
+
* });
|
|
327
|
+
* }
|
|
328
|
+
*
|
|
329
|
+
* async getMessageHistory(withUsername: string): Promise<MessageHistoryEntry[]> {
|
|
330
|
+
* // Implementation here
|
|
331
|
+
* return [];
|
|
302
332
|
* }
|
|
303
333
|
* }
|
|
334
|
+
*
|
|
335
|
+
* // Usage
|
|
336
|
+
* const identity = new SHIP_00(config);
|
|
337
|
+
* await identity.login('alice', 'password123');
|
|
338
|
+
* await identity.publishPublicKey();
|
|
339
|
+
*
|
|
340
|
+
* const messaging = new SecureMessagingApp(identity);
|
|
341
|
+
* await messaging.sendMessage('bob', 'Hello Bob!');
|
|
304
342
|
* ```
|
|
305
343
|
*/
|