@agentuity/cli 0.0.42 → 0.0.44
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/AGENTS.md +1 -1
- package/README.md +1 -1
- package/bin/cli.ts +7 -5
- package/dist/api.d.ts +3 -3
- package/dist/api.d.ts.map +1 -1
- package/dist/auth.d.ts +10 -2
- package/dist/auth.d.ts.map +1 -1
- package/dist/banner.d.ts.map +1 -1
- package/dist/cli.d.ts.map +1 -1
- package/dist/cmd/auth/api.d.ts +4 -4
- package/dist/cmd/auth/api.d.ts.map +1 -1
- package/dist/cmd/auth/index.d.ts.map +1 -1
- package/dist/cmd/auth/login.d.ts.map +1 -1
- package/dist/cmd/auth/signup.d.ts.map +1 -1
- package/dist/cmd/auth/ssh/add.d.ts +2 -0
- package/dist/cmd/auth/ssh/add.d.ts.map +1 -0
- package/dist/cmd/auth/ssh/api.d.ts +16 -0
- package/dist/cmd/auth/ssh/api.d.ts.map +1 -0
- package/dist/cmd/auth/ssh/delete.d.ts +2 -0
- package/dist/cmd/auth/ssh/delete.d.ts.map +1 -0
- package/dist/cmd/auth/ssh/index.d.ts +3 -0
- package/dist/cmd/auth/ssh/index.d.ts.map +1 -0
- package/dist/cmd/auth/ssh/list.d.ts +2 -0
- package/dist/cmd/auth/ssh/list.d.ts.map +1 -0
- package/dist/cmd/auth/whoami.d.ts +2 -0
- package/dist/cmd/auth/whoami.d.ts.map +1 -0
- package/dist/cmd/bundle/ast.d.ts +14 -3
- package/dist/cmd/bundle/ast.d.ts.map +1 -1
- package/dist/cmd/bundle/ast.test.d.ts +2 -0
- package/dist/cmd/bundle/ast.test.d.ts.map +1 -0
- package/dist/cmd/bundle/bundler.d.ts +6 -1
- package/dist/cmd/bundle/bundler.d.ts.map +1 -1
- package/dist/cmd/bundle/file.d.ts.map +1 -1
- package/dist/cmd/bundle/fix-duplicate-exports.d.ts +2 -0
- package/dist/cmd/bundle/fix-duplicate-exports.d.ts.map +1 -0
- package/dist/cmd/bundle/fix-duplicate-exports.test.d.ts +2 -0
- package/dist/cmd/bundle/fix-duplicate-exports.test.d.ts.map +1 -0
- package/dist/cmd/bundle/index.d.ts +1 -1
- package/dist/cmd/bundle/index.d.ts.map +1 -1
- package/dist/cmd/bundle/plugin.d.ts +2 -0
- package/dist/cmd/bundle/plugin.d.ts.map +1 -1
- package/dist/cmd/cloud/deploy.d.ts.map +1 -0
- package/dist/cmd/cloud/domain.d.ts +17 -0
- package/dist/cmd/cloud/domain.d.ts.map +1 -0
- package/dist/cmd/cloud/index.d.ts.map +1 -0
- package/dist/cmd/cloud/resource/add.d.ts +2 -0
- package/dist/cmd/cloud/resource/add.d.ts.map +1 -0
- package/dist/cmd/cloud/resource/delete.d.ts +2 -0
- package/dist/cmd/cloud/resource/delete.d.ts.map +1 -0
- package/dist/cmd/cloud/resource/index.d.ts +3 -0
- package/dist/cmd/cloud/resource/index.d.ts.map +1 -0
- package/dist/cmd/cloud/resource/list.d.ts +2 -0
- package/dist/cmd/cloud/resource/list.d.ts.map +1 -0
- package/dist/cmd/cloud/scp/download.d.ts +2 -0
- package/dist/cmd/cloud/scp/download.d.ts.map +1 -0
- package/dist/cmd/cloud/scp/index.d.ts +3 -0
- package/dist/cmd/cloud/scp/index.d.ts.map +1 -0
- package/dist/cmd/cloud/scp/upload.d.ts +2 -0
- package/dist/cmd/cloud/scp/upload.d.ts.map +1 -0
- package/dist/cmd/cloud/ssh.d.ts +2 -0
- package/dist/cmd/cloud/ssh.d.ts.map +1 -0
- package/dist/cmd/dev/api.d.ts +18 -0
- package/dist/cmd/dev/api.d.ts.map +1 -0
- package/dist/cmd/dev/download.d.ts +11 -0
- package/dist/cmd/dev/download.d.ts.map +1 -0
- package/dist/cmd/dev/index.d.ts.map +1 -1
- package/dist/cmd/dev/templates.d.ts +3 -0
- package/dist/cmd/dev/templates.d.ts.map +1 -0
- package/dist/cmd/env/delete.d.ts +2 -0
- package/dist/cmd/env/delete.d.ts.map +1 -0
- package/dist/cmd/env/get.d.ts +2 -0
- package/dist/cmd/env/get.d.ts.map +1 -0
- package/dist/cmd/env/import.d.ts +2 -0
- package/dist/cmd/env/import.d.ts.map +1 -0
- package/dist/cmd/env/index.d.ts +2 -0
- package/dist/cmd/env/index.d.ts.map +1 -0
- package/dist/cmd/env/list.d.ts.map +1 -0
- package/dist/cmd/env/pull.d.ts +2 -0
- package/dist/cmd/env/pull.d.ts.map +1 -0
- package/dist/cmd/env/push.d.ts +2 -0
- package/dist/cmd/env/push.d.ts.map +1 -0
- package/dist/cmd/env/set.d.ts +2 -0
- package/dist/cmd/env/set.d.ts.map +1 -0
- package/dist/cmd/profile/show.d.ts.map +1 -1
- package/dist/cmd/project/create.d.ts.map +1 -1
- package/dist/cmd/project/delete.d.ts.map +1 -1
- package/dist/cmd/project/download.d.ts +1 -1
- package/dist/cmd/project/download.d.ts.map +1 -1
- package/dist/cmd/project/list.d.ts.map +1 -1
- package/dist/cmd/project/show.d.ts.map +1 -1
- package/dist/cmd/project/template-flow.d.ts +5 -1
- package/dist/cmd/project/template-flow.d.ts.map +1 -1
- package/dist/cmd/secret/delete.d.ts +2 -0
- package/dist/cmd/secret/delete.d.ts.map +1 -0
- package/dist/cmd/secret/get.d.ts +2 -0
- package/dist/cmd/secret/get.d.ts.map +1 -0
- package/dist/cmd/secret/import.d.ts +2 -0
- package/dist/cmd/secret/import.d.ts.map +1 -0
- package/dist/cmd/secret/index.d.ts +2 -0
- package/dist/cmd/secret/index.d.ts.map +1 -0
- package/dist/cmd/secret/list.d.ts +2 -0
- package/dist/cmd/secret/list.d.ts.map +1 -0
- package/dist/cmd/secret/pull.d.ts +2 -0
- package/dist/cmd/secret/pull.d.ts.map +1 -0
- package/dist/cmd/secret/push.d.ts +2 -0
- package/dist/cmd/secret/push.d.ts.map +1 -0
- package/dist/cmd/secret/set.d.ts +2 -0
- package/dist/cmd/secret/set.d.ts.map +1 -0
- package/dist/cmd/version/index.d.ts.map +1 -1
- package/dist/config.d.ts +11 -3
- package/dist/config.d.ts.map +1 -1
- package/dist/crypto/box.d.ts +65 -0
- package/dist/crypto/box.d.ts.map +1 -0
- package/dist/crypto/box.test.d.ts +2 -0
- package/dist/crypto/box.test.d.ts.map +1 -0
- package/dist/download.d.ts.map +1 -1
- package/dist/env-util.d.ts +67 -0
- package/dist/env-util.d.ts.map +1 -0
- package/dist/env-util.test.d.ts +2 -0
- package/dist/env-util.test.d.ts.map +1 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/schema-parser.d.ts.map +1 -1
- package/dist/steps.d.ts +4 -1
- package/dist/steps.d.ts.map +1 -1
- package/dist/terminal.d.ts.map +1 -1
- package/dist/tui.d.ts +32 -2
- package/dist/tui.d.ts.map +1 -1
- package/dist/types.d.ts +250 -127
- package/dist/types.d.ts.map +1 -1
- package/dist/utils/detectSubagent.d.ts +15 -0
- package/dist/utils/detectSubagent.d.ts.map +1 -0
- package/dist/utils/zip.d.ts +7 -0
- package/dist/utils/zip.d.ts.map +1 -0
- package/package.json +11 -3
- package/src/api-errors.md +2 -2
- package/src/api.ts +12 -7
- package/src/auth.ts +116 -7
- package/src/banner.ts +13 -6
- package/src/cli.ts +709 -36
- package/src/cmd/auth/api.ts +10 -16
- package/src/cmd/auth/index.ts +3 -1
- package/src/cmd/auth/login.ts +24 -8
- package/src/cmd/auth/signup.ts +15 -11
- package/src/cmd/auth/ssh/add.ts +263 -0
- package/src/cmd/auth/ssh/api.ts +94 -0
- package/src/cmd/auth/ssh/delete.ts +102 -0
- package/src/cmd/auth/ssh/index.ts +10 -0
- package/src/cmd/auth/ssh/list.ts +74 -0
- package/src/cmd/auth/whoami.ts +69 -0
- package/src/cmd/bundle/ast.test.ts +565 -0
- package/src/cmd/bundle/ast.ts +457 -44
- package/src/cmd/bundle/bundler.ts +255 -57
- package/src/cmd/bundle/file.ts +6 -12
- package/src/cmd/bundle/fix-duplicate-exports.test.ts +387 -0
- package/src/cmd/bundle/fix-duplicate-exports.ts +204 -0
- package/src/cmd/bundle/index.ts +11 -11
- package/src/cmd/bundle/patch/aisdk.ts +1 -1
- package/src/cmd/bundle/plugin.ts +373 -53
- package/src/cmd/cloud/deploy.ts +336 -0
- package/src/cmd/cloud/domain.ts +92 -0
- package/src/cmd/cloud/index.ts +11 -0
- package/src/cmd/cloud/resource/add.ts +56 -0
- package/src/cmd/cloud/resource/delete.ts +120 -0
- package/src/cmd/cloud/resource/index.ts +11 -0
- package/src/cmd/cloud/resource/list.ts +69 -0
- package/src/cmd/cloud/scp/download.ts +59 -0
- package/src/cmd/cloud/scp/index.ts +9 -0
- package/src/cmd/cloud/scp/upload.ts +62 -0
- package/src/cmd/cloud/ssh.ts +68 -0
- package/src/cmd/dev/api.ts +46 -0
- package/src/cmd/dev/download.ts +111 -0
- package/src/cmd/dev/index.ts +362 -34
- package/src/cmd/dev/templates.ts +84 -0
- package/src/cmd/env/delete.ts +47 -0
- package/src/cmd/env/get.ts +53 -0
- package/src/cmd/env/import.ts +102 -0
- package/src/cmd/env/index.ts +22 -0
- package/src/cmd/env/list.ts +56 -0
- package/src/cmd/env/pull.ts +80 -0
- package/src/cmd/env/push.ts +37 -0
- package/src/cmd/env/set.ts +71 -0
- package/src/cmd/index.ts +2 -2
- package/src/cmd/profile/show.ts +15 -6
- package/src/cmd/project/create.ts +7 -2
- package/src/cmd/project/delete.ts +75 -18
- package/src/cmd/project/download.ts +3 -3
- package/src/cmd/project/list.ts +8 -8
- package/src/cmd/project/show.ts +3 -7
- package/src/cmd/project/template-flow.ts +186 -48
- package/src/cmd/secret/delete.ts +40 -0
- package/src/cmd/secret/get.ts +54 -0
- package/src/cmd/secret/import.ts +64 -0
- package/src/cmd/secret/index.ts +22 -0
- package/src/cmd/secret/list.ts +56 -0
- package/src/cmd/secret/pull.ts +78 -0
- package/src/cmd/secret/push.ts +37 -0
- package/src/cmd/secret/set.ts +45 -0
- package/src/cmd/version/index.ts +2 -1
- package/src/config.ts +257 -27
- package/src/crypto/box.test.ts +431 -0
- package/src/crypto/box.ts +477 -0
- package/src/download.ts +1 -0
- package/src/env-util.test.ts +194 -0
- package/src/env-util.ts +290 -0
- package/src/index.ts +5 -1
- package/src/schema-parser.ts +2 -3
- package/src/steps.ts +144 -10
- package/src/terminal.ts +24 -23
- package/src/tui.ts +208 -68
- package/src/types.ts +292 -202
- package/src/utils/detectSubagent.ts +31 -0
- package/src/utils/zip.ts +38 -0
- package/dist/cmd/example/create-user.d.ts +0 -2
- package/dist/cmd/example/create-user.d.ts.map +0 -1
- package/dist/cmd/example/create.d.ts +0 -2
- package/dist/cmd/example/create.d.ts.map +0 -1
- package/dist/cmd/example/deploy.d.ts.map +0 -1
- package/dist/cmd/example/index.d.ts.map +0 -1
- package/dist/cmd/example/list.d.ts.map +0 -1
- package/dist/cmd/example/optional-auth.d.ts +0 -3
- package/dist/cmd/example/optional-auth.d.ts.map +0 -1
- package/dist/cmd/example/run-command.d.ts +0 -2
- package/dist/cmd/example/run-command.d.ts.map +0 -1
- package/dist/cmd/example/sound.d.ts +0 -3
- package/dist/cmd/example/sound.d.ts.map +0 -1
- package/dist/cmd/example/spinner.d.ts +0 -2
- package/dist/cmd/example/spinner.d.ts.map +0 -1
- package/dist/cmd/example/steps.d.ts +0 -2
- package/dist/cmd/example/steps.d.ts.map +0 -1
- package/dist/cmd/example/version.d.ts +0 -2
- package/dist/cmd/example/version.d.ts.map +0 -1
- package/dist/logger.d.ts +0 -24
- package/dist/logger.d.ts.map +0 -1
- package/src/cmd/example/create-user.ts +0 -38
- package/src/cmd/example/create.ts +0 -31
- package/src/cmd/example/deploy.ts +0 -36
- package/src/cmd/example/index.ts +0 -29
- package/src/cmd/example/list.ts +0 -32
- package/src/cmd/example/optional-auth.ts +0 -38
- package/src/cmd/example/run-command.ts +0 -45
- package/src/cmd/example/sound.ts +0 -14
- package/src/cmd/example/spinner.ts +0 -44
- package/src/cmd/example/steps.ts +0 -66
- package/src/cmd/example/version.ts +0 -13
- package/src/logger.ts +0 -235
- /package/dist/cmd/{example → cloud}/deploy.d.ts +0 -0
- /package/dist/cmd/{example → cloud}/index.d.ts +0 -0
- /package/dist/cmd/{example → env}/list.d.ts +0 -0
|
@@ -0,0 +1,431 @@
|
|
|
1
|
+
import { describe, test, expect, beforeAll } from 'bun:test';
|
|
2
|
+
import { generateKeyPairSync, KeyObject } from 'node:crypto';
|
|
3
|
+
import { Readable, Writable } from 'node:stream';
|
|
4
|
+
import { encryptFIPSKEMDEMStream, decryptFIPSKEMDEMStream } from './box';
|
|
5
|
+
|
|
6
|
+
function createReadableStream(data: Buffer): Readable {
|
|
7
|
+
return Readable.from([data]);
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
class CollectorStream extends Writable {
|
|
11
|
+
private chunks: Buffer[] = [];
|
|
12
|
+
|
|
13
|
+
_write(chunk: Buffer, _encoding: string, callback: () => void): void {
|
|
14
|
+
this.chunks.push(chunk);
|
|
15
|
+
callback();
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
getData(): Buffer {
|
|
19
|
+
return Buffer.concat(this.chunks);
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
function generateP256KeyPair(): { publicKey: KeyObject; privateKey: KeyObject } {
|
|
24
|
+
return generateKeyPairSync('ec', {
|
|
25
|
+
namedCurve: 'prime256v1',
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function generateP384KeyPair(): { publicKey: KeyObject; privateKey: KeyObject } {
|
|
30
|
+
return generateKeyPairSync('ec', {
|
|
31
|
+
namedCurve: 'secp384r1',
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
describe('crypto/box', () => {
|
|
36
|
+
describe('TestBasicEncryptDecrypt', () => {
|
|
37
|
+
let keyPair: { publicKey: KeyObject; privateKey: KeyObject };
|
|
38
|
+
|
|
39
|
+
beforeAll(() => {
|
|
40
|
+
keyPair = generateP256KeyPair();
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
const testCases = [
|
|
44
|
+
{ name: 'empty', data: Buffer.alloc(0) },
|
|
45
|
+
{ name: 'small', data: Buffer.from('hello world') },
|
|
46
|
+
{ name: 'medium', data: Buffer.alloc(1000).fill('A') },
|
|
47
|
+
{ name: 'large', data: Buffer.alloc(100000).fill('B') },
|
|
48
|
+
{ name: 'exactly_one_frame', data: Buffer.alloc(64 * 1024).fill('C') },
|
|
49
|
+
{ name: 'just_over_one_frame', data: Buffer.alloc(64 * 1024 + 1).fill('D') },
|
|
50
|
+
];
|
|
51
|
+
|
|
52
|
+
for (const tc of testCases) {
|
|
53
|
+
test(tc.name, async () => {
|
|
54
|
+
const src = createReadableStream(tc.data);
|
|
55
|
+
const encrypted = new CollectorStream();
|
|
56
|
+
const written = await encryptFIPSKEMDEMStream(keyPair.publicKey, src, encrypted);
|
|
57
|
+
|
|
58
|
+
expect(written).toBe(tc.data.length);
|
|
59
|
+
|
|
60
|
+
const encryptedData = encrypted.getData();
|
|
61
|
+
const decryptSrc = createReadableStream(encryptedData);
|
|
62
|
+
const decrypted = new CollectorStream();
|
|
63
|
+
const read = await decryptFIPSKEMDEMStream(keyPair.privateKey, decryptSrc, decrypted);
|
|
64
|
+
|
|
65
|
+
expect(read).toBe(tc.data.length);
|
|
66
|
+
|
|
67
|
+
const decryptedData = decrypted.getData();
|
|
68
|
+
expect(decryptedData.equals(tc.data)).toBe(true);
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
describe('TestDifferentKeys', () => {
|
|
74
|
+
test('should fail to decrypt with wrong key', async () => {
|
|
75
|
+
const keyPair1 = generateP256KeyPair();
|
|
76
|
+
const keyPair2 = generateP256KeyPair();
|
|
77
|
+
|
|
78
|
+
const data = Buffer.from('test data');
|
|
79
|
+
|
|
80
|
+
const src = createReadableStream(data);
|
|
81
|
+
const encrypted = new CollectorStream();
|
|
82
|
+
await encryptFIPSKEMDEMStream(keyPair1.publicKey, src, encrypted);
|
|
83
|
+
|
|
84
|
+
const encryptedData = encrypted.getData();
|
|
85
|
+
const decryptSrc = createReadableStream(encryptedData);
|
|
86
|
+
const decrypted = new CollectorStream();
|
|
87
|
+
|
|
88
|
+
await expect(
|
|
89
|
+
decryptFIPSKEMDEMStream(keyPair2.privateKey, decryptSrc, decrypted)
|
|
90
|
+
).rejects.toThrow('DEK unwrap failed');
|
|
91
|
+
});
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
describe('TestMalformedHeaders', () => {
|
|
95
|
+
let keyPair: { publicKey: KeyObject; privateKey: KeyObject };
|
|
96
|
+
|
|
97
|
+
beforeAll(() => {
|
|
98
|
+
keyPair = generateP256KeyPair();
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
const testCases = [
|
|
102
|
+
{ name: 'empty', data: Buffer.alloc(0), err: 'unexpected EOF' },
|
|
103
|
+
{ name: 'partial_len', data: Buffer.from([0]), err: 'unexpected EOF' },
|
|
104
|
+
{
|
|
105
|
+
name: 'invalid_wrapped_len',
|
|
106
|
+
data: Buffer.from([0x10, 0x00]),
|
|
107
|
+
err: 'invalid wrapped DEK length',
|
|
108
|
+
},
|
|
109
|
+
{ name: 'zero_len', data: Buffer.from([0x00, 0x00]), err: 'invalid wrapped DEK length' },
|
|
110
|
+
];
|
|
111
|
+
|
|
112
|
+
for (const tc of testCases) {
|
|
113
|
+
test(tc.name, async () => {
|
|
114
|
+
const src = createReadableStream(tc.data);
|
|
115
|
+
const decrypted = new CollectorStream();
|
|
116
|
+
|
|
117
|
+
await expect(
|
|
118
|
+
decryptFIPSKEMDEMStream(keyPair.privateKey, src, decrypted)
|
|
119
|
+
).rejects.toThrow(tc.err);
|
|
120
|
+
});
|
|
121
|
+
}
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
describe('TestMalformedChunks', () => {
|
|
125
|
+
test('should fail authentication for malformed chunk', async () => {
|
|
126
|
+
const keyPair = generateP256KeyPair();
|
|
127
|
+
|
|
128
|
+
const buf = Buffer.alloc(2 + 113 + 12 + 2 + 32);
|
|
129
|
+
let offset = 0;
|
|
130
|
+
|
|
131
|
+
buf.writeUInt16BE(113, offset); // reasonable wrapped length (65+32+16)
|
|
132
|
+
offset += 2;
|
|
133
|
+
offset += 113;
|
|
134
|
+
offset += 12;
|
|
135
|
+
|
|
136
|
+
buf.writeUInt16BE(32, offset); // reasonable chunk size
|
|
137
|
+
offset += 2;
|
|
138
|
+
|
|
139
|
+
const src = createReadableStream(buf);
|
|
140
|
+
const decrypted = new CollectorStream();
|
|
141
|
+
|
|
142
|
+
await expect(
|
|
143
|
+
decryptFIPSKEMDEMStream(keyPair.privateKey, src, decrypted)
|
|
144
|
+
).rejects.toThrow();
|
|
145
|
+
});
|
|
146
|
+
});
|
|
147
|
+
|
|
148
|
+
describe('TestStreamEOF', () => {
|
|
149
|
+
test('should handle empty stream', async () => {
|
|
150
|
+
const keyPair = generateP256KeyPair();
|
|
151
|
+
|
|
152
|
+
const src = createReadableStream(Buffer.alloc(0));
|
|
153
|
+
const encrypted = new CollectorStream();
|
|
154
|
+
|
|
155
|
+
const written = await encryptFIPSKEMDEMStream(keyPair.publicKey, src, encrypted);
|
|
156
|
+
expect(written).toBe(0);
|
|
157
|
+
|
|
158
|
+
const encryptedData = encrypted.getData();
|
|
159
|
+
const decryptSrc = createReadableStream(encryptedData);
|
|
160
|
+
const decrypted = new CollectorStream();
|
|
161
|
+
|
|
162
|
+
const read = await decryptFIPSKEMDEMStream(keyPair.privateKey, decryptSrc, decrypted);
|
|
163
|
+
expect(read).toBe(0);
|
|
164
|
+
});
|
|
165
|
+
});
|
|
166
|
+
|
|
167
|
+
describe('TestNonceReuseProtection', () => {
|
|
168
|
+
test('different encryptions should produce different ciphertexts', async () => {
|
|
169
|
+
const keyPair = generateP256KeyPair();
|
|
170
|
+
const data = Buffer.from('test data for nonce reuse protection');
|
|
171
|
+
|
|
172
|
+
const src1 = createReadableStream(data);
|
|
173
|
+
const encrypted1 = new CollectorStream();
|
|
174
|
+
await encryptFIPSKEMDEMStream(keyPair.publicKey, src1, encrypted1);
|
|
175
|
+
|
|
176
|
+
const src2 = createReadableStream(data);
|
|
177
|
+
const encrypted2 = new CollectorStream();
|
|
178
|
+
await encryptFIPSKEMDEMStream(keyPair.publicKey, src2, encrypted2);
|
|
179
|
+
|
|
180
|
+
const enc1Data = encrypted1.getData();
|
|
181
|
+
const enc2Data = encrypted2.getData();
|
|
182
|
+
expect(enc1Data.equals(enc2Data)).toBe(false);
|
|
183
|
+
|
|
184
|
+
const decryptSrc1 = createReadableStream(enc1Data);
|
|
185
|
+
const decrypted1 = new CollectorStream();
|
|
186
|
+
await decryptFIPSKEMDEMStream(keyPair.privateKey, decryptSrc1, decrypted1);
|
|
187
|
+
|
|
188
|
+
const decryptSrc2 = createReadableStream(enc2Data);
|
|
189
|
+
const decrypted2 = new CollectorStream();
|
|
190
|
+
await decryptFIPSKEMDEMStream(keyPair.privateKey, decryptSrc2, decrypted2);
|
|
191
|
+
|
|
192
|
+
expect(decrypted1.getData().equals(data)).toBe(true);
|
|
193
|
+
expect(decrypted2.getData().equals(data)).toBe(true);
|
|
194
|
+
});
|
|
195
|
+
});
|
|
196
|
+
|
|
197
|
+
describe('TestFrameSizeBoundaries', () => {
|
|
198
|
+
let keyPair: { publicKey: KeyObject; privateKey: KeyObject };
|
|
199
|
+
|
|
200
|
+
beforeAll(() => {
|
|
201
|
+
keyPair = generateP256KeyPair();
|
|
202
|
+
});
|
|
203
|
+
|
|
204
|
+
const FRAME = 65519;
|
|
205
|
+
const testCases = [
|
|
206
|
+
{ name: 'exactly_max_frame', size: FRAME },
|
|
207
|
+
{ name: 'max_frame_minus_1', size: FRAME - 1 },
|
|
208
|
+
{ name: 'max_frame_plus_1', size: FRAME + 1 },
|
|
209
|
+
{ name: 'half_frame', size: Math.floor(FRAME / 2) },
|
|
210
|
+
{ name: 'double_frame', size: FRAME * 2 },
|
|
211
|
+
];
|
|
212
|
+
|
|
213
|
+
for (const tc of testCases) {
|
|
214
|
+
test(tc.name, async () => {
|
|
215
|
+
const data = Buffer.alloc(tc.size).fill('A');
|
|
216
|
+
|
|
217
|
+
const src = createReadableStream(data);
|
|
218
|
+
const encrypted = new CollectorStream();
|
|
219
|
+
const written = await encryptFIPSKEMDEMStream(keyPair.publicKey, src, encrypted);
|
|
220
|
+
|
|
221
|
+
expect(written).toBe(tc.size);
|
|
222
|
+
|
|
223
|
+
const encryptedData = encrypted.getData();
|
|
224
|
+
const decryptSrc = createReadableStream(encryptedData);
|
|
225
|
+
const decrypted = new CollectorStream();
|
|
226
|
+
const read = await decryptFIPSKEMDEMStream(keyPair.privateKey, decryptSrc, decrypted);
|
|
227
|
+
|
|
228
|
+
expect(read).toBe(tc.size);
|
|
229
|
+
|
|
230
|
+
const decryptedData = decrypted.getData();
|
|
231
|
+
expect(decryptedData.equals(data)).toBe(true);
|
|
232
|
+
});
|
|
233
|
+
}
|
|
234
|
+
});
|
|
235
|
+
|
|
236
|
+
describe('TestUint16OverflowProtection', () => {
|
|
237
|
+
test('should not overflow with maximum frame size', async () => {
|
|
238
|
+
const FRAME = 65519;
|
|
239
|
+
const GCM_TAG = 16;
|
|
240
|
+
|
|
241
|
+
const maxExpected = FRAME + GCM_TAG;
|
|
242
|
+
expect(maxExpected).toBeLessThanOrEqual(0xffff);
|
|
243
|
+
|
|
244
|
+
const keyPair = generateP256KeyPair();
|
|
245
|
+
const data = Buffer.alloc(FRAME).fill('B');
|
|
246
|
+
|
|
247
|
+
const src = createReadableStream(data);
|
|
248
|
+
const encrypted = new CollectorStream();
|
|
249
|
+
|
|
250
|
+
await expect(encryptFIPSKEMDEMStream(keyPair.publicKey, src, encrypted)).resolves.toBe(
|
|
251
|
+
FRAME
|
|
252
|
+
);
|
|
253
|
+
});
|
|
254
|
+
});
|
|
255
|
+
|
|
256
|
+
describe('TestUnsupportedCurves', () => {
|
|
257
|
+
test('should reject P-384 keys', async () => {
|
|
258
|
+
const keyPair384 = generateP384KeyPair();
|
|
259
|
+
const data = Buffer.from('test data');
|
|
260
|
+
|
|
261
|
+
const src = createReadableStream(data);
|
|
262
|
+
const encrypted = new CollectorStream();
|
|
263
|
+
|
|
264
|
+
await expect(
|
|
265
|
+
encryptFIPSKEMDEMStream(keyPair384.publicKey, src, encrypted)
|
|
266
|
+
).rejects.toThrow('only P-256 keys supported');
|
|
267
|
+
|
|
268
|
+
const decryptSrc = createReadableStream(Buffer.alloc(0));
|
|
269
|
+
const decrypted = new CollectorStream();
|
|
270
|
+
|
|
271
|
+
await expect(
|
|
272
|
+
decryptFIPSKEMDEMStream(keyPair384.privateKey, decryptSrc, decrypted)
|
|
273
|
+
).rejects.toThrow('only P-256 keys supported');
|
|
274
|
+
});
|
|
275
|
+
});
|
|
276
|
+
|
|
277
|
+
describe('TestConcurrentOperations', () => {
|
|
278
|
+
test('should handle concurrent encrypt/decrypt operations', async () => {
|
|
279
|
+
const keyPair = generateP256KeyPair();
|
|
280
|
+
const numGoroutines = 10;
|
|
281
|
+
const dataSize = 10000;
|
|
282
|
+
|
|
283
|
+
const promises: Promise<void>[] = [];
|
|
284
|
+
|
|
285
|
+
for (let i = 0; i < numGoroutines; i++) {
|
|
286
|
+
const promise = (async (id: number) => {
|
|
287
|
+
const data = Buffer.alloc(Math.floor(dataSize / 10))
|
|
288
|
+
.fill(`data${id}`)
|
|
289
|
+
.subarray(0, Math.floor(dataSize / 10));
|
|
290
|
+
|
|
291
|
+
const src = createReadableStream(data);
|
|
292
|
+
const encrypted = new CollectorStream();
|
|
293
|
+
await encryptFIPSKEMDEMStream(keyPair.publicKey, src, encrypted);
|
|
294
|
+
|
|
295
|
+
const encryptedData = encrypted.getData();
|
|
296
|
+
const decryptSrc = createReadableStream(encryptedData);
|
|
297
|
+
const decrypted = new CollectorStream();
|
|
298
|
+
await decryptFIPSKEMDEMStream(keyPair.privateKey, decryptSrc, decrypted);
|
|
299
|
+
|
|
300
|
+
const decryptedData = decrypted.getData();
|
|
301
|
+
if (!decryptedData.equals(data)) {
|
|
302
|
+
throw new Error(`goroutine ${id} data mismatch`);
|
|
303
|
+
}
|
|
304
|
+
})(i);
|
|
305
|
+
|
|
306
|
+
promises.push(promise);
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
await Promise.all(promises);
|
|
310
|
+
});
|
|
311
|
+
});
|
|
312
|
+
|
|
313
|
+
describe('TestDifferentKeyPairs', () => {
|
|
314
|
+
test('should work with correct key and fail with wrong key', async () => {
|
|
315
|
+
const keyPair1 = generateP256KeyPair();
|
|
316
|
+
const keyPair2 = generateP256KeyPair();
|
|
317
|
+
const data = Buffer.from('test data');
|
|
318
|
+
|
|
319
|
+
const src = createReadableStream(data);
|
|
320
|
+
const encrypted = new CollectorStream();
|
|
321
|
+
const written = await encryptFIPSKEMDEMStream(keyPair1.publicKey, src, encrypted);
|
|
322
|
+
|
|
323
|
+
expect(written).toBe(data.length);
|
|
324
|
+
|
|
325
|
+
const encryptedData = encrypted.getData();
|
|
326
|
+
const decryptSrc1 = createReadableStream(encryptedData);
|
|
327
|
+
const decrypted1 = new CollectorStream();
|
|
328
|
+
const read = await decryptFIPSKEMDEMStream(keyPair1.privateKey, decryptSrc1, decrypted1);
|
|
329
|
+
|
|
330
|
+
expect(read).toBe(data.length);
|
|
331
|
+
expect(decrypted1.getData().equals(data)).toBe(true);
|
|
332
|
+
|
|
333
|
+
const decryptSrc2 = createReadableStream(encryptedData);
|
|
334
|
+
const decrypted2 = new CollectorStream();
|
|
335
|
+
|
|
336
|
+
await expect(
|
|
337
|
+
decryptFIPSKEMDEMStream(keyPair2.privateKey, decryptSrc2, decrypted2)
|
|
338
|
+
).rejects.toThrow();
|
|
339
|
+
|
|
340
|
+
expect(decrypted2.getData().length).toBe(0);
|
|
341
|
+
});
|
|
342
|
+
});
|
|
343
|
+
|
|
344
|
+
describe('TestPartialCorruption', () => {
|
|
345
|
+
test('should handle corrupted data gracefully', async () => {
|
|
346
|
+
const keyPair = generateP256KeyPair();
|
|
347
|
+
const testData = Buffer.from('This is test data for corruption testing');
|
|
348
|
+
|
|
349
|
+
const src = createReadableStream(testData);
|
|
350
|
+
const encrypted = new CollectorStream();
|
|
351
|
+
await encryptFIPSKEMDEMStream(keyPair.publicKey, src, encrypted);
|
|
352
|
+
|
|
353
|
+
const validEncrypted = encrypted.getData();
|
|
354
|
+
|
|
355
|
+
const corruptPositions = [
|
|
356
|
+
0, // Header start
|
|
357
|
+
1, // Header middle
|
|
358
|
+
Math.floor(validEncrypted.length / 4), // Early data
|
|
359
|
+
Math.floor(validEncrypted.length / 2), // Middle data
|
|
360
|
+
Math.floor((3 * validEncrypted.length) / 4), // Late data
|
|
361
|
+
validEncrypted.length - 1, // End data
|
|
362
|
+
];
|
|
363
|
+
|
|
364
|
+
for (const pos of corruptPositions) {
|
|
365
|
+
if (pos >= validEncrypted.length) {
|
|
366
|
+
continue;
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
const corrupted = Buffer.from(validEncrypted);
|
|
370
|
+
corrupted[pos] ^= 0x01; // Flip one bit
|
|
371
|
+
|
|
372
|
+
const decryptSrc = createReadableStream(corrupted);
|
|
373
|
+
const decrypted = new CollectorStream();
|
|
374
|
+
|
|
375
|
+
await expect(
|
|
376
|
+
decryptFIPSKEMDEMStream(keyPair.privateKey, decryptSrc, decrypted)
|
|
377
|
+
).rejects.toThrow();
|
|
378
|
+
}
|
|
379
|
+
});
|
|
380
|
+
});
|
|
381
|
+
|
|
382
|
+
describe('TestLargeData', () => {
|
|
383
|
+
test('should handle multi-megabyte data', async () => {
|
|
384
|
+
const keyPair = generateP256KeyPair();
|
|
385
|
+
const data = Buffer.alloc(1024 * 1024).fill('X');
|
|
386
|
+
|
|
387
|
+
const src = createReadableStream(data);
|
|
388
|
+
const encrypted = new CollectorStream();
|
|
389
|
+
const written = await encryptFIPSKEMDEMStream(keyPair.publicKey, src, encrypted);
|
|
390
|
+
|
|
391
|
+
expect(written).toBe(data.length);
|
|
392
|
+
|
|
393
|
+
const encryptedData = encrypted.getData();
|
|
394
|
+
const decryptSrc = createReadableStream(encryptedData);
|
|
395
|
+
const decrypted = new CollectorStream();
|
|
396
|
+
const read = await decryptFIPSKEMDEMStream(keyPair.privateKey, decryptSrc, decrypted);
|
|
397
|
+
|
|
398
|
+
expect(read).toBe(data.length);
|
|
399
|
+
|
|
400
|
+
const decryptedData = decrypted.getData();
|
|
401
|
+
expect(decryptedData.equals(data)).toBe(true);
|
|
402
|
+
});
|
|
403
|
+
});
|
|
404
|
+
|
|
405
|
+
describe('TestChunkTooLarge', () => {
|
|
406
|
+
test('should reject chunks that are too large', async () => {
|
|
407
|
+
const keyPair = generateP256KeyPair();
|
|
408
|
+
const data = Buffer.from('test data');
|
|
409
|
+
|
|
410
|
+
const src = createReadableStream(data);
|
|
411
|
+
const encrypted = new CollectorStream();
|
|
412
|
+
await encryptFIPSKEMDEMStream(keyPair.publicKey, src, encrypted);
|
|
413
|
+
|
|
414
|
+
const validEncrypted = encrypted.getData();
|
|
415
|
+
const headerSize = 2 + validEncrypted.readUInt16BE(0) + 12;
|
|
416
|
+
const chunkSizeOffset = headerSize;
|
|
417
|
+
|
|
418
|
+
const corrupted = Buffer.from(validEncrypted);
|
|
419
|
+
const FRAME = 65519;
|
|
420
|
+
const GCM_TAG = 16;
|
|
421
|
+
corrupted.writeUInt16BE(FRAME + GCM_TAG, chunkSizeOffset);
|
|
422
|
+
|
|
423
|
+
const decryptSrc = createReadableStream(corrupted);
|
|
424
|
+
const decrypted = new CollectorStream();
|
|
425
|
+
|
|
426
|
+
await expect(
|
|
427
|
+
decryptFIPSKEMDEMStream(keyPair.privateKey, decryptSrc, decrypted)
|
|
428
|
+
).rejects.toThrow();
|
|
429
|
+
});
|
|
430
|
+
});
|
|
431
|
+
});
|