agentlock-shared 0.1.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/.turbo/turbo-build.log +4 -0
- package/.turbo/turbo-test.log +34 -0
- package/dist/__tests__/content-crypto.test.d.ts +2 -0
- package/dist/__tests__/content-crypto.test.d.ts.map +1 -0
- package/dist/__tests__/content-crypto.test.js +117 -0
- package/dist/__tests__/content-crypto.test.js.map +1 -0
- package/dist/__tests__/crypto.test.d.ts +2 -0
- package/dist/__tests__/crypto.test.d.ts.map +1 -0
- package/dist/__tests__/crypto.test.js +53 -0
- package/dist/__tests__/crypto.test.js.map +1 -0
- package/dist/__tests__/policy.test.d.ts +2 -0
- package/dist/__tests__/policy.test.d.ts.map +1 -0
- package/dist/__tests__/policy.test.js +80 -0
- package/dist/__tests__/policy.test.js.map +1 -0
- package/dist/__tests__/redact.test.d.ts +2 -0
- package/dist/__tests__/redact.test.d.ts.map +1 -0
- package/dist/__tests__/redact.test.js +39 -0
- package/dist/__tests__/redact.test.js.map +1 -0
- package/dist/__tests__/signing.test.d.ts +2 -0
- package/dist/__tests__/signing.test.d.ts.map +1 -0
- package/dist/__tests__/signing.test.js +51 -0
- package/dist/__tests__/signing.test.js.map +1 -0
- package/dist/content-crypto.d.ts +24 -0
- package/dist/content-crypto.d.ts.map +1 -0
- package/dist/content-crypto.js +58 -0
- package/dist/content-crypto.js.map +1 -0
- package/dist/crypto.d.ts +13 -0
- package/dist/crypto.d.ts.map +1 -0
- package/dist/crypto.js +85 -0
- package/dist/crypto.js.map +1 -0
- package/dist/index.d.ts +9 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +25 -0
- package/dist/index.js.map +1 -0
- package/dist/mcp-catalog.d.ts +15 -0
- package/dist/mcp-catalog.d.ts.map +1 -0
- package/dist/mcp-catalog.js +160 -0
- package/dist/mcp-catalog.js.map +1 -0
- package/dist/plans.d.ts +24 -0
- package/dist/plans.d.ts.map +1 -0
- package/dist/plans.js +80 -0
- package/dist/plans.js.map +1 -0
- package/dist/policy.d.ts +10 -0
- package/dist/policy.d.ts.map +1 -0
- package/dist/policy.js +168 -0
- package/dist/policy.js.map +1 -0
- package/dist/redact.d.ts +4 -0
- package/dist/redact.d.ts.map +1 -0
- package/dist/redact.js +115 -0
- package/dist/redact.js.map +1 -0
- package/dist/schemas.d.ts +128 -0
- package/dist/schemas.d.ts.map +1 -0
- package/dist/schemas.js +47 -0
- package/dist/schemas.js.map +1 -0
- package/dist/signing.d.ts +23 -0
- package/dist/signing.d.ts.map +1 -0
- package/dist/signing.js +96 -0
- package/dist/signing.js.map +1 -0
- package/dist/types.d.ts +184 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +3 -0
- package/dist/types.js.map +1 -0
- package/package.json +29 -0
- package/src/__tests__/policy.test.ts +88 -0
- package/src/__tests__/redact.test.ts +41 -0
- package/src/__tests__/signing.test.ts +55 -0
- package/src/crypto.ts +87 -0
- package/src/index.ts +8 -0
- package/src/mcp-catalog.ts +181 -0
- package/src/plans.ts +96 -0
- package/src/policy.ts +186 -0
- package/src/redact.ts +114 -0
- package/src/schemas.ts +53 -0
- package/src/signing.ts +120 -0
- package/src/types.ts +212 -0
- package/test-gateway.mjs +47 -0
- package/tsconfig.json +10 -0
- package/vitest.config.ts +8 -0
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
|
|
2
|
+
> @agentlock/shared@0.1.0 test D:\agentlock\packages\shared
|
|
3
|
+
> vitest run
|
|
4
|
+
|
|
5
|
+
▲ [WARNING] The condition "types" here will never be used as it comes after both "import" and "require" [package.json]
|
|
6
|
+
|
|
7
|
+
package.json:11:6:
|
|
8
|
+
11 │ "types": "./dist/index.d.ts"
|
|
9
|
+
╵ ~~~~~~~
|
|
10
|
+
|
|
11
|
+
The "import" condition comes earlier and will be used for all "import" statements:
|
|
12
|
+
|
|
13
|
+
package.json:9:6:
|
|
14
|
+
9 │ "import": "./dist/index.js",
|
|
15
|
+
╵ ~~~~~~~~
|
|
16
|
+
|
|
17
|
+
The "require" condition comes earlier and will be used for all "require" calls:
|
|
18
|
+
|
|
19
|
+
package.json:10:6:
|
|
20
|
+
10 │ "require": "./dist/index.js",
|
|
21
|
+
╵ ~~~~~~~~~
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
[1m[46m RUN [49m[22m [36mv4.0.18 [39m[90mD:/agentlock/packages/shared[39m
|
|
25
|
+
|
|
26
|
+
[32m✓[39m src/__tests__/redact.test.ts [2m([22m[2m5 tests[22m[2m)[22m[32m 4[2mms[22m[39m
|
|
27
|
+
[32m✓[39m src/__tests__/policy.test.ts [2m([22m[2m7 tests[22m[2m)[22m[32m 4[2mms[22m[39m
|
|
28
|
+
[32m✓[39m src/__tests__/signing.test.ts [2m([22m[2m7 tests[22m[2m)[22m[32m 68[2mms[22m[39m
|
|
29
|
+
|
|
30
|
+
[2m Test Files [22m [1m[32m3 passed[39m[22m[90m (3)[39m
|
|
31
|
+
[2m Tests [22m [1m[32m19 passed[39m[22m[90m (19)[39m
|
|
32
|
+
[2m Start at [22m 21:09:06
|
|
33
|
+
[2m Duration [22m 482ms[2m (transform 192ms, setup 0ms, import 287ms, tests 75ms, environment 0ms)[22m
|
|
34
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"content-crypto.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/content-crypto.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
const vitest_1 = require("vitest");
|
|
7
|
+
const content_crypto_1 = require("../content-crypto");
|
|
8
|
+
const crypto_1 = require("../crypto");
|
|
9
|
+
const tweetnacl_1 = __importDefault(require("tweetnacl"));
|
|
10
|
+
const tweetnacl_util_1 = require("tweetnacl-util");
|
|
11
|
+
(0, vitest_1.describe)('content-crypto', () => {
|
|
12
|
+
(0, vitest_1.describe)('generateWCK', () => {
|
|
13
|
+
(0, vitest_1.it)('returns a 32-byte key', () => {
|
|
14
|
+
const wck = (0, content_crypto_1.generateWCK)();
|
|
15
|
+
(0, vitest_1.expect)(wck).toBeInstanceOf(Uint8Array);
|
|
16
|
+
(0, vitest_1.expect)(wck.length).toBe(32);
|
|
17
|
+
});
|
|
18
|
+
(0, vitest_1.it)('generates unique keys', () => {
|
|
19
|
+
const a = (0, content_crypto_1.generateWCK)();
|
|
20
|
+
const b = (0, content_crypto_1.generateWCK)();
|
|
21
|
+
(0, vitest_1.expect)(Buffer.from(a).equals(Buffer.from(b))).toBe(false);
|
|
22
|
+
});
|
|
23
|
+
});
|
|
24
|
+
(0, vitest_1.describe)('wrapKey / unwrapKey (server roundtrip)', () => {
|
|
25
|
+
(0, vitest_1.it)('wraps and unwraps a WCK with MASTER_KEY', () => {
|
|
26
|
+
const masterKey = (0, crypto_1.generateKey)();
|
|
27
|
+
const wck = (0, content_crypto_1.generateWCK)();
|
|
28
|
+
const { ciphertext, nonce } = (0, content_crypto_1.wrapKey)(wck, masterKey);
|
|
29
|
+
(0, vitest_1.expect)(typeof ciphertext).toBe('string');
|
|
30
|
+
(0, vitest_1.expect)(typeof nonce).toBe('string');
|
|
31
|
+
const unwrapped = (0, content_crypto_1.unwrapKey)(ciphertext, nonce, masterKey);
|
|
32
|
+
(0, vitest_1.expect)(Buffer.from(unwrapped).equals(Buffer.from(wck))).toBe(true);
|
|
33
|
+
});
|
|
34
|
+
(0, vitest_1.it)('throws with wrong wrapping key', () => {
|
|
35
|
+
const masterKey = (0, crypto_1.generateKey)();
|
|
36
|
+
const wrongKey = (0, crypto_1.generateKey)();
|
|
37
|
+
const wck = (0, content_crypto_1.generateWCK)();
|
|
38
|
+
const { ciphertext, nonce } = (0, content_crypto_1.wrapKey)(wck, masterKey);
|
|
39
|
+
(0, vitest_1.expect)(() => (0, content_crypto_1.unwrapKey)(ciphertext, nonce, wrongKey)).toThrow('unwrapKey failed');
|
|
40
|
+
});
|
|
41
|
+
(0, vitest_1.it)('throws with corrupted ciphertext', () => {
|
|
42
|
+
const masterKey = (0, crypto_1.generateKey)();
|
|
43
|
+
const wck = (0, content_crypto_1.generateWCK)();
|
|
44
|
+
const { ciphertext, nonce } = (0, content_crypto_1.wrapKey)(wck, masterKey);
|
|
45
|
+
// Corrupt ciphertext
|
|
46
|
+
const bytes = (0, tweetnacl_util_1.decodeBase64)(ciphertext);
|
|
47
|
+
bytes[0] ^= 0xff;
|
|
48
|
+
const corrupted = Buffer.from(bytes).toString('base64');
|
|
49
|
+
(0, vitest_1.expect)(() => (0, content_crypto_1.unwrapKey)(corrupted, nonce, masterKey)).toThrow();
|
|
50
|
+
});
|
|
51
|
+
});
|
|
52
|
+
(0, vitest_1.describe)('wrapWCKForUser / unwrapWCKFromUser (passphrase roundtrip)', () => {
|
|
53
|
+
(0, vitest_1.it)('wraps and unwraps with passphrase', () => {
|
|
54
|
+
const wck = (0, content_crypto_1.generateWCK)();
|
|
55
|
+
const passphrase = 'my-strong-passphrase-2024!';
|
|
56
|
+
const { ciphertext, nonce, salt } = (0, content_crypto_1.wrapWCKForUser)(wck, passphrase);
|
|
57
|
+
(0, vitest_1.expect)(typeof ciphertext).toBe('string');
|
|
58
|
+
(0, vitest_1.expect)(typeof nonce).toBe('string');
|
|
59
|
+
(0, vitest_1.expect)(typeof salt).toBe('string');
|
|
60
|
+
const unwrapped = (0, content_crypto_1.unwrapWCKFromUser)(ciphertext, nonce, salt, passphrase);
|
|
61
|
+
(0, vitest_1.expect)(Buffer.from(unwrapped).equals(Buffer.from(wck))).toBe(true);
|
|
62
|
+
});
|
|
63
|
+
(0, vitest_1.it)('throws with wrong passphrase', () => {
|
|
64
|
+
const wck = (0, content_crypto_1.generateWCK)();
|
|
65
|
+
const { ciphertext, nonce, salt } = (0, content_crypto_1.wrapWCKForUser)(wck, 'correct-pass');
|
|
66
|
+
(0, vitest_1.expect)(() => (0, content_crypto_1.unwrapWCKFromUser)(ciphertext, nonce, salt, 'wrong-pass')).toThrow();
|
|
67
|
+
});
|
|
68
|
+
});
|
|
69
|
+
(0, vitest_1.describe)('deriveKEK', () => {
|
|
70
|
+
(0, vitest_1.it)('is deterministic for same passphrase+salt', () => {
|
|
71
|
+
const salt = tweetnacl_1.default.randomBytes(32);
|
|
72
|
+
const kek1 = (0, content_crypto_1.deriveKEK)('test-passphrase', salt);
|
|
73
|
+
const kek2 = (0, content_crypto_1.deriveKEK)('test-passphrase', salt);
|
|
74
|
+
(0, vitest_1.expect)(Buffer.from(kek1).equals(Buffer.from(kek2))).toBe(true);
|
|
75
|
+
});
|
|
76
|
+
(0, vitest_1.it)('produces different keys for different passphrases', () => {
|
|
77
|
+
const salt = tweetnacl_1.default.randomBytes(32);
|
|
78
|
+
const kek1 = (0, content_crypto_1.deriveKEK)('pass-1', salt);
|
|
79
|
+
const kek2 = (0, content_crypto_1.deriveKEK)('pass-2', salt);
|
|
80
|
+
(0, vitest_1.expect)(Buffer.from(kek1).equals(Buffer.from(kek2))).toBe(false);
|
|
81
|
+
});
|
|
82
|
+
(0, vitest_1.it)('produces different keys for different salts', () => {
|
|
83
|
+
const salt1 = tweetnacl_1.default.randomBytes(32);
|
|
84
|
+
const salt2 = tweetnacl_1.default.randomBytes(32);
|
|
85
|
+
const kek1 = (0, content_crypto_1.deriveKEK)('same-pass', salt1);
|
|
86
|
+
const kek2 = (0, content_crypto_1.deriveKEK)('same-pass', salt2);
|
|
87
|
+
(0, vitest_1.expect)(Buffer.from(kek1).equals(Buffer.from(kek2))).toBe(false);
|
|
88
|
+
});
|
|
89
|
+
(0, vitest_1.it)('returns a 32-byte key', () => {
|
|
90
|
+
const salt = tweetnacl_1.default.randomBytes(32);
|
|
91
|
+
const kek = (0, content_crypto_1.deriveKEK)('test', salt);
|
|
92
|
+
(0, vitest_1.expect)(kek.length).toBe(32);
|
|
93
|
+
});
|
|
94
|
+
});
|
|
95
|
+
(0, vitest_1.describe)('cross-compatibility with existing encrypt/decrypt', () => {
|
|
96
|
+
(0, vitest_1.it)('WCK works as a key with existing encrypt/decrypt', () => {
|
|
97
|
+
const wck = (0, content_crypto_1.generateWCK)();
|
|
98
|
+
const data = JSON.stringify({ tool: 'demo.write', action_type: 'write' });
|
|
99
|
+
const encrypted = (0, crypto_1.encrypt)(data, wck);
|
|
100
|
+
const decrypted = (0, crypto_1.decrypt)(encrypted, wck);
|
|
101
|
+
(0, vitest_1.expect)(decrypted).toBe(data);
|
|
102
|
+
});
|
|
103
|
+
(0, vitest_1.it)('data encrypted with WCK cannot be decrypted with MASTER_KEY', () => {
|
|
104
|
+
const wck = (0, content_crypto_1.generateWCK)();
|
|
105
|
+
const masterKey = (0, crypto_1.generateKey)();
|
|
106
|
+
const encrypted = (0, crypto_1.encrypt)('sensitive data', wck);
|
|
107
|
+
(0, vitest_1.expect)(() => (0, crypto_1.decrypt)(encrypted, masterKey)).toThrow();
|
|
108
|
+
});
|
|
109
|
+
});
|
|
110
|
+
(0, vitest_1.describe)('version constants', () => {
|
|
111
|
+
(0, vitest_1.it)('has correct version values', () => {
|
|
112
|
+
(0, vitest_1.expect)(content_crypto_1.PAYLOAD_VERSION_LEGACY).toBe(0);
|
|
113
|
+
(0, vitest_1.expect)(content_crypto_1.PAYLOAD_VERSION_WCK).toBe(1);
|
|
114
|
+
});
|
|
115
|
+
});
|
|
116
|
+
});
|
|
117
|
+
//# sourceMappingURL=content-crypto.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"content-crypto.test.js","sourceRoot":"","sources":["../../src/__tests__/content-crypto.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"crypto.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/crypto.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const vitest_1 = require("vitest");
|
|
4
|
+
const crypto_1 = require("../crypto");
|
|
5
|
+
(0, vitest_1.describe)('crypto', () => {
|
|
6
|
+
(0, vitest_1.describe)('encrypt / decrypt', () => {
|
|
7
|
+
(0, vitest_1.it)('roundtrips plaintext', () => {
|
|
8
|
+
const key = (0, crypto_1.generateKey)();
|
|
9
|
+
const plaintext = 'Hello, world!';
|
|
10
|
+
const encrypted = (0, crypto_1.encrypt)(plaintext, key);
|
|
11
|
+
(0, vitest_1.expect)((0, crypto_1.decrypt)(encrypted, key)).toBe(plaintext);
|
|
12
|
+
});
|
|
13
|
+
(0, vitest_1.it)('throws with wrong key', () => {
|
|
14
|
+
const key = (0, crypto_1.generateKey)();
|
|
15
|
+
const wrongKey = (0, crypto_1.generateKey)();
|
|
16
|
+
const encrypted = (0, crypto_1.encrypt)('secret', key);
|
|
17
|
+
(0, vitest_1.expect)(() => (0, crypto_1.decrypt)(encrypted, wrongKey)).toThrow('Decryption failed');
|
|
18
|
+
});
|
|
19
|
+
(0, vitest_1.it)('handles JSON payloads', () => {
|
|
20
|
+
const key = (0, crypto_1.generateKey)();
|
|
21
|
+
const data = JSON.stringify({ foo: 'bar', num: 42, arr: [1, 2, 3] });
|
|
22
|
+
const encrypted = (0, crypto_1.encrypt)(data, key);
|
|
23
|
+
(0, vitest_1.expect)(JSON.parse((0, crypto_1.decrypt)(encrypted, key))).toEqual(JSON.parse(data));
|
|
24
|
+
});
|
|
25
|
+
});
|
|
26
|
+
(0, vitest_1.describe)('encryptDEK / decryptDEK', () => {
|
|
27
|
+
(0, vitest_1.it)('roundtrips a DEK through master key', () => {
|
|
28
|
+
const masterKey = (0, crypto_1.generateKey)();
|
|
29
|
+
const dek = (0, crypto_1.generateKey)();
|
|
30
|
+
const encrypted = (0, crypto_1.encryptDEK)(dek, masterKey);
|
|
31
|
+
const decrypted = (0, crypto_1.decryptDEK)(encrypted, masterKey);
|
|
32
|
+
(0, vitest_1.expect)(Buffer.from(decrypted).equals(Buffer.from(dek))).toBe(true);
|
|
33
|
+
});
|
|
34
|
+
});
|
|
35
|
+
(0, vitest_1.describe)('encryptCredential / decryptCredential', () => {
|
|
36
|
+
(0, vitest_1.it)('roundtrips a credential payload', () => {
|
|
37
|
+
const masterKey = (0, crypto_1.generateKey)();
|
|
38
|
+
const payload = { api_key: 'sk-test-123', endpoint: 'https://api.example.com' };
|
|
39
|
+
const { encryptedDEK, encryptedPayload } = (0, crypto_1.encryptCredential)(payload, masterKey);
|
|
40
|
+
(0, vitest_1.expect)(typeof encryptedDEK).toBe('string');
|
|
41
|
+
(0, vitest_1.expect)(typeof encryptedPayload).toBe('string');
|
|
42
|
+
const decrypted = (0, crypto_1.decryptCredential)(encryptedDEK, encryptedPayload, masterKey);
|
|
43
|
+
(0, vitest_1.expect)(decrypted).toEqual(payload);
|
|
44
|
+
});
|
|
45
|
+
(0, vitest_1.it)('fails with wrong master key', () => {
|
|
46
|
+
const masterKey = (0, crypto_1.generateKey)();
|
|
47
|
+
const wrongKey = (0, crypto_1.generateKey)();
|
|
48
|
+
const { encryptedDEK, encryptedPayload } = (0, crypto_1.encryptCredential)({ secret: 'value' }, masterKey);
|
|
49
|
+
(0, vitest_1.expect)(() => (0, crypto_1.decryptCredential)(encryptedDEK, encryptedPayload, wrongKey)).toThrow();
|
|
50
|
+
});
|
|
51
|
+
});
|
|
52
|
+
});
|
|
53
|
+
//# sourceMappingURL=crypto.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"crypto.test.js","sourceRoot":"","sources":["../../src/__tests__/crypto.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"policy.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/policy.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const vitest_1 = require("vitest");
|
|
4
|
+
const policy_js_1 = require("../policy.js");
|
|
5
|
+
(0, vitest_1.describe)('Policy Engine', () => {
|
|
6
|
+
(0, vitest_1.it)('should ALLOW read actions by default', () => {
|
|
7
|
+
const action = { action_type: 'read', tool: 'http', payload: {} };
|
|
8
|
+
(0, vitest_1.expect)((0, policy_js_1.evaluatePolicy)(action, policy_js_1.DEFAULT_POLICY_RULES).decision).toBe('ALLOW');
|
|
9
|
+
});
|
|
10
|
+
(0, vitest_1.it)('should REQUIRE_APPROVAL for write actions', () => {
|
|
11
|
+
const action = { action_type: 'write', tool: 'demo', payload: {} };
|
|
12
|
+
(0, vitest_1.expect)((0, policy_js_1.evaluatePolicy)(action, policy_js_1.DEFAULT_POLICY_RULES).decision).toBe('REQUIRE_APPROVAL');
|
|
13
|
+
});
|
|
14
|
+
(0, vitest_1.it)('should BLOCK admin actions', () => {
|
|
15
|
+
const action = { action_type: 'admin', tool: 'system', payload: {} };
|
|
16
|
+
(0, vitest_1.expect)((0, policy_js_1.evaluatePolicy)(action, policy_js_1.DEFAULT_POLICY_RULES).decision).toBe('BLOCK');
|
|
17
|
+
});
|
|
18
|
+
(0, vitest_1.it)('should REQUIRE_APPROVAL for financial actions', () => {
|
|
19
|
+
const action = { action_type: 'financial', tool: 'stripe', payload: {} };
|
|
20
|
+
(0, vitest_1.expect)((0, policy_js_1.evaluatePolicy)(action, policy_js_1.DEFAULT_POLICY_RULES).decision).toBe('REQUIRE_APPROVAL');
|
|
21
|
+
});
|
|
22
|
+
(0, vitest_1.it)('should BLOCK disallowed HTTP domains', () => {
|
|
23
|
+
const action = {
|
|
24
|
+
action_type: 'read',
|
|
25
|
+
tool: 'http',
|
|
26
|
+
payload: { url: 'https://evil.com/data', method: 'GET' },
|
|
27
|
+
};
|
|
28
|
+
const rules = {
|
|
29
|
+
...policy_js_1.DEFAULT_POLICY_RULES,
|
|
30
|
+
http: { allowedDomains: ['trusted.com'], allowedMethods: ['GET'], blockList: [] },
|
|
31
|
+
};
|
|
32
|
+
(0, vitest_1.expect)((0, policy_js_1.evaluatePolicy)(action, rules).decision).toBe('BLOCK');
|
|
33
|
+
});
|
|
34
|
+
(0, vitest_1.it)('should BLOCK explicitly blocklisted domains', () => {
|
|
35
|
+
const action = {
|
|
36
|
+
action_type: 'read',
|
|
37
|
+
tool: 'http',
|
|
38
|
+
payload: { url: 'https://evil.com/data', method: 'GET' },
|
|
39
|
+
};
|
|
40
|
+
const rules = {
|
|
41
|
+
...policy_js_1.DEFAULT_POLICY_RULES,
|
|
42
|
+
http: { allowedDomains: [], allowedMethods: ['GET'], blockList: ['evil.com'] },
|
|
43
|
+
};
|
|
44
|
+
(0, vitest_1.expect)((0, policy_js_1.evaluatePolicy)(action, rules).decision).toBe('BLOCK');
|
|
45
|
+
});
|
|
46
|
+
(0, vitest_1.it)('should ALLOW admin actions when defaultMode is allow and no matching rule', () => {
|
|
47
|
+
const action = { action_type: 'admin', tool: 'system', payload: {} };
|
|
48
|
+
const rules = { ...policy_js_1.DEFAULT_POLICY_RULES, defaultMode: 'allow', rules: [] };
|
|
49
|
+
const result = (0, policy_js_1.evaluatePolicy)(action, rules);
|
|
50
|
+
(0, vitest_1.expect)(result.decision).toBe('ALLOW');
|
|
51
|
+
(0, vitest_1.expect)(result.reason).toBe('Default policy');
|
|
52
|
+
});
|
|
53
|
+
(0, vitest_1.it)('should ALLOW financial actions when defaultMode is allow and no matching rule', () => {
|
|
54
|
+
const action = { action_type: 'financial', tool: 'stripe', payload: {} };
|
|
55
|
+
const rules = { ...policy_js_1.DEFAULT_POLICY_RULES, defaultMode: 'allow', rules: [] };
|
|
56
|
+
const result = (0, policy_js_1.evaluatePolicy)(action, rules);
|
|
57
|
+
(0, vitest_1.expect)(result.decision).toBe('ALLOW');
|
|
58
|
+
(0, vitest_1.expect)(result.reason).toBe('Default policy');
|
|
59
|
+
});
|
|
60
|
+
(0, vitest_1.it)('should still respect explicit rules for admin even with defaultMode allow', () => {
|
|
61
|
+
const action = { action_type: 'admin', tool: 'system', payload: {} };
|
|
62
|
+
const rules = {
|
|
63
|
+
...policy_js_1.DEFAULT_POLICY_RULES,
|
|
64
|
+
defaultMode: 'allow',
|
|
65
|
+
rules: [{ action_type: 'admin', decision: 'BLOCK' }],
|
|
66
|
+
};
|
|
67
|
+
(0, vitest_1.expect)((0, policy_js_1.evaluatePolicy)(action, rules).decision).toBe('BLOCK');
|
|
68
|
+
});
|
|
69
|
+
(0, vitest_1.it)('should BLOCK when cost exceeds limit', () => {
|
|
70
|
+
const action = {
|
|
71
|
+
action_type: 'financial',
|
|
72
|
+
tool: 'stripe',
|
|
73
|
+
payload: {},
|
|
74
|
+
cost_estimate: 1000,
|
|
75
|
+
};
|
|
76
|
+
const rules = { ...policy_js_1.DEFAULT_POLICY_RULES, limits: { maxCostPerAction: 100 } };
|
|
77
|
+
(0, vitest_1.expect)((0, policy_js_1.evaluatePolicy)(action, rules).decision).toBe('BLOCK');
|
|
78
|
+
});
|
|
79
|
+
});
|
|
80
|
+
//# sourceMappingURL=policy.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"policy.test.js","sourceRoot":"","sources":["../../src/__tests__/policy.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"redact.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/redact.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const vitest_1 = require("vitest");
|
|
4
|
+
const redact_js_1 = require("../redact.js");
|
|
5
|
+
(0, vitest_1.describe)('Redaction', () => {
|
|
6
|
+
(0, vitest_1.it)('should redact api_key fields', () => {
|
|
7
|
+
const obj = { name: 'test', api_key: 'super-secret-123', data: { token: 'abc' } };
|
|
8
|
+
const result = (0, redact_js_1.redact)(obj);
|
|
9
|
+
(0, vitest_1.expect)(result.api_key).toBe('[REDACTED]');
|
|
10
|
+
(0, vitest_1.expect)(result.data.token).toBe('[REDACTED]');
|
|
11
|
+
(0, vitest_1.expect)(result.name).toBe('test');
|
|
12
|
+
});
|
|
13
|
+
(0, vitest_1.it)('should redact Authorization headers', () => {
|
|
14
|
+
const headers = { Authorization: 'Bearer secret', 'Content-Type': 'application/json' };
|
|
15
|
+
const result = (0, redact_js_1.redactHeaders)(headers);
|
|
16
|
+
(0, vitest_1.expect)(result['Authorization']).toBe('[REDACTED]');
|
|
17
|
+
(0, vitest_1.expect)(result['Content-Type']).toBe('application/json');
|
|
18
|
+
});
|
|
19
|
+
(0, vitest_1.it)('should handle nested objects', () => {
|
|
20
|
+
const obj = { level1: { level2: { password: 'secret', safe: 'ok' } } };
|
|
21
|
+
const result = (0, redact_js_1.redact)(obj);
|
|
22
|
+
(0, vitest_1.expect)(result.level1.level2.password).toBe('[REDACTED]');
|
|
23
|
+
(0, vitest_1.expect)(result.level1.level2.safe).toBe('ok');
|
|
24
|
+
});
|
|
25
|
+
(0, vitest_1.it)('should handle arrays', () => {
|
|
26
|
+
const obj = { items: [{ token: 'secret1' }, { token: 'secret2' }] };
|
|
27
|
+
const result = (0, redact_js_1.redact)(obj);
|
|
28
|
+
(0, vitest_1.expect)(result.items[0].token).toBe('[REDACTED]');
|
|
29
|
+
(0, vitest_1.expect)(result.items[1].token).toBe('[REDACTED]');
|
|
30
|
+
});
|
|
31
|
+
(0, vitest_1.it)('should not redact safe fields', () => {
|
|
32
|
+
const obj = { name: 'test', url: 'https://example.com', status: 200 };
|
|
33
|
+
const result = (0, redact_js_1.redact)(obj);
|
|
34
|
+
(0, vitest_1.expect)(result.name).toBe('test');
|
|
35
|
+
(0, vitest_1.expect)(result.url).toBe('https://example.com');
|
|
36
|
+
(0, vitest_1.expect)(result.status).toBe(200);
|
|
37
|
+
});
|
|
38
|
+
});
|
|
39
|
+
//# sourceMappingURL=redact.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"redact.test.js","sourceRoot":"","sources":["../../src/__tests__/redact.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"signing.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/signing.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const vitest_1 = require("vitest");
|
|
4
|
+
const signing_js_1 = require("../signing.js");
|
|
5
|
+
(0, vitest_1.describe)('Ed25519 Signing', () => {
|
|
6
|
+
(0, vitest_1.it)('should generate valid keypair', () => {
|
|
7
|
+
const kp = (0, signing_js_1.generateKeypair)();
|
|
8
|
+
(0, vitest_1.expect)(kp.publicKey).toBeTruthy();
|
|
9
|
+
(0, vitest_1.expect)(kp.privateKey).toBeTruthy();
|
|
10
|
+
(0, vitest_1.expect)(kp.publicKey.length).toBeGreaterThan(0);
|
|
11
|
+
});
|
|
12
|
+
(0, vitest_1.it)('should sign and verify a request', () => {
|
|
13
|
+
const kp = (0, signing_js_1.generateKeypair)();
|
|
14
|
+
const body = { action_type: 'write', tool: 'demo', payload: { key: 'value' } };
|
|
15
|
+
const headers = (0, signing_js_1.signRequest)(body, 'agent-123', kp.privateKey);
|
|
16
|
+
(0, vitest_1.expect)(() => (0, signing_js_1.verifyRequest)(body, headers, kp.publicKey)).not.toThrow();
|
|
17
|
+
});
|
|
18
|
+
(0, vitest_1.it)('should reject tampered body (top-level field)', () => {
|
|
19
|
+
const kp = (0, signing_js_1.generateKeypair)();
|
|
20
|
+
const body = { action_type: 'write', tool: 'demo', payload: { key: 'value' } };
|
|
21
|
+
const headers = (0, signing_js_1.signRequest)(body, 'agent-123', kp.privateKey);
|
|
22
|
+
const tampered = { ...body, tool: 'admin' };
|
|
23
|
+
(0, vitest_1.expect)(() => (0, signing_js_1.verifyRequest)(tampered, headers, kp.publicKey)).toThrow('Invalid signature');
|
|
24
|
+
});
|
|
25
|
+
(0, vitest_1.it)('should reject tampered nested payload field', () => {
|
|
26
|
+
const kp = (0, signing_js_1.generateKeypair)();
|
|
27
|
+
const body = { action_type: 'write', tool: 'demo', payload: { key: 'value', amount: 100 } };
|
|
28
|
+
const headers = (0, signing_js_1.signRequest)(body, 'agent-123', kp.privateKey);
|
|
29
|
+
const tampered = { ...body, payload: { key: 'value', amount: 999999 } };
|
|
30
|
+
(0, vitest_1.expect)(() => (0, signing_js_1.verifyRequest)(tampered, headers, kp.publicKey)).toThrow('Invalid signature');
|
|
31
|
+
});
|
|
32
|
+
(0, vitest_1.it)('canonicalStringify should sort keys recursively at all nesting levels', () => {
|
|
33
|
+
const obj = { z: 1, a: { y: 2, b: 3 }, m: [{ q: 4, c: 5 }] };
|
|
34
|
+
const result = (0, signing_js_1.canonicalStringify)(obj);
|
|
35
|
+
// All object levels must have sorted keys
|
|
36
|
+
(0, vitest_1.expect)(result).toBe('{"a":{"b":3,"y":2},"m":[{"c":5,"q":4}],"z":1}');
|
|
37
|
+
});
|
|
38
|
+
(0, vitest_1.it)('should reject missing headers', () => {
|
|
39
|
+
const kp = (0, signing_js_1.generateKeypair)();
|
|
40
|
+
const body = { action_type: 'write', tool: 'demo', payload: {} };
|
|
41
|
+
(0, vitest_1.expect)(() => (0, signing_js_1.verifyRequest)(body, {}, kp.publicKey)).toThrow('Missing required signature headers');
|
|
42
|
+
});
|
|
43
|
+
(0, vitest_1.it)('should reject stale timestamp', () => {
|
|
44
|
+
const kp = (0, signing_js_1.generateKeypair)();
|
|
45
|
+
const body = { action_type: 'write', tool: 'demo', payload: {} };
|
|
46
|
+
const headers = (0, signing_js_1.signRequest)(body, 'agent-123', kp.privateKey);
|
|
47
|
+
headers['x-timestamp'] = String(Date.now() - 10 * 60 * 1000);
|
|
48
|
+
(0, vitest_1.expect)(() => (0, signing_js_1.verifyRequest)(body, headers, kp.publicKey)).toThrow('Timestamp skew');
|
|
49
|
+
});
|
|
50
|
+
});
|
|
51
|
+
//# sourceMappingURL=signing.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"signing.test.js","sourceRoot":"","sources":["../../src/__tests__/signing.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/** Payload encrypted with MASTER_KEY (legacy) */
|
|
2
|
+
export declare const PAYLOAD_VERSION_LEGACY = 0;
|
|
3
|
+
/** Payload encrypted with per-workspace WCK */
|
|
4
|
+
export declare const PAYLOAD_VERSION_WCK = 1;
|
|
5
|
+
/** Generate a random 32-byte Workspace Content Key */
|
|
6
|
+
export declare function generateWCK(): Uint8Array;
|
|
7
|
+
/** Wrap a WCK using a wrapping key (e.g. MASTER_KEY). Returns base64 ciphertext + nonce. */
|
|
8
|
+
export declare function wrapKey(wck: Uint8Array, wrappingKey: Uint8Array): {
|
|
9
|
+
ciphertext: string;
|
|
10
|
+
nonce: string;
|
|
11
|
+
};
|
|
12
|
+
/** Unwrap a WCK using a wrapping key. Returns the raw 32-byte WCK. */
|
|
13
|
+
export declare function unwrapKey(ciphertext: string, nonce: string, wrappingKey: Uint8Array): Uint8Array;
|
|
14
|
+
/** Derive a Key Encryption Key from a passphrase using scrypt. */
|
|
15
|
+
export declare function deriveKEK(passphrase: string, salt: Uint8Array): Uint8Array;
|
|
16
|
+
/** Wrap a WCK for a user using their passphrase. Returns base64 strings. */
|
|
17
|
+
export declare function wrapWCKForUser(wck: Uint8Array, passphrase: string): {
|
|
18
|
+
ciphertext: string;
|
|
19
|
+
nonce: string;
|
|
20
|
+
salt: string;
|
|
21
|
+
};
|
|
22
|
+
/** Unwrap a WCK using a user's passphrase. Returns the raw 32-byte WCK. */
|
|
23
|
+
export declare function unwrapWCKFromUser(ciphertext: string, nonce: string, salt: string, passphrase: string): Uint8Array;
|
|
24
|
+
//# sourceMappingURL=content-crypto.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"content-crypto.d.ts","sourceRoot":"","sources":["../src/content-crypto.ts"],"names":[],"mappings":"AAIA,iDAAiD;AACjD,eAAO,MAAM,sBAAsB,IAAI,CAAC;AACxC,+CAA+C;AAC/C,eAAO,MAAM,mBAAmB,IAAI,CAAC;AAErC,sDAAsD;AACtD,wBAAgB,WAAW,IAAI,UAAU,CAExC;AAED,4FAA4F;AAC5F,wBAAgB,OAAO,CACrB,GAAG,EAAE,UAAU,EACf,WAAW,EAAE,UAAU,GACtB;IAAE,UAAU,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAIvC;AAED,sEAAsE;AACtE,wBAAgB,SAAS,CACvB,UAAU,EAAE,MAAM,EAClB,KAAK,EAAE,MAAM,EACb,WAAW,EAAE,UAAU,GACtB,UAAU,CAQZ;AAED,kEAAkE;AAClE,wBAAgB,SAAS,CACvB,UAAU,EAAE,MAAM,EAClB,IAAI,EAAE,UAAU,GACf,UAAU,CAGZ;AAED,4EAA4E;AAC5E,wBAAgB,cAAc,CAC5B,GAAG,EAAE,UAAU,EACf,UAAU,EAAE,MAAM,GACjB;IAAE,UAAU,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAKrD;AAED,2EAA2E;AAC3E,wBAAgB,iBAAiB,CAC/B,UAAU,EAAE,MAAM,EAClB,KAAK,EAAE,MAAM,EACb,IAAI,EAAE,MAAM,EACZ,UAAU,EAAE,MAAM,GACjB,UAAU,CAIZ"}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.PAYLOAD_VERSION_WCK = exports.PAYLOAD_VERSION_LEGACY = void 0;
|
|
7
|
+
exports.generateWCK = generateWCK;
|
|
8
|
+
exports.wrapKey = wrapKey;
|
|
9
|
+
exports.unwrapKey = unwrapKey;
|
|
10
|
+
exports.deriveKEK = deriveKEK;
|
|
11
|
+
exports.wrapWCKForUser = wrapWCKForUser;
|
|
12
|
+
exports.unwrapWCKFromUser = unwrapWCKFromUser;
|
|
13
|
+
const tweetnacl_1 = __importDefault(require("tweetnacl"));
|
|
14
|
+
const tweetnacl_util_1 = require("tweetnacl-util");
|
|
15
|
+
const scrypt_1 = require("@noble/hashes/scrypt");
|
|
16
|
+
/** Payload encrypted with MASTER_KEY (legacy) */
|
|
17
|
+
exports.PAYLOAD_VERSION_LEGACY = 0;
|
|
18
|
+
/** Payload encrypted with per-workspace WCK */
|
|
19
|
+
exports.PAYLOAD_VERSION_WCK = 1;
|
|
20
|
+
/** Generate a random 32-byte Workspace Content Key */
|
|
21
|
+
function generateWCK() {
|
|
22
|
+
return tweetnacl_1.default.randomBytes(32);
|
|
23
|
+
}
|
|
24
|
+
/** Wrap a WCK using a wrapping key (e.g. MASTER_KEY). Returns base64 ciphertext + nonce. */
|
|
25
|
+
function wrapKey(wck, wrappingKey) {
|
|
26
|
+
const nonce = tweetnacl_1.default.randomBytes(tweetnacl_1.default.secretbox.nonceLength);
|
|
27
|
+
const box = tweetnacl_1.default.secretbox(wck, nonce, wrappingKey);
|
|
28
|
+
return { ciphertext: (0, tweetnacl_util_1.encodeBase64)(box), nonce: (0, tweetnacl_util_1.encodeBase64)(nonce) };
|
|
29
|
+
}
|
|
30
|
+
/** Unwrap a WCK using a wrapping key. Returns the raw 32-byte WCK. */
|
|
31
|
+
function unwrapKey(ciphertext, nonce, wrappingKey) {
|
|
32
|
+
const box = (0, tweetnacl_util_1.decodeBase64)(ciphertext);
|
|
33
|
+
const n = (0, tweetnacl_util_1.decodeBase64)(nonce);
|
|
34
|
+
const result = tweetnacl_1.default.secretbox.open(box, n, wrappingKey);
|
|
35
|
+
if (!result) {
|
|
36
|
+
throw new Error('unwrapKey failed: invalid wrapping key or corrupted data');
|
|
37
|
+
}
|
|
38
|
+
return result;
|
|
39
|
+
}
|
|
40
|
+
/** Derive a Key Encryption Key from a passphrase using scrypt. */
|
|
41
|
+
function deriveKEK(passphrase, salt) {
|
|
42
|
+
const pw = new TextEncoder().encode(passphrase);
|
|
43
|
+
return (0, scrypt_1.scrypt)(pw, salt, { N: 2 ** 15, r: 8, p: 1, dkLen: 32 });
|
|
44
|
+
}
|
|
45
|
+
/** Wrap a WCK for a user using their passphrase. Returns base64 strings. */
|
|
46
|
+
function wrapWCKForUser(wck, passphrase) {
|
|
47
|
+
const salt = tweetnacl_1.default.randomBytes(32);
|
|
48
|
+
const kek = deriveKEK(passphrase, salt);
|
|
49
|
+
const { ciphertext, nonce } = wrapKey(wck, kek);
|
|
50
|
+
return { ciphertext, nonce, salt: (0, tweetnacl_util_1.encodeBase64)(salt) };
|
|
51
|
+
}
|
|
52
|
+
/** Unwrap a WCK using a user's passphrase. Returns the raw 32-byte WCK. */
|
|
53
|
+
function unwrapWCKFromUser(ciphertext, nonce, salt, passphrase) {
|
|
54
|
+
const saltBytes = (0, tweetnacl_util_1.decodeBase64)(salt);
|
|
55
|
+
const kek = deriveKEK(passphrase, saltBytes);
|
|
56
|
+
return unwrapKey(ciphertext, nonce, kek);
|
|
57
|
+
}
|
|
58
|
+
//# sourceMappingURL=content-crypto.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"content-crypto.js","sourceRoot":"","sources":["../src/content-crypto.ts"],"names":[],"mappings":";;;;;;AAUA,kCAEC;AAGD,0BAOC;AAGD,8BAYC;AAGD,8BAMC;AAGD,wCAQC;AAGD,8CASC;AArED,0DAA6B;AAC7B,mDAA4D;AAC5D,iDAA8C;AAE9C,iDAAiD;AACpC,QAAA,sBAAsB,GAAG,CAAC,CAAC;AACxC,+CAA+C;AAClC,QAAA,mBAAmB,GAAG,CAAC,CAAC;AAErC,sDAAsD;AACtD,SAAgB,WAAW;IACzB,OAAO,mBAAI,CAAC,WAAW,CAAC,EAAE,CAAC,CAAC;AAC9B,CAAC;AAED,4FAA4F;AAC5F,SAAgB,OAAO,CACrB,GAAe,EACf,WAAuB;IAEvB,MAAM,KAAK,GAAG,mBAAI,CAAC,WAAW,CAAC,mBAAI,CAAC,SAAS,CAAC,WAAW,CAAC,CAAC;IAC3D,MAAM,GAAG,GAAG,mBAAI,CAAC,SAAS,CAAC,GAAG,EAAE,KAAK,EAAE,WAAW,CAAC,CAAC;IACpD,OAAO,EAAE,UAAU,EAAE,IAAA,6BAAY,EAAC,GAAG,CAAC,EAAE,KAAK,EAAE,IAAA,6BAAY,EAAC,KAAK,CAAC,EAAE,CAAC;AACvE,CAAC;AAED,sEAAsE;AACtE,SAAgB,SAAS,CACvB,UAAkB,EAClB,KAAa,EACb,WAAuB;IAEvB,MAAM,GAAG,GAAG,IAAA,6BAAY,EAAC,UAAU,CAAC,CAAC;IACrC,MAAM,CAAC,GAAG,IAAA,6BAAY,EAAC,KAAK,CAAC,CAAC;IAC9B,MAAM,MAAM,GAAG,mBAAI,CAAC,SAAS,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,EAAE,WAAW,CAAC,CAAC;IACxD,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,MAAM,IAAI,KAAK,CAAC,0DAA0D,CAAC,CAAC;IAC9E,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,kEAAkE;AAClE,SAAgB,SAAS,CACvB,UAAkB,EAClB,IAAgB;IAEhB,MAAM,EAAE,GAAG,IAAI,WAAW,EAAE,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC;IAChD,OAAO,IAAA,eAAM,EAAC,EAAE,EAAE,IAAI,EAAE,EAAE,CAAC,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,KAAK,EAAE,EAAE,EAAE,CAAC,CAAC;AACjE,CAAC;AAED,4EAA4E;AAC5E,SAAgB,cAAc,CAC5B,GAAe,EACf,UAAkB;IAElB,MAAM,IAAI,GAAG,mBAAI,CAAC,WAAW,CAAC,EAAE,CAAC,CAAC;IAClC,MAAM,GAAG,GAAG,SAAS,CAAC,UAAU,EAAE,IAAI,CAAC,CAAC;IACxC,MAAM,EAAE,UAAU,EAAE,KAAK,EAAE,GAAG,OAAO,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;IAChD,OAAO,EAAE,UAAU,EAAE,KAAK,EAAE,IAAI,EAAE,IAAA,6BAAY,EAAC,IAAI,CAAC,EAAE,CAAC;AACzD,CAAC;AAED,2EAA2E;AAC3E,SAAgB,iBAAiB,CAC/B,UAAkB,EAClB,KAAa,EACb,IAAY,EACZ,UAAkB;IAElB,MAAM,SAAS,GAAG,IAAA,6BAAY,EAAC,IAAI,CAAC,CAAC;IACrC,MAAM,GAAG,GAAG,SAAS,CAAC,UAAU,EAAE,SAAS,CAAC,CAAC;IAC7C,OAAO,SAAS,CAAC,UAAU,EAAE,KAAK,EAAE,GAAG,CAAC,CAAC;AAC3C,CAAC"}
|
package/dist/crypto.d.ts
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export declare function generateKey(): Uint8Array;
|
|
2
|
+
export declare function encrypt(data: string, key: Uint8Array): string;
|
|
3
|
+
export declare function decrypt(encryptedData: string, key: Uint8Array): string;
|
|
4
|
+
export declare function encryptDEK(dek: Uint8Array, masterKey: Uint8Array): string;
|
|
5
|
+
export declare function decryptDEK(encryptedDEK: string, masterKey: Uint8Array): Uint8Array;
|
|
6
|
+
export declare function getMasterKey(): Uint8Array;
|
|
7
|
+
export declare function generateMasterKey(): string;
|
|
8
|
+
export declare function encryptCredential(payload: Record<string, unknown>, masterKey: Uint8Array): {
|
|
9
|
+
encryptedDEK: string;
|
|
10
|
+
encryptedPayload: string;
|
|
11
|
+
};
|
|
12
|
+
export declare function decryptCredential(encryptedDEK: string, encryptedPayload: string, masterKey: Uint8Array): Record<string, unknown>;
|
|
13
|
+
//# sourceMappingURL=crypto.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"crypto.d.ts","sourceRoot":"","sources":["../src/crypto.ts"],"names":[],"mappings":"AAGA,wBAAgB,WAAW,IAAI,UAAU,CAExC;AAED,wBAAgB,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,UAAU,GAAG,MAAM,CAU7D;AAED,wBAAgB,OAAO,CAAC,aAAa,EAAE,MAAM,EAAE,GAAG,EAAE,UAAU,GAAG,MAAM,CAWtE;AAED,wBAAgB,UAAU,CAAC,GAAG,EAAE,UAAU,EAAE,SAAS,EAAE,UAAU,GAAG,MAAM,CAEzE;AAED,wBAAgB,UAAU,CAAC,YAAY,EAAE,MAAM,EAAE,SAAS,EAAE,UAAU,GAAG,UAAU,CAGlF;AAMD,wBAAgB,YAAY,IAAI,UAAU,CAMzC;AAED,wBAAgB,iBAAiB,IAAI,MAAM,CAE1C;AAED,wBAAgB,iBAAiB,CAC/B,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAChC,SAAS,EAAE,UAAU,GACpB;IAAE,YAAY,EAAE,MAAM,CAAC;IAAC,gBAAgB,EAAE,MAAM,CAAA;CAAE,CAUpD;AAED,wBAAgB,iBAAiB,CAC/B,YAAY,EAAE,MAAM,EACpB,gBAAgB,EAAE,MAAM,EACxB,SAAS,EAAE,UAAU,GACpB,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAUzB"}
|