@1claw/cli 0.34.0 → 0.34.2
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/README.md +122 -1
- package/dist/src/ai-clients.d.ts +19 -0
- package/dist/src/ai-clients.d.ts.map +1 -0
- package/dist/src/ai-clients.js +218 -0
- package/dist/src/ai-clients.js.map +1 -0
- package/dist/src/commands/daemon.d.ts +3 -0
- package/dist/src/commands/daemon.d.ts.map +1 -0
- package/dist/src/commands/daemon.js +347 -0
- package/dist/src/commands/daemon.js.map +1 -0
- package/dist/src/commands/env.d.ts.map +1 -1
- package/dist/src/commands/env.js +122 -19
- package/dist/src/commands/env.js.map +1 -1
- package/dist/src/commands/import.d.ts +3 -0
- package/dist/src/commands/import.d.ts.map +1 -0
- package/dist/src/commands/import.js +175 -0
- package/dist/src/commands/import.js.map +1 -0
- package/dist/src/commands/local.d.ts +3 -0
- package/dist/src/commands/local.d.ts.map +1 -0
- package/dist/src/commands/local.js +505 -0
- package/dist/src/commands/local.js.map +1 -0
- package/dist/src/commands/setup.d.ts +3 -0
- package/dist/src/commands/setup.d.ts.map +1 -0
- package/dist/src/commands/setup.js +304 -0
- package/dist/src/commands/setup.js.map +1 -0
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +9 -0
- package/dist/src/index.js.map +1 -1
- package/dist/src/local-cache.d.ts +19 -0
- package/dist/src/local-cache.d.ts.map +1 -0
- package/dist/src/local-cache.js +131 -0
- package/dist/src/local-cache.js.map +1 -0
- package/dist/src/local-policy.d.ts +39 -0
- package/dist/src/local-policy.d.ts.map +1 -0
- package/dist/src/local-policy.js +123 -0
- package/dist/src/local-policy.js.map +1 -0
- package/dist/src/local-vault.d.ts +39 -0
- package/dist/src/local-vault.d.ts.map +1 -0
- package/dist/src/local-vault.js +166 -0
- package/dist/src/local-vault.js.map +1 -0
- package/dist/src/secret-proxy.d.ts +27 -0
- package/dist/src/secret-proxy.d.ts.map +1 -0
- package/dist/src/secret-proxy.js +73 -0
- package/dist/src/secret-proxy.js.map +1 -0
- package/package.json +1 -1
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
import { existsSync, readFileSync, writeFileSync } from "node:fs";
|
|
2
|
+
import { homedir } from "node:os";
|
|
3
|
+
import { join } from "node:path";
|
|
4
|
+
const CONFIG_DIR = process.env.ONECLAW_CONFIG_DIR || join(homedir(), ".config", "1claw");
|
|
5
|
+
export const POLICY_FILE = join(CONFIG_DIR, "policy.json");
|
|
6
|
+
const DEFAULT_POLICY = {
|
|
7
|
+
version: 1,
|
|
8
|
+
defaults: {
|
|
9
|
+
inject_as: "bearer",
|
|
10
|
+
header_name: "Authorization",
|
|
11
|
+
},
|
|
12
|
+
secrets: {},
|
|
13
|
+
};
|
|
14
|
+
export function loadPolicy() {
|
|
15
|
+
if (!existsSync(POLICY_FILE)) {
|
|
16
|
+
return { ...DEFAULT_POLICY, secrets: {} };
|
|
17
|
+
}
|
|
18
|
+
try {
|
|
19
|
+
return JSON.parse(readFileSync(POLICY_FILE, "utf-8"));
|
|
20
|
+
}
|
|
21
|
+
catch {
|
|
22
|
+
return { ...DEFAULT_POLICY, secrets: {} };
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
export function savePolicy(policy) {
|
|
26
|
+
writeFileSync(POLICY_FILE, JSON.stringify(policy, null, 2) + "\n", "utf-8");
|
|
27
|
+
}
|
|
28
|
+
export function policyExists() {
|
|
29
|
+
return existsSync(POLICY_FILE);
|
|
30
|
+
}
|
|
31
|
+
export function getPolicyPath() {
|
|
32
|
+
return POLICY_FILE;
|
|
33
|
+
}
|
|
34
|
+
export function getSecretPolicy(policy, secretName) {
|
|
35
|
+
return policy.secrets[secretName] ?? null;
|
|
36
|
+
}
|
|
37
|
+
export function setSecretPolicy(policy, secretName, sp) {
|
|
38
|
+
policy.secrets[secretName] = sp;
|
|
39
|
+
}
|
|
40
|
+
export function removeSecretPolicy(policy, secretName) {
|
|
41
|
+
if (!(secretName in policy.secrets))
|
|
42
|
+
return false;
|
|
43
|
+
delete policy.secrets[secretName];
|
|
44
|
+
return true;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Check if a request URL is allowed by the secret's policy.
|
|
48
|
+
* When no policy exists for a secret, all hosts are denied by default
|
|
49
|
+
* (fail-closed — the daemon won't inject a secret without a policy).
|
|
50
|
+
*/
|
|
51
|
+
export function isHostAllowed(policy, secretName, targetUrl) {
|
|
52
|
+
const sp = policy.secrets[secretName];
|
|
53
|
+
if (!sp) {
|
|
54
|
+
return {
|
|
55
|
+
allowed: false,
|
|
56
|
+
reason: `No policy defined for secret "${secretName}". Add one with: 1claw daemon policy add ${secretName} --hosts <host1,host2>`,
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
if (sp.allowed_hosts.length === 0) {
|
|
60
|
+
return {
|
|
61
|
+
allowed: false,
|
|
62
|
+
reason: `Secret "${secretName}" has an empty allowed_hosts list.`,
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
let hostname;
|
|
66
|
+
try {
|
|
67
|
+
hostname = new URL(targetUrl).hostname;
|
|
68
|
+
}
|
|
69
|
+
catch {
|
|
70
|
+
return {
|
|
71
|
+
allowed: false,
|
|
72
|
+
reason: `Invalid URL: "${targetUrl}"`,
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
for (const pattern of sp.allowed_hosts) {
|
|
76
|
+
if (pattern === "*") {
|
|
77
|
+
return { allowed: true, reason: "Wildcard policy" };
|
|
78
|
+
}
|
|
79
|
+
if (pattern.startsWith("*.")) {
|
|
80
|
+
const suffix = pattern.slice(2);
|
|
81
|
+
if (hostname === suffix || hostname.endsWith("." + suffix)) {
|
|
82
|
+
return { allowed: true, reason: `Matches *.${suffix}` };
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
else if (hostname === pattern) {
|
|
86
|
+
return { allowed: true, reason: `Matches ${pattern}` };
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
return {
|
|
90
|
+
allowed: false,
|
|
91
|
+
reason: `Host "${hostname}" is not in the allowed list for "${secretName}": [${sp.allowed_hosts.join(", ")}]`,
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Resolve how to inject a secret into a request.
|
|
96
|
+
*/
|
|
97
|
+
export function resolveInjection(policy, secretName, secretValue) {
|
|
98
|
+
const sp = policy.secrets[secretName];
|
|
99
|
+
const injectAs = sp?.inject_as ?? policy.defaults.inject_as;
|
|
100
|
+
const headers = {};
|
|
101
|
+
const queryParams = {};
|
|
102
|
+
switch (injectAs) {
|
|
103
|
+
case "bearer":
|
|
104
|
+
headers["Authorization"] = `Bearer ${secretValue}`;
|
|
105
|
+
break;
|
|
106
|
+
case "basic":
|
|
107
|
+
headers["Authorization"] =
|
|
108
|
+
`Basic ${Buffer.from(secretValue).toString("base64")}`;
|
|
109
|
+
break;
|
|
110
|
+
case "header": {
|
|
111
|
+
const headerName = sp?.header_name ?? policy.defaults.header_name ?? "Authorization";
|
|
112
|
+
headers[headerName] = secretValue;
|
|
113
|
+
break;
|
|
114
|
+
}
|
|
115
|
+
case "query": {
|
|
116
|
+
const param = sp?.query_param ?? secretName;
|
|
117
|
+
queryParams[param] = secretValue;
|
|
118
|
+
break;
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
return { headers, queryParams };
|
|
122
|
+
}
|
|
123
|
+
//# sourceMappingURL=local-policy.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"local-policy.js","sourceRoot":"","sources":["../../src/local-policy.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
export interface LocalSecret {
|
|
2
|
+
value: string;
|
|
3
|
+
type: string;
|
|
4
|
+
created_at: string;
|
|
5
|
+
updated_at: string;
|
|
6
|
+
synced_to_cloud: boolean;
|
|
7
|
+
cloud_vault_id: string | null;
|
|
8
|
+
cloud_path: string | null;
|
|
9
|
+
}
|
|
10
|
+
export interface LocalVaultData {
|
|
11
|
+
version: number;
|
|
12
|
+
created_at: string;
|
|
13
|
+
updated_at: string;
|
|
14
|
+
secrets: Record<string, LocalSecret>;
|
|
15
|
+
}
|
|
16
|
+
export declare function getVaultPath(): string;
|
|
17
|
+
export declare function vaultExists(): boolean;
|
|
18
|
+
export declare function createVault(passphrase: string): LocalVaultData;
|
|
19
|
+
export declare function loadVault(passphrase: string): LocalVaultData;
|
|
20
|
+
export declare function saveVault(vault: LocalVaultData, passphrase: string): void;
|
|
21
|
+
export declare function addSecret(vault: LocalVaultData, name: string, value: string, type?: string): void;
|
|
22
|
+
export declare function removeSecret(vault: LocalVaultData, name: string): boolean;
|
|
23
|
+
export declare function getSecret(vault: LocalVaultData, name: string): LocalSecret | null;
|
|
24
|
+
export declare function listSecrets(vault: LocalVaultData): Array<{
|
|
25
|
+
name: string;
|
|
26
|
+
type: string;
|
|
27
|
+
synced: boolean;
|
|
28
|
+
updated_at: string;
|
|
29
|
+
}>;
|
|
30
|
+
export declare function markSynced(vault: LocalVaultData, name: string, cloudVaultId: string, cloudPath: string): void;
|
|
31
|
+
export declare function getVaultInfo(): {
|
|
32
|
+
exists: boolean;
|
|
33
|
+
sizeBytes?: number;
|
|
34
|
+
path: string;
|
|
35
|
+
};
|
|
36
|
+
export declare function deleteVault(): boolean;
|
|
37
|
+
export declare function exportAsEnv(vault: LocalVaultData): string;
|
|
38
|
+
export declare function fingerprintPassphrase(passphrase: string): string;
|
|
39
|
+
//# sourceMappingURL=local-vault.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"local-vault.d.ts","sourceRoot":"","sources":["../../src/local-vault.ts"],"names":[],"mappings":"AAiCA,MAAM,WAAW,WAAW;IACxB,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,eAAe,EAAE,OAAO,CAAC;IACzB,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;CAC7B;AAED,MAAM,WAAW,cAAc;IAC3B,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC;CACxC;AAuDD,wBAAgB,YAAY,IAAI,MAAM,CAErC;AAED,wBAAgB,WAAW,IAAI,OAAO,CAErC;AAED,wBAAgB,WAAW,CAAC,UAAU,EAAE,MAAM,GAAG,cAAc,CAe9D;AAED,wBAAgB,SAAS,CAAC,UAAU,EAAE,MAAM,GAAG,cAAc,CAU5D;AAED,wBAAgB,SAAS,CAAC,KAAK,EAAE,cAAc,EAAE,UAAU,EAAE,MAAM,GAAG,IAAI,CAkBzE;AAED,wBAAgB,SAAS,CACrB,KAAK,EAAE,cAAc,EACrB,IAAI,EAAE,MAAM,EACZ,KAAK,EAAE,MAAM,EACb,IAAI,GAAE,MAAkB,GACzB,IAAI,CAWN;AAED,wBAAgB,YAAY,CAAC,KAAK,EAAE,cAAc,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAIzE;AAED,wBAAgB,SAAS,CACrB,KAAK,EAAE,cAAc,EACrB,IAAI,EAAE,MAAM,GACb,WAAW,GAAG,IAAI,CAEpB;AAED,wBAAgB,WAAW,CACvB,KAAK,EAAE,cAAc,GACtB,KAAK,CAAC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,OAAO,CAAC;IAAC,UAAU,EAAE,MAAM,CAAA;CAAE,CAAC,CAO5E;AAED,wBAAgB,UAAU,CACtB,KAAK,EAAE,cAAc,EACrB,IAAI,EAAE,MAAM,EACZ,YAAY,EAAE,MAAM,EACpB,SAAS,EAAE,MAAM,GAClB,IAAI,CAMN;AAED,wBAAgB,YAAY,IAAI;IAC5B,MAAM,EAAE,OAAO,CAAC;IAChB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,IAAI,EAAE,MAAM,CAAC;CAChB,CAMA;AAED,wBAAgB,WAAW,IAAI,OAAO,CAIrC;AAED,wBAAgB,WAAW,CAAC,KAAK,EAAE,cAAc,GAAG,MAAM,CAOzD;AAED,wBAAgB,qBAAqB,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,CAKhE"}
|
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
import { existsSync, readFileSync, writeFileSync, mkdirSync, chmodSync, statSync, unlinkSync, renameSync, } from "node:fs";
|
|
2
|
+
import { createCipheriv, createDecipheriv, randomBytes, pbkdf2Sync, createHash, } from "node:crypto";
|
|
3
|
+
import { homedir } from "node:os";
|
|
4
|
+
import { join } from "node:path";
|
|
5
|
+
const CONFIG_DIR = process.env.ONECLAW_CONFIG_DIR || join(homedir(), ".config", "1claw");
|
|
6
|
+
const VAULT_FILE = process.env.ONECLAW_LOCAL_VAULT || join(CONFIG_DIR, "local-vault.enc");
|
|
7
|
+
const ALGORITHM = "aes-256-gcm";
|
|
8
|
+
const IV_LENGTH = 12;
|
|
9
|
+
const TAG_LENGTH = 16;
|
|
10
|
+
const SALT_LENGTH = 16;
|
|
11
|
+
const PBKDF2_ITERATIONS = 100_000;
|
|
12
|
+
const FILE_VERSION = 1;
|
|
13
|
+
function deriveKey(passphrase, salt) {
|
|
14
|
+
return pbkdf2Sync(passphrase, salt, PBKDF2_ITERATIONS, 32, "sha256");
|
|
15
|
+
}
|
|
16
|
+
function encrypt(plaintext, passphrase) {
|
|
17
|
+
const salt = randomBytes(SALT_LENGTH);
|
|
18
|
+
const key = deriveKey(passphrase, salt);
|
|
19
|
+
const iv = randomBytes(IV_LENGTH);
|
|
20
|
+
const cipher = createCipheriv(ALGORITHM, key, iv);
|
|
21
|
+
const encrypted = Buffer.concat([
|
|
22
|
+
cipher.update(plaintext, "utf-8"),
|
|
23
|
+
cipher.final(),
|
|
24
|
+
]);
|
|
25
|
+
const tag = cipher.getAuthTag();
|
|
26
|
+
// Wire format: [version:1][salt:16][iv:12][tag:16][ciphertext]
|
|
27
|
+
return Buffer.concat([
|
|
28
|
+
Buffer.from([FILE_VERSION]),
|
|
29
|
+
salt,
|
|
30
|
+
iv,
|
|
31
|
+
tag,
|
|
32
|
+
encrypted,
|
|
33
|
+
]);
|
|
34
|
+
}
|
|
35
|
+
function decrypt(data, passphrase) {
|
|
36
|
+
const version = data[0];
|
|
37
|
+
if (version !== FILE_VERSION) {
|
|
38
|
+
throw new Error(`Unsupported vault file version: ${version}`);
|
|
39
|
+
}
|
|
40
|
+
let offset = 1;
|
|
41
|
+
const salt = data.subarray(offset, offset + SALT_LENGTH);
|
|
42
|
+
offset += SALT_LENGTH;
|
|
43
|
+
const iv = data.subarray(offset, offset + IV_LENGTH);
|
|
44
|
+
offset += IV_LENGTH;
|
|
45
|
+
const tag = data.subarray(offset, offset + TAG_LENGTH);
|
|
46
|
+
offset += TAG_LENGTH;
|
|
47
|
+
const encrypted = data.subarray(offset);
|
|
48
|
+
const key = deriveKey(passphrase, salt);
|
|
49
|
+
const decipher = createDecipheriv(ALGORITHM, key, iv);
|
|
50
|
+
decipher.setAuthTag(tag);
|
|
51
|
+
const decrypted = Buffer.concat([
|
|
52
|
+
decipher.update(encrypted),
|
|
53
|
+
decipher.final(),
|
|
54
|
+
]);
|
|
55
|
+
return decrypted.toString("utf-8");
|
|
56
|
+
}
|
|
57
|
+
export function getVaultPath() {
|
|
58
|
+
return VAULT_FILE;
|
|
59
|
+
}
|
|
60
|
+
export function vaultExists() {
|
|
61
|
+
return existsSync(VAULT_FILE);
|
|
62
|
+
}
|
|
63
|
+
export function createVault(passphrase) {
|
|
64
|
+
if (!existsSync(CONFIG_DIR)) {
|
|
65
|
+
mkdirSync(CONFIG_DIR, { recursive: true });
|
|
66
|
+
}
|
|
67
|
+
const now = new Date().toISOString();
|
|
68
|
+
const vault = {
|
|
69
|
+
version: FILE_VERSION,
|
|
70
|
+
created_at: now,
|
|
71
|
+
updated_at: now,
|
|
72
|
+
secrets: {},
|
|
73
|
+
};
|
|
74
|
+
saveVault(vault, passphrase);
|
|
75
|
+
return vault;
|
|
76
|
+
}
|
|
77
|
+
export function loadVault(passphrase) {
|
|
78
|
+
if (!existsSync(VAULT_FILE)) {
|
|
79
|
+
throw new Error("No local vault found. Run `1claw local init` first.");
|
|
80
|
+
}
|
|
81
|
+
const data = readFileSync(VAULT_FILE);
|
|
82
|
+
const json = decrypt(data, passphrase);
|
|
83
|
+
return JSON.parse(json);
|
|
84
|
+
}
|
|
85
|
+
export function saveVault(vault, passphrase) {
|
|
86
|
+
vault.updated_at = new Date().toISOString();
|
|
87
|
+
const json = JSON.stringify(vault);
|
|
88
|
+
const encrypted = encrypt(json, passphrase);
|
|
89
|
+
if (!existsSync(CONFIG_DIR)) {
|
|
90
|
+
mkdirSync(CONFIG_DIR, { recursive: true });
|
|
91
|
+
}
|
|
92
|
+
const tmpPath = VAULT_FILE + ".tmp";
|
|
93
|
+
writeFileSync(tmpPath, encrypted);
|
|
94
|
+
try {
|
|
95
|
+
chmodSync(tmpPath, 0o600);
|
|
96
|
+
}
|
|
97
|
+
catch {
|
|
98
|
+
// best-effort
|
|
99
|
+
}
|
|
100
|
+
renameSync(tmpPath, VAULT_FILE);
|
|
101
|
+
}
|
|
102
|
+
export function addSecret(vault, name, value, type = "api_key") {
|
|
103
|
+
const now = new Date().toISOString();
|
|
104
|
+
vault.secrets[name] = {
|
|
105
|
+
value,
|
|
106
|
+
type,
|
|
107
|
+
created_at: vault.secrets[name]?.created_at ?? now,
|
|
108
|
+
updated_at: now,
|
|
109
|
+
synced_to_cloud: false,
|
|
110
|
+
cloud_vault_id: null,
|
|
111
|
+
cloud_path: null,
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
export function removeSecret(vault, name) {
|
|
115
|
+
if (!(name in vault.secrets))
|
|
116
|
+
return false;
|
|
117
|
+
delete vault.secrets[name];
|
|
118
|
+
return true;
|
|
119
|
+
}
|
|
120
|
+
export function getSecret(vault, name) {
|
|
121
|
+
return vault.secrets[name] ?? null;
|
|
122
|
+
}
|
|
123
|
+
export function listSecrets(vault) {
|
|
124
|
+
return Object.entries(vault.secrets).map(([name, s]) => ({
|
|
125
|
+
name,
|
|
126
|
+
type: s.type,
|
|
127
|
+
synced: s.synced_to_cloud,
|
|
128
|
+
updated_at: s.updated_at,
|
|
129
|
+
}));
|
|
130
|
+
}
|
|
131
|
+
export function markSynced(vault, name, cloudVaultId, cloudPath) {
|
|
132
|
+
const secret = vault.secrets[name];
|
|
133
|
+
if (!secret)
|
|
134
|
+
return;
|
|
135
|
+
secret.synced_to_cloud = true;
|
|
136
|
+
secret.cloud_vault_id = cloudVaultId;
|
|
137
|
+
secret.cloud_path = cloudPath;
|
|
138
|
+
}
|
|
139
|
+
export function getVaultInfo() {
|
|
140
|
+
if (!existsSync(VAULT_FILE)) {
|
|
141
|
+
return { exists: false, path: VAULT_FILE };
|
|
142
|
+
}
|
|
143
|
+
const stat = statSync(VAULT_FILE);
|
|
144
|
+
return { exists: true, sizeBytes: stat.size, path: VAULT_FILE };
|
|
145
|
+
}
|
|
146
|
+
export function deleteVault() {
|
|
147
|
+
if (!existsSync(VAULT_FILE))
|
|
148
|
+
return false;
|
|
149
|
+
unlinkSync(VAULT_FILE);
|
|
150
|
+
return true;
|
|
151
|
+
}
|
|
152
|
+
export function exportAsEnv(vault) {
|
|
153
|
+
return Object.entries(vault.secrets)
|
|
154
|
+
.map(([name, s]) => {
|
|
155
|
+
const val = s.value.includes(" ") ? `"${s.value}"` : s.value;
|
|
156
|
+
return `${name}=${val}`;
|
|
157
|
+
})
|
|
158
|
+
.join("\n") + "\n";
|
|
159
|
+
}
|
|
160
|
+
export function fingerprintPassphrase(passphrase) {
|
|
161
|
+
return createHash("sha256")
|
|
162
|
+
.update(passphrase)
|
|
163
|
+
.digest("hex")
|
|
164
|
+
.slice(0, 8);
|
|
165
|
+
}
|
|
166
|
+
//# sourceMappingURL=local-vault.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"local-vault.js","sourceRoot":"","sources":["../../src/local-vault.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { type PolicyFile } from "./local-policy.js";
|
|
2
|
+
import type { LocalVaultData } from "./local-vault.js";
|
|
3
|
+
export interface ProxyRequest {
|
|
4
|
+
secretName: string;
|
|
5
|
+
url: string;
|
|
6
|
+
method?: string;
|
|
7
|
+
headers?: Record<string, string>;
|
|
8
|
+
body?: string;
|
|
9
|
+
}
|
|
10
|
+
export interface ProxyResponse {
|
|
11
|
+
status: number;
|
|
12
|
+
headers: Record<string, string>;
|
|
13
|
+
body: string;
|
|
14
|
+
}
|
|
15
|
+
export interface ProxyResult {
|
|
16
|
+
success: boolean;
|
|
17
|
+
response?: ProxyResponse;
|
|
18
|
+
error?: string;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Execute an HTTP request with a secret injected, without exposing
|
|
22
|
+
* the secret value to the caller. The secret is resolved from the
|
|
23
|
+
* local vault, checked against the policy, and injected into the
|
|
24
|
+
* request per the policy rules.
|
|
25
|
+
*/
|
|
26
|
+
export declare function proxyRequest(req: ProxyRequest, vault: LocalVaultData, policy: PolicyFile): Promise<ProxyResult>;
|
|
27
|
+
//# sourceMappingURL=secret-proxy.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"secret-proxy.d.ts","sourceRoot":"","sources":["../../src/secret-proxy.ts"],"names":[],"mappings":"AAGA,OAAO,EACH,KAAK,UAAU,EAGlB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAEvD,MAAM,WAAW,YAAY;IACzB,UAAU,EAAE,MAAM,CAAC;IACnB,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACjC,IAAI,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,aAAa;IAC1B,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAChC,IAAI,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,WAAW;IACxB,OAAO,EAAE,OAAO,CAAC;IACjB,QAAQ,CAAC,EAAE,aAAa,CAAC;IACzB,KAAK,CAAC,EAAE,MAAM,CAAC;CAClB;AAED;;;;;GAKG;AACH,wBAAsB,YAAY,CAC9B,GAAG,EAAE,YAAY,EACjB,KAAK,EAAE,cAAc,EACrB,MAAM,EAAE,UAAU,GACnB,OAAO,CAAC,WAAW,CAAC,CAyEtB"}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { request as httpsRequest } from "node:https";
|
|
2
|
+
import { request as httpRequest } from "node:http";
|
|
3
|
+
import { URL } from "node:url";
|
|
4
|
+
import { isHostAllowed, resolveInjection, } from "./local-policy.js";
|
|
5
|
+
/**
|
|
6
|
+
* Execute an HTTP request with a secret injected, without exposing
|
|
7
|
+
* the secret value to the caller. The secret is resolved from the
|
|
8
|
+
* local vault, checked against the policy, and injected into the
|
|
9
|
+
* request per the policy rules.
|
|
10
|
+
*/
|
|
11
|
+
export async function proxyRequest(req, vault, policy) {
|
|
12
|
+
const secret = vault.secrets[req.secretName];
|
|
13
|
+
if (!secret) {
|
|
14
|
+
return {
|
|
15
|
+
success: false,
|
|
16
|
+
error: `Secret "${req.secretName}" not found in local vault.`,
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
const hostCheck = isHostAllowed(policy, req.secretName, req.url);
|
|
20
|
+
if (!hostCheck.allowed) {
|
|
21
|
+
return { success: false, error: hostCheck.reason };
|
|
22
|
+
}
|
|
23
|
+
const injection = resolveInjection(policy, req.secretName, secret.value);
|
|
24
|
+
const url = new URL(req.url);
|
|
25
|
+
for (const [k, v] of Object.entries(injection.queryParams)) {
|
|
26
|
+
url.searchParams.set(k, v);
|
|
27
|
+
}
|
|
28
|
+
const mergedHeaders = {
|
|
29
|
+
...(req.headers ?? {}),
|
|
30
|
+
...injection.headers,
|
|
31
|
+
};
|
|
32
|
+
const method = req.method ?? "GET";
|
|
33
|
+
return new Promise((resolve) => {
|
|
34
|
+
const isHttps = url.protocol === "https:";
|
|
35
|
+
const requestFn = isHttps ? httpsRequest : httpRequest;
|
|
36
|
+
const upstreamReq = requestFn(url, { method, headers: mergedHeaders }, (res) => {
|
|
37
|
+
const chunks = [];
|
|
38
|
+
res.on("data", (c) => chunks.push(c));
|
|
39
|
+
res.on("end", () => {
|
|
40
|
+
const body = Buffer.concat(chunks).toString("utf-8");
|
|
41
|
+
const responseHeaders = {};
|
|
42
|
+
for (const [k, v] of Object.entries(res.headers)) {
|
|
43
|
+
if (typeof v === "string")
|
|
44
|
+
responseHeaders[k] = v;
|
|
45
|
+
else if (Array.isArray(v))
|
|
46
|
+
responseHeaders[k] = v.join(", ");
|
|
47
|
+
}
|
|
48
|
+
resolve({
|
|
49
|
+
success: true,
|
|
50
|
+
response: {
|
|
51
|
+
status: res.statusCode ?? 502,
|
|
52
|
+
headers: responseHeaders,
|
|
53
|
+
body,
|
|
54
|
+
},
|
|
55
|
+
});
|
|
56
|
+
});
|
|
57
|
+
});
|
|
58
|
+
upstreamReq.on("error", (err) => {
|
|
59
|
+
resolve({
|
|
60
|
+
success: false,
|
|
61
|
+
error: `Upstream request failed: ${err.message}`,
|
|
62
|
+
});
|
|
63
|
+
});
|
|
64
|
+
upstreamReq.setTimeout(30_000, () => {
|
|
65
|
+
upstreamReq.destroy(new Error("Request timed out (30s)"));
|
|
66
|
+
});
|
|
67
|
+
if (req.body) {
|
|
68
|
+
upstreamReq.write(req.body);
|
|
69
|
+
}
|
|
70
|
+
upstreamReq.end();
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
//# sourceMappingURL=secret-proxy.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"secret-proxy.js","sourceRoot":"","sources":["../../src/secret-proxy.ts"],"names":[],"mappings":"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"}
|