@storacha/encrypt-upload-client 1.1.80 → 1.1.82

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 (64) hide show
  1. package/dist/crypto/adapters/kms-crypto-adapter.d.ts +4 -10
  2. package/dist/crypto/adapters/kms-crypto-adapter.d.ts.map +1 -1
  3. package/dist/crypto/adapters/kms-crypto-adapter.js +4 -4
  4. package/dist/examples/decrypt-test.d.ts +2 -0
  5. package/dist/examples/decrypt-test.d.ts.map +1 -0
  6. package/dist/examples/decrypt-test.js +102 -0
  7. package/dist/examples/encrypt-test.d.ts +2 -0
  8. package/dist/examples/encrypt-test.d.ts.map +1 -0
  9. package/dist/examples/encrypt-test.js +93 -0
  10. package/dist/test/cid-verification.spec.d.ts +2 -0
  11. package/dist/test/cid-verification.spec.d.ts.map +1 -0
  12. package/dist/test/cid-verification.spec.js +314 -0
  13. package/dist/test/crypto-compatibility.spec.d.ts +2 -0
  14. package/dist/test/crypto-compatibility.spec.d.ts.map +1 -0
  15. package/dist/test/crypto-compatibility.spec.js +124 -0
  16. package/dist/test/crypto-counter-security.spec.d.ts +2 -0
  17. package/dist/test/crypto-counter-security.spec.d.ts.map +1 -0
  18. package/dist/test/crypto-counter-security.spec.js +147 -0
  19. package/dist/test/crypto-streaming.spec.d.ts +2 -0
  20. package/dist/test/crypto-streaming.spec.d.ts.map +1 -0
  21. package/dist/test/crypto-streaming.spec.js +129 -0
  22. package/dist/test/encrypted-metadata.spec.d.ts +2 -0
  23. package/dist/test/encrypted-metadata.spec.d.ts.map +1 -0
  24. package/dist/test/encrypted-metadata.spec.js +68 -0
  25. package/dist/test/factories.spec.d.ts +2 -0
  26. package/dist/test/factories.spec.d.ts.map +1 -0
  27. package/dist/test/factories.spec.js +129 -0
  28. package/dist/test/file-metadata.spec.d.ts +2 -0
  29. package/dist/test/file-metadata.spec.d.ts.map +1 -0
  30. package/dist/test/file-metadata.spec.js +433 -0
  31. package/dist/test/fixtures/test-fixtures.d.ts +28 -0
  32. package/dist/test/fixtures/test-fixtures.d.ts.map +1 -0
  33. package/dist/test/fixtures/test-fixtures.js +63 -0
  34. package/dist/test/helpers/test-file-utils.d.ts +60 -0
  35. package/dist/test/helpers/test-file-utils.d.ts.map +1 -0
  36. package/dist/test/helpers/test-file-utils.js +139 -0
  37. package/dist/test/https-enforcement.spec.d.ts +2 -0
  38. package/dist/test/https-enforcement.spec.d.ts.map +1 -0
  39. package/dist/test/https-enforcement.spec.js +125 -0
  40. package/dist/test/kms-crypto-adapter.spec.d.ts +2 -0
  41. package/dist/test/kms-crypto-adapter.spec.d.ts.map +1 -0
  42. package/dist/test/kms-crypto-adapter.spec.js +305 -0
  43. package/dist/test/lit-crypto-adapter.spec.d.ts +2 -0
  44. package/dist/test/lit-crypto-adapter.spec.d.ts.map +1 -0
  45. package/dist/test/lit-crypto-adapter.spec.js +76 -0
  46. package/dist/test/memory-efficiency.spec.d.ts +2 -0
  47. package/dist/test/memory-efficiency.spec.d.ts.map +1 -0
  48. package/dist/test/memory-efficiency.spec.js +93 -0
  49. package/dist/test/mocks/key-manager.d.ts +58 -0
  50. package/dist/test/mocks/key-manager.d.ts.map +1 -0
  51. package/dist/test/mocks/key-manager.js +137 -0
  52. package/dist/test/node-crypto-adapter.spec.d.ts +2 -0
  53. package/dist/test/node-crypto-adapter.spec.d.ts.map +1 -0
  54. package/dist/test/node-crypto-adapter.spec.js +103 -0
  55. package/dist/test/node-generic-crypto-adapter.spec.d.ts +2 -0
  56. package/dist/test/node-generic-crypto-adapter.spec.d.ts.map +1 -0
  57. package/dist/test/node-generic-crypto-adapter.spec.js +95 -0
  58. package/dist/test/setup.d.ts +2 -0
  59. package/dist/test/setup.d.ts.map +1 -0
  60. package/dist/test/setup.js +12 -0
  61. package/dist/tsconfig.spec.tsbuildinfo +1 -0
  62. package/dist/types.d.ts +1 -2
  63. package/dist/types.d.ts.map +1 -1
  64. package/package.json +4 -4
@@ -0,0 +1,76 @@
1
+ import './setup.js';
2
+ import { test, describe } from 'node:test';
3
+ import assert from 'node:assert';
4
+ import { GenericAesCtrStreamingCrypto } from '../src/crypto/symmetric/generic-aes-ctr-streaming-crypto.js';
5
+ import { LitCryptoAdapter } from '../src/crypto/adapters/lit-crypto-adapter.js';
6
+ import { stringToUint8Array, streamToUint8Array, uint8ArrayToString, } from './helpers/test-file-utils.js';
7
+ // Mock Lit client - cast to any for testing
8
+ const mockLitClient = /** @type {any} */ ({
9
+ // Add mock methods as needed
10
+ });
11
+ const mockAuthManager = /** @type {any} */ ({
12
+ // Add mock methods as needed
13
+ });
14
+ await describe('LitCryptoAdapter', async () => {
15
+ await describe('Generic AES-CTR Crypto Implementation', async () => {
16
+ await test('should delegate symmetric crypto operations to the generic implementation', async () => {
17
+ const symmetricCrypto = new GenericAesCtrStreamingCrypto();
18
+ const adapter = new LitCryptoAdapter(symmetricCrypto, mockLitClient, mockAuthManager);
19
+ const originalText = 'Op, this is a test for strategy-based encryption!';
20
+ const blob = new Blob([stringToUint8Array(originalText)]);
21
+ // Test that it delegates to the symmetric crypto implementation
22
+ const { key, iv, encryptedStream } = await adapter.encryptStream(blob);
23
+ assert(key instanceof Uint8Array, 'Key should be a Uint8Array');
24
+ assert(iv instanceof Uint8Array, 'IV should be a Uint8Array');
25
+ assert(encryptedStream instanceof ReadableStream, 'Encrypted stream should be a ReadableStream');
26
+ // Test decryption delegation
27
+ const decryptedStream = await adapter.decryptStream(encryptedStream, key, iv);
28
+ const decryptedBytes = await streamToUint8Array(decryptedStream);
29
+ const decryptedText = uint8ArrayToString(decryptedBytes);
30
+ assert.strictEqual(decryptedText, originalText, 'Decrypted text should match original');
31
+ });
32
+ await test('should initialize Generic Lit adapter with correct configuration', async () => {
33
+ const symmetricCrypto = new GenericAesCtrStreamingCrypto();
34
+ const adapter = new LitCryptoAdapter(symmetricCrypto, mockLitClient, mockAuthManager);
35
+ // Test that the adapter has the required methods
36
+ assert(typeof adapter.encryptSymmetricKey === 'function', 'encryptSymmetricKey should be a function');
37
+ assert(typeof adapter.decryptSymmetricKey === 'function', 'decryptSymmetricKey should be a function');
38
+ // Verify adapter has the lit client
39
+ assert.strictEqual(adapter.litClient, mockLitClient, 'Adapter should store the Lit client');
40
+ // Verify it uses the correct crypto implementation
41
+ assert(adapter.symmetricCrypto instanceof GenericAesCtrStreamingCrypto, 'Should use GenericAesCtrStreamingCrypto');
42
+ });
43
+ });
44
+ await describe('Cross-Implementation Compatibility', async () => {
45
+ await test('should demonstrate algorithm differences between implementations', async () => {
46
+ const genericCrypto = new GenericAesCtrStreamingCrypto();
47
+ const genericAdapter = new LitCryptoAdapter(genericCrypto, mockLitClient, mockAuthManager);
48
+ const originalText = 'Test data for algorithm comparison';
49
+ const blob = new Blob([stringToUint8Array(originalText)]);
50
+ // Encrypt with all adapters
51
+ const genericResult = await genericAdapter.encryptStream(blob);
52
+ // Convert streams to bytes
53
+ const genericEncrypted = await streamToUint8Array(genericResult.encryptedStream);
54
+ // Verify both can decrypt their own data
55
+ const genericDecryptStream = new ReadableStream({
56
+ start(controller) {
57
+ controller.enqueue(genericEncrypted);
58
+ controller.close();
59
+ },
60
+ });
61
+ const genericDecrypted = await genericAdapter.decryptStream(genericDecryptStream, genericResult.key, genericResult.iv);
62
+ const genericDecryptedBytes = await streamToUint8Array(genericDecrypted);
63
+ // Should decrypt to the same original text
64
+ assert.strictEqual(uint8ArrayToString(genericDecryptedBytes), originalText, 'Generic adapter should decrypt correctly');
65
+ console.log('All crypto implementations work with Lit adapter');
66
+ });
67
+ await test('should verify factory function behavior', async () => {
68
+ const { createGenericLitAdapter } = await import('../src/crypto/factories.node.js');
69
+ const genericAdapter = createGenericLitAdapter(mockLitClient, mockAuthManager);
70
+ // Verify factory functions create adapters with correct crypto implementations
71
+ assert(genericAdapter.symmetricCrypto instanceof GenericAesCtrStreamingCrypto, 'Generic factory should create adapter with GenericAesCtrStreamingCrypto');
72
+ console.log('Factory functions create adapters with correct crypto implementations');
73
+ });
74
+ });
75
+ });
76
+ //# sourceMappingURL=lit-crypto-adapter.spec.js.map
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=memory-efficiency.spec.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"memory-efficiency.spec.d.ts","sourceRoot":"","sources":["../../test/memory-efficiency.spec.js"],"names":[],"mappings":""}
@@ -0,0 +1,93 @@
1
+ import './setup.js';
2
+ import { test, describe } from 'node:test';
3
+ import assert from 'node:assert';
4
+ import { GenericAesCtrStreamingCrypto } from '../src/crypto/symmetric/generic-aes-ctr-streaming-crypto.js';
5
+ import { createTestFile } from './helpers/test-file-utils.js';
6
+ /**
7
+ * These tests demonstrate why streaming is necessary for large files.
8
+ * They show that buffered approaches fail with memory errors while streaming succeeds.
9
+ */
10
+ await describe('Memory Efficiency - Why Streaming Matters', async () => {
11
+ await test('should show streaming handles progressively larger files', async () => {
12
+ const streamingCrypto = new GenericAesCtrStreamingCrypto();
13
+ // Test with multiple sizes to show streaming scales linearly
14
+ const testSizes = [5, 10, 15, 20, 50, 100, 500, 1000]; // MB - sizes that would challenge buffered approaches
15
+ for (const sizeMB of testSizes) {
16
+ console.log(`Processing ${sizeMB}MB file...`);
17
+ const testFile = createTestFile(sizeMB);
18
+ const startTime = Date.now();
19
+ const { encryptedStream } = await streamingCrypto.encryptStream(testFile);
20
+ let processedBytes = 0;
21
+ let chunkCount = 0;
22
+ const reader = encryptedStream.getReader();
23
+ try {
24
+ // eslint-disable-next-line no-constant-condition
25
+ while (true) {
26
+ const { done, value } = await reader.read();
27
+ if (done)
28
+ break;
29
+ processedBytes += value.length;
30
+ chunkCount++;
31
+ }
32
+ }
33
+ finally {
34
+ reader.releaseLock();
35
+ }
36
+ const processingTime = Date.now() - startTime;
37
+ const throughput = processedBytes / 1024 / 1024 / (processingTime / 1000); // MB/s
38
+ assert.strictEqual(processedBytes, testFile.size, `Should process entire ${sizeMB}MB file`);
39
+ console.log(`✓ ${sizeMB}MB: ${chunkCount} chunks, ${throughput.toFixed(1)} MB/s`);
40
+ }
41
+ console.log('DEMONSTRATED: Streaming handles large files with consistent performance');
42
+ });
43
+ await test('should project memory behavior for realistic file sizes', async () => {
44
+ const streamingCrypto = new GenericAesCtrStreamingCrypto();
45
+ // Test with a size we can actually handle to project larger files
46
+ const testFile = createTestFile(5); // 5MB
47
+ const getMemoryUsage = () => {
48
+ if (globalThis.gc)
49
+ globalThis.gc();
50
+ return process.memoryUsage ? process.memoryUsage().heapUsed : 0;
51
+ };
52
+ const baseMemory = getMemoryUsage();
53
+ const { encryptedStream } = await streamingCrypto.encryptStream(testFile);
54
+ let peakMemoryDelta = 0;
55
+ let processedBytes = 0;
56
+ const reader = encryptedStream.getReader();
57
+ try {
58
+ // eslint-disable-next-line no-constant-condition
59
+ while (true) {
60
+ const { done, value } = await reader.read();
61
+ if (done)
62
+ break;
63
+ processedBytes += value.length;
64
+ // Sample memory usage
65
+ const currentMemory = getMemoryUsage();
66
+ const memoryDelta = currentMemory - baseMemory;
67
+ peakMemoryDelta = Math.max(peakMemoryDelta, memoryDelta);
68
+ }
69
+ }
70
+ finally {
71
+ reader.releaseLock();
72
+ }
73
+ const peakMemoryMB = peakMemoryDelta / 1024 / 1024;
74
+ const fileSize = testFile.size / 1024 / 1024;
75
+ const memoryEfficiency = (peakMemoryDelta / testFile.size) * 100;
76
+ console.log(`File size: ${fileSize.toFixed(1)}MB`);
77
+ console.log(`Peak memory delta: ${peakMemoryMB.toFixed(2)}MB`);
78
+ console.log(`Memory efficiency: ${memoryEfficiency.toFixed(1)}% of file size`);
79
+ // Project to larger file sizes
80
+ console.log('\nProjected memory usage:');
81
+ const projectedSizes = [100, 1000, 5000]; // MB = 100MB, 1GB, 5GB
82
+ for (const sizeMB of projectedSizes) {
83
+ const projectedMemory = (memoryEfficiency / 100) * sizeMB;
84
+ const sizeLabel = sizeMB >= 1000 ? `${sizeMB / 1000}GB` : `${sizeMB}MB`;
85
+ console.log(` ${sizeLabel}: ~${projectedMemory.toFixed(1)}MB memory`);
86
+ }
87
+ // Memory should be bounded (much less than file size)
88
+ assert(peakMemoryMB < fileSize, 'Streaming should use less memory than file size');
89
+ assert(memoryEfficiency < 50, 'Memory usage should be less than 50% of file size');
90
+ console.log('DEMONSTRATED: Streaming memory usage scales sub-linearly with file size');
91
+ });
92
+ });
93
+ //# sourceMappingURL=memory-efficiency.spec.js.map
@@ -0,0 +1,58 @@
1
+ /**
2
+ * Create mock KMS service with proper capability handlers
3
+ *
4
+ * @param {object} options
5
+ * @param {string} options.mockPublicKey - Mock RSA public key in PEM format
6
+ * @param {string} [options.mockProvider] - Mock KMS provider
7
+ * @param {string} [options.mockAlgorithm] - Mock algorithm
8
+ * @param {Function} [options.onEncryptionSetup] - Optional callback for setup calls
9
+ * @param {Function} [options.onKeyDecrypt] - Optional callback for decrypt calls
10
+ */
11
+ export function createMockKeyManagerService(options: {
12
+ mockPublicKey: string;
13
+ mockProvider?: string | undefined;
14
+ mockAlgorithm?: string | undefined;
15
+ onEncryptionSetup?: Function | undefined;
16
+ onKeyDecrypt?: Function | undefined;
17
+ }): {
18
+ space: {
19
+ encryption: {
20
+ setup: Server.ServiceMethod<Server.API.Capability<"space/encryption/setup", `did:key:${string}` & `did:${string}` & Server.API.Phantom<{
21
+ protocol: "did:";
22
+ }>, Partial<Pick<{
23
+ location: string | undefined;
24
+ keyring: string | undefined;
25
+ }, "location" | "keyring">>>, {
26
+ publicKey: string;
27
+ provider: string;
28
+ algorithm: string;
29
+ }, Server.API.Failure & {
30
+ name: string;
31
+ message: string;
32
+ }>;
33
+ key: {
34
+ decrypt: Server.ServiceMethod<Server.API.Capability<"space/encryption/key/decrypt", `did:key:${string}` & `did:${string}` & Server.API.Phantom<{
35
+ protocol: "did:";
36
+ }>, Pick<{
37
+ key: Uint8Array<ArrayBufferLike>;
38
+ }, "key">>, {
39
+ decryptedSymmetricKey: string;
40
+ }, Server.API.Failure & {
41
+ name: string;
42
+ message: string;
43
+ }>;
44
+ };
45
+ };
46
+ };
47
+ };
48
+ /**
49
+ * Create a mock key manager service server
50
+ *
51
+ * @param {object} service - The service object with capability handlers
52
+ * @param {*} keyManagerServiceDID - The key manager service DID keypair
53
+ * @param {number} port - The port to listen on
54
+ * @param {boolean} [useHttps] - Whether to use HTTPS URLs (testing HTTPS scenarios)
55
+ */
56
+ export function createMockKeyManagerServer(service: object, keyManagerServiceDID: any, port: number, useHttps?: boolean): Promise<any>;
57
+ import * as Server from '@ucanto/server';
58
+ //# sourceMappingURL=key-manager.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"key-manager.d.ts","sourceRoot":"","sources":["../../../test/mocks/key-manager.js"],"names":[],"mappings":"AAMA;;;;;;;;;GASG;AACH,qDANG;IAAwB,aAAa,EAA7B,MAAM;IACW,YAAY;IACZ,aAAa;IACX,iBAAiB;IACjB,YAAY;CACzC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAwEA;AAED;;;;;;;GAOG;AACH,oDALW,MAAM,wBACN,GAAC,QACD,MAAM,aACN,OAAO,gBA6DjB;wBA3JuB,gBAAgB"}
@@ -0,0 +1,137 @@
1
+ import { createServer } from 'node:http';
2
+ import * as Server from '@ucanto/server';
3
+ import { CAR } from '@ucanto/transport';
4
+ import * as Space from '@storacha/capabilities/space';
5
+ import { base64 } from 'multiformats/bases/base64';
6
+ /**
7
+ * Create mock KMS service with proper capability handlers
8
+ *
9
+ * @param {object} options
10
+ * @param {string} options.mockPublicKey - Mock RSA public key in PEM format
11
+ * @param {string} [options.mockProvider] - Mock KMS provider
12
+ * @param {string} [options.mockAlgorithm] - Mock algorithm
13
+ * @param {Function} [options.onEncryptionSetup] - Optional callback for setup calls
14
+ * @param {Function} [options.onKeyDecrypt] - Optional callback for decrypt calls
15
+ */
16
+ export function createMockKeyManagerService(options) {
17
+ const { mockPublicKey, mockProvider = 'google-kms', mockAlgorithm = 'RSA-OAEP-2048-SHA256', onEncryptionSetup, onKeyDecrypt, } = options;
18
+ return {
19
+ space: {
20
+ encryption: {
21
+ setup: Server.provide(Space.EncryptionSetup, async (input) => {
22
+ // Call optional callback for testing
23
+ if (onEncryptionSetup) {
24
+ onEncryptionSetup(input);
25
+ }
26
+ // Validate the space DID format
27
+ if (!input.capability.with.startsWith('did:key:')) {
28
+ return Server.error({
29
+ name: 'InvalidSpace',
30
+ message: 'Space DID must be a did:key',
31
+ });
32
+ }
33
+ // Return mock RSA public key and metadata
34
+ return Server.ok({
35
+ publicKey: mockPublicKey,
36
+ provider: mockProvider,
37
+ algorithm: mockAlgorithm,
38
+ });
39
+ }),
40
+ key: {
41
+ decrypt: Server.provide(Space.EncryptionKeyDecrypt, async (input) => {
42
+ // Call optional callback for testing
43
+ if (onKeyDecrypt) {
44
+ onKeyDecrypt(input);
45
+ }
46
+ // Validate the space DID
47
+ if (!input.capability.with.startsWith('did:key:')) {
48
+ return Server.error({
49
+ name: 'InvalidSpace',
50
+ message: 'Space DID must be a did:key',
51
+ });
52
+ }
53
+ // Validate encrypted key is provided
54
+ if (!input.capability.nb.key) {
55
+ return Server.error({
56
+ name: 'KeyNotFound',
57
+ message: 'key is required',
58
+ });
59
+ }
60
+ // For testing purposes, "decrypt" by converting bytes back to base64 string
61
+ // In real implementation, this would call Google KMS
62
+ const keyBytes = input.capability.nb.key;
63
+ // No base64 decode here, just return the bytes as base64 string for mock
64
+ const mockDecryptedKey = base64.encode(keyBytes);
65
+ return Server.ok({
66
+ decryptedSymmetricKey: mockDecryptedKey,
67
+ });
68
+ }),
69
+ },
70
+ },
71
+ },
72
+ };
73
+ }
74
+ /**
75
+ * Create a mock key manager service server
76
+ *
77
+ * @param {object} service - The service object with capability handlers
78
+ * @param {*} keyManagerServiceDID - The key manager service DID keypair
79
+ * @param {number} port - The port to listen on
80
+ * @param {boolean} [useHttps] - Whether to use HTTPS URLs (testing HTTPS scenarios)
81
+ */
82
+ export function createMockKeyManagerServer(service, keyManagerServiceDID, port, useHttps = false) {
83
+ const ucantoServer = Server.create({
84
+ id: keyManagerServiceDID,
85
+ service,
86
+ codec: CAR.inbound,
87
+ validateAuthorization: () => ({ ok: {} }), // Skip auth validation for tests
88
+ });
89
+ const httpServer = createServer(async (req, res) => {
90
+ res.setHeader('Access-Control-Allow-Origin', '*');
91
+ res.setHeader('Access-Control-Allow-Methods', '*');
92
+ res.setHeader('Access-Control-Allow-Headers', '*');
93
+ if (req.method === 'OPTIONS')
94
+ return res.end();
95
+ if (req.method === 'POST') {
96
+ const bodyBuffer = Buffer.concat(await collect(req));
97
+ const reqHeaders = /** @type {Record<string, string>} */ (Object.fromEntries(Object.entries(req.headers)));
98
+ const { headers, body, status } = await ucantoServer.request({
99
+ body: new Uint8Array(bodyBuffer.buffer, bodyBuffer.byteOffset, bodyBuffer.byteLength),
100
+ headers: reqHeaders,
101
+ });
102
+ for (const [key, value] of Object.entries(headers)) {
103
+ res.setHeader(key, value);
104
+ }
105
+ res.writeHead(status ?? 200);
106
+ res.end(body);
107
+ }
108
+ else {
109
+ res.end();
110
+ }
111
+ });
112
+ return new Promise((resolve, reject) => {
113
+ httpServer.listen(port, (/** @type {Error | undefined} */ err) => {
114
+ if (err) {
115
+ reject(err);
116
+ }
117
+ else {
118
+ const protocol = useHttps ? 'https' : 'http';
119
+ resolve({
120
+ server: httpServer,
121
+ url: `${protocol}://localhost:${port}`,
122
+ close: () => new Promise((resolve) => httpServer.close(resolve)),
123
+ });
124
+ }
125
+ });
126
+ });
127
+ }
128
+ /** @param {import('node:stream').Readable} stream */
129
+ const collect = (stream) => {
130
+ return /** @type {Promise<Buffer[]>} */ (new Promise((resolve, reject) => {
131
+ const chunks = /** @type {Buffer[]} */ ([]);
132
+ stream.on('data', (chunk) => chunks.push(Buffer.from(chunk)));
133
+ stream.on('error', (err) => reject(err));
134
+ stream.on('end', () => resolve(chunks));
135
+ }));
136
+ };
137
+ //# sourceMappingURL=key-manager.js.map
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=node-crypto-adapter.spec.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"node-crypto-adapter.spec.d.ts","sourceRoot":"","sources":["../../test/node-crypto-adapter.spec.js"],"names":[],"mappings":""}
@@ -0,0 +1,103 @@
1
+ import { test, describe } from 'node:test';
2
+ import assert from 'node:assert';
3
+ import { NodeAesCbcCrypto } from '../src/crypto/symmetric/node-aes-cbc-crypto.js';
4
+ import { stringToUint8Array, uint8ArrayToString, streamToUint8Array, createMockBlob, } from './helpers/test-file-utils.js';
5
+ await describe('NodeAesCbcCrypto', async () => {
6
+ await test('should encrypt and decrypt data and return the original data', async () => {
7
+ const adapter = new NodeAesCbcCrypto();
8
+ const originalText = 'Hello, this is a test for Node.js AES-CBC encryption!';
9
+ const mockBlob = createMockBlob(stringToUint8Array(originalText));
10
+ // Encrypt
11
+ const { key, iv, encryptedStream } = await adapter.encryptStream(mockBlob);
12
+ // Decrypt
13
+ const decryptedStream = await adapter.decryptStream(encryptedStream, key, iv);
14
+ const decryptedBytes = await streamToUint8Array(decryptedStream);
15
+ const decryptedText = uint8ArrayToString(decryptedBytes);
16
+ assert.strictEqual(decryptedText, originalText);
17
+ });
18
+ await test('should handle empty data', async () => {
19
+ const adapter = new NodeAesCbcCrypto();
20
+ const mockBlob = createMockBlob(new Uint8Array(0));
21
+ const { key, iv, encryptedStream } = await adapter.encryptStream(mockBlob);
22
+ const decryptedStream = await adapter.decryptStream(encryptedStream, key, iv);
23
+ const decryptedBytes = await streamToUint8Array(decryptedStream);
24
+ assert.strictEqual(decryptedBytes.length, 0);
25
+ });
26
+ await test('should combine key and IV correctly', async () => {
27
+ const adapter = new NodeAesCbcCrypto();
28
+ const key = new Uint8Array(32).fill(3); // 32-byte AES-256 key
29
+ const iv = new Uint8Array(16).fill(6); // 16-byte AES-CBC IV
30
+ const combined = adapter.combineKeyAndIV(key, iv);
31
+ assert.strictEqual(combined.length, 48, 'Combined length should be 48 bytes (32 + 16)');
32
+ // Verify first 32 bytes are the key
33
+ for (let i = 0; i < 32; i++) {
34
+ assert.strictEqual(combined[i], 3, `Key byte ${i} should match`);
35
+ }
36
+ // Verify last 16 bytes are the IV
37
+ for (let i = 32; i < 48; i++) {
38
+ assert.strictEqual(combined[i], 6, `IV byte ${i - 32} should match`);
39
+ }
40
+ });
41
+ await test('should split combined key and IV correctly', async () => {
42
+ const adapter = new NodeAesCbcCrypto();
43
+ const originalKey = new Uint8Array(32).fill(123);
44
+ const originalIV = new Uint8Array(16).fill(234);
45
+ const combined = adapter.combineKeyAndIV(originalKey, originalIV);
46
+ const { key, iv } = adapter.splitKeyAndIV(combined);
47
+ assert.strictEqual(key.length, 32, 'Split key should be 32 bytes');
48
+ assert.strictEqual(iv.length, 16, 'Split IV should be 16 bytes');
49
+ // Verify key matches
50
+ for (let i = 0; i < 32; i++) {
51
+ assert.strictEqual(key[i], originalKey[i], `Key byte ${i} should match original`);
52
+ }
53
+ // Verify IV matches
54
+ for (let i = 0; i < 16; i++) {
55
+ assert.strictEqual(iv[i], originalIV[i], `IV byte ${i} should match original`);
56
+ }
57
+ });
58
+ await test('should roundtrip combine/split correctly', async () => {
59
+ const adapter = new NodeAesCbcCrypto();
60
+ const { randomBytes } = await import('crypto');
61
+ // Convert Buffer to Uint8Array to match the expected types
62
+ const originalKey = new Uint8Array(randomBytes(32));
63
+ const originalIV = new Uint8Array(randomBytes(16));
64
+ const combined = adapter.combineKeyAndIV(originalKey, originalIV);
65
+ const { key, iv } = adapter.splitKeyAndIV(combined);
66
+ assert.deepStrictEqual(key, originalKey, 'Roundtrip key should match original');
67
+ assert.deepStrictEqual(iv, originalIV, 'Roundtrip IV should match original');
68
+ });
69
+ await test('should validate key length in combineKeyAndIV', async () => {
70
+ const adapter = new NodeAesCbcCrypto();
71
+ const wrongKey = new Uint8Array(31); // Wrong size
72
+ const correctIV = new Uint8Array(16);
73
+ assert.throws(() => adapter.combineKeyAndIV(wrongKey, correctIV), {
74
+ name: 'Error',
75
+ message: 'AES-256 key must be 32 bytes, got 31',
76
+ }, 'Should throw error for wrong key size');
77
+ });
78
+ await test('should validate IV length in combineKeyAndIV', async () => {
79
+ const adapter = new NodeAesCbcCrypto();
80
+ const correctKey = new Uint8Array(32);
81
+ const wrongIV = new Uint8Array(15); // Wrong size
82
+ assert.throws(() => adapter.combineKeyAndIV(correctKey, wrongIV), {
83
+ name: 'Error',
84
+ message: 'AES-CBC IV must be 16 bytes, got 15',
85
+ }, 'Should throw error for wrong IV size');
86
+ });
87
+ await test('should validate combined length in splitKeyAndIV', async () => {
88
+ const adapter = new NodeAesCbcCrypto();
89
+ const wrongCombined = new Uint8Array(47); // Wrong size
90
+ assert.throws(() => adapter.splitKeyAndIV(wrongCombined), {
91
+ name: 'Error',
92
+ message: 'AES-256-CBC combined key+IV must be 48 bytes, got 47',
93
+ }, 'Should throw error for wrong combined size');
94
+ });
95
+ await test('should use constants for validation', async () => {
96
+ const adapter = new NodeAesCbcCrypto();
97
+ // Test with different wrong sizes to ensure constants are used
98
+ assert.throws(() => adapter.combineKeyAndIV(new Uint8Array(16), new Uint8Array(16)), /AES-256 key must be 32 bytes, got 16/, 'Should use KEY_LENGTH constant in error message');
99
+ assert.throws(() => adapter.combineKeyAndIV(new Uint8Array(32), new Uint8Array(8)), /AES-CBC IV must be 16 bytes, got 8/, 'Should use IV_LENGTH constant in error message');
100
+ assert.throws(() => adapter.splitKeyAndIV(new Uint8Array(32)), /AES-256-CBC combined key\+IV must be 48 bytes, got 32/, 'Should use calculated expected length in error message');
101
+ });
102
+ });
103
+ //# sourceMappingURL=node-crypto-adapter.spec.js.map
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=node-generic-crypto-adapter.spec.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"node-generic-crypto-adapter.spec.d.ts","sourceRoot":"","sources":["../../test/node-generic-crypto-adapter.spec.js"],"names":[],"mappings":""}
@@ -0,0 +1,95 @@
1
+ import './setup.js';
2
+ import { test, describe } from 'node:test';
3
+ import assert from 'node:assert';
4
+ import { GenericAesCtrStreamingCrypto } from '../src/crypto/symmetric/generic-aes-ctr-streaming-crypto.js';
5
+ import { stringToUint8Array, streamToUint8Array, uint8ArrayToString, } from './helpers/test-file-utils.js';
6
+ await describe('GenericAesCtrStreamingCrypto (Node Environment)', async () => {
7
+ await test('should encrypt and decrypt a Blob and return the original data', async () => {
8
+ const adapter = new GenericAesCtrStreamingCrypto();
9
+ const originalText = 'Op, this is a test for streaming encryption!';
10
+ const blob = new Blob([stringToUint8Array(originalText)]);
11
+ // Encrypt
12
+ const { key, iv, encryptedStream } = await adapter.encryptStream(blob);
13
+ // Decrypt
14
+ const decryptedStream = await adapter.decryptStream(encryptedStream, key, iv);
15
+ const decryptedBytes = await streamToUint8Array(decryptedStream);
16
+ const decryptedText = uint8ArrayToString(decryptedBytes);
17
+ assert.strictEqual(decryptedText, originalText);
18
+ });
19
+ await test('should handle empty data', async () => {
20
+ const adapter = new GenericAesCtrStreamingCrypto();
21
+ const blob = new Blob([]);
22
+ const { key, iv, encryptedStream } = await adapter.encryptStream(blob);
23
+ const decryptedStream = await adapter.decryptStream(encryptedStream, key, iv);
24
+ const decryptedBytes = await streamToUint8Array(decryptedStream);
25
+ assert.strictEqual(decryptedBytes.length, 0);
26
+ });
27
+ await test('should combine key and IV correctly', async () => {
28
+ const adapter = new GenericAesCtrStreamingCrypto();
29
+ const key = new Uint8Array(32).fill(1); // 32-byte AES-256 key
30
+ const iv = new Uint8Array(16).fill(2); // 16-byte AES-CTR IV
31
+ const combined = adapter.combineKeyAndIV(key, iv);
32
+ assert.strictEqual(combined.length, 48, 'Combined length should be 48 bytes (32 + 16)');
33
+ // Verify first 32 bytes are the key
34
+ for (let i = 0; i < 32; i++) {
35
+ assert.strictEqual(combined[i], 1, `Key byte ${i} should match`);
36
+ }
37
+ // Verify last 16 bytes are the IV
38
+ for (let i = 32; i < 48; i++) {
39
+ assert.strictEqual(combined[i], 2, `IV byte ${i - 32} should match`);
40
+ }
41
+ });
42
+ await test('should split combined key and IV correctly', async () => {
43
+ const adapter = new GenericAesCtrStreamingCrypto();
44
+ const originalKey = new Uint8Array(32).fill(42);
45
+ const originalIV = new Uint8Array(16).fill(84);
46
+ const combined = adapter.combineKeyAndIV(originalKey, originalIV);
47
+ const { key, iv } = adapter.splitKeyAndIV(combined);
48
+ assert.strictEqual(key.length, 32, 'Split key should be 32 bytes');
49
+ assert.strictEqual(iv.length, 16, 'Split IV should be 16 bytes');
50
+ // Verify key matches
51
+ for (let i = 0; i < 32; i++) {
52
+ assert.strictEqual(key[i], originalKey[i], `Key byte ${i} should match original`);
53
+ }
54
+ // Verify IV matches
55
+ for (let i = 0; i < 16; i++) {
56
+ assert.strictEqual(iv[i], originalIV[i], `IV byte ${i} should match original`);
57
+ }
58
+ });
59
+ await test('should roundtrip combine/split correctly', async () => {
60
+ const adapter = new GenericAesCtrStreamingCrypto();
61
+ const originalKey = globalThis.crypto.getRandomValues(new Uint8Array(32));
62
+ const originalIV = globalThis.crypto.getRandomValues(new Uint8Array(16));
63
+ const combined = adapter.combineKeyAndIV(originalKey, originalIV);
64
+ const { key, iv } = adapter.splitKeyAndIV(combined);
65
+ assert.deepStrictEqual(key, originalKey, 'Roundtrip key should match original');
66
+ assert.deepStrictEqual(iv, originalIV, 'Roundtrip IV should match original');
67
+ });
68
+ await test('should validate key length in combineKeyAndIV', async () => {
69
+ const adapter = new GenericAesCtrStreamingCrypto();
70
+ const wrongKey = new Uint8Array(31); // Wrong size
71
+ const correctIV = new Uint8Array(16);
72
+ assert.throws(() => adapter.combineKeyAndIV(wrongKey, correctIV), {
73
+ name: 'Error',
74
+ message: 'AES-256 key must be 32 bytes, got 31',
75
+ }, 'Should throw error for wrong key size');
76
+ });
77
+ await test('should validate IV length in combineKeyAndIV', async () => {
78
+ const adapter = new GenericAesCtrStreamingCrypto();
79
+ const correctKey = new Uint8Array(32);
80
+ const wrongIV = new Uint8Array(15); // Wrong size
81
+ assert.throws(() => adapter.combineKeyAndIV(correctKey, wrongIV), {
82
+ name: 'Error',
83
+ message: 'AES-CTR IV must be 16 bytes, got 15',
84
+ }, 'Should throw error for wrong IV size');
85
+ });
86
+ await test('should validate combined length in splitKeyAndIV', async () => {
87
+ const adapter = new GenericAesCtrStreamingCrypto();
88
+ const wrongCombined = new Uint8Array(47); // Wrong size
89
+ assert.throws(() => adapter.splitKeyAndIV(wrongCombined), {
90
+ name: 'Error',
91
+ message: 'AES-256-CTR combined key+IV must be 48 bytes, got 47',
92
+ }, 'Should throw error for wrong combined size');
93
+ });
94
+ });
95
+ //# sourceMappingURL=node-generic-crypto-adapter.spec.js.map
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=setup.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"setup.d.ts","sourceRoot":"","sources":["../../test/setup.js"],"names":[],"mappings":""}
@@ -0,0 +1,12 @@
1
+ // Centralized polyfill for globalThis.crypto for Node.js <19
2
+ if (typeof globalThis.crypto === 'undefined') {
3
+ try {
4
+ // @ts-expect-error
5
+ globalThis.crypto = (await import('crypto')).webcrypto;
6
+ }
7
+ catch (e) {
8
+ throw new Error('globalThis.crypto is not available.');
9
+ }
10
+ }
11
+ export {};
12
+ //# sourceMappingURL=setup.js.map