shogun-core 3.3.4 → 3.3.5
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/defaultVendors-node_modules_shogun-ipfs_node_modules_axios_index_js.shogun-core.js +4073 -2
- package/dist/browser/defaultVendors-node_modules_shogun-ipfs_node_modules_axios_index_js.shogun-core.js.map +1 -0
- package/dist/browser/shogun-core.js +597 -343
- package/dist/browser/shogun-core.js.map +1 -1
- package/dist/ship/examples/identity-cli.js +12 -4
- package/dist/ship/examples/vault-cli.js +2 -2
- package/dist/ship/implementation/SHIP_06.js +574 -289
- package/dist/ship/interfaces/ISHIP_06.js +135 -85
- package/dist/src/gundb/db.js +7 -49
- package/dist/types/ship/implementation/SHIP_06.d.ts +90 -55
- package/dist/types/ship/interfaces/ISHIP_06.d.ts +383 -231
- package/package.json +2 -8
- package/dist/ship/examples/ephemeral-cli.js +0 -234
- package/dist/ship/implementation/SHIP_07.js +0 -635
- package/dist/ship/interfaces/ISHIP_07.js +0 -194
- package/dist/types/ship/examples/ephemeral-cli.d.ts +0 -13
- package/dist/types/ship/implementation/SHIP_07.d.ts +0 -101
- package/dist/types/ship/interfaces/ISHIP_07.d.ts +0 -522
|
@@ -1,224 +1,313 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* SHIP-06:
|
|
2
|
+
* SHIP-06: Secure Vault Interface
|
|
3
3
|
*
|
|
4
|
-
* @title ISHIP_06 -
|
|
5
|
-
* @notice Interface for
|
|
6
|
-
* @dev
|
|
4
|
+
* @title ISHIP_06 - Secure Encrypted Vault
|
|
5
|
+
* @notice Interface for secure encrypted key-value storage on GunDB
|
|
6
|
+
* @dev This interface depends on ISHIP_00 for identity and encryption
|
|
7
7
|
*
|
|
8
8
|
* ## Abstract
|
|
9
9
|
*
|
|
10
|
-
* This standard defines an interface for
|
|
11
|
-
* -
|
|
12
|
-
* -
|
|
13
|
-
* -
|
|
14
|
-
* -
|
|
15
|
-
* -
|
|
10
|
+
* This standard defines an interface for secure vault storage that allows:
|
|
11
|
+
* - End-to-end encrypted key-value storage
|
|
12
|
+
* - Soft delete with recovery
|
|
13
|
+
* - Export/import for backup
|
|
14
|
+
* - Rich metadata support
|
|
15
|
+
* - Simple, secure, focused on storage only
|
|
16
16
|
*
|
|
17
17
|
* ## Dependencies
|
|
18
18
|
*
|
|
19
|
-
* -
|
|
20
|
-
* -
|
|
21
|
-
* -
|
|
22
|
-
*
|
|
23
|
-
* ## Modes
|
|
24
|
-
*
|
|
25
|
-
* **Standalone**: new SHIP_06(gunPeers[], roomId)
|
|
26
|
-
* **With Identity**: new SHIP_06(ISHIP_00, roomId)
|
|
19
|
+
* - ISHIP_00: Identity and authentication layer
|
|
20
|
+
* - GunDB: P2P storage
|
|
21
|
+
* - SEA: Cryptography (AES-256-GCM)
|
|
27
22
|
*
|
|
28
23
|
* ## Inspiration
|
|
29
24
|
*
|
|
30
|
-
* Based on
|
|
31
|
-
*
|
|
25
|
+
* Based on Gunsafe (https://github.com/draeder/gunsafe)
|
|
26
|
+
* Adapted for Shogun ecosystem with SHIP-00 integration
|
|
32
27
|
*/
|
|
33
|
-
import type {
|
|
28
|
+
import type { ISHIP_00 } from "./ISHIP_00";
|
|
29
|
+
/**
|
|
30
|
+
* @notice Vault record structure
|
|
31
|
+
*/
|
|
32
|
+
export interface VaultRecord {
|
|
33
|
+
name: string;
|
|
34
|
+
data: any;
|
|
35
|
+
created: number;
|
|
36
|
+
updated: number;
|
|
37
|
+
deleted: boolean;
|
|
38
|
+
metadata?: RecordMetadata;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* @notice Encrypted record (stored in GunDB)
|
|
42
|
+
*/
|
|
43
|
+
export interface EncryptedRecord {
|
|
44
|
+
data: string;
|
|
45
|
+
created: string;
|
|
46
|
+
updated: string;
|
|
47
|
+
deleted: boolean;
|
|
48
|
+
metadata?: string;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* @notice Record metadata
|
|
52
|
+
*/
|
|
53
|
+
export interface RecordMetadata {
|
|
54
|
+
type?: string;
|
|
55
|
+
description?: string;
|
|
56
|
+
tags?: string[];
|
|
57
|
+
expiresAt?: number;
|
|
58
|
+
[key: string]: any;
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* @notice Vault operation result
|
|
62
|
+
*/
|
|
63
|
+
export interface VaultResult {
|
|
64
|
+
success: boolean;
|
|
65
|
+
error?: string;
|
|
66
|
+
recordName?: string;
|
|
67
|
+
recordCount?: number;
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* @notice Vault statistics
|
|
71
|
+
*/
|
|
72
|
+
export interface VaultStats {
|
|
73
|
+
totalRecords: number;
|
|
74
|
+
activeRecords: number;
|
|
75
|
+
deletedRecords: number;
|
|
76
|
+
totalSize: number;
|
|
77
|
+
created: number;
|
|
78
|
+
lastModified: number;
|
|
79
|
+
recordsByType?: Record<string, number>;
|
|
80
|
+
}
|
|
34
81
|
/**
|
|
35
|
-
* @notice
|
|
82
|
+
* @notice Options for retrieving records
|
|
36
83
|
*/
|
|
37
|
-
export interface
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
content: string;
|
|
41
|
-
timestamp: number;
|
|
42
|
-
type: "broadcast" | "direct";
|
|
84
|
+
export interface GetOptions {
|
|
85
|
+
includeDeleted?: boolean;
|
|
86
|
+
decrypt?: boolean;
|
|
43
87
|
}
|
|
44
88
|
/**
|
|
45
|
-
* @notice
|
|
89
|
+
* @notice Options for listing records
|
|
46
90
|
*/
|
|
47
|
-
export interface
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
91
|
+
export interface ListOptions {
|
|
92
|
+
includeDeleted?: boolean;
|
|
93
|
+
filterByTag?: string;
|
|
94
|
+
filterByType?: string;
|
|
95
|
+
sortBy?: "name" | "created" | "updated";
|
|
96
|
+
sortDesc?: boolean;
|
|
52
97
|
}
|
|
53
98
|
/**
|
|
54
|
-
* @notice
|
|
99
|
+
* @notice Options for importing vault
|
|
55
100
|
*/
|
|
56
|
-
export interface
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
connectedAt: number;
|
|
101
|
+
export interface ImportOptions {
|
|
102
|
+
merge?: boolean;
|
|
103
|
+
overwrite?: boolean;
|
|
104
|
+
skipDeleted?: boolean;
|
|
61
105
|
}
|
|
62
106
|
/**
|
|
63
|
-
* @
|
|
64
|
-
|
|
65
|
-
|
|
107
|
+
* @notice Options for exporting vault
|
|
108
|
+
*/
|
|
109
|
+
export interface ExportOptions {
|
|
110
|
+
includeDeleted?: boolean;
|
|
111
|
+
pretty?: boolean;
|
|
112
|
+
filterByTag?: string;
|
|
113
|
+
filterByType?: string;
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* @title ISHIP_07 - Secure Vault
|
|
117
|
+
* @notice Main interface for secure encrypted vault
|
|
118
|
+
* @dev Depends on ISHIP_00 for all identity and encryption operations
|
|
66
119
|
*
|
|
67
|
-
* Constructor
|
|
120
|
+
* Constructor pattern:
|
|
68
121
|
* ```typescript
|
|
69
|
-
*
|
|
70
|
-
*
|
|
71
|
-
* constructor(
|
|
72
|
-
* peers: string[], // Gun relay peers
|
|
73
|
-
* roomId: string,
|
|
74
|
-
* config?: { debug?: boolean }
|
|
75
|
-
* ) {}
|
|
76
|
-
* }
|
|
77
|
-
*
|
|
78
|
-
* // Identity mode (with SHIP-00)
|
|
79
|
-
* class EphemeralMessaging implements ISHIP_06 {
|
|
80
|
-
* constructor(
|
|
81
|
-
* identity: ISHIP_00, // Authenticated identity
|
|
82
|
-
* roomId: string,
|
|
83
|
-
* config?: EphemeralConfig
|
|
84
|
-
* ) {}
|
|
122
|
+
* class SecureVault implements ISHIP_07 {
|
|
123
|
+
* constructor(private identity: ISHIP_00) {}
|
|
85
124
|
* }
|
|
86
125
|
* ```
|
|
87
126
|
*/
|
|
88
127
|
export interface ISHIP_06 {
|
|
89
128
|
/**
|
|
90
|
-
* @notice
|
|
91
|
-
* @dev
|
|
92
|
-
*
|
|
93
|
-
* Flow:
|
|
94
|
-
* 1. Hash room ID with SHA-256 for swarm identifier
|
|
95
|
-
* 2. Join WebTorrent swarm with hashed ID
|
|
96
|
-
* 3. Listen for peer connections
|
|
97
|
-
* 4. Exchange SEA public keys with peers
|
|
98
|
-
* 5. Establish encrypted channels
|
|
99
|
-
*/
|
|
100
|
-
connect(): Promise<void>;
|
|
101
|
-
/**
|
|
102
|
-
* @notice Disconnect from swarm
|
|
103
|
-
* @dev Closes all P2P connections and leaves swarm
|
|
104
|
-
*/
|
|
105
|
-
disconnect(): void;
|
|
106
|
-
/**
|
|
107
|
-
* @notice Check if connected to swarm
|
|
108
|
-
* @return True if connected
|
|
129
|
+
* @notice Get the identity provider
|
|
130
|
+
* @dev Returns the ISHIP_00 instance used for identity operations
|
|
131
|
+
* @return Identity provider instance
|
|
109
132
|
*/
|
|
110
|
-
|
|
133
|
+
getIdentity(): ISHIP_00;
|
|
111
134
|
/**
|
|
112
|
-
* @notice
|
|
113
|
-
* @
|
|
135
|
+
* @notice Initialize vault
|
|
136
|
+
* @dev Sets up vault node structure in user's Gun space
|
|
137
|
+
*
|
|
138
|
+
* Prerequisites:
|
|
139
|
+
* - User must be authenticated (via ISHIP_00)
|
|
140
|
+
*
|
|
141
|
+
* Flow:
|
|
142
|
+
* 1. Verify user authentication
|
|
143
|
+
* 2. Create vault node structure
|
|
144
|
+
* 3. Initialize metadata
|
|
114
145
|
*/
|
|
115
|
-
|
|
146
|
+
initialize(): Promise<void>;
|
|
116
147
|
/**
|
|
117
|
-
* @notice
|
|
118
|
-
* @return
|
|
148
|
+
* @notice Check if vault is initialized
|
|
149
|
+
* @return True if vault is initialized
|
|
119
150
|
*/
|
|
120
|
-
|
|
151
|
+
isInitialized(): boolean;
|
|
121
152
|
/**
|
|
122
|
-
* @notice
|
|
123
|
-
* @dev
|
|
124
|
-
* @param
|
|
153
|
+
* @notice Store encrypted record in vault
|
|
154
|
+
* @dev Encrypts data with SEA and stores in user's vault node
|
|
155
|
+
* @param name Record name/key (must be unique)
|
|
156
|
+
* @param data Data to encrypt and store (any type)
|
|
157
|
+
* @param metadata Optional metadata
|
|
158
|
+
* @return Operation result
|
|
125
159
|
*
|
|
126
160
|
* Prerequisites:
|
|
127
|
-
* -
|
|
128
|
-
* - User must be authenticated
|
|
161
|
+
* - Vault must be initialized
|
|
162
|
+
* - User must be authenticated
|
|
129
163
|
*
|
|
130
164
|
* Flow:
|
|
131
|
-
* 1.
|
|
132
|
-
* 2.
|
|
133
|
-
*
|
|
134
|
-
*
|
|
135
|
-
*
|
|
165
|
+
* 1. Validate record name
|
|
166
|
+
* 2. Encrypt data with SEA
|
|
167
|
+
* 3. Encrypt metadata if provided
|
|
168
|
+
* 4. Store in gun.user().get('vault').get('records').get(name)
|
|
169
|
+
* 5. Update vault metadata
|
|
136
170
|
*/
|
|
137
|
-
|
|
171
|
+
put(name: string, data: any, metadata?: RecordMetadata): Promise<VaultResult>;
|
|
138
172
|
/**
|
|
139
|
-
* @notice
|
|
140
|
-
* @dev
|
|
141
|
-
* @param
|
|
142
|
-
* @param
|
|
173
|
+
* @notice Retrieve and decrypt record from vault
|
|
174
|
+
* @dev Retrieves and decrypts record from user's vault node
|
|
175
|
+
* @param name Record name/key
|
|
176
|
+
* @param options Retrieval options
|
|
177
|
+
* @return Decrypted record or null if not found
|
|
143
178
|
*
|
|
144
179
|
* Prerequisites:
|
|
145
|
-
* -
|
|
146
|
-
* -
|
|
147
|
-
* - User must be authenticated (via ISHIP_00)
|
|
180
|
+
* - Vault must be initialized
|
|
181
|
+
* - User must be authenticated
|
|
148
182
|
*
|
|
149
183
|
* Flow:
|
|
150
|
-
* 1.
|
|
151
|
-
* 2.
|
|
152
|
-
* 3.
|
|
153
|
-
* 4.
|
|
184
|
+
* 1. Retrieve encrypted record from Gun
|
|
185
|
+
* 2. Decrypt data with SEA
|
|
186
|
+
* 3. Decrypt metadata if present
|
|
187
|
+
* 4. Return decrypted record
|
|
154
188
|
*/
|
|
155
|
-
|
|
189
|
+
get(name: string, options?: GetOptions): Promise<VaultRecord | null>;
|
|
156
190
|
/**
|
|
157
|
-
* @notice
|
|
158
|
-
* @dev
|
|
159
|
-
* @param
|
|
191
|
+
* @notice Delete record from vault (soft delete)
|
|
192
|
+
* @dev Marks record as deleted without removing data
|
|
193
|
+
* @param name Record name/key (optional - deletes all if omitted)
|
|
194
|
+
* @return Operation result
|
|
160
195
|
*
|
|
161
|
-
*
|
|
162
|
-
* -
|
|
196
|
+
* Soft Delete:
|
|
197
|
+
* - Record data remains encrypted in Gun
|
|
198
|
+
* - Marked as deleted (deleted: true)
|
|
199
|
+
* - Can be recovered before compaction
|
|
200
|
+
* - Not returned by default in list/get
|
|
201
|
+
*/
|
|
202
|
+
delete(name?: string): Promise<VaultResult>;
|
|
203
|
+
/**
|
|
204
|
+
* @notice List all record names in vault
|
|
205
|
+
* @dev Returns array of record names matching criteria
|
|
206
|
+
* @param options List options
|
|
207
|
+
* @return Array of record names
|
|
163
208
|
*
|
|
164
|
-
*
|
|
165
|
-
* 1.
|
|
166
|
-
* 2.
|
|
167
|
-
* 3.
|
|
168
|
-
* 4.
|
|
169
|
-
* 5. Call callback with decrypted message
|
|
209
|
+
* Flow:
|
|
210
|
+
* 1. Retrieve all records from vault node
|
|
211
|
+
* 2. Apply filters (deleted, tags, type)
|
|
212
|
+
* 3. Sort if requested
|
|
213
|
+
* 4. Return record names
|
|
170
214
|
*/
|
|
171
|
-
|
|
215
|
+
list(options?: ListOptions): Promise<string[]>;
|
|
172
216
|
/**
|
|
173
|
-
* @notice
|
|
174
|
-
* @
|
|
175
|
-
* @
|
|
217
|
+
* @notice Check if record exists
|
|
218
|
+
* @param name Record name/key
|
|
219
|
+
* @return True if record exists (and not deleted)
|
|
176
220
|
*/
|
|
177
|
-
|
|
221
|
+
exists(name: string): Promise<boolean>;
|
|
178
222
|
/**
|
|
179
|
-
* @notice
|
|
180
|
-
* @dev
|
|
181
|
-
* @param
|
|
223
|
+
* @notice Update existing record
|
|
224
|
+
* @dev Updates record data and timestamp
|
|
225
|
+
* @param name Record name/key
|
|
226
|
+
* @param data New data
|
|
227
|
+
* @return Operation result
|
|
228
|
+
*
|
|
229
|
+
* Flow:
|
|
230
|
+
* 1. Check if record exists
|
|
231
|
+
* 2. Encrypt new data
|
|
232
|
+
* 3. Update record with new data
|
|
233
|
+
* 4. Update timestamp
|
|
182
234
|
*/
|
|
183
|
-
|
|
235
|
+
update(name: string, data: any): Promise<VaultResult>;
|
|
184
236
|
/**
|
|
185
|
-
* @notice
|
|
186
|
-
* @dev
|
|
187
|
-
* @param
|
|
237
|
+
* @notice Export entire vault (encrypted)
|
|
238
|
+
* @dev Exports all vault records as encrypted JSON string
|
|
239
|
+
* @param password Optional additional encryption password
|
|
240
|
+
* @param options Export options
|
|
241
|
+
* @return Encrypted vault backup as string
|
|
242
|
+
*
|
|
243
|
+
* Flow:
|
|
244
|
+
* 1. Retrieve all records
|
|
245
|
+
* 2. Optionally filter records
|
|
246
|
+
* 3. Serialize to JSON
|
|
247
|
+
* 4. Optionally encrypt with additional password
|
|
248
|
+
* 5. Return as base64 string
|
|
249
|
+
*/
|
|
250
|
+
export(password?: string, options?: ExportOptions): Promise<string>;
|
|
251
|
+
/**
|
|
252
|
+
* @notice Import vault from backup
|
|
253
|
+
* @dev Imports and decrypts vault backup
|
|
254
|
+
* @param backupData Exported vault data
|
|
255
|
+
* @param password Optional decryption password
|
|
256
|
+
* @param options Import options
|
|
257
|
+
* @return Operation result
|
|
258
|
+
*
|
|
259
|
+
* Flow:
|
|
260
|
+
* 1. Decode base64 backup
|
|
261
|
+
* 2. Decrypt with password if provided
|
|
262
|
+
* 3. Parse JSON
|
|
263
|
+
* 4. For each record:
|
|
264
|
+
* - Check if exists (if merge mode)
|
|
265
|
+
* - Import or skip based on options
|
|
266
|
+
* 5. Update vault metadata
|
|
188
267
|
*/
|
|
189
|
-
|
|
268
|
+
import(backupData: string, password?: string, options?: ImportOptions): Promise<VaultResult>;
|
|
190
269
|
/**
|
|
191
|
-
* @notice Get
|
|
192
|
-
* @
|
|
270
|
+
* @notice Get vault statistics
|
|
271
|
+
* @dev Returns statistics about vault contents
|
|
272
|
+
* @return Vault statistics
|
|
193
273
|
*/
|
|
194
|
-
|
|
274
|
+
getStats(): Promise<VaultStats>;
|
|
195
275
|
/**
|
|
196
|
-
* @notice
|
|
197
|
-
* @
|
|
198
|
-
* @return
|
|
276
|
+
* @notice Clear all records (soft delete all)
|
|
277
|
+
* @dev Marks all records as deleted
|
|
278
|
+
* @return Operation result
|
|
199
279
|
*/
|
|
200
|
-
|
|
280
|
+
clear(): Promise<VaultResult>;
|
|
201
281
|
/**
|
|
202
|
-
* @notice
|
|
203
|
-
* @dev
|
|
204
|
-
* @return
|
|
282
|
+
* @notice Compact vault (remove deleted records permanently)
|
|
283
|
+
* @dev Permanently removes soft-deleted records
|
|
284
|
+
* @return Operation result
|
|
285
|
+
*
|
|
286
|
+
* ⚠️ WARNING:
|
|
287
|
+
* - This operation is irreversible
|
|
288
|
+
* - Deleted records cannot be recovered after compaction
|
|
205
289
|
*/
|
|
206
|
-
|
|
290
|
+
compact(): Promise<VaultResult>;
|
|
207
291
|
/**
|
|
208
|
-
* @notice
|
|
209
|
-
* @dev
|
|
210
|
-
* @param
|
|
292
|
+
* @notice Search records by content
|
|
293
|
+
* @dev Searches decrypted content (expensive operation)
|
|
294
|
+
* @param query Search query
|
|
295
|
+
* @return Array of matching record names
|
|
211
296
|
*/
|
|
212
|
-
|
|
297
|
+
search(query: string): Promise<string[]>;
|
|
213
298
|
}
|
|
214
299
|
/**
|
|
215
|
-
* @notice
|
|
300
|
+
* @notice Vault configuration
|
|
216
301
|
*/
|
|
217
|
-
export interface
|
|
302
|
+
export interface VaultConfig {
|
|
303
|
+
/**
|
|
304
|
+
* @notice Identity provider (SHIP-00 instance)
|
|
305
|
+
*/
|
|
306
|
+
identity: ISHIP_00;
|
|
218
307
|
/**
|
|
219
|
-
* @notice
|
|
308
|
+
* @notice Vault node name in Gun (default: "vault")
|
|
220
309
|
*/
|
|
221
|
-
|
|
310
|
+
vaultNodeName?: string;
|
|
222
311
|
/**
|
|
223
312
|
* @notice Enable debug logging
|
|
224
313
|
*/
|
|
@@ -227,59 +316,60 @@ export interface EphemeralConfig {
|
|
|
227
316
|
* @notice Operation timeout (ms)
|
|
228
317
|
*/
|
|
229
318
|
timeout?: number;
|
|
319
|
+
/**
|
|
320
|
+
* @notice Enable automatic backup
|
|
321
|
+
*/
|
|
322
|
+
autoBackup?: boolean;
|
|
323
|
+
/**
|
|
324
|
+
* @notice Backup interval (ms)
|
|
325
|
+
*/
|
|
326
|
+
backupInterval?: number;
|
|
230
327
|
}
|
|
231
328
|
/**
|
|
232
|
-
* @notice Event emitter interface for SHIP-
|
|
329
|
+
* @notice Event emitter interface for SHIP-07
|
|
233
330
|
*/
|
|
234
|
-
export interface
|
|
331
|
+
export interface ISHIP_07Events {
|
|
235
332
|
/**
|
|
236
|
-
* Emitted when
|
|
333
|
+
* Emitted when vault is initialized
|
|
237
334
|
*/
|
|
238
|
-
|
|
335
|
+
initialized: () => void;
|
|
239
336
|
/**
|
|
240
|
-
* Emitted when
|
|
337
|
+
* Emitted when record is added
|
|
241
338
|
*/
|
|
242
|
-
|
|
339
|
+
recordAdded: (name: string) => void;
|
|
243
340
|
/**
|
|
244
|
-
* Emitted when
|
|
341
|
+
* Emitted when record is updated
|
|
245
342
|
*/
|
|
246
|
-
|
|
343
|
+
recordUpdated: (name: string) => void;
|
|
247
344
|
/**
|
|
248
|
-
* Emitted when
|
|
345
|
+
* Emitted when record is deleted
|
|
249
346
|
*/
|
|
250
|
-
|
|
347
|
+
recordDeleted: (name: string) => void;
|
|
251
348
|
/**
|
|
252
|
-
* Emitted when
|
|
349
|
+
* Emitted when vault is exported
|
|
253
350
|
*/
|
|
254
|
-
|
|
351
|
+
exported: (size: number) => void;
|
|
255
352
|
/**
|
|
256
|
-
* Emitted when
|
|
353
|
+
* Emitted when vault is imported
|
|
257
354
|
*/
|
|
258
|
-
|
|
355
|
+
imported: (recordCount: number) => void;
|
|
259
356
|
/**
|
|
260
357
|
* Emitted on error
|
|
261
358
|
*/
|
|
262
359
|
error: (error: Error) => void;
|
|
263
360
|
}
|
|
264
361
|
/**
|
|
265
|
-
* Example of how to implement
|
|
362
|
+
* Example of how to implement ISHIP_07 with ISHIP_00 dependency
|
|
266
363
|
*
|
|
267
364
|
* ```typescript
|
|
268
365
|
* import { ISHIP_00 } from './ISHIP_00';
|
|
269
|
-
* import {
|
|
270
|
-
*
|
|
271
|
-
*
|
|
272
|
-
*
|
|
273
|
-
* private
|
|
274
|
-
*
|
|
275
|
-
* private
|
|
276
|
-
* private messageCallbacks: ((msg: EphemeralMessage) => void)[] = [];
|
|
277
|
-
*
|
|
278
|
-
* constructor(
|
|
279
|
-
* private identity: ISHIP_00,
|
|
280
|
-
* private roomId: string,
|
|
281
|
-
* private config?: EphemeralConfig
|
|
282
|
-
* ) {
|
|
366
|
+
* import { ISHIP_07, VaultRecord, VaultResult } from './ISHIP_07';
|
|
367
|
+
*
|
|
368
|
+
* class SecureVault implements ISHIP_07 {
|
|
369
|
+
* private vaultNode: any;
|
|
370
|
+
* private initialized: boolean = false;
|
|
371
|
+
*
|
|
372
|
+
* constructor(private identity: ISHIP_00) {
|
|
283
373
|
* if (!identity.isLoggedIn()) {
|
|
284
374
|
* throw new Error('User must be authenticated via SHIP-00');
|
|
285
375
|
* }
|
|
@@ -289,82 +379,144 @@ export interface ISHIP_06Events {
|
|
|
289
379
|
* return this.identity;
|
|
290
380
|
* }
|
|
291
381
|
*
|
|
292
|
-
* async
|
|
293
|
-
* //
|
|
294
|
-
* const
|
|
295
|
-
* this.
|
|
296
|
-
*
|
|
297
|
-
* // 2. Hash room ID
|
|
298
|
-
* const swarmId = await crypto.hashText(this.roomId);
|
|
299
|
-
*
|
|
300
|
-
* // 3. Create Bugout swarm
|
|
301
|
-
* this.bugout = new Bugout(swarmId, {
|
|
302
|
-
* iceServers: this.config?.iceServers
|
|
303
|
-
* });
|
|
304
|
-
*
|
|
305
|
-
* // 4. Set SEA pair
|
|
306
|
-
* await this.bugout.SEA(this.ephemeralPair);
|
|
382
|
+
* async initialize(): Promise<void> {
|
|
383
|
+
* // Get Gun user node
|
|
384
|
+
* const gun = this.identity.shogun.db.gun;
|
|
385
|
+
* this.vaultNode = gun.user().get('vault').get('records');
|
|
307
386
|
*
|
|
308
|
-
* //
|
|
309
|
-
*
|
|
310
|
-
*
|
|
387
|
+
* // Initialize vault metadata
|
|
388
|
+
* await gun.user().get('vault').get('metadata').put({
|
|
389
|
+
* version: '1.0.0',
|
|
390
|
+
* created: Date.now().toString()
|
|
311
391
|
* });
|
|
312
392
|
*
|
|
313
|
-
* this.
|
|
314
|
-
* this.handleMessage(address, pubkeys, message);
|
|
315
|
-
* });
|
|
393
|
+
* this.initialized = true;
|
|
316
394
|
* }
|
|
317
395
|
*
|
|
318
|
-
*
|
|
319
|
-
*
|
|
320
|
-
* this.bugout.destroy();
|
|
321
|
-
* }
|
|
396
|
+
* isInitialized(): boolean {
|
|
397
|
+
* return this.initialized;
|
|
322
398
|
* }
|
|
323
399
|
*
|
|
324
|
-
* async
|
|
325
|
-
* if (!this.
|
|
326
|
-
*
|
|
400
|
+
* async put(name: string, data: any, metadata?: RecordMetadata): Promise<VaultResult> {
|
|
401
|
+
* if (!this.initialized) {
|
|
402
|
+
* return { success: false, error: 'Vault not initialized' };
|
|
327
403
|
* }
|
|
328
404
|
*
|
|
329
|
-
*
|
|
405
|
+
* try {
|
|
406
|
+
* // Get SEA crypto
|
|
407
|
+
* const crypto = this.identity.shogun.db.crypto;
|
|
408
|
+
* const pair = this.identity.getKeyPair();
|
|
409
|
+
*
|
|
410
|
+
* if (!pair) {
|
|
411
|
+
* return { success: false, error: 'Cannot access key pair' };
|
|
412
|
+
* }
|
|
413
|
+
*
|
|
414
|
+
* // Encrypt data
|
|
415
|
+
* const encryptedData = await crypto.encrypt(
|
|
416
|
+
* JSON.stringify(data),
|
|
417
|
+
* pair.epriv
|
|
418
|
+
* );
|
|
419
|
+
*
|
|
420
|
+
* // Encrypt metadata if provided
|
|
421
|
+
* const encryptedMetadata = metadata
|
|
422
|
+
* ? await crypto.encrypt(JSON.stringify(metadata), pair.epriv)
|
|
423
|
+
* : undefined;
|
|
424
|
+
*
|
|
425
|
+
* // Store in vault
|
|
426
|
+
* const record = {
|
|
427
|
+
* data: encryptedData,
|
|
428
|
+
* created: Date.now().toString(),
|
|
429
|
+
* updated: Date.now().toString(),
|
|
430
|
+
* deleted: false,
|
|
431
|
+
* metadata: encryptedMetadata
|
|
432
|
+
* };
|
|
433
|
+
*
|
|
434
|
+
* await this.vaultNode.get(name).put(record);
|
|
435
|
+
*
|
|
436
|
+
* return { success: true, recordName: name };
|
|
437
|
+
* } catch (error: any) {
|
|
438
|
+
* return { success: false, error: error.message };
|
|
439
|
+
* }
|
|
330
440
|
* }
|
|
331
441
|
*
|
|
332
|
-
* async
|
|
333
|
-
* if (!this.
|
|
334
|
-
*
|
|
442
|
+
* async get(name: string, options?: GetOptions): Promise<VaultRecord | null> {
|
|
443
|
+
* if (!this.initialized) {
|
|
444
|
+
* return null;
|
|
335
445
|
* }
|
|
336
446
|
*
|
|
337
|
-
*
|
|
447
|
+
* try {
|
|
448
|
+
* // Retrieve from vault
|
|
449
|
+
* const encryptedRecord = await this.vaultNode.get(name).then();
|
|
450
|
+
*
|
|
451
|
+
* if (!encryptedRecord || !encryptedRecord.data) {
|
|
452
|
+
* return null;
|
|
453
|
+
* }
|
|
454
|
+
*
|
|
455
|
+
* // Skip if deleted (unless includeDeleted)
|
|
456
|
+
* if (encryptedRecord.deleted && !options?.includeDeleted) {
|
|
457
|
+
* return null;
|
|
458
|
+
* }
|
|
459
|
+
*
|
|
460
|
+
* // Decrypt data
|
|
461
|
+
* const crypto = this.identity.shogun.db.crypto;
|
|
462
|
+
* const pair = this.identity.getKeyPair();
|
|
463
|
+
*
|
|
464
|
+
* if (!pair) {
|
|
465
|
+
* return null;
|
|
466
|
+
* }
|
|
467
|
+
*
|
|
468
|
+
* const decryptedData = await crypto.decrypt(
|
|
469
|
+
* encryptedRecord.data,
|
|
470
|
+
* pair.epriv
|
|
471
|
+
* );
|
|
472
|
+
*
|
|
473
|
+
* // Decrypt metadata if present
|
|
474
|
+
* const decryptedMetadata = encryptedRecord.metadata
|
|
475
|
+
* ? JSON.parse(await crypto.decrypt(encryptedRecord.metadata, pair.epriv))
|
|
476
|
+
* : undefined;
|
|
477
|
+
*
|
|
478
|
+
* return {
|
|
479
|
+
* name,
|
|
480
|
+
* data: JSON.parse(decryptedData),
|
|
481
|
+
* created: parseInt(encryptedRecord.created),
|
|
482
|
+
* updated: parseInt(encryptedRecord.updated),
|
|
483
|
+
* deleted: encryptedRecord.deleted,
|
|
484
|
+
* metadata: decryptedMetadata
|
|
485
|
+
* };
|
|
486
|
+
* } catch (error) {
|
|
487
|
+
* console.error('Error retrieving record:', error);
|
|
488
|
+
* return null;
|
|
489
|
+
* }
|
|
338
490
|
* }
|
|
339
491
|
*
|
|
340
|
-
*
|
|
341
|
-
*
|
|
492
|
+
* async delete(name?: string): Promise<VaultResult> {
|
|
493
|
+
* // Implementation here
|
|
494
|
+
* return { success: true };
|
|
342
495
|
* }
|
|
343
496
|
*
|
|
344
|
-
*
|
|
345
|
-
*
|
|
346
|
-
*
|
|
347
|
-
* fromPubKey: pubkeys.pub,
|
|
348
|
-
* content,
|
|
349
|
-
* timestamp: Date.now(),
|
|
350
|
-
* type: 'broadcast'
|
|
351
|
-
* };
|
|
352
|
-
*
|
|
353
|
-
* this.messageCallbacks.forEach(cb => cb(message));
|
|
497
|
+
* async list(options?: ListOptions): Promise<string[]> {
|
|
498
|
+
* // Implementation here
|
|
499
|
+
* return [];
|
|
354
500
|
* }
|
|
501
|
+
*
|
|
502
|
+
* // ... implement other methods
|
|
355
503
|
* }
|
|
356
504
|
*
|
|
357
505
|
* // Usage
|
|
358
506
|
* const identity = new SHIP_00(config);
|
|
359
507
|
* await identity.login('alice', 'password123');
|
|
360
508
|
*
|
|
361
|
-
* const
|
|
362
|
-
* await
|
|
509
|
+
* const vault = new SecureVault(identity);
|
|
510
|
+
* await vault.initialize();
|
|
363
511
|
*
|
|
364
|
-
*
|
|
365
|
-
*
|
|
512
|
+
* // Store encrypted data
|
|
513
|
+
* await vault.put('my-password', 'super_secret', {
|
|
514
|
+
* type: 'password',
|
|
515
|
+
* description: 'GitHub password'
|
|
366
516
|
* });
|
|
367
517
|
*
|
|
368
|
-
*
|
|
518
|
+
* // Retrieve decrypted data
|
|
519
|
+
* const record = await vault.get('my-password');
|
|
520
|
+
* console.log('Password:', record?.data);
|
|
369
521
|
* ```
|
|
370
522
|
*/
|