wolfronix-sdk 2.4.3 → 2.4.4
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 +189 -726
- package/dist/index.d.mts +161 -3
- package/dist/index.d.ts +161 -3
- package/dist/index.global.js +3 -3
- package/dist/index.js +1067 -18
- package/dist/index.mjs +1067 -18
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -1,726 +1,189 @@
|
|
|
1
|
-
# wolfronix-sdk
|
|
2
|
-
|
|
3
|
-
Official JavaScript/TypeScript SDK for
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
-
|
|
11
|
-
-
|
|
12
|
-
-
|
|
13
|
-
-
|
|
14
|
-
-
|
|
15
|
-
-
|
|
16
|
-
-
|
|
17
|
-
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
```
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
###
|
|
72
|
-
|
|
73
|
-
```
|
|
74
|
-
await wfx.
|
|
75
|
-
//
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
await wfx.
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
const { files } = await wfx.listFiles();
|
|
191
|
-
setFiles(files);
|
|
192
|
-
};
|
|
193
|
-
|
|
194
|
-
const handleDownload = async (fileId: string, filename: string) => {
|
|
195
|
-
const blob = await wfx.decrypt(fileId);
|
|
196
|
-
const url = URL.createObjectURL(blob);
|
|
197
|
-
const a = document.createElement('a');
|
|
198
|
-
a.href = url;
|
|
199
|
-
a.download = filename;
|
|
200
|
-
a.click();
|
|
201
|
-
URL.revokeObjectURL(url);
|
|
202
|
-
};
|
|
203
|
-
|
|
204
|
-
return (
|
|
205
|
-
<div>
|
|
206
|
-
<input type="file" onChange={(e) => handleUpload(e.target.files![0])} />
|
|
207
|
-
{files.map(f => (
|
|
208
|
-
<div key={f.file_id}>
|
|
209
|
-
{f.original_name}
|
|
210
|
-
<button onClick={() => handleDownload(f.file_id, f.original_name)}>
|
|
211
|
-
Download
|
|
212
|
-
</button>
|
|
213
|
-
</div>
|
|
214
|
-
))}
|
|
215
|
-
</div>
|
|
216
|
-
);
|
|
217
|
-
}
|
|
218
|
-
```
|
|
219
|
-
|
|
220
|
-
### React Hook
|
|
221
|
-
|
|
222
|
-
```typescript
|
|
223
|
-
// hooks/useWolfronix.ts
|
|
224
|
-
import { useState, useCallback, useMemo } from 'react';
|
|
225
|
-
import Wolfronix, { FileInfo } from 'wolfronix-sdk';
|
|
226
|
-
|
|
227
|
-
export function useWolfronix(baseUrl: string, clientId?: string, wolfronixKey?: string) {
|
|
228
|
-
const [isLoading, setIsLoading] = useState(false);
|
|
229
|
-
const [error, setError] = useState<Error | null>(null);
|
|
230
|
-
const [files, setFiles] = useState<FileInfo[]>([]);
|
|
231
|
-
|
|
232
|
-
const client = useMemo(
|
|
233
|
-
() => new Wolfronix({ baseUrl, clientId, wolfronixKey }),
|
|
234
|
-
[baseUrl, clientId, wolfronixKey]
|
|
235
|
-
);
|
|
236
|
-
|
|
237
|
-
const login = useCallback(async (email: string, password: string) => {
|
|
238
|
-
setIsLoading(true);
|
|
239
|
-
try {
|
|
240
|
-
return await client.login(email, password);
|
|
241
|
-
} catch (e) {
|
|
242
|
-
setError(e as Error);
|
|
243
|
-
throw e;
|
|
244
|
-
} finally {
|
|
245
|
-
setIsLoading(false);
|
|
246
|
-
}
|
|
247
|
-
}, [client]);
|
|
248
|
-
|
|
249
|
-
const encrypt = useCallback(async (file: File) => {
|
|
250
|
-
setIsLoading(true);
|
|
251
|
-
try {
|
|
252
|
-
const result = await client.encrypt(file);
|
|
253
|
-
const { files } = await client.listFiles();
|
|
254
|
-
setFiles(files);
|
|
255
|
-
return result;
|
|
256
|
-
} catch (e) {
|
|
257
|
-
setError(e as Error);
|
|
258
|
-
throw e;
|
|
259
|
-
} finally {
|
|
260
|
-
setIsLoading(false);
|
|
261
|
-
}
|
|
262
|
-
}, [client]);
|
|
263
|
-
|
|
264
|
-
const decrypt = useCallback(async (fileId: string) => {
|
|
265
|
-
setIsLoading(true);
|
|
266
|
-
try {
|
|
267
|
-
return await client.decrypt(fileId);
|
|
268
|
-
} catch (e) {
|
|
269
|
-
setError(e as Error);
|
|
270
|
-
throw e;
|
|
271
|
-
} finally {
|
|
272
|
-
setIsLoading(false);
|
|
273
|
-
}
|
|
274
|
-
}, [client]);
|
|
275
|
-
|
|
276
|
-
return { client, isLoading, error, files, login, encrypt, decrypt };
|
|
277
|
-
}
|
|
278
|
-
```
|
|
279
|
-
|
|
280
|
-
### Node.js (Server-Side)
|
|
281
|
-
|
|
282
|
-
```typescript
|
|
283
|
-
import Wolfronix from 'wolfronix-sdk';
|
|
284
|
-
import * as fs from 'fs';
|
|
285
|
-
|
|
286
|
-
const wfx = new Wolfronix({
|
|
287
|
-
baseUrl: 'https://wolfronix-server:9443',
|
|
288
|
-
clientId: 'your-client-id',
|
|
289
|
-
wolfronixKey: 'your-api-key',
|
|
290
|
-
insecure: true // For self-signed certs in development
|
|
291
|
-
});
|
|
292
|
-
|
|
293
|
-
async function main() {
|
|
294
|
-
await wfx.login('user@example.com', 'password123');
|
|
295
|
-
|
|
296
|
-
// Encrypt a file
|
|
297
|
-
const fileBuffer = fs.readFileSync('document.pdf');
|
|
298
|
-
const { file_id } = await wfx.encrypt(fileBuffer, 'document.pdf');
|
|
299
|
-
console.log('Encrypted file ID:', file_id);
|
|
300
|
-
|
|
301
|
-
// List all files
|
|
302
|
-
const { files } = await wfx.listFiles();
|
|
303
|
-
console.log('Your files:', files);
|
|
304
|
-
|
|
305
|
-
// Decrypt and save
|
|
306
|
-
const decrypted = await wfx.decryptToBuffer(file_id);
|
|
307
|
-
fs.writeFileSync('decrypted.pdf', Buffer.from(decrypted));
|
|
308
|
-
}
|
|
309
|
-
|
|
310
|
-
main();
|
|
311
|
-
```
|
|
312
|
-
|
|
313
|
-
---
|
|
314
|
-
|
|
315
|
-
## API Reference
|
|
316
|
-
|
|
317
|
-
### Constructor
|
|
318
|
-
|
|
319
|
-
```typescript
|
|
320
|
-
new Wolfronix(config: WolfronixConfig | string)
|
|
321
|
-
```
|
|
322
|
-
|
|
323
|
-
| Option | Type | Default | Description |
|
|
324
|
-
|--------|------|---------|-------------|
|
|
325
|
-
| `baseUrl` | `string` | **required** | Wolfronix server URL |
|
|
326
|
-
| `clientId` | `string` | `''` | Enterprise client ID |
|
|
327
|
-
| `wolfronixKey` | `string` | `''` | API key (sent as `X-Wolfronix-Key` header) |
|
|
328
|
-
| `timeout` | `number` | `30000` | Request timeout in ms (file uploads bypass this) |
|
|
329
|
-
| `retries` | `number` | `3` | Max retry attempts with exponential backoff |
|
|
330
|
-
| `insecure` | `boolean` | `false` | Skip SSL verification (Node.js only) |
|
|
331
|
-
|
|
332
|
-
You can also pass just a URL string: `new Wolfronix('https://server:9443')`
|
|
333
|
-
|
|
334
|
-
---
|
|
335
|
-
|
|
336
|
-
### Authentication
|
|
337
|
-
|
|
338
|
-
| Method | Returns | Description |
|
|
339
|
-
|--------|---------|-------------|
|
|
340
|
-
| `register(email, password)` | `Promise<AuthResponse>` | Generate RSA keys + register (first time) |
|
|
341
|
-
| `login(email, password)` | `Promise<AuthResponse>` | Fetch & unwrap keys (subsequent logins) |
|
|
342
|
-
| `setToken(token, userId?)` | `void` | Set auth token directly (for custom auth) |
|
|
343
|
-
| `logout()` | `void` | Clear keys and session from memory |
|
|
344
|
-
| `isAuthenticated()` | `boolean` | Check if user is logged in |
|
|
345
|
-
| `getUserId()` | `string \| null` | Get current user ID |
|
|
346
|
-
| `hasPrivateKey()` | `boolean` | Check if RSA private key is loaded in memory |
|
|
347
|
-
|
|
348
|
-
---
|
|
349
|
-
|
|
350
|
-
### File Operations
|
|
351
|
-
|
|
352
|
-
| Method | Returns | Description |
|
|
353
|
-
|--------|---------|-------------|
|
|
354
|
-
| `encrypt(file, filename?)` | `Promise<EncryptResponse>` | Encrypt and store a file |
|
|
355
|
-
| `decrypt(fileId, role?)` | `Promise<Blob>` | Decrypt file → Blob (for browser display/download) |
|
|
356
|
-
| `decryptToBuffer(fileId, role?)` | `Promise<ArrayBuffer>` | Decrypt file → ArrayBuffer (for Node.js) |
|
|
357
|
-
| `getFileKey(fileId)` | `Promise<KeyPartResponse>` | Get encrypted key_part_a (advanced use) |
|
|
358
|
-
| `listFiles()` | `Promise<ListFilesResponse>` | List user's encrypted files |
|
|
359
|
-
| `deleteFile(fileId)` | `Promise<DeleteResponse>` | Delete an encrypted file |
|
|
360
|
-
|
|
361
|
-
**`EncryptResponse` fields:**
|
|
362
|
-
```typescript
|
|
363
|
-
{
|
|
364
|
-
status: string;
|
|
365
|
-
file_id: string;
|
|
366
|
-
file_size: number;
|
|
367
|
-
enc_time_ms: number;
|
|
368
|
-
// Detailed timing breakdown:
|
|
369
|
-
upload_ms?: number; // Network upload time
|
|
370
|
-
read_ms?: number; // Server file read time
|
|
371
|
-
encrypt_ms?: number; // AES-256-GCM encryption time
|
|
372
|
-
store_ms?: number; // Storage write time
|
|
373
|
-
}
|
|
374
|
-
```
|
|
375
|
-
|
|
376
|
-
---
|
|
377
|
-
|
|
378
|
-
### E2E Chat Encryption
|
|
379
|
-
|
|
380
|
-
Turn any chat app into a secure, end-to-end encrypted messenger.
|
|
381
|
-
|
|
382
|
-
| Method | Returns | Description |
|
|
383
|
-
|--------|---------|-------------|
|
|
384
|
-
| `getPublicKey(userId, clientId?)` | `Promise<CryptoKey>` | Fetch a user's RSA public key |
|
|
385
|
-
| `encryptMessage(text, recipientId)` | `Promise<string>` | Encrypt text for a recipient (returns JSON packet) |
|
|
386
|
-
| `decryptMessage(packetString)` | `Promise<string>` | Decrypt a received message packet |
|
|
387
|
-
|
|
388
|
-
**Sender (Alice):**
|
|
389
|
-
```typescript
|
|
390
|
-
const securePacket = await wfx.encryptMessage("Secret meeting at 5 PM", "bob_user_id");
|
|
391
|
-
|
|
392
|
-
// Send via your regular chat backend (Socket.io, Firebase, etc.)
|
|
393
|
-
chatSocket.emit('message', { to: 'bob', text: securePacket });
|
|
394
|
-
```
|
|
395
|
-
|
|
396
|
-
**Recipient (Bob):**
|
|
397
|
-
```typescript
|
|
398
|
-
chatSocket.on('message', async (msg) => {
|
|
399
|
-
const plainText = await wfx.decryptMessage(msg.text);
|
|
400
|
-
console.log("Decrypted:", plainText);
|
|
401
|
-
});
|
|
402
|
-
```
|
|
403
|
-
|
|
404
|
-
---
|
|
405
|
-
|
|
406
|
-
### Server-Side Message Encryption
|
|
407
|
-
|
|
408
|
-
For messages that need **server-managed** encryption (Layer 3/4 dual-key split):
|
|
409
|
-
|
|
410
|
-
| Method | Returns | Description |
|
|
411
|
-
|--------|---------|-------------|
|
|
412
|
-
| `serverEncrypt(message, options?)` | `Promise<ServerEncryptResult>` | Encrypt a message server-side |
|
|
413
|
-
| `serverDecrypt(params)` | `Promise<string>` | Decrypt a server-encrypted message |
|
|
414
|
-
| `serverEncryptBatch(messages, options?)` | `Promise<ServerBatchEncryptResult>` | Batch encrypt multiple messages |
|
|
415
|
-
| `serverDecryptBatchItem(item)` | `Promise<string>` | Decrypt a single batch item |
|
|
416
|
-
|
|
417
|
-
```typescript
|
|
418
|
-
// Encrypt
|
|
419
|
-
const encrypted = await wfx.serverEncrypt("Confidential data", { layer: 4 });
|
|
420
|
-
|
|
421
|
-
// Decrypt
|
|
422
|
-
const original = await wfx.serverDecrypt({
|
|
423
|
-
encryptedMessage: encrypted.encrypted_message,
|
|
424
|
-
nonce: encrypted.nonce,
|
|
425
|
-
keyPartA: encrypted.key_part_a,
|
|
426
|
-
messageTag: encrypted.message_tag
|
|
427
|
-
});
|
|
428
|
-
|
|
429
|
-
// Batch encrypt
|
|
430
|
-
const batch = await wfx.serverEncryptBatch([
|
|
431
|
-
{ id: 'msg1', message: 'Hello' },
|
|
432
|
-
{ id: 'msg2', message: 'World' }
|
|
433
|
-
], { layer: 4 });
|
|
434
|
-
```
|
|
435
|
-
|
|
436
|
-
---
|
|
437
|
-
|
|
438
|
-
### Real-Time Streaming Encryption
|
|
439
|
-
|
|
440
|
-
For encrypting/decrypting live data streams (audio, video, real-time feeds) via WebSocket:
|
|
441
|
-
|
|
442
|
-
| Method | Returns | Description |
|
|
443
|
-
|--------|---------|-------------|
|
|
444
|
-
| `createStream(direction, streamKey?)` | `Promise<WolfronixStream>` | Open a streaming encryption session |
|
|
445
|
-
|
|
446
|
-
```typescript
|
|
447
|
-
// Encrypt stream
|
|
448
|
-
const stream = await wfx.createStream('encrypt');
|
|
449
|
-
stream.onData((chunk, seq) => sendToRecipient(chunk));
|
|
450
|
-
stream.onError((err) => console.error(err));
|
|
451
|
-
|
|
452
|
-
const processed = await stream.send('data to encrypt'); // Text
|
|
453
|
-
const processed2 = await stream.sendBinary(audioChunk); // Binary
|
|
454
|
-
|
|
455
|
-
// Save these for the recipient to decrypt:
|
|
456
|
-
console.log('Key:', stream.keyPartA, 'Tag:', stream.streamTag);
|
|
457
|
-
|
|
458
|
-
const summary = await stream.end();
|
|
459
|
-
console.log('Chunks processed:', summary.chunksProcessed);
|
|
460
|
-
|
|
461
|
-
// Decrypt stream (recipient)
|
|
462
|
-
const decStream = await wfx.createStream('decrypt', {
|
|
463
|
-
keyPartA: senderKeyPartA,
|
|
464
|
-
streamTag: senderStreamTag
|
|
465
|
-
});
|
|
466
|
-
decStream.onData((chunk, seq) => playAudio(chunk));
|
|
467
|
-
```
|
|
468
|
-
|
|
469
|
-
---
|
|
470
|
-
|
|
471
|
-
### Admin API (Enterprise Client Management)
|
|
472
|
-
|
|
473
|
-
For managing enterprise clients programmatically:
|
|
474
|
-
|
|
475
|
-
```typescript
|
|
476
|
-
import { WolfronixAdmin } from 'wolfronix-sdk';
|
|
477
|
-
|
|
478
|
-
const admin = new WolfronixAdmin({
|
|
479
|
-
baseUrl: 'https://your-server:9443',
|
|
480
|
-
adminKey: 'your-admin-api-key'
|
|
481
|
-
});
|
|
482
|
-
```
|
|
483
|
-
|
|
484
|
-
| Method | Returns | Description |
|
|
485
|
-
|--------|---------|-------------|
|
|
486
|
-
| `registerClient(params)` | `Promise<RegisterClientResponse>` | Register a new enterprise client |
|
|
487
|
-
| `listClients()` | `Promise<ListClientsResponse>` | List all registered clients |
|
|
488
|
-
| `getClient(clientId)` | `Promise<EnterpriseClient>` | Get details for a specific client |
|
|
489
|
-
| `updateClient(clientId, params)` | `Promise<UpdateClientResponse>` | Update client configuration |
|
|
490
|
-
| `deactivateClient(clientId)` | `Promise<DeactivateClientResponse>` | Deactivate (revoke) a client |
|
|
491
|
-
| `healthCheck()` | `Promise<boolean>` | Check server health |
|
|
492
|
-
|
|
493
|
-
```typescript
|
|
494
|
-
// Register a new client with Supabase connector
|
|
495
|
-
const result = await admin.registerClient({
|
|
496
|
-
client_id: 'acme_corp',
|
|
497
|
-
client_name: 'Acme Corporation',
|
|
498
|
-
db_type: 'supabase', // or: mongodb, mysql, firebase, postgresql, custom_api
|
|
499
|
-
db_config: JSON.stringify({
|
|
500
|
-
supabase_url: 'https://xxx.supabase.co',
|
|
501
|
-
supabase_service_key: 'eyJ...'
|
|
502
|
-
})
|
|
503
|
-
});
|
|
504
|
-
|
|
505
|
-
console.log('Wolfronix Key:', result.wolfronix_key); // Give this to the client
|
|
506
|
-
```
|
|
507
|
-
|
|
508
|
-
---
|
|
509
|
-
|
|
510
|
-
### Utility Methods
|
|
511
|
-
|
|
512
|
-
| Method | Returns | Description |
|
|
513
|
-
|--------|---------|-------------|
|
|
514
|
-
| `getMetrics()` | `Promise<MetricsResponse>` | Get encryption/decryption stats |
|
|
515
|
-
| `healthCheck()` | `Promise<boolean>` | Check if server is reachable |
|
|
516
|
-
|
|
517
|
-
---
|
|
518
|
-
|
|
519
|
-
## Error Handling
|
|
520
|
-
|
|
521
|
-
The SDK provides typed error classes for different failure scenarios:
|
|
522
|
-
|
|
523
|
-
```typescript
|
|
524
|
-
import Wolfronix, {
|
|
525
|
-
WolfronixError, // Base error class
|
|
526
|
-
AuthenticationError, // Invalid credentials or expired session
|
|
527
|
-
FileNotFoundError, // File doesn't exist
|
|
528
|
-
PermissionDeniedError, // Not authorized for this file
|
|
529
|
-
NetworkError, // Server unreachable
|
|
530
|
-
ValidationError // Invalid input parameters
|
|
531
|
-
} from 'wolfronix-sdk';
|
|
532
|
-
|
|
533
|
-
try {
|
|
534
|
-
await wfx.encrypt(file);
|
|
535
|
-
} catch (error) {
|
|
536
|
-
if (error instanceof AuthenticationError) {
|
|
537
|
-
// Redirect to login
|
|
538
|
-
} else if (error instanceof FileNotFoundError) {
|
|
539
|
-
// File was deleted
|
|
540
|
-
} else if (error instanceof NetworkError) {
|
|
541
|
-
// Server down — SDK already retried 3 times
|
|
542
|
-
} else if (error instanceof ValidationError) {
|
|
543
|
-
// Bad input (e.g., missing file, empty message)
|
|
544
|
-
}
|
|
545
|
-
}
|
|
546
|
-
```
|
|
547
|
-
|
|
548
|
-
All errors include:
|
|
549
|
-
- `error.message` — Human-readable description
|
|
550
|
-
- `error.code` — Machine-readable error code
|
|
551
|
-
- `error.statusCode` — HTTP status code (if applicable)
|
|
552
|
-
- `error.details` — Server error details (if available)
|
|
553
|
-
|
|
554
|
-
---
|
|
555
|
-
|
|
556
|
-
## Security Architecture
|
|
557
|
-
|
|
558
|
-
### How It Works
|
|
559
|
-
|
|
560
|
-
```
|
|
561
|
-
Your App Wolfronix Engine
|
|
562
|
-
┌──────────────┐ ┌────────────────────────┐
|
|
563
|
-
User ──────▶ │ SDK (Browser)│ ──────────▶ │ AES-256-GCM Encrypt │
|
|
564
|
-
Password │ │ HTTPS │ RSA Dual-Key Split │
|
|
565
|
-
│ RSA Keys │ │ RBAC Masking │
|
|
566
|
-
│ (client- │ ◀────────── │ │
|
|
567
|
-
│ side only) │ Encrypted │ Stores NOTHING │
|
|
568
|
-
└──────────────┘ Blob Only │ decryptable alone │
|
|
569
|
-
└────────────────────────┘
|
|
570
|
-
│
|
|
571
|
-
▼
|
|
572
|
-
┌────────────────────────┐
|
|
573
|
-
│ Your Database │
|
|
574
|
-
│ (Supabase, MongoDB, │
|
|
575
|
-
│ PostgreSQL, etc.) │
|
|
576
|
-
│ Stores encrypted │
|
|
577
|
-
│ blobs only │
|
|
578
|
-
└────────────────────────┘
|
|
579
|
-
```
|
|
580
|
-
|
|
581
|
-
### Key Security Properties
|
|
582
|
-
|
|
583
|
-
| Property | Implementation |
|
|
584
|
-
|----------|---------------|
|
|
585
|
-
| **Encryption** | AES-256-GCM (authenticated, tamper-proof) |
|
|
586
|
-
| **Key Transport** | RSA-OAEP with SHA-256 |
|
|
587
|
-
| **Key Wrapping** | PBKDF2 (100,000 iterations) + AES-GCM |
|
|
588
|
-
| **Dual-Key Split** | AES key split in half; each half encrypted with different RSA key |
|
|
589
|
-
| **Zero-Knowledge** | Private keys wrapped client-side; server never sees raw keys |
|
|
590
|
-
| **Auth** | API key (`X-Wolfronix-Key`) + zero-knowledge login |
|
|
591
|
-
|
|
592
|
-
### Zero-Knowledge Decryption Flow
|
|
593
|
-
|
|
594
|
-
```
|
|
595
|
-
Client Wolfronix Server
|
|
596
|
-
│ │
|
|
597
|
-
│ GET /files/{id}/key │
|
|
598
|
-
│──────────────────────────────────────►│
|
|
599
|
-
│ { key_part_a: "<RSA-OAEP encrypted>"}│
|
|
600
|
-
│◄──────────────────────────────────────│
|
|
601
|
-
│ │
|
|
602
|
-
│ [Decrypt key_part_a locally │
|
|
603
|
-
│ with private key (RSA-OAEP)] │
|
|
604
|
-
│ │
|
|
605
|
-
│ POST /files/{id}/decrypt │
|
|
606
|
-
│ { decrypted_key_a: "<base64>" } │
|
|
607
|
-
│──────────────────────────────────────►│
|
|
608
|
-
│ │
|
|
609
|
-
│ [Server combines key_a + key_b, │
|
|
610
|
-
│ decrypts with AES-256-GCM] │
|
|
611
|
-
│ │
|
|
612
|
-
│ <decrypted file bytes> │
|
|
613
|
-
│◄──────────────────────────────────────│
|
|
614
|
-
```
|
|
615
|
-
|
|
616
|
-
---
|
|
617
|
-
|
|
618
|
-
## TypeScript Types
|
|
619
|
-
|
|
620
|
-
All interfaces are exported for full type safety:
|
|
621
|
-
|
|
622
|
-
```typescript
|
|
623
|
-
import Wolfronix, {
|
|
624
|
-
// Config
|
|
625
|
-
WolfronixConfig,
|
|
626
|
-
WolfronixAdminConfig,
|
|
627
|
-
|
|
628
|
-
// Responses
|
|
629
|
-
AuthResponse,
|
|
630
|
-
EncryptResponse,
|
|
631
|
-
FileInfo,
|
|
632
|
-
ListFilesResponse,
|
|
633
|
-
DeleteResponse,
|
|
634
|
-
KeyPartResponse,
|
|
635
|
-
MetricsResponse,
|
|
636
|
-
|
|
637
|
-
// Message Encryption
|
|
638
|
-
EncryptMessagePacket,
|
|
639
|
-
ServerEncryptResult,
|
|
640
|
-
ServerDecryptParams,
|
|
641
|
-
ServerBatchEncryptResult,
|
|
642
|
-
|
|
643
|
-
// Streaming
|
|
644
|
-
WolfronixStream,
|
|
645
|
-
StreamSession,
|
|
646
|
-
StreamChunk,
|
|
647
|
-
|
|
648
|
-
// Enterprise Admin
|
|
649
|
-
WolfronixAdmin,
|
|
650
|
-
RegisterClientRequest,
|
|
651
|
-
RegisterClientResponse,
|
|
652
|
-
EnterpriseClient,
|
|
653
|
-
ListClientsResponse,
|
|
654
|
-
UpdateClientRequest,
|
|
655
|
-
UpdateClientResponse,
|
|
656
|
-
DeactivateClientResponse,
|
|
657
|
-
|
|
658
|
-
// Error Classes
|
|
659
|
-
WolfronixError,
|
|
660
|
-
AuthenticationError,
|
|
661
|
-
FileNotFoundError,
|
|
662
|
-
PermissionDeniedError,
|
|
663
|
-
NetworkError,
|
|
664
|
-
ValidationError
|
|
665
|
-
} from 'wolfronix-sdk';
|
|
666
|
-
```
|
|
667
|
-
|
|
668
|
-
---
|
|
669
|
-
|
|
670
|
-
## Real-World Use Cases
|
|
671
|
-
|
|
672
|
-
| Industry | Application | How Wolfronix Helps |
|
|
673
|
-
|----------|------------|---------------------|
|
|
674
|
-
| 🏥 **Healthcare** | Patient records, lab reports | HIPAA-compliant encryption at rest |
|
|
675
|
-
| 🏦 **Finance** | Invoices, tax docs, receipts | End-to-end encrypted banking documents |
|
|
676
|
-
| ⚖️ **Legal** | Contracts, case files | Zero-knowledge confidential storage |
|
|
677
|
-
| ☁️ **Cloud Storage** | Drive/Dropbox alternatives | Encrypted file vault with user-owned keys |
|
|
678
|
-
| 🏢 **Enterprise** | HR records, internal docs | Per-employee encryption isolation |
|
|
679
|
-
| 💬 **Messaging** | Chat attachments | Encrypted file sharing + E2E messages |
|
|
680
|
-
| 🎓 **Education** | Exam papers, student data | Tamper-proof academic records |
|
|
681
|
-
|
|
682
|
-
---
|
|
683
|
-
|
|
684
|
-
## Backend Integration
|
|
685
|
-
|
|
686
|
-
Your backend only needs to store/retrieve encrypted blobs. Wolfronix handles all crypto.
|
|
687
|
-
|
|
688
|
-
### Supported Connectors (Managed)
|
|
689
|
-
|
|
690
|
-
| Connector | `db_type` | What You Provide |
|
|
691
|
-
|-----------|-----------|-----------------|
|
|
692
|
-
| Supabase | `supabase` | `supabase_url`, `supabase_service_key` |
|
|
693
|
-
| MongoDB | `mongodb` | `connection_string`, `database` |
|
|
694
|
-
| MySQL | `mysql` | `host`, `port`, `user`, `password`, `database` |
|
|
695
|
-
| Firebase | `firebase` | `project_id`, `service_account_key` |
|
|
696
|
-
| PostgreSQL | `postgresql` | `host`, `port`, `user`, `password`, `database` |
|
|
697
|
-
| Custom API | `custom_api` | Your own REST endpoint |
|
|
698
|
-
|
|
699
|
-
### Custom API Mode
|
|
700
|
-
|
|
701
|
-
If using `custom_api`, your backend must implement these endpoints:
|
|
702
|
-
|
|
703
|
-
| Method | Endpoint | Purpose |
|
|
704
|
-
|--------|----------|---------|
|
|
705
|
-
| `POST` | `/wolfronix/files/upload` | Store encrypted file + metadata |
|
|
706
|
-
| `GET` | `/wolfronix/files/{id}` | Retrieve file metadata |
|
|
707
|
-
| `GET` | `/wolfronix/files/{id}/data` | Retrieve encrypted blob |
|
|
708
|
-
| `DELETE` | `/wolfronix/files/{id}` | Delete file |
|
|
709
|
-
|
|
710
|
-
---
|
|
711
|
-
|
|
712
|
-
## Requirements
|
|
713
|
-
|
|
714
|
-
- **Node.js:** 18+ (for server-side usage)
|
|
715
|
-
- **Browser:** Any modern browser with Web Crypto API (Chrome, Firefox, Safari, Edge)
|
|
716
|
-
- **Wolfronix Engine:** v2.4.1+
|
|
717
|
-
|
|
718
|
-
## License
|
|
719
|
-
|
|
720
|
-
MIT License — see [LICENSE](./LICENSE) for details.
|
|
721
|
-
|
|
722
|
-
## Links
|
|
723
|
-
|
|
724
|
-
- [npm Package](https://www.npmjs.com/package/wolfronix-sdk)
|
|
725
|
-
- [GitHub](https://github.com/wolfronix/sdk-javascript)
|
|
726
|
-
- [Report Issues](https://github.com/wolfronix/sdk-javascript/issues)
|
|
1
|
+
# wolfronix-sdk
|
|
2
|
+
|
|
3
|
+
Official JavaScript/TypeScript SDK for Wolfronix zero-knowledge encryption.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- Client-side key generation and private key wrapping
|
|
8
|
+
- Optional 24-word recovery phrase on registration
|
|
9
|
+
- Account recovery flow (`recoverAccount`)
|
|
10
|
+
- File encryption/decryption
|
|
11
|
+
- Resumable chunked uploads for large files (`encryptResumable`)
|
|
12
|
+
- 1:1 E2E messaging (`encryptMessage` / `decryptMessage`)
|
|
13
|
+
- PFS ratchet messaging (`createPfsPreKeyBundle`, `initPfsSession`, `pfsEncryptMessage`, `pfsDecryptMessage`)
|
|
14
|
+
- Group sender-key messaging (`encryptGroupMessage`, `decryptGroupMessage`)
|
|
15
|
+
- Server-side message encryption APIs
|
|
16
|
+
- Streaming encryption/decryption over WebSocket
|
|
17
|
+
- Enterprise admin client management APIs
|
|
18
|
+
|
|
19
|
+
## Installation
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
npm install wolfronix-sdk
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
## Browser Usage
|
|
26
|
+
|
|
27
|
+
```html
|
|
28
|
+
<script src="https://unpkg.com/wolfronix-sdk/dist/index.global.js"></script>
|
|
29
|
+
<script>
|
|
30
|
+
const wfx = new WolfronixSDK.default({
|
|
31
|
+
baseUrl: 'https://your-server:9443',
|
|
32
|
+
clientId: 'your-client-id',
|
|
33
|
+
wolfronixKey: 'your-wolfronix-key'
|
|
34
|
+
});
|
|
35
|
+
</script>
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
## Quick Start
|
|
39
|
+
|
|
40
|
+
```ts
|
|
41
|
+
import Wolfronix from 'wolfronix-sdk';
|
|
42
|
+
|
|
43
|
+
const wfx = new Wolfronix({
|
|
44
|
+
baseUrl: 'https://your-server:9443',
|
|
45
|
+
clientId: 'your-client-id',
|
|
46
|
+
wolfronixKey: 'your-wolfronix-key'
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
await wfx.register('user@example.com', 'password123', { enableRecovery: true });
|
|
50
|
+
await wfx.login('user@example.com', 'password123');
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
## Authentication API
|
|
54
|
+
|
|
55
|
+
| Method | Returns |
|
|
56
|
+
|---|---|
|
|
57
|
+
| `register(email, password, options?)` | `Promise<AuthResponse & Partial<RecoverySetup>>` |
|
|
58
|
+
| `login(email, password)` | `Promise<AuthResponse>` |
|
|
59
|
+
| `recoverAccount(email, recoveryPhrase, newPassword)` | `Promise<AuthResponse>` |
|
|
60
|
+
| `rotateIdentityKeys(password, recoveryPhrase?)` | `Promise<{ success: boolean; message: string; recoveryPhrase?: string }>` |
|
|
61
|
+
| `setToken(token, userId?)` | `void` |
|
|
62
|
+
| `logout()` | `void` |
|
|
63
|
+
| `isAuthenticated()` | `boolean` |
|
|
64
|
+
| `getUserId()` | `string \| null` |
|
|
65
|
+
| `hasPrivateKey()` | `boolean` |
|
|
66
|
+
|
|
67
|
+
Notes:
|
|
68
|
+
- `register(..., { enableRecovery: true })` returns `recoveryPhrase` and `recoveryWords`.
|
|
69
|
+
- `rotateIdentityKeys` currently throws `NOT_SUPPORTED` on the current server API.
|
|
70
|
+
|
|
71
|
+
### Recovery Example
|
|
72
|
+
|
|
73
|
+
```ts
|
|
74
|
+
const reg = await wfx.register('user@example.com', 'password123', { enableRecovery: true });
|
|
75
|
+
console.log(reg.recoveryPhrase); // Save offline securely
|
|
76
|
+
|
|
77
|
+
await wfx.recoverAccount('user@example.com', reg.recoveryPhrase!, 'newPassword123');
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
## File API
|
|
81
|
+
|
|
82
|
+
| Method | Returns |
|
|
83
|
+
|---|---|
|
|
84
|
+
| `encrypt(file, filename?)` | `Promise<EncryptResponse>` |
|
|
85
|
+
| `encryptResumable(file, options?)` | `Promise<{ result: ChunkedEncryptResult; state: ResumableUploadState }>` |
|
|
86
|
+
| `decrypt(fileId, role?)` | `Promise<Blob>` |
|
|
87
|
+
| `decryptToBuffer(fileId, role?)` | `Promise<ArrayBuffer>` |
|
|
88
|
+
| `decryptChunkedToBuffer(manifest, role?)` | `Promise<ArrayBuffer>` |
|
|
89
|
+
| `decryptChunkedManifest(manifest, role?)` | `Promise<Blob>` |
|
|
90
|
+
| `getFileKey(fileId)` | `Promise<KeyPartResponse>` |
|
|
91
|
+
| `listFiles()` | `Promise<ListFilesResponse>` |
|
|
92
|
+
| `deleteFile(fileId)` | `Promise<DeleteResponse>` |
|
|
93
|
+
|
|
94
|
+
### Resumable Upload Example
|
|
95
|
+
|
|
96
|
+
```ts
|
|
97
|
+
const { result, state } = await wfx.encryptResumable(file, {
|
|
98
|
+
chunkSizeBytes: 10 * 1024 * 1024,
|
|
99
|
+
onProgress: (uploaded, total) => console.log(`${uploaded}/${total}`)
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
const manifest = {
|
|
103
|
+
filename: result.filename,
|
|
104
|
+
chunk_file_ids: result.chunk_file_ids
|
|
105
|
+
};
|
|
106
|
+
|
|
107
|
+
const mergedBlob = await wfx.decryptChunkedManifest(manifest);
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
## E2E Messaging API
|
|
111
|
+
|
|
112
|
+
| Method | Returns |
|
|
113
|
+
|---|---|
|
|
114
|
+
| `getPublicKey(userId, clientId?)` | `Promise<CryptoKey>` |
|
|
115
|
+
| `encryptMessage(text, recipientId)` | `Promise<string>` |
|
|
116
|
+
| `decryptMessage(packetString)` | `Promise<string>` |
|
|
117
|
+
|
|
118
|
+
## PFS Ratchet API
|
|
119
|
+
|
|
120
|
+
| Method | Returns |
|
|
121
|
+
|---|---|
|
|
122
|
+
| `createPfsPreKeyBundle()` | `Promise<PfsPreKeyBundle>` |
|
|
123
|
+
| `initPfsSession(sessionId, peerBundle, asInitiator)` | `Promise<PfsSessionState>` |
|
|
124
|
+
| `exportPfsSession(sessionId)` | `PfsSessionState` |
|
|
125
|
+
| `importPfsSession(session)` | `void` |
|
|
126
|
+
| `pfsEncryptMessage(sessionId, plaintext)` | `Promise<PfsMessagePacket>` |
|
|
127
|
+
| `pfsDecryptMessage(sessionId, packet)` | `Promise<string>` |
|
|
128
|
+
|
|
129
|
+
## Group Sender-Key API
|
|
130
|
+
|
|
131
|
+
| Method | Returns |
|
|
132
|
+
|---|---|
|
|
133
|
+
| `encryptGroupMessage(text, groupId, recipientIds)` | `Promise<string>` |
|
|
134
|
+
| `decryptGroupMessage(packetJson)` | `Promise<string>` |
|
|
135
|
+
|
|
136
|
+
## Server Message Encryption API
|
|
137
|
+
|
|
138
|
+
| Method | Returns |
|
|
139
|
+
|---|---|
|
|
140
|
+
| `serverEncrypt(message, options?)` | `Promise<ServerEncryptResult>` |
|
|
141
|
+
| `serverDecrypt(params)` | `Promise<string>` |
|
|
142
|
+
| `serverEncryptBatch(messages, options?)` | `Promise<ServerBatchEncryptResult>` |
|
|
143
|
+
| `serverDecryptBatchItem(batchResult, index)` | `Promise<string>` |
|
|
144
|
+
|
|
145
|
+
## Streaming API
|
|
146
|
+
|
|
147
|
+
| Method | Returns |
|
|
148
|
+
|---|---|
|
|
149
|
+
| `createStream(direction, streamKey?)` | `Promise<WolfronixStream>` |
|
|
150
|
+
|
|
151
|
+
## Admin API
|
|
152
|
+
|
|
153
|
+
```ts
|
|
154
|
+
import { WolfronixAdmin } from 'wolfronix-sdk';
|
|
155
|
+
|
|
156
|
+
const admin = new WolfronixAdmin({
|
|
157
|
+
baseUrl: 'https://your-server:9443',
|
|
158
|
+
adminKey: 'your-admin-api-key'
|
|
159
|
+
});
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
| Method | Returns |
|
|
163
|
+
|---|---|
|
|
164
|
+
| `registerClient(params)` | `Promise<RegisterClientResponse>` |
|
|
165
|
+
| `listClients()` | `Promise<ListClientsResponse>` |
|
|
166
|
+
| `getClient(clientId)` | `Promise<EnterpriseClient>` |
|
|
167
|
+
| `updateClient(clientId, params)` | `Promise<UpdateClientResponse>` |
|
|
168
|
+
| `deactivateClient(clientId)` | `Promise<DeactivateClientResponse>` |
|
|
169
|
+
| `healthCheck()` | `Promise<boolean>` |
|
|
170
|
+
|
|
171
|
+
## Errors
|
|
172
|
+
|
|
173
|
+
The SDK throws typed errors:
|
|
174
|
+
- `WolfronixError`
|
|
175
|
+
- `AuthenticationError`
|
|
176
|
+
- `FileNotFoundError`
|
|
177
|
+
- `PermissionDeniedError`
|
|
178
|
+
- `NetworkError`
|
|
179
|
+
- `ValidationError`
|
|
180
|
+
|
|
181
|
+
## Requirements
|
|
182
|
+
|
|
183
|
+
- Node.js 18+
|
|
184
|
+
- Modern browsers with Web Crypto API
|
|
185
|
+
- Wolfronix Engine v2.4.1+
|
|
186
|
+
|
|
187
|
+
## License
|
|
188
|
+
|
|
189
|
+
MIT
|