@vaultsandbox/client 0.5.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.
Files changed (51) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +612 -0
  3. package/dist/client.d.ts +231 -0
  4. package/dist/client.js +432 -0
  5. package/dist/client.js.map +1 -0
  6. package/dist/crypto/constants.d.ts +13 -0
  7. package/dist/crypto/constants.js +14 -0
  8. package/dist/crypto/constants.js.map +1 -0
  9. package/dist/crypto/decrypt.d.ts +41 -0
  10. package/dist/crypto/decrypt.js +112 -0
  11. package/dist/crypto/decrypt.js.map +1 -0
  12. package/dist/crypto/keypair.d.ts +39 -0
  13. package/dist/crypto/keypair.js +109 -0
  14. package/dist/crypto/keypair.js.map +1 -0
  15. package/dist/crypto/signature.d.ts +28 -0
  16. package/dist/crypto/signature.js +89 -0
  17. package/dist/crypto/signature.js.map +1 -0
  18. package/dist/crypto/utils.d.ts +28 -0
  19. package/dist/crypto/utils.js +60 -0
  20. package/dist/crypto/utils.js.map +1 -0
  21. package/dist/email.d.ts +63 -0
  22. package/dist/email.js +186 -0
  23. package/dist/email.js.map +1 -0
  24. package/dist/http/api-client.d.ts +145 -0
  25. package/dist/http/api-client.js +242 -0
  26. package/dist/http/api-client.js.map +1 -0
  27. package/dist/inbox.d.ts +120 -0
  28. package/dist/inbox.js +243 -0
  29. package/dist/inbox.js.map +1 -0
  30. package/dist/index.d.ts +14 -0
  31. package/dist/index.js +17 -0
  32. package/dist/index.js.map +1 -0
  33. package/dist/strategies/delivery-strategy.d.ts +29 -0
  34. package/dist/strategies/delivery-strategy.js +2 -0
  35. package/dist/strategies/delivery-strategy.js.map +1 -0
  36. package/dist/strategies/polling-strategy.d.ts +36 -0
  37. package/dist/strategies/polling-strategy.js +146 -0
  38. package/dist/strategies/polling-strategy.js.map +1 -0
  39. package/dist/strategies/sse-strategy.d.ts +49 -0
  40. package/dist/strategies/sse-strategy.js +266 -0
  41. package/dist/strategies/sse-strategy.js.map +1 -0
  42. package/dist/types/index.d.ts +434 -0
  43. package/dist/types/index.js +127 -0
  44. package/dist/types/index.js.map +1 -0
  45. package/dist/utils/email-utils.d.ts +19 -0
  46. package/dist/utils/email-utils.js +92 -0
  47. package/dist/utils/email-utils.js.map +1 -0
  48. package/dist/utils/sleep.d.ts +6 -0
  49. package/dist/utils/sleep.js +9 -0
  50. package/dist/utils/sleep.js.map +1 -0
  51. package/package.json +85 -0
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Centralized cryptographic constants for the VaultSandbox client
3
+ */
4
+ /**
5
+ * HKDF context string used for key derivation
6
+ * This context ensures that derived keys are bound to this specific application and version
7
+ */
8
+ export declare const HKDF_CONTEXT = "vaultsandbox:email:v1";
9
+ /**
10
+ * ML-DSA-65 (Dilithium3) public key size in bytes
11
+ * This is the standard size for ML-DSA-65 public keys
12
+ */
13
+ export declare const MLDSA65_PUBLIC_KEY_SIZE = 1952;
@@ -0,0 +1,14 @@
1
+ /**
2
+ * Centralized cryptographic constants for the VaultSandbox client
3
+ */
4
+ /**
5
+ * HKDF context string used for key derivation
6
+ * This context ensures that derived keys are bound to this specific application and version
7
+ */
8
+ export const HKDF_CONTEXT = 'vaultsandbox:email:v1';
9
+ /**
10
+ * ML-DSA-65 (Dilithium3) public key size in bytes
11
+ * This is the standard size for ML-DSA-65 public keys
12
+ */
13
+ export const MLDSA65_PUBLIC_KEY_SIZE = 1952;
14
+ //# sourceMappingURL=constants.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"constants.js","sourceRoot":"","sources":["../../src/crypto/constants.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH;;;GAGG;AACH,MAAM,CAAC,MAAM,YAAY,GAAG,uBAAuB,CAAC;AAEpD;;;GAGG;AACH,MAAM,CAAC,MAAM,uBAAuB,GAAG,IAAI,CAAC"}
@@ -0,0 +1,41 @@
1
+ /**
2
+ * Email decryption using ML-KEM-768 + AES-256-GCM with HKDF-SHA-512
3
+ * Based on working reference implementation
4
+ */
5
+ import type { Keypair, EncryptedData } from '../types/index.js';
6
+ /**
7
+ * Decrypts an encrypted payload using the complete reference implementation flow
8
+ *
9
+ * @param encryptedData - The encrypted data from the server
10
+ * @param keypair - The recipient's keypair
11
+ * @returns The decrypted plaintext as a Uint8Array
12
+ * @throws DecryptionError if decryption fails
13
+ */
14
+ export declare function decrypt(encryptedData: EncryptedData, keypair: Keypair): Promise<Uint8Array>;
15
+ /**
16
+ * Decrypts and parses email metadata
17
+ *
18
+ * @param encryptedData - The encrypted metadata
19
+ * @param keypair - The recipient's keypair
20
+ * @returns The decrypted metadata as a parsed JSON object
21
+ * @throws DecryptionError if decryption or parsing fails
22
+ */
23
+ export declare function decryptMetadata<T = unknown>(encryptedData: EncryptedData, keypair: Keypair): Promise<T>;
24
+ /**
25
+ * Decrypts and parses email body (parsed content)
26
+ *
27
+ * @param encryptedData - The encrypted parsed content
28
+ * @param keypair - The recipient's keypair
29
+ * @returns The decrypted parsed content as a JSON object
30
+ * @throws DecryptionError if decryption or parsing fails
31
+ */
32
+ export declare function decryptParsed<T = unknown>(encryptedData: EncryptedData, keypair: Keypair): Promise<T>;
33
+ /**
34
+ * Decrypts raw email source
35
+ *
36
+ * @param encryptedData - The encrypted raw email
37
+ * @param keypair - The recipient's keypair
38
+ * @returns The decrypted raw email as a string
39
+ * @throws DecryptionError if decryption fails
40
+ */
41
+ export declare function decryptRaw(encryptedData: EncryptedData, keypair: Keypair): Promise<string>;
@@ -0,0 +1,112 @@
1
+ /**
2
+ * Email decryption using ML-KEM-768 + AES-256-GCM with HKDF-SHA-512
3
+ * Based on working reference implementation
4
+ */
5
+ import { ml_kem768 } from '@noble/post-quantum/ml-kem.js';
6
+ import { fromBase64Url, ensureOwnBuffer, fromBase64 } from './utils.js';
7
+ import { DecryptionError, SignatureVerificationError } from '../types/index.js';
8
+ import { verifySignature } from './signature.js';
9
+ import { deriveKey } from './keypair.js';
10
+ import { HKDF_CONTEXT } from './constants.js';
11
+ /**
12
+ * Decrypts an encrypted payload using the complete reference implementation flow
13
+ *
14
+ * @param encryptedData - The encrypted data from the server
15
+ * @param keypair - The recipient's keypair
16
+ * @returns The decrypted plaintext as a Uint8Array
17
+ * @throws DecryptionError if decryption fails
18
+ */
19
+ export async function decrypt(encryptedData, keypair) {
20
+ try {
21
+ // 0. SECURITY: Verify signature BEFORE decryption (prevent tampering)
22
+ verifySignature(encryptedData);
23
+ // 1. Decode all components
24
+ const ctKem = fromBase64Url(encryptedData.ct_kem);
25
+ const nonceBytes = fromBase64Url(encryptedData.nonce);
26
+ const aadBytes = fromBase64Url(encryptedData.aad);
27
+ const ciphertextBytes = fromBase64Url(encryptedData.ciphertext);
28
+ // 2. KEM Decapsulation to get shared secret
29
+ const sharedSecret = ml_kem768.decapsulate(ctKem, ensureOwnBuffer(keypair.secretKey));
30
+ // 3. Derive AES-256 key using HKDF-SHA-512
31
+ const aesKey = await deriveKey(sharedSecret, HKDF_CONTEXT, aadBytes, ctKem);
32
+ // 4. Decrypt with AES-256-GCM
33
+ // Ensure all buffers are properly aligned
34
+ const aesKeyClean = ensureOwnBuffer(aesKey);
35
+ const nonceClean = ensureOwnBuffer(nonceBytes);
36
+ const aadClean = ensureOwnBuffer(aadBytes);
37
+ const ciphertextClean = ensureOwnBuffer(ciphertextBytes);
38
+ // TypeScript doesn't recognize Uint8Array as BufferSource, but WebCrypto API accepts it
39
+ // The cast is safe because Uint8Array implements ArrayBufferView which extends BufferSource
40
+ const cryptoKey = await crypto.subtle.importKey('raw', aesKeyClean, { name: 'AES-GCM' }, false, ['decrypt']);
41
+ // TypeScript doesn't recognize Uint8Array as BufferSource, but WebCrypto API accepts it
42
+ // The cast is safe because Uint8Array implements ArrayBufferView which extends BufferSource
43
+ const plaintext = await crypto.subtle.decrypt({
44
+ name: 'AES-GCM',
45
+ iv: nonceClean,
46
+ additionalData: aadClean,
47
+ tagLength: 128, // 16 bytes
48
+ }, cryptoKey, ciphertextClean);
49
+ return new Uint8Array(plaintext);
50
+ }
51
+ catch (error) {
52
+ // Re-throw signature verification errors as-is (critical security failures)
53
+ if (error instanceof SignatureVerificationError) {
54
+ throw error;
55
+ }
56
+ if (error instanceof DecryptionError) {
57
+ throw error;
58
+ }
59
+ throw new DecryptionError(`Decryption failed: ${error instanceof Error ? error.message : String(error)}`);
60
+ }
61
+ }
62
+ /**
63
+ * Decrypts and parses email metadata
64
+ *
65
+ * @param encryptedData - The encrypted metadata
66
+ * @param keypair - The recipient's keypair
67
+ * @returns The decrypted metadata as a parsed JSON object
68
+ * @throws DecryptionError if decryption or parsing fails
69
+ */
70
+ export async function decryptMetadata(encryptedData, keypair) {
71
+ const plaintext = await decrypt(encryptedData, keypair);
72
+ try {
73
+ const jsonString = new TextDecoder().decode(plaintext);
74
+ return JSON.parse(jsonString);
75
+ }
76
+ catch (error) {
77
+ throw new DecryptionError(`Failed to parse decrypted metadata: ${error instanceof Error ? error.message : String(error)}`);
78
+ }
79
+ }
80
+ /**
81
+ * Decrypts and parses email body (parsed content)
82
+ *
83
+ * @param encryptedData - The encrypted parsed content
84
+ * @param keypair - The recipient's keypair
85
+ * @returns The decrypted parsed content as a JSON object
86
+ * @throws DecryptionError if decryption or parsing fails
87
+ */
88
+ export async function decryptParsed(encryptedData, keypair) {
89
+ return decryptMetadata(encryptedData, keypair);
90
+ }
91
+ /**
92
+ * Decrypts raw email source
93
+ *
94
+ * @param encryptedData - The encrypted raw email
95
+ * @param keypair - The recipient's keypair
96
+ * @returns The decrypted raw email as a string
97
+ * @throws DecryptionError if decryption fails
98
+ */
99
+ export async function decryptRaw(encryptedData, keypair) {
100
+ const plaintext = await decrypt(encryptedData, keypair);
101
+ try {
102
+ // Decrypted content is a base64-encoded string
103
+ const base64String = new TextDecoder().decode(plaintext);
104
+ // Decode the base64 to get the actual raw email content
105
+ const rawEmailBytes = fromBase64(base64String);
106
+ return new TextDecoder().decode(rawEmailBytes);
107
+ }
108
+ catch (error) {
109
+ throw new DecryptionError(`Failed to decode decrypted raw email: ${error instanceof Error ? error.message : String(error)}`);
110
+ }
111
+ }
112
+ //# sourceMappingURL=decrypt.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"decrypt.js","sourceRoot":"","sources":["../../src/crypto/decrypt.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,39 @@
1
+ /**
2
+ * ML-KEM-768 (Kyber768) keypair generation
3
+ */
4
+ import type { Keypair } from '../types/index.js';
5
+ /**
6
+ * ML-KEM-768 public key size in bytes
7
+ */
8
+ export declare const PUBLIC_KEY_SIZE = 1184;
9
+ /**
10
+ * ML-KEM-768 secret key size in bytes
11
+ */
12
+ export declare const SECRET_KEY_SIZE = 2400;
13
+ /**
14
+ * Generates a new ML-KEM-768 keypair for inbox encryption
15
+ * Uses internal randomness - no seed required
16
+ *
17
+ * @returns A keypair containing public key, secret key, and base64url-encoded public key
18
+ */
19
+ export declare function generateKeypair(): Keypair;
20
+ /**
21
+ * Validates that a keypair has the correct structure and sizes
22
+ *
23
+ * @param keypair - The keypair to validate
24
+ * @returns True if valid, false otherwise
25
+ */
26
+ export declare function validateKeypair(keypair: Keypair): boolean;
27
+ /**
28
+ * Derive AES-256 key using WebCrypto's native HKDF-SHA-512
29
+ * Matches the reference implementation exactly
30
+ */
31
+ export declare function deriveKey(ikm: Uint8Array, context: string, aad: Uint8Array, ctKem: Uint8Array): Promise<Uint8Array>;
32
+ /**
33
+ * Derives a public key from a secret key in ML-KEM (Kyber)
34
+ * In ML-KEM, the public key is embedded in the secret key
35
+ *
36
+ * @param secretKey - The secret key bytes
37
+ * @returns The derived public key bytes
38
+ */
39
+ export declare function derivePublicKeyFromSecret(secretKey: Uint8Array): Uint8Array;
@@ -0,0 +1,109 @@
1
+ /**
2
+ * ML-KEM-768 (Kyber768) keypair generation
3
+ */
4
+ import { ml_kem768 } from '@noble/post-quantum/ml-kem.js';
5
+ import { toBase64Url, fromBase64Url, ensureOwnBuffer, concatBuffers } from './utils.js';
6
+ import { DecryptionError } from '../types/index.js';
7
+ /**
8
+ * ML-KEM-768 public key size in bytes
9
+ */
10
+ export const PUBLIC_KEY_SIZE = 1184;
11
+ /**
12
+ * ML-KEM-768 secret key size in bytes
13
+ */
14
+ export const SECRET_KEY_SIZE = 2400;
15
+ /**
16
+ * Generates a new ML-KEM-768 keypair for inbox encryption
17
+ * Uses internal randomness - no seed required
18
+ *
19
+ * @returns A keypair containing public key, secret key, and base64url-encoded public key
20
+ */
21
+ export function generateKeypair() {
22
+ const keypair = ml_kem768.keygen();
23
+ return {
24
+ publicKey: keypair.publicKey,
25
+ secretKey: keypair.secretKey,
26
+ publicKeyB64: toBase64Url(keypair.publicKey),
27
+ };
28
+ }
29
+ /**
30
+ * Validates that a keypair has the correct structure and sizes
31
+ *
32
+ * @param keypair - The keypair to validate
33
+ * @returns True if valid, false otherwise
34
+ */
35
+ export function validateKeypair(keypair) {
36
+ if (!keypair.publicKey || !keypair.secretKey || !keypair.publicKeyB64) {
37
+ return false;
38
+ }
39
+ if (keypair.publicKey.length !== PUBLIC_KEY_SIZE) {
40
+ return false;
41
+ }
42
+ if (keypair.secretKey.length !== SECRET_KEY_SIZE) {
43
+ return false;
44
+ }
45
+ // Verify base64url encoding matches public key bytes
46
+ try {
47
+ const decodedPublicKey = fromBase64Url(keypair.publicKeyB64);
48
+ if (decodedPublicKey.length !== keypair.publicKey.length) {
49
+ return false;
50
+ }
51
+ for (let i = 0; i < decodedPublicKey.length; i++) {
52
+ if (decodedPublicKey[i] !== keypair.publicKey[i]) {
53
+ return false;
54
+ }
55
+ }
56
+ }
57
+ catch {
58
+ return false;
59
+ }
60
+ return true;
61
+ }
62
+ /**
63
+ * Derive AES-256 key using WebCrypto's native HKDF-SHA-512
64
+ * Matches the reference implementation exactly
65
+ */
66
+ export async function deriveKey(ikm, context, aad, ctKem) {
67
+ const contextBytes = new TextEncoder().encode(context);
68
+ // Hash KEM ciphertext for salt
69
+ const saltBuffer = await crypto.subtle.digest('SHA-256', ctKem);
70
+ const salt = new Uint8Array(saltBuffer);
71
+ // Add aad_length prefix (4 bytes, big-endian)
72
+ const aadLength = new Uint8Array(4);
73
+ new DataView(aadLength.buffer).setUint32(0, aad.length, false);
74
+ const info = concatBuffers(contextBytes, aadLength, aad);
75
+ // Ensure buffers are owned (not views)
76
+ const ikmClean = ensureOwnBuffer(ikm);
77
+ const saltClean = ensureOwnBuffer(salt);
78
+ const infoClean = ensureOwnBuffer(info);
79
+ // Use WebCrypto's native HKDF with SHA-256(ctKem) salt
80
+ // TypeScript doesn't recognize Uint8Array as BufferSource, but WebCrypto API accepts it
81
+ // The cast is safe because Uint8Array implements ArrayBufferView which extends BufferSource
82
+ const baseKey = await crypto.subtle.importKey('raw', ikmClean, 'HKDF', false, [
83
+ 'deriveBits',
84
+ ]);
85
+ const derivedBits = await crypto.subtle.deriveBits({
86
+ name: 'HKDF',
87
+ hash: 'SHA-512',
88
+ salt: saltClean,
89
+ // TypeScript doesn't recognize Uint8Array as BufferSource, but WebCrypto API accepts it
90
+ // The cast is safe because Uint8Array implements ArrayBufferView which extends BufferSource
91
+ info: infoClean,
92
+ }, baseKey, 256);
93
+ return ensureOwnBuffer(new Uint8Array(derivedBits));
94
+ }
95
+ /**
96
+ * Derives a public key from a secret key in ML-KEM (Kyber)
97
+ * In ML-KEM, the public key is embedded in the secret key
98
+ *
99
+ * @param secretKey - The secret key bytes
100
+ * @returns The derived public key bytes
101
+ */
102
+ export function derivePublicKeyFromSecret(secretKey) {
103
+ if (secretKey.length !== SECRET_KEY_SIZE) {
104
+ throw new DecryptionError(`Cannot derive public key: secret key has invalid length ${secretKey.length}, expected ${SECRET_KEY_SIZE}`);
105
+ }
106
+ // In ML-KEM, the public key is appended to the secret key
107
+ return secretKey.slice(secretKey.length - PUBLIC_KEY_SIZE);
108
+ }
109
+ //# sourceMappingURL=keypair.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"keypair.js","sourceRoot":"","sources":["../../src/crypto/keypair.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,28 @@
1
+ /**
2
+ * ML-DSA-65 (Dilithium3) signature verification
3
+ * Based on working reference implementation
4
+ */
5
+ import type { EncryptedData } from '../types/index.js';
6
+ /**
7
+ * Verifies an ML-DSA-65 signature on encrypted data
8
+ * IMPORTANT: Must be called BEFORE decryption for security
9
+ *
10
+ * @param encryptedData - The encrypted data with signature
11
+ * @returns True if signature is valid
12
+ * @throws SignatureVerificationError if verification fails
13
+ */
14
+ export declare function verifySignature(encryptedData: EncryptedData): boolean;
15
+ /**
16
+ * Verifies a signature without throwing an error
17
+ *
18
+ * @param encryptedData - The encrypted data with signature
19
+ * @returns True if signature is valid, false otherwise
20
+ */
21
+ export declare function verifySignatureSafe(encryptedData: EncryptedData): boolean;
22
+ /**
23
+ * Validates that a server public key has the correct format and size
24
+ *
25
+ * @param serverPublicKey - The server's public key (base64url)
26
+ * @returns True if valid, false otherwise
27
+ */
28
+ export declare function validateServerPublicKey(serverPublicKey: string): boolean;
@@ -0,0 +1,89 @@
1
+ /**
2
+ * ML-DSA-65 (Dilithium3) signature verification
3
+ * Based on working reference implementation
4
+ */
5
+ import { ml_dsa65 } from '@noble/post-quantum/ml-dsa.js';
6
+ import { fromBase64Url, ensureOwnBuffer, concatBuffers } from './utils.js';
7
+ import { SignatureVerificationError } from '../types/index.js';
8
+ import { HKDF_CONTEXT, MLDSA65_PUBLIC_KEY_SIZE } from './constants.js';
9
+ /**
10
+ * Builds the algorithm ciphersuite string from algs object
11
+ */
12
+ function buildAlgsCiphersuite(algs) {
13
+ return `${algs.kem}:${algs.sig}:${algs.aead}:${algs.kdf}`;
14
+ }
15
+ /**
16
+ * Build transcript for signature verification
17
+ * This matches the server-side transcript construction exactly
18
+ */
19
+ function buildTranscript(version, algsCiphersuite, ctKem, nonce, aad, ciphertext, serverSigPk, context) {
20
+ const versionBytes = new Uint8Array([version]);
21
+ const algsBytes = new TextEncoder().encode(algsCiphersuite);
22
+ const contextBytes = new TextEncoder().encode(context);
23
+ return concatBuffers(versionBytes, algsBytes, contextBytes, ctKem, nonce, aad, ciphertext, serverSigPk);
24
+ }
25
+ /**
26
+ * Verifies an ML-DSA-65 signature on encrypted data
27
+ * IMPORTANT: Must be called BEFORE decryption for security
28
+ *
29
+ * @param encryptedData - The encrypted data with signature
30
+ * @returns True if signature is valid
31
+ * @throws SignatureVerificationError if verification fails
32
+ */
33
+ export function verifySignature(encryptedData) {
34
+ try {
35
+ // 1. Decode all components
36
+ const signature = fromBase64Url(encryptedData.sig);
37
+ const ctKem = fromBase64Url(encryptedData.ct_kem);
38
+ const nonceBytes = fromBase64Url(encryptedData.nonce);
39
+ const aadBytes = fromBase64Url(encryptedData.aad);
40
+ const ciphertextBytes = fromBase64Url(encryptedData.ciphertext);
41
+ const serverSigPk = fromBase64Url(encryptedData.server_sig_pk);
42
+ // 2. Build the transcript (exactly as the server did)
43
+ const algsCiphersuite = buildAlgsCiphersuite(encryptedData.algs);
44
+ const transcript = buildTranscript(encryptedData.v, algsCiphersuite, ctKem, nonceBytes, aadBytes, ciphertextBytes, serverSigPk, HKDF_CONTEXT);
45
+ // 3. Verify the signature
46
+ // Noble's ML-DSA verify signature order: (signature, message, publicKey)
47
+ const isValid = ml_dsa65.verify(ensureOwnBuffer(signature), ensureOwnBuffer(transcript), ensureOwnBuffer(serverSigPk));
48
+ if (!isValid) {
49
+ throw new SignatureVerificationError('SIGNATURE VERIFICATION FAILED - Data may be tampered!');
50
+ }
51
+ return true;
52
+ }
53
+ catch (error) {
54
+ if (error instanceof SignatureVerificationError) {
55
+ throw error;
56
+ }
57
+ throw new SignatureVerificationError(`Signature verification error: ${error instanceof Error ? error.message : String(error)}`);
58
+ }
59
+ }
60
+ /**
61
+ * Verifies a signature without throwing an error
62
+ *
63
+ * @param encryptedData - The encrypted data with signature
64
+ * @returns True if signature is valid, false otherwise
65
+ */
66
+ export function verifySignatureSafe(encryptedData) {
67
+ try {
68
+ return verifySignature(encryptedData);
69
+ }
70
+ catch {
71
+ return false;
72
+ }
73
+ }
74
+ /**
75
+ * Validates that a server public key has the correct format and size
76
+ *
77
+ * @param serverPublicKey - The server's public key (base64url)
78
+ * @returns True if valid, false otherwise
79
+ */
80
+ export function validateServerPublicKey(serverPublicKey) {
81
+ try {
82
+ const publicKey = fromBase64Url(serverPublicKey);
83
+ return publicKey.length === MLDSA65_PUBLIC_KEY_SIZE;
84
+ }
85
+ catch {
86
+ return false;
87
+ }
88
+ }
89
+ //# sourceMappingURL=signature.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"signature.js","sourceRoot":"","sources":["../../src/crypto/signature.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,28 @@
1
+ /**
2
+ * Crypto utilities for base64url encoding/decoding and buffer operations
3
+ */
4
+ /**
5
+ * Converts a Uint8Array to a base64url-encoded string (no padding)
6
+ */
7
+ export declare function toBase64Url(buffer: Uint8Array): string;
8
+ /**
9
+ * Converts a base64url-encoded string to a Uint8Array
10
+ */
11
+ export declare function fromBase64Url(base64url: string): Uint8Array;
12
+ /**
13
+ * Ensures a buffer is owned (not a view) for WebCrypto compatibility.
14
+ * WebCrypto operations require buffers to be properly aligned and owned.
15
+ */
16
+ export declare function ensureOwnBuffer(buffer: Uint8Array): Uint8Array;
17
+ /**
18
+ * Concatenates multiple Uint8Arrays into a single Uint8Array
19
+ */
20
+ export declare function concatBuffers(...buffers: Uint8Array[]): Uint8Array;
21
+ /**
22
+ * Converts a Uint8Array to a standard base64-encoded string
23
+ */
24
+ export declare function toBase64(buffer: Uint8Array): string;
25
+ /**
26
+ * Converts a standard base64-encoded string to a Uint8Array
27
+ */
28
+ export declare function fromBase64(base64: string): Uint8Array;
@@ -0,0 +1,60 @@
1
+ /**
2
+ * Crypto utilities for base64url encoding/decoding and buffer operations
3
+ */
4
+ /**
5
+ * Converts a Uint8Array to a base64url-encoded string (no padding)
6
+ */
7
+ export function toBase64Url(buffer) {
8
+ const base64 = Buffer.from(buffer).toString('base64');
9
+ return base64.replace(/\+/g, '-').replace(/\//g, '_').replace(/=/g, '');
10
+ }
11
+ /**
12
+ * Converts a base64url-encoded string to a Uint8Array
13
+ */
14
+ export function fromBase64Url(base64url) {
15
+ // Add padding if needed
16
+ let base64 = base64url.replace(/-/g, '+').replace(/_/g, '/');
17
+ const pad = base64.length % 4;
18
+ if (pad) {
19
+ base64 += '='.repeat(4 - pad);
20
+ }
21
+ return new Uint8Array(Buffer.from(base64, 'base64'));
22
+ }
23
+ /**
24
+ * Ensures a buffer is owned (not a view) for WebCrypto compatibility.
25
+ * WebCrypto operations require buffers to be properly aligned and owned.
26
+ */
27
+ export function ensureOwnBuffer(buffer) {
28
+ // Check if buffer is a view of another buffer
29
+ if (buffer.byteOffset !== 0 || buffer.byteLength !== buffer.buffer.byteLength) {
30
+ // Create a new buffer with copied data
31
+ return new Uint8Array(buffer);
32
+ }
33
+ return buffer;
34
+ }
35
+ /**
36
+ * Concatenates multiple Uint8Arrays into a single Uint8Array
37
+ */
38
+ export function concatBuffers(...buffers) {
39
+ const totalLength = buffers.reduce((sum, buf) => sum + buf.length, 0);
40
+ const result = new Uint8Array(totalLength);
41
+ let offset = 0;
42
+ for (const buf of buffers) {
43
+ result.set(buf, offset);
44
+ offset += buf.length;
45
+ }
46
+ return result;
47
+ }
48
+ /**
49
+ * Converts a Uint8Array to a standard base64-encoded string
50
+ */
51
+ export function toBase64(buffer) {
52
+ return Buffer.from(buffer).toString('base64');
53
+ }
54
+ /**
55
+ * Converts a standard base64-encoded string to a Uint8Array
56
+ */
57
+ export function fromBase64(base64) {
58
+ return new Uint8Array(Buffer.from(base64, 'base64'));
59
+ }
60
+ //# sourceMappingURL=utils.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"utils.js","sourceRoot":"","sources":["../../src/crypto/utils.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH;;GAEG;AACH,MAAM,UAAU,WAAW,CAAC,MAAkB;IAC5C,MAAM,MAAM,GAAG,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;IACtD,OAAO,MAAM,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;AAC1E,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,aAAa,CAAC,SAAiB;IAC7C,wBAAwB;IACxB,IAAI,MAAM,GAAG,SAAS,CAAC,OAAO,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC;IAC7D,MAAM,GAAG,GAAG,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC;IAC9B,IAAI,GAAG,EAAE,CAAC;QACR,MAAM,IAAI,GAAG,CAAC,MAAM,CAAC,CAAC,GAAG,GAAG,CAAC,CAAC;IAChC,CAAC;IACD,OAAO,IAAI,UAAU,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC,CAAC;AACvD,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,eAAe,CAAC,MAAkB;IAChD,8CAA8C;IAC9C,IAAI,MAAM,CAAC,UAAU,KAAK,CAAC,IAAI,MAAM,CAAC,UAAU,KAAK,MAAM,CAAC,MAAM,CAAC,UAAU,EAAE,CAAC;QAC9E,uCAAuC;QACvC,OAAO,IAAI,UAAU,CAAC,MAAM,CAAC,CAAC;IAChC,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,aAAa,CAAC,GAAG,OAAqB;IACpD,MAAM,WAAW,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE,CAAC,GAAG,GAAG,GAAG,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC;IACtE,MAAM,MAAM,GAAG,IAAI,UAAU,CAAC,WAAW,CAAC,CAAC;IAC3C,IAAI,MAAM,GAAG,CAAC,CAAC;IACf,KAAK,MAAM,GAAG,IAAI,OAAO,EAAE,CAAC;QAC1B,MAAM,CAAC,GAAG,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC;QACxB,MAAM,IAAI,GAAG,CAAC,MAAM,CAAC;IACvB,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,QAAQ,CAAC,MAAkB;IACzC,OAAO,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;AAChD,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,UAAU,CAAC,MAAc;IACvC,OAAO,IAAI,UAAU,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC,CAAC;AACvD,CAAC"}
@@ -0,0 +1,63 @@
1
+ /**
2
+ * Email model - represents a decrypted email with convenient accessors
3
+ */
4
+ import type { IEmail, EmailData, DecryptedMetadata, DecryptedParsed, AttachmentData, AuthResults as IAuthResults, RawEmail, Keypair } from './types/index.js';
5
+ import type { ApiClient } from './http/api-client.js';
6
+ /**
7
+ * Represents a fully decrypted email, providing access to its content,
8
+ * attachments, and metadata.
9
+ */
10
+ export declare class Email implements IEmail {
11
+ /** The unique identifier for the email. */
12
+ readonly id: string;
13
+ /** The sender's email address. */
14
+ readonly from: string;
15
+ /** An array of recipient email addresses. */
16
+ readonly to: string[];
17
+ /** The subject of the email. */
18
+ readonly subject: string;
19
+ /** The date and time the email was received. */
20
+ readonly receivedAt: Date;
21
+ /** A boolean indicating whether the email has been read. */
22
+ readonly isRead: boolean;
23
+ /** The plain text content of the email, or `null` if not available. */
24
+ readonly text: string | null;
25
+ /** The HTML content of the email, or `null` if not available. */
26
+ readonly html: string | null;
27
+ /** An array of attachments found in the email. */
28
+ readonly attachments: AttachmentData[];
29
+ /** An array of URLs extracted from the email's content. */
30
+ readonly links: string[];
31
+ /** An object containing the email's headers. */
32
+ readonly headers: Record<string, unknown>;
33
+ /** The email's authentication results (SPF, DKIM, DMARC). */
34
+ readonly authResults: IAuthResults;
35
+ /** Any other metadata associated with the email. */
36
+ readonly metadata: Record<string, unknown>;
37
+ private emailAddress;
38
+ private apiClient;
39
+ private keypair;
40
+ /**
41
+ * @internal
42
+ * Do not construct this class directly.
43
+ */
44
+ constructor(emailData: EmailData, metadata: DecryptedMetadata, parsed: DecryptedParsed | null, emailAddress: string, apiClient: ApiClient, keypair: Keypair);
45
+ /**
46
+ * Marks this email as read.
47
+ *
48
+ * @returns A promise that resolves when the email is marked as read.
49
+ */
50
+ markAsRead(): Promise<void>;
51
+ /**
52
+ * Deletes this email from the inbox.
53
+ *
54
+ * @returns A promise that resolves when the email is deleted.
55
+ */
56
+ delete(): Promise<void>;
57
+ /**
58
+ * Fetches the raw, decrypted source of the email.
59
+ *
60
+ * @returns A promise that resolves to the raw email data.
61
+ */
62
+ getRaw(): Promise<RawEmail>;
63
+ }