@vaultsandbox/client 0.6.0 → 0.7.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/LICENSE +190 -21
- package/README.md +3 -3
- package/dist/client.d.ts +11 -3
- package/dist/client.js +83 -30
- package/dist/client.js.map +1 -1
- package/dist/crypto/decrypt.js +12 -4
- package/dist/crypto/decrypt.js.map +1 -1
- package/dist/crypto/signature.js +3 -1
- package/dist/crypto/signature.js.map +1 -1
- package/dist/email.d.ts +2 -2
- package/dist/email.js +25 -12
- package/dist/email.js.map +1 -1
- package/dist/http/api-client.d.ts +4 -2
- package/dist/http/api-client.js +17 -3
- package/dist/http/api-client.js.map +1 -1
- package/dist/inbox.d.ts +69 -3
- package/dist/inbox.js +142 -14
- package/dist/inbox.js.map +1 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/dist/strategies/delivery-strategy.d.ts +7 -5
- package/dist/strategies/polling-strategy.d.ts +5 -5
- package/dist/strategies/polling-strategy.js +46 -21
- package/dist/strategies/polling-strategy.js.map +1 -1
- package/dist/strategies/sse-strategy.d.ts +8 -3
- package/dist/strategies/sse-strategy.js +112 -15
- package/dist/strategies/sse-strategy.js.map +1 -1
- package/dist/sync/inbox-sync.d.ts +31 -0
- package/dist/sync/inbox-sync.js +52 -0
- package/dist/sync/inbox-sync.js.map +1 -0
- package/dist/types/index.d.ts +64 -17
- package/dist/types/index.js.map +1 -1
- package/dist/utils/email-utils.d.ts +14 -3
- package/dist/utils/email-utils.js +41 -1
- package/dist/utils/email-utils.js.map +1 -1
- package/dist/utils/hash.d.ts +15 -0
- package/dist/utils/hash.js +31 -0
- package/dist/utils/hash.js.map +1 -0
- package/package.json +5 -5
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Inbox synchronization utilities for hash-based sync with deletion handling
|
|
3
|
+
*/
|
|
4
|
+
import type { ApiClient } from '../http/api-client.js';
|
|
5
|
+
import type { EmailData } from '../types/index.js';
|
|
6
|
+
/**
|
|
7
|
+
* Result of a sync operation.
|
|
8
|
+
*/
|
|
9
|
+
export interface SyncResult {
|
|
10
|
+
/** Emails that exist on the server but not locally */
|
|
11
|
+
added: EmailData[];
|
|
12
|
+
/** Email IDs that exist locally but not on the server */
|
|
13
|
+
deleted: string[];
|
|
14
|
+
/** Whether the inbox was already in sync (no changes) */
|
|
15
|
+
unchanged: boolean;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Synchronizes the local email cache with the server using hash comparison.
|
|
19
|
+
*
|
|
20
|
+
* This implements the spec's hash-based sync algorithm:
|
|
21
|
+
* 1. Compute local hash from current email IDs
|
|
22
|
+
* 2. Get server hash via /sync endpoint
|
|
23
|
+
* 3. If hashes match, no sync needed
|
|
24
|
+
* 4. If hashes differ, fetch full email list and reconcile
|
|
25
|
+
*
|
|
26
|
+
* @param apiClient - The API client for server communication
|
|
27
|
+
* @param emailAddress - The inbox email address
|
|
28
|
+
* @param localEmails - Map of local email IDs to EmailData
|
|
29
|
+
* @returns Promise resolving to sync result with added/deleted emails
|
|
30
|
+
*/
|
|
31
|
+
export declare function syncInbox(apiClient: ApiClient, emailAddress: string, localEmails: Map<string, EmailData>): Promise<SyncResult>;
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Inbox synchronization utilities for hash-based sync with deletion handling
|
|
3
|
+
*/
|
|
4
|
+
import createDebug from 'debug';
|
|
5
|
+
import { computeEmailsHash } from '../utils/hash.js';
|
|
6
|
+
const debug = createDebug('vaultsandbox:sync');
|
|
7
|
+
/**
|
|
8
|
+
* Synchronizes the local email cache with the server using hash comparison.
|
|
9
|
+
*
|
|
10
|
+
* This implements the spec's hash-based sync algorithm:
|
|
11
|
+
* 1. Compute local hash from current email IDs
|
|
12
|
+
* 2. Get server hash via /sync endpoint
|
|
13
|
+
* 3. If hashes match, no sync needed
|
|
14
|
+
* 4. If hashes differ, fetch full email list and reconcile
|
|
15
|
+
*
|
|
16
|
+
* @param apiClient - The API client for server communication
|
|
17
|
+
* @param emailAddress - The inbox email address
|
|
18
|
+
* @param localEmails - Map of local email IDs to EmailData
|
|
19
|
+
* @returns Promise resolving to sync result with added/deleted emails
|
|
20
|
+
*/
|
|
21
|
+
export async function syncInbox(apiClient, emailAddress, localEmails) {
|
|
22
|
+
debug('Starting sync for inbox %s', emailAddress);
|
|
23
|
+
// Step 1: Compute local hash from current email IDs
|
|
24
|
+
const localIds = Array.from(localEmails.keys());
|
|
25
|
+
const localHash = computeEmailsHash(localIds);
|
|
26
|
+
debug('Computed local hash: %s (from %d emails)', localHash, localIds.length);
|
|
27
|
+
// Step 2: Get server hash
|
|
28
|
+
const syncStatus = await apiClient.getSyncStatus(emailAddress);
|
|
29
|
+
debug('Server hash: %s (with %d emails)', syncStatus.emailsHash, syncStatus.emailCount);
|
|
30
|
+
// Step 3: Compare hashes
|
|
31
|
+
if (localHash === syncStatus.emailsHash) {
|
|
32
|
+
debug('Hashes match - inbox %s is in sync', emailAddress);
|
|
33
|
+
return { added: [], deleted: [], unchanged: true };
|
|
34
|
+
}
|
|
35
|
+
debug('Hash mismatch detected for inbox %s - fetching full email list', emailAddress);
|
|
36
|
+
// Step 4: Fetch full email list from server
|
|
37
|
+
const serverEmails = await apiClient.listEmails(emailAddress, false);
|
|
38
|
+
const serverIds = new Set(serverEmails.map((e) => e.id));
|
|
39
|
+
const localIdSet = new Set(localIds);
|
|
40
|
+
// Step 5: Find new emails (on server but not local)
|
|
41
|
+
const newEmails = serverEmails.filter((e) => !localIdSet.has(e.id));
|
|
42
|
+
debug('Found %d new emails on server', newEmails.length);
|
|
43
|
+
// Step 6: Find deleted emails (local but not on server)
|
|
44
|
+
const deletedIds = localIds.filter((id) => !serverIds.has(id));
|
|
45
|
+
debug('Found %d emails deleted from server', deletedIds.length);
|
|
46
|
+
return {
|
|
47
|
+
added: newEmails,
|
|
48
|
+
deleted: deletedIds,
|
|
49
|
+
unchanged: false,
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
//# sourceMappingURL=inbox-sync.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"inbox-sync.js","sourceRoot":"","sources":["../../src/sync/inbox-sync.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,WAAW,MAAM,OAAO,CAAC;AAChC,OAAO,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AAIrD,MAAM,KAAK,GAAG,WAAW,CAAC,mBAAmB,CAAC,CAAC;AAc/C;;;;;;;;;;;;;GAaG;AACH,MAAM,CAAC,KAAK,UAAU,SAAS,CAC7B,SAAoB,EACpB,YAAoB,EACpB,WAAmC;IAEnC,KAAK,CAAC,4BAA4B,EAAE,YAAY,CAAC,CAAC;IAElD,oDAAoD;IACpD,MAAM,QAAQ,GAAG,KAAK,CAAC,IAAI,CAAC,WAAW,CAAC,IAAI,EAAE,CAAC,CAAC;IAChD,MAAM,SAAS,GAAG,iBAAiB,CAAC,QAAQ,CAAC,CAAC;IAC9C,KAAK,CAAC,0CAA0C,EAAE,SAAS,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAC;IAE9E,0BAA0B;IAC1B,MAAM,UAAU,GAAG,MAAM,SAAS,CAAC,aAAa,CAAC,YAAY,CAAC,CAAC;IAC/D,KAAK,CAAC,kCAAkC,EAAE,UAAU,CAAC,UAAU,EAAE,UAAU,CAAC,UAAU,CAAC,CAAC;IAExF,yBAAyB;IACzB,IAAI,SAAS,KAAK,UAAU,CAAC,UAAU,EAAE,CAAC;QACxC,KAAK,CAAC,oCAAoC,EAAE,YAAY,CAAC,CAAC;QAC1D,OAAO,EAAE,KAAK,EAAE,EAAE,EAAE,OAAO,EAAE,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC;IACrD,CAAC;IAED,KAAK,CAAC,gEAAgE,EAAE,YAAY,CAAC,CAAC;IAEtF,4CAA4C;IAC5C,MAAM,YAAY,GAAG,MAAM,SAAS,CAAC,UAAU,CAAC,YAAY,EAAE,KAAK,CAAC,CAAC;IACrE,MAAM,SAAS,GAAG,IAAI,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;IACzD,MAAM,UAAU,GAAG,IAAI,GAAG,CAAC,QAAQ,CAAC,CAAC;IAErC,oDAAoD;IACpD,MAAM,SAAS,GAAG,YAAY,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;IACpE,KAAK,CAAC,+BAA+B,EAAE,SAAS,CAAC,MAAM,CAAC,CAAC;IAEzD,wDAAwD;IACxD,MAAM,UAAU,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC,SAAS,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC;IAC/D,KAAK,CAAC,qCAAqC,EAAE,UAAU,CAAC,MAAM,CAAC,CAAC;IAEhE,OAAO;QACL,KAAK,EAAE,SAAS;QAChB,OAAO,EAAE,UAAU;QACnB,SAAS,EAAE,KAAK;KACjB,CAAC;AACJ,CAAC"}
|
package/dist/types/index.d.ts
CHANGED
|
@@ -11,11 +11,10 @@ export interface ClientConfig {
|
|
|
11
11
|
apiKey: string;
|
|
12
12
|
/**
|
|
13
13
|
* The email delivery strategy to use.
|
|
14
|
-
* - `sse`: Use Server-Sent Events for real-time updates.
|
|
14
|
+
* - `sse`: Use Server-Sent Events for real-time updates (default).
|
|
15
15
|
* - `polling`: Use traditional polling.
|
|
16
|
-
* - `auto`: Use SSE if available, otherwise fall back to polling (default).
|
|
17
16
|
*/
|
|
18
|
-
strategy?: 'sse' | 'polling'
|
|
17
|
+
strategy?: 'sse' | 'polling';
|
|
19
18
|
/** The base interval for polling in milliseconds (default: 2000). */
|
|
20
19
|
pollingInterval?: number;
|
|
21
20
|
/** The maximum number of retries for failed HTTP requests (default: 3). */
|
|
@@ -37,6 +36,10 @@ export interface CreateInboxOptions {
|
|
|
37
36
|
ttl?: number;
|
|
38
37
|
/** A specific email address to request for the inbox. */
|
|
39
38
|
emailAddress?: string;
|
|
39
|
+
/** Enable or disable email authentication checks (SPF, DKIM, DMARC, PTR). Omit to use server default. */
|
|
40
|
+
emailAuth?: boolean;
|
|
41
|
+
/** Request encrypted or plain inbox. Omit to use server default based on encryptionPolicy. */
|
|
42
|
+
encryption?: 'encrypted' | 'plain';
|
|
40
43
|
}
|
|
41
44
|
/**
|
|
42
45
|
* Exported inbox data structure for sharing or backup purposes.
|
|
@@ -52,10 +55,12 @@ export interface ExportedInboxData {
|
|
|
52
55
|
expiresAt: string;
|
|
53
56
|
/** Unique hash identifier for the inbox */
|
|
54
57
|
inboxHash: string;
|
|
55
|
-
/**
|
|
56
|
-
|
|
57
|
-
/** ML-
|
|
58
|
-
|
|
58
|
+
/** Whether this inbox uses encryption. */
|
|
59
|
+
encrypted: boolean;
|
|
60
|
+
/** Server's ML-DSA-65 public key (base64url encoded, 1952 bytes decoded). Only present for encrypted inboxes. */
|
|
61
|
+
serverSigPk?: string;
|
|
62
|
+
/** ML-KEM-768 secret key (base64url encoded, 2400 bytes decoded). Only present for encrypted inboxes. */
|
|
63
|
+
secretKey?: string;
|
|
59
64
|
/** ISO 8601 timestamp when the export was created */
|
|
60
65
|
exportedAt: string;
|
|
61
66
|
}
|
|
@@ -71,8 +76,12 @@ export interface InboxData {
|
|
|
71
76
|
expiresAt: string;
|
|
72
77
|
/** Base64URL-encoded SHA-256 hash of the client KEM public key, used for SSE subscriptions and API references. */
|
|
73
78
|
inboxHash: string;
|
|
74
|
-
/**
|
|
75
|
-
|
|
79
|
+
/** Whether this inbox uses encryption. */
|
|
80
|
+
encrypted: boolean;
|
|
81
|
+
/** Base64URL-encoded server signing public key for verifying server signatures. Only present for encrypted inboxes. */
|
|
82
|
+
serverSigPk?: string;
|
|
83
|
+
/** Whether email authentication checks (SPF, DKIM, DMARC, PTR) are enabled for this inbox. */
|
|
84
|
+
emailAuth?: boolean;
|
|
76
85
|
}
|
|
77
86
|
/**
|
|
78
87
|
* The synchronization status of an inbox.
|
|
@@ -106,10 +115,10 @@ export interface WaitForCountOptions {
|
|
|
106
115
|
timeout?: number;
|
|
107
116
|
}
|
|
108
117
|
/**
|
|
109
|
-
*
|
|
118
|
+
* Encrypted email data returned from the API.
|
|
110
119
|
* @internal
|
|
111
120
|
*/
|
|
112
|
-
export interface
|
|
121
|
+
export interface EncryptedEmailData {
|
|
113
122
|
id: string;
|
|
114
123
|
inboxId: string;
|
|
115
124
|
receivedAt: string;
|
|
@@ -117,6 +126,26 @@ export interface EmailData {
|
|
|
117
126
|
encryptedMetadata: EncryptedData;
|
|
118
127
|
encryptedParsed?: EncryptedData;
|
|
119
128
|
}
|
|
129
|
+
/**
|
|
130
|
+
* Plain (unencrypted) email data returned from the API.
|
|
131
|
+
* @internal
|
|
132
|
+
*/
|
|
133
|
+
export interface PlainEmailData {
|
|
134
|
+
id: string;
|
|
135
|
+
inboxId: string;
|
|
136
|
+
receivedAt: string;
|
|
137
|
+
isRead: boolean;
|
|
138
|
+
/** Base64-encoded JSON metadata */
|
|
139
|
+
metadata: string;
|
|
140
|
+
/** Base64-encoded JSON parsed content */
|
|
141
|
+
parsed?: string;
|
|
142
|
+
}
|
|
143
|
+
/**
|
|
144
|
+
* Raw email data returned from the API (encrypted or plain).
|
|
145
|
+
* Use `isEncryptedEmailData()` type guard to discriminate.
|
|
146
|
+
* @internal
|
|
147
|
+
*/
|
|
148
|
+
export type EmailData = EncryptedEmailData | PlainEmailData;
|
|
120
149
|
/**
|
|
121
150
|
* The structure of encrypted data returned from the server.
|
|
122
151
|
* @internal
|
|
@@ -187,17 +216,21 @@ export interface RawEmail {
|
|
|
187
216
|
raw: string;
|
|
188
217
|
}
|
|
189
218
|
/**
|
|
219
|
+
* Raw email data from the API (encrypted or plain).
|
|
190
220
|
* @internal
|
|
191
221
|
*/
|
|
192
222
|
export interface RawEmailData {
|
|
193
223
|
id: string;
|
|
194
|
-
|
|
224
|
+
/** Encrypted raw email content. Present for encrypted inboxes. */
|
|
225
|
+
encryptedRaw?: EncryptedData;
|
|
226
|
+
/** Base64-encoded raw email content. Present for plain inboxes. */
|
|
227
|
+
raw?: string;
|
|
195
228
|
}
|
|
196
229
|
/**
|
|
197
230
|
* The result of an SPF (Sender Policy Framework) validation check.
|
|
198
231
|
*/
|
|
199
232
|
export interface SPFResult {
|
|
200
|
-
result: 'pass' | 'fail' | 'softfail' | 'neutral' | 'none' | 'temperror' | 'permerror';
|
|
233
|
+
result: 'pass' | 'fail' | 'softfail' | 'neutral' | 'none' | 'temperror' | 'permerror' | 'skipped';
|
|
201
234
|
domain?: string;
|
|
202
235
|
ip?: string;
|
|
203
236
|
details?: string;
|
|
@@ -206,7 +239,7 @@ export interface SPFResult {
|
|
|
206
239
|
* The result of a DKIM (DomainKeys Identified Mail) validation check.
|
|
207
240
|
*/
|
|
208
241
|
export interface DKIMResult {
|
|
209
|
-
result: 'pass' | 'fail' | 'none';
|
|
242
|
+
result: 'pass' | 'fail' | 'none' | 'skipped';
|
|
210
243
|
domain?: string;
|
|
211
244
|
selector?: string;
|
|
212
245
|
signature?: string;
|
|
@@ -215,7 +248,7 @@ export interface DKIMResult {
|
|
|
215
248
|
* The result of a DMARC (Domain-based Message Authentication, Reporting, and Conformance) validation check.
|
|
216
249
|
*/
|
|
217
250
|
export interface DMARCResult {
|
|
218
|
-
result: 'pass' | 'fail' | 'none';
|
|
251
|
+
result: 'pass' | 'fail' | 'none' | 'skipped';
|
|
219
252
|
policy?: 'none' | 'quarantine' | 'reject';
|
|
220
253
|
aligned?: boolean;
|
|
221
254
|
domain?: string;
|
|
@@ -224,7 +257,7 @@ export interface DMARCResult {
|
|
|
224
257
|
* The result of a reverse DNS validation check.
|
|
225
258
|
*/
|
|
226
259
|
export interface ReverseDNSResult {
|
|
227
|
-
|
|
260
|
+
result: 'pass' | 'fail' | 'none' | 'skipped';
|
|
228
261
|
ip?: string;
|
|
229
262
|
hostname?: string;
|
|
230
263
|
}
|
|
@@ -291,12 +324,22 @@ export interface IEmail {
|
|
|
291
324
|
export interface AuthResults extends AuthResultsData {
|
|
292
325
|
validate(): AuthValidation;
|
|
293
326
|
}
|
|
327
|
+
/**
|
|
328
|
+
* The server's encryption policy for inboxes.
|
|
329
|
+
* - `always`: All inboxes are encrypted, no override allowed
|
|
330
|
+
* - `enabled`: Inboxes are encrypted by default, can request plain
|
|
331
|
+
* - `disabled`: Inboxes are plain by default, can request encrypted
|
|
332
|
+
* - `never`: All inboxes are plain, no override allowed
|
|
333
|
+
*/
|
|
334
|
+
export type EncryptionPolicy = 'always' | 'enabled' | 'disabled' | 'never';
|
|
294
335
|
/**
|
|
295
336
|
* Information about the VaultSandbox server.
|
|
296
337
|
*/
|
|
297
338
|
export interface ServerInfo {
|
|
298
339
|
/** Base64URL-encoded server signing public key for ML-DSA-65. */
|
|
299
340
|
serverSigPk: string;
|
|
341
|
+
/** The server's encryption policy for inboxes. */
|
|
342
|
+
encryptionPolicy: EncryptionPolicy;
|
|
300
343
|
/** Cryptographic algorithms supported by the server. */
|
|
301
344
|
algs: {
|
|
302
345
|
/** Key encapsulation mechanism algorithm (e.g., 'ML-KEM-768'). */
|
|
@@ -337,12 +380,16 @@ export interface SSEConfig {
|
|
|
337
380
|
backoffMultiplier?: number;
|
|
338
381
|
}
|
|
339
382
|
/**
|
|
383
|
+
* SSE message data for new email notifications.
|
|
340
384
|
* @internal
|
|
341
385
|
*/
|
|
342
386
|
export interface SSEMessageData {
|
|
343
387
|
inboxId: string;
|
|
344
388
|
emailId: string;
|
|
345
|
-
|
|
389
|
+
/** Encrypted metadata. Present for encrypted inboxes. */
|
|
390
|
+
encryptedMetadata?: EncryptedData;
|
|
391
|
+
/** Base64-encoded JSON metadata. Present for plain inboxes. */
|
|
392
|
+
metadata?: string;
|
|
346
393
|
}
|
|
347
394
|
/**
|
|
348
395
|
* A quantum-safe keypair used for encryption and decryption.
|
package/dist/types/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/types/index.ts"],"names":[],"mappings":"AAAA;;GAEG;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/types/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,14 +1,25 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Shared email utilities for decryption and filtering
|
|
3
3
|
*/
|
|
4
|
-
import type { Keypair, EmailData, IEmail, WaitOptions } from '../types/index.js';
|
|
4
|
+
import type { Keypair, EmailData, EncryptedEmailData, PlainEmailData, IEmail, WaitOptions } from '../types/index.js';
|
|
5
5
|
import type { ApiClient } from '../http/api-client.js';
|
|
6
6
|
/**
|
|
7
|
-
*
|
|
7
|
+
* Type guard to determine if email data is encrypted.
|
|
8
|
+
* @param email - The email data to check
|
|
9
|
+
* @returns true if the email has encryptedMetadata (encrypted format)
|
|
10
|
+
*/
|
|
11
|
+
export declare function isEncryptedEmailData(email: EmailData): email is EncryptedEmailData;
|
|
12
|
+
/**
|
|
13
|
+
* Decrypts an EncryptedEmailData object into an Email instance.
|
|
8
14
|
* Expects full email data with encryptedParsed content.
|
|
9
15
|
* IMPORTANT: Signature verification happens BEFORE decryption for security
|
|
10
16
|
*/
|
|
11
|
-
export declare function decryptEmailData(emailData:
|
|
17
|
+
export declare function decryptEmailData(emailData: EncryptedEmailData, keypair: Keypair, emailAddress: string, apiClient: ApiClient): Promise<IEmail>;
|
|
18
|
+
/**
|
|
19
|
+
* Decodes a PlainEmailData object into an Email instance.
|
|
20
|
+
* Plain emails have base64-encoded metadata and parsed content.
|
|
21
|
+
*/
|
|
22
|
+
export declare function decodeBase64EmailData(emailData: PlainEmailData, emailAddress: string, apiClient: ApiClient): IEmail;
|
|
12
23
|
/**
|
|
13
24
|
* Finds the first email matching the specified criteria
|
|
14
25
|
*/
|
|
@@ -6,7 +6,15 @@ import { decryptMetadata, decryptParsed } from '../crypto/decrypt.js';
|
|
|
6
6
|
import { verifySignature } from '../crypto/signature.js';
|
|
7
7
|
import { fromBase64 } from '../crypto/utils.js';
|
|
8
8
|
/**
|
|
9
|
-
*
|
|
9
|
+
* Type guard to determine if email data is encrypted.
|
|
10
|
+
* @param email - The email data to check
|
|
11
|
+
* @returns true if the email has encryptedMetadata (encrypted format)
|
|
12
|
+
*/
|
|
13
|
+
export function isEncryptedEmailData(email) {
|
|
14
|
+
return 'encryptedMetadata' in email;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Decrypts an EncryptedEmailData object into an Email instance.
|
|
10
18
|
* Expects full email data with encryptedParsed content.
|
|
11
19
|
* IMPORTANT: Signature verification happens BEFORE decryption for security
|
|
12
20
|
*/
|
|
@@ -39,6 +47,36 @@ export async function decryptEmailData(emailData, keypair, emailAddress, apiClie
|
|
|
39
47
|
}
|
|
40
48
|
return new Email(emailData, metadata, parsed, emailAddress, apiClient, keypair);
|
|
41
49
|
}
|
|
50
|
+
/**
|
|
51
|
+
* Decodes a PlainEmailData object into an Email instance.
|
|
52
|
+
* Plain emails have base64-encoded metadata and parsed content.
|
|
53
|
+
*/
|
|
54
|
+
export function decodeBase64EmailData(emailData, emailAddress, apiClient) {
|
|
55
|
+
// Decode base64 metadata
|
|
56
|
+
const metadataJson = Buffer.from(emailData.metadata, 'base64').toString('utf-8');
|
|
57
|
+
const metadata = JSON.parse(metadataJson);
|
|
58
|
+
// Decode parsed content if available
|
|
59
|
+
let parsed = null;
|
|
60
|
+
if (emailData.parsed) {
|
|
61
|
+
const parsedJson = Buffer.from(emailData.parsed, 'base64').toString('utf-8');
|
|
62
|
+
parsed = JSON.parse(parsedJson);
|
|
63
|
+
// Transform attachment content from base64 strings to Uint8Array
|
|
64
|
+
// Same as encrypted path - server sends attachment content as base64
|
|
65
|
+
if (parsed?.attachments) {
|
|
66
|
+
parsed.attachments = parsed.attachments.map((att) => {
|
|
67
|
+
if (att.content && typeof att.content === 'string') {
|
|
68
|
+
return {
|
|
69
|
+
...att,
|
|
70
|
+
content: fromBase64(att.content),
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
return att;
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
// Pass null for keypair since plain emails don't need decryption
|
|
78
|
+
return new Email(emailData, metadata, parsed, emailAddress, apiClient, null);
|
|
79
|
+
}
|
|
42
80
|
/**
|
|
43
81
|
* Finds the first email matching the specified criteria
|
|
44
82
|
*/
|
|
@@ -56,6 +94,7 @@ export function findMatchingEmail(emails, options) {
|
|
|
56
94
|
export function matchesFilters(email, options) {
|
|
57
95
|
// Check subject filter
|
|
58
96
|
if (options.subject) {
|
|
97
|
+
/* istanbul ignore else - defensive check for non-TypeScript callers */
|
|
59
98
|
if (typeof options.subject === 'string') {
|
|
60
99
|
if (!email.subject.includes(options.subject)) {
|
|
61
100
|
return false;
|
|
@@ -69,6 +108,7 @@ export function matchesFilters(email, options) {
|
|
|
69
108
|
}
|
|
70
109
|
// Check from filter
|
|
71
110
|
if (options.from) {
|
|
111
|
+
/* istanbul ignore else - defensive check for non-TypeScript callers */
|
|
72
112
|
if (typeof options.from === 'string') {
|
|
73
113
|
if (!email.from.includes(options.from)) {
|
|
74
114
|
return false;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"email-utils.js","sourceRoot":"","sources":["../../src/utils/email-utils.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,KAAK,EAAE,MAAM,aAAa,CAAC;AACpC,OAAO,EAAE,eAAe,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AACtE,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AACzD,OAAO,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;
|
|
1
|
+
{"version":3,"file":"email-utils.js","sourceRoot":"","sources":["../../src/utils/email-utils.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Hash utilities for email synchronization
|
|
3
|
+
*/
|
|
4
|
+
/**
|
|
5
|
+
* Computes the emails hash using the spec algorithm:
|
|
6
|
+
* BASE64URL(SHA256(SORT(emailIds).join(",")))
|
|
7
|
+
*
|
|
8
|
+
* This hash is used to efficiently detect changes between
|
|
9
|
+
* the local and server email lists without transferring
|
|
10
|
+
* the full list.
|
|
11
|
+
*
|
|
12
|
+
* @param emailIds - Array of email IDs to hash
|
|
13
|
+
* @returns Base64URL encoded SHA-256 hash (no padding)
|
|
14
|
+
*/
|
|
15
|
+
export declare function computeEmailsHash(emailIds: string[]): string;
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Hash utilities for email synchronization
|
|
3
|
+
*/
|
|
4
|
+
import { createHash } from 'crypto';
|
|
5
|
+
/**
|
|
6
|
+
* Computes the emails hash using the spec algorithm:
|
|
7
|
+
* BASE64URL(SHA256(SORT(emailIds).join(",")))
|
|
8
|
+
*
|
|
9
|
+
* This hash is used to efficiently detect changes between
|
|
10
|
+
* the local and server email lists without transferring
|
|
11
|
+
* the full list.
|
|
12
|
+
*
|
|
13
|
+
* @param emailIds - Array of email IDs to hash
|
|
14
|
+
* @returns Base64URL encoded SHA-256 hash (no padding)
|
|
15
|
+
*/
|
|
16
|
+
export function computeEmailsHash(emailIds) {
|
|
17
|
+
const sorted = [...emailIds].sort();
|
|
18
|
+
const joined = sorted.join(',');
|
|
19
|
+
const hash = createHash('sha256').update(joined).digest();
|
|
20
|
+
return base64UrlEncode(hash);
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Encodes a buffer as Base64URL (RFC 4648 §5) without padding.
|
|
24
|
+
*
|
|
25
|
+
* @param buffer - The buffer to encode
|
|
26
|
+
* @returns Base64URL encoded string without padding
|
|
27
|
+
*/
|
|
28
|
+
function base64UrlEncode(buffer) {
|
|
29
|
+
return buffer.toString('base64').replace(/\+/g, '-').replace(/\//g, '_').replace(/=+$/, '');
|
|
30
|
+
}
|
|
31
|
+
//# sourceMappingURL=hash.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hash.js","sourceRoot":"","sources":["../../src/utils/hash.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,UAAU,EAAE,MAAM,QAAQ,CAAC;AAEpC;;;;;;;;;;GAUG;AACH,MAAM,UAAU,iBAAiB,CAAC,QAAkB;IAClD,MAAM,MAAM,GAAG,CAAC,GAAG,QAAQ,CAAC,CAAC,IAAI,EAAE,CAAC;IACpC,MAAM,MAAM,GAAG,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IAChC,MAAM,IAAI,GAAG,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,MAAM,EAAE,CAAC;IAC1D,OAAO,eAAe,CAAC,IAAI,CAAC,CAAC;AAC/B,CAAC;AAED;;;;;GAKG;AACH,SAAS,eAAe,CAAC,MAAc;IACrC,OAAO,MAAM,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;AAC9F,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vaultsandbox/client",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.7.0",
|
|
4
4
|
"description": "Node.js SDK for VaultSandbox Gateway — quantum-safe email testing with zero crypto knowledge required. Create isolated inboxes, validate SPF/DKIM/DMARC, and test your full email stack in CI/CD pipelines.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"homepage": "https://github.com/vaultsandbox/client-node",
|
|
@@ -38,7 +38,7 @@
|
|
|
38
38
|
"vaultsandbox"
|
|
39
39
|
],
|
|
40
40
|
"author": "Antero <antero@vaultsandbox.com>",
|
|
41
|
-
"license": "
|
|
41
|
+
"license": "Apache-2.0",
|
|
42
42
|
"publishConfig": {
|
|
43
43
|
"access": "public"
|
|
44
44
|
},
|
|
@@ -61,7 +61,7 @@
|
|
|
61
61
|
"prepublishOnly": "npm run clean && npm run build"
|
|
62
62
|
},
|
|
63
63
|
"dependencies": {
|
|
64
|
-
"@noble/post-quantum": "0.5.
|
|
64
|
+
"@noble/post-quantum": "0.5.4",
|
|
65
65
|
"axios": "1.13.2",
|
|
66
66
|
"debug": "4.4.3",
|
|
67
67
|
"eventsource": "4.1.0"
|
|
@@ -70,8 +70,8 @@
|
|
|
70
70
|
"@types/debug": "4.1.12",
|
|
71
71
|
"@types/jest": "30.0.0",
|
|
72
72
|
"@types/node": "24.10.2",
|
|
73
|
-
"@typescript-eslint/eslint-plugin": "8.
|
|
74
|
-
"@typescript-eslint/parser": "8.
|
|
73
|
+
"@typescript-eslint/eslint-plugin": "8.52.0",
|
|
74
|
+
"@typescript-eslint/parser": "8.52.0",
|
|
75
75
|
"dotenv": "17.2.3",
|
|
76
76
|
"eslint": "9.39.1",
|
|
77
77
|
"eslint-config-prettier": "10.1.8",
|