lucifer-gate 0.7.3 → 0.7.4-alpha.3.3ee2b12
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 +40 -0
- package/dist/server/create_app.js +83 -1
- package/dist/server/create_app.js.map +1 -1
- package/dist/server/domains/request-proxy/config/proxy_config.js +21 -0
- package/dist/server/domains/request-proxy/config/proxy_config.js.map +1 -1
- package/dist/server/domains/request-proxy/service/proxy_approval_cache.js +48 -0
- package/dist/server/domains/request-proxy/service/proxy_approval_cache.js.map +1 -0
- package/dist/server/domains/request-proxy/service/proxy_auth.js +204 -0
- package/dist/server/domains/request-proxy/service/proxy_auth.js.map +1 -0
- package/dist/server/domains/request-proxy/service/proxy_server.js +79 -13
- package/dist/server/domains/request-proxy/service/proxy_server.js.map +1 -1
- package/dist/server/domains/request-proxy/types/proxy_types.js +2 -0
- package/dist/server/domains/request-proxy/types/proxy_types.js.map +1 -1
- package/dist/server/test/integration-setup.js +3 -1
- package/dist/server/test/integration-setup.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -115,6 +115,43 @@ A request to `http://localhost:6060/v1/chat/completions` is forwarded to
|
|
|
115
115
|
any caller-supplied header of the same name, so callers never need (and
|
|
116
116
|
cannot spoof) the upstream credential.
|
|
117
117
|
|
|
118
|
+
#### Gating the proxy with a lucifer-gate API key
|
|
119
|
+
|
|
120
|
+
Each mapping can require the caller to present a valid lucifer-gate token —
|
|
121
|
+
placed in the **upstream SDK's native auth header** so client SDKs work
|
|
122
|
+
unmodified. The server validates the token, strips it from the outgoing
|
|
123
|
+
request, and injects the real upstream credential from `headers`.
|
|
124
|
+
|
|
125
|
+
```json
|
|
126
|
+
{
|
|
127
|
+
"proxies": [
|
|
128
|
+
{
|
|
129
|
+
"port": 6060,
|
|
130
|
+
"baseUrl": "https://api.openai.com",
|
|
131
|
+
"authMode": "api-key",
|
|
132
|
+
"apiKeyHeader": "authorization",
|
|
133
|
+
"apiKeyPrefix": "Bearer ",
|
|
134
|
+
"headers": { "Authorization": "Bearer sk-openai-REAL" }
|
|
135
|
+
},
|
|
136
|
+
{
|
|
137
|
+
"port": 6061,
|
|
138
|
+
"baseUrl": "https://api.anthropic.com",
|
|
139
|
+
"authMode": "api-key-telegram",
|
|
140
|
+
"apiKeyHeader": "x-api-key",
|
|
141
|
+
"telegramApprovalTtlSeconds": 3600,
|
|
142
|
+
"headers": { "x-api-key": "sk-ant-REAL" }
|
|
143
|
+
}
|
|
144
|
+
]
|
|
145
|
+
}
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
Available `authMode` values:
|
|
149
|
+
|
|
150
|
+
- `"none"` (default) — open proxy, today's behavior.
|
|
151
|
+
- `"api-key"` — require a valid lucifer-gate token in `apiKeyHeader`.
|
|
152
|
+
- `"api-key-telegram"` — `"api-key"` plus Telegram approval, cached per
|
|
153
|
+
`(api-key-id, port)` for `telegramApprovalTtlSeconds` (default 3600s).
|
|
154
|
+
|
|
118
155
|
File semantics:
|
|
119
156
|
|
|
120
157
|
- File missing → feature disabled (no behavior change for existing installs).
|
|
@@ -125,6 +162,9 @@ File semantics:
|
|
|
125
162
|
- Listeners bind to `127.0.0.1` by default. Set `"host": "0.0.0.0"` on a
|
|
126
163
|
mapping to expose it beyond loopback; when doing so, the operator is
|
|
127
164
|
responsible for fronting the listener with access control.
|
|
165
|
+
- When `authMode` is `"api-key"` or `"api-key-telegram"`, the gateway must
|
|
166
|
+
be initialised (i.e. `api-keys.json` present); otherwise startup fails
|
|
167
|
+
fast with a descriptive error.
|
|
128
168
|
|
|
129
169
|
See [docs/specs/transparent-proxy.md](docs/specs/transparent-proxy.md) for
|
|
130
170
|
the full contract.
|
|
@@ -48,6 +48,82 @@ function initApprovalChannel(deps, autoApprove, telegramApiRoot) {
|
|
|
48
48
|
}
|
|
49
49
|
return channels.length === 1 ? channels[0] : createMultiApprovalChannel(channels);
|
|
50
50
|
}
|
|
51
|
+
/**
|
|
52
|
+
* Adapter from the command-gateway ApiKeyStore to the proxy-domain
|
|
53
|
+
* ProxyTokenValidator contract. Kept in this composition file so
|
|
54
|
+
* `request-proxy` never imports from `command-gateway`.
|
|
55
|
+
*/
|
|
56
|
+
function createProxyTokenValidator(apiKeyStore) {
|
|
57
|
+
return {
|
|
58
|
+
validate(rawToken) {
|
|
59
|
+
const entry = apiKeyStore.findByKey(rawToken);
|
|
60
|
+
if (!entry)
|
|
61
|
+
return undefined;
|
|
62
|
+
return { keyId: entry.id, keyName: entry.name };
|
|
63
|
+
},
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Adapter from the command-gateway ApprovalChannel to the proxy-domain
|
|
68
|
+
* ProxyApprovalRequester contract. Synthesises a human-readable descriptor
|
|
69
|
+
* as the "command" string and races against an approval timeout so the
|
|
70
|
+
* proxy request cannot block indefinitely waiting for a human.
|
|
71
|
+
*/
|
|
72
|
+
function createProxyApprovalRequester(approvalChannel, approvalTimeoutSeconds) {
|
|
73
|
+
return {
|
|
74
|
+
async request(ctx) {
|
|
75
|
+
const descriptor = `HTTP proxy ${ctx.method} ${ctx.path} (port ${ctx.port}) by ${ctx.keyName}`;
|
|
76
|
+
let timer;
|
|
77
|
+
const timeoutPromise = new Promise((resolve) => {
|
|
78
|
+
timer = setTimeout(() => resolve('timeout'), approvalTimeoutSeconds * 1000);
|
|
79
|
+
});
|
|
80
|
+
try {
|
|
81
|
+
const approvalPromise = approvalChannel
|
|
82
|
+
.requestApproval(descriptor, ctx.keyName, ctx.ip, ctx.requestId, { level: 'safe', warnings: [] })
|
|
83
|
+
.then((r) => (r.decision === 'approved' ? 'approved' : 'denied'));
|
|
84
|
+
const outcome = await Promise.race([approvalPromise, timeoutPromise]);
|
|
85
|
+
if (outcome === 'timeout') {
|
|
86
|
+
approvalChannel.cancel?.(ctx.requestId);
|
|
87
|
+
}
|
|
88
|
+
return outcome;
|
|
89
|
+
}
|
|
90
|
+
catch (err) {
|
|
91
|
+
log.warn({ err, requestId: ctx.requestId }, 'Proxy approval channel threw');
|
|
92
|
+
return 'error';
|
|
93
|
+
}
|
|
94
|
+
finally {
|
|
95
|
+
if (timer)
|
|
96
|
+
clearTimeout(timer);
|
|
97
|
+
}
|
|
98
|
+
},
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* Adapter from proxy audit events to the command-gateway audit log, so
|
|
103
|
+
* proxy auth/approval activity shows up in `lucifer-gate log` alongside
|
|
104
|
+
* command activity.
|
|
105
|
+
*/
|
|
106
|
+
function createProxyAuditSink(auditLog) {
|
|
107
|
+
return {
|
|
108
|
+
record(event) {
|
|
109
|
+
try {
|
|
110
|
+
auditLog.append({
|
|
111
|
+
ts: event.ts,
|
|
112
|
+
type: event.type,
|
|
113
|
+
requestId: event.requestId,
|
|
114
|
+
command: `HTTP proxy ${event.method} ${event.path} (port ${event.port})`,
|
|
115
|
+
apiKeyName: event.keyName,
|
|
116
|
+
ip: event.ip,
|
|
117
|
+
approvedBy: event.source,
|
|
118
|
+
error: event.reason,
|
|
119
|
+
});
|
|
120
|
+
}
|
|
121
|
+
catch (err) {
|
|
122
|
+
log.warn({ err }, 'Failed to write proxy audit event');
|
|
123
|
+
}
|
|
124
|
+
},
|
|
125
|
+
};
|
|
126
|
+
}
|
|
51
127
|
export function createApp(options = {}) {
|
|
52
128
|
const serverConfig = getServerConfig();
|
|
53
129
|
const metadataRepository = createRuntimeMetadataRepository();
|
|
@@ -73,6 +149,7 @@ export function createApp(options = {}) {
|
|
|
73
149
|
}
|
|
74
150
|
let approvalChannel;
|
|
75
151
|
let cleanupInterval;
|
|
152
|
+
const proxyDeps = {};
|
|
76
153
|
// Only initialize gateway if config files exist
|
|
77
154
|
if (fs.existsSync(apiKeysPath) && fs.existsSync(commandRulesPath)) {
|
|
78
155
|
const db = getDatabase(gatewayConfig.dataDir);
|
|
@@ -91,6 +168,11 @@ export function createApp(options = {}) {
|
|
|
91
168
|
approvalStore.removeExpired();
|
|
92
169
|
pendingStore.cleanup(gatewayConfig.approvalTimeoutSeconds * 1000);
|
|
93
170
|
}, 60_000);
|
|
171
|
+
// Wire the proxy bridges over gateway stores so request-proxy stays
|
|
172
|
+
// isolated from command-gateway code (Dependency Rules).
|
|
173
|
+
proxyDeps.tokenValidator = createProxyTokenValidator(apiKeyStore);
|
|
174
|
+
proxyDeps.approvalRequester = createProxyApprovalRequester(approvalChannel, gatewayConfig.approvalTimeoutSeconds);
|
|
175
|
+
proxyDeps.auditSink = createProxyAuditSink(auditLog);
|
|
94
176
|
log.info('Command gateway initialized');
|
|
95
177
|
}
|
|
96
178
|
else {
|
|
@@ -105,7 +187,7 @@ export function createApp(options = {}) {
|
|
|
105
187
|
const proxyConfig = loadProxyConfig(proxyConfigPath);
|
|
106
188
|
if (proxyConfig && proxyConfig.proxies.length > 0) {
|
|
107
189
|
validateProxyPorts(proxyConfig.proxies, gatewayConfig.port);
|
|
108
|
-
proxyServers = createProxyServers(proxyConfig.proxies);
|
|
190
|
+
proxyServers = createProxyServers(proxyConfig.proxies, proxyDeps);
|
|
109
191
|
log.info({ count: proxyConfig.proxies.length }, 'Transparent proxy mappings configured');
|
|
110
192
|
}
|
|
111
193
|
async function start() {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"create_app.js","sourceRoot":"","sources":["../../server/src/create_app.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,SAAS,CAAA;AACxB,OAAO,IAAI,MAAM,WAAW,CAAA;AAC5B,OAAO,OAAO,MAAM,SAAS,CAAA;AAC7B,OAAO,EAAE,eAAe,EAAE,MAAM,gDAAgD,CAAA;AAChF,OAAO,EAAE,oBAAoB,EAAE,MAAM,sDAAsD,CAAA;AAC3F,OAAO,EAAE,+BAA+B,EAAE,MAAM,kEAAkE,CAAA;AAClH,OAAO,EAAE,yBAAyB,EAAE,MAAM,wDAAwD,CAAA;AAClG,OAAO,EAAE,iBAAiB,EAAE,MAAM,oDAAoD,CAAA;AACtF,OAAO,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,kDAAkD,CAAA;AAC7F,OAAO,EAAE,mBAAmB,EAAE,MAAM,wDAAwD,CAAA;AAC5F,OAAO,EAAE,cAAc,EAAE,MAAM,mDAAmD,CAAA;AAClF,OAAO,EAAE,iBAAiB,EAAE,MAAM,uDAAuD,CAAA;AACzF,OAAO,EAAE,uBAAuB,EAAE,MAAM,6DAA6D,CAAA;AACrG,OAAO,EAAE,yBAAyB,EAAE,MAAM,+DAA+D,CAAA;AACzG,OAAO,EAAE,qBAAqB,EAAE,MAAM,0DAA0D,CAAA;AAChG,OAAO,EAAE,6BAA6B,EAAE,MAAM,gEAAgE,CAAA;AAC9G,OAAO,EAAE,wBAAwB,EAAE,MAAM,2DAA2D,CAAA;AACpG,OAAO,EAAE,wBAAwB,EAAE,MAAM,2DAA2D,CAAA;AACpG,OAAO,EAAE,0BAA0B,EAAE,MAAM,6DAA6D,CAAA;AACxG,OAAO,EAAE,sBAAsB,EAAE,MAAM,2DAA2D,CAAA;AAElG,OAAO,EAAE,eAAe,EAAE,kBAAkB,EAAE,MAAM,gDAAgD,CAAA;AACpG,OAAO,EAAE,kBAAkB,
|
|
1
|
+
{"version":3,"file":"create_app.js","sourceRoot":"","sources":["../../server/src/create_app.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,SAAS,CAAA;AACxB,OAAO,IAAI,MAAM,WAAW,CAAA;AAC5B,OAAO,OAAO,MAAM,SAAS,CAAA;AAC7B,OAAO,EAAE,eAAe,EAAE,MAAM,gDAAgD,CAAA;AAChF,OAAO,EAAE,oBAAoB,EAAE,MAAM,sDAAsD,CAAA;AAC3F,OAAO,EAAE,+BAA+B,EAAE,MAAM,kEAAkE,CAAA;AAClH,OAAO,EAAE,yBAAyB,EAAE,MAAM,wDAAwD,CAAA;AAClG,OAAO,EAAE,iBAAiB,EAAE,MAAM,oDAAoD,CAAA;AACtF,OAAO,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,kDAAkD,CAAA;AAC7F,OAAO,EAAE,mBAAmB,EAAE,MAAM,wDAAwD,CAAA;AAC5F,OAAO,EAAE,cAAc,EAAE,MAAM,mDAAmD,CAAA;AAClF,OAAO,EAAE,iBAAiB,EAAE,MAAM,uDAAuD,CAAA;AACzF,OAAO,EAAE,uBAAuB,EAAE,MAAM,6DAA6D,CAAA;AACrG,OAAO,EAAE,yBAAyB,EAAE,MAAM,+DAA+D,CAAA;AACzG,OAAO,EAAE,qBAAqB,EAAE,MAAM,0DAA0D,CAAA;AAChG,OAAO,EAAE,6BAA6B,EAAE,MAAM,gEAAgE,CAAA;AAC9G,OAAO,EAAE,wBAAwB,EAAE,MAAM,2DAA2D,CAAA;AACpG,OAAO,EAAE,wBAAwB,EAAE,MAAM,2DAA2D,CAAA;AACpG,OAAO,EAAE,0BAA0B,EAAE,MAAM,6DAA6D,CAAA;AACxG,OAAO,EAAE,sBAAsB,EAAE,MAAM,2DAA2D,CAAA;AAElG,OAAO,EAAE,eAAe,EAAE,kBAAkB,EAAE,MAAM,gDAAgD,CAAA;AACpG,OAAO,EAAE,kBAAkB,EAA2C,MAAM,iDAAiD,CAAA;AAQ7H,OAAO,EAAE,iBAAiB,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAA;AAE/D,MAAM,GAAG,GAAG,iBAAiB,CAAC,KAAK,CAAC,CAAA;AAgBpC,SAAS,mBAAmB,CAAC,IAAiB,EAAE,WAAoB,EAAE,eAAwB;IAC5F,IAAI,WAAW,EAAE,CAAC;QAChB,OAAO,wBAAwB,EAAE,CAAA;IACnC,CAAC;IAED,MAAM,QAAQ,GAAsB,EAAE,CAAA;IACtC,MAAM,EAAE,GAAG,EAAE,YAAY,EAAE,aAAa,EAAE,QAAQ,EAAE,aAAa,EAAE,GAAG,IAAI,CAAA;IAE1E,MAAM,aAAa,GAAG,OAAO,CAAC,GAAG,CAAC,sBAAsB,CAAA;IACxD,MAAM,MAAM,GAAG,aAAa,CAAC,cAAc,IAAI,OAAO,CAAC,GAAG,CAAC,wBAAwB,CAAA;IACnF,IAAI,aAAa,IAAI,MAAM,EAAE,CAAC;QAC5B,MAAM,eAAe,GAAG,eAAe,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,eAAe,EAAE,CAAC,CAAC,CAAC,SAAS,CAAA;QAClF,QAAQ,CAAC,IAAI,CAAC,6BAA6B,CAAC,aAAa,EAAE,MAAM,EAAE,YAAY,EAAE,aAAa,EAAE,QAAQ,EAAE,eAAe,CAAC,CAAC,CAAA;IAC7H,CAAC;IAED,MAAM,eAAe,GAAG,aAAa,CAAC,eAAe,CAAA;IACrD,MAAM,eAAe,GAAG,aAAa,CAAC,eAAe,CAAA;IACrD,IAAI,eAAe,IAAI,eAAe,EAAE,CAAC;QACvC,MAAM,UAAU,GAAG,wBAAwB,EAAE,CAAA;QAC7C,QAAQ,CAAC,IAAI,CAAC,UAAU,CAAC,CAAA;QACzB,sBAAsB,CAAC,EAAE,MAAM,EAAE,GAAG,EAAE,eAAe,EAAE,eAAe,EAAE,UAAU,EAAE,aAAa,EAAE,QAAQ,EAAE,CAAC,CAAA;QAC9G,GAAG,CAAC,IAAI,CAAC,6CAA6C,CAAC,CAAA;IACzD,CAAC;IAED,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC1B,MAAM,IAAI,KAAK,CACb,uGAAuG;YACvG,2FAA2F,CAC5F,CAAA;IACH,CAAC;IAED,OAAO,QAAQ,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,0BAA0B,CAAC,QAAQ,CAAC,CAAA;AACnF,CAAC;AAED;;;;GAIG;AACH,SAAS,yBAAyB,CAAC,WAAiD;IAClF,OAAO;QACL,QAAQ,CAAC,QAAgB;YACvB,MAAM,KAAK,GAAG,WAAW,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAA;YAC7C,IAAI,CAAC,KAAK;gBAAE,OAAO,SAAS,CAAA;YAC5B,OAAO,EAAE,KAAK,EAAE,KAAK,CAAC,EAAE,EAAE,OAAO,EAAE,KAAK,CAAC,IAAI,EAAE,CAAA;QACjD,CAAC;KACF,CAAA;AACH,CAAC;AAED;;;;;GAKG;AACH,SAAS,4BAA4B,CACnC,eAAgC,EAChC,sBAA8B;IAE9B,OAAO;QACL,KAAK,CAAC,OAAO,CAAC,GAAyB;YACrC,MAAM,UAAU,GAAG,cAAc,GAAG,CAAC,MAAM,IAAI,GAAG,CAAC,IAAI,UAAU,GAAG,CAAC,IAAI,QAAQ,GAAG,CAAC,OAAO,EAAE,CAAA;YAC9F,IAAI,KAAgD,CAAA;YACpD,MAAM,cAAc,GAAG,IAAI,OAAO,CAAY,CAAC,OAAO,EAAE,EAAE;gBACxD,KAAK,GAAG,UAAU,CAAC,GAAG,EAAE,CAAC,OAAO,CAAC,SAAS,CAAC,EAAE,sBAAsB,GAAG,IAAI,CAAC,CAAA;YAC7E,CAAC,CAAC,CAAA;YAEF,IAAI,CAAC;gBACH,MAAM,eAAe,GAAG,eAAe;qBACpC,eAAe,CAAC,UAAU,EAAE,GAAG,CAAC,OAAO,EAAE,GAAG,CAAC,EAAE,EAAE,GAAG,CAAC,SAAS,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,EAAE,EAAE,CAAC;qBAChG,IAAI,CAAC,CAAC,CAAC,EAAyB,EAAE,CAAC,CAAC,CAAC,CAAC,QAAQ,KAAK,UAAU,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAA;gBAE1F,MAAM,OAAO,GAAG,MAAM,OAAO,CAAC,IAAI,CAAuB,CAAC,eAAe,EAAE,cAAc,CAAC,CAAC,CAAA;gBAE3F,IAAI,OAAO,KAAK,SAAS,EAAE,CAAC;oBAC1B,eAAe,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,SAAS,CAAC,CAAA;gBACzC,CAAC;gBACD,OAAO,OAAO,CAAA;YAChB,CAAC;YAAC,OAAO,GAAG,EAAE,CAAC;gBACb,GAAG,CAAC,IAAI,CAAC,EAAE,GAAG,EAAE,SAAS,EAAE,GAAG,CAAC,SAAS,EAAE,EAAE,8BAA8B,CAAC,CAAA;gBAC3E,OAAO,OAAO,CAAA;YAChB,CAAC;oBAAS,CAAC;gBACT,IAAI,KAAK;oBAAE,YAAY,CAAC,KAAK,CAAC,CAAA;YAChC,CAAC;QACH,CAAC;KACF,CAAA;AACH,CAAC;AAED;;;;GAIG;AACH,SAAS,oBAAoB,CAAC,QAA2C;IACvE,OAAO;QACL,MAAM,CAAC,KAAK;YACV,IAAI,CAAC;gBACH,QAAQ,CAAC,MAAM,CAAC;oBACd,EAAE,EAAE,KAAK,CAAC,EAAE;oBACZ,IAAI,EAAE,KAAK,CAAC,IAAI;oBAChB,SAAS,EAAE,KAAK,CAAC,SAAS;oBAC1B,OAAO,EAAE,cAAc,KAAK,CAAC,MAAM,IAAI,KAAK,CAAC,IAAI,UAAU,KAAK,CAAC,IAAI,GAAG;oBACxE,UAAU,EAAE,KAAK,CAAC,OAAO;oBACzB,EAAE,EAAE,KAAK,CAAC,EAAE;oBACZ,UAAU,EAAE,KAAK,CAAC,MAAM;oBACxB,KAAK,EAAE,KAAK,CAAC,MAAM;iBACpB,CAAC,CAAA;YACJ,CAAC;YAAC,OAAO,GAAG,EAAE,CAAC;gBACb,GAAG,CAAC,IAAI,CAAC,EAAE,GAAG,EAAE,EAAE,mCAAmC,CAAC,CAAA;YACxD,CAAC;QACH,CAAC;KACF,CAAA;AACH,CAAC;AAED,MAAM,UAAU,SAAS,CAAC,UAA4B,EAAE;IACtD,MAAM,YAAY,GAAG,eAAe,EAAE,CAAA;IACtC,MAAM,kBAAkB,GAAG,+BAA+B,EAAE,CAAA;IAC5D,MAAM,eAAe,GAAG,yBAAyB,CAAC,YAAY,EAAE,kBAAkB,CAAC,CAAA;IACnF,MAAM,GAAG,GAAG,OAAO,EAAE,CAAA;IAErB,GAAG,CAAC,OAAO,CAAC,cAAc,CAAC,CAAA;IAC3B,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC,CAAA;IACvB,oBAAoB,CAAC,GAAG,EAAE,eAAe,CAAC,CAAA;IAE1C,qCAAqC;IACrC,MAAM,aAAa,GAAG,iBAAiB,CAAC,OAAO,CAAC,UAAU,CAAC,CAAA;IAC3D,MAAM,SAAS,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,GAAG,EAAE,CAAA;IACrG,MAAM,WAAW,GAAG,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,eAAe,CAAC,CAAA;IACzD,MAAM,gBAAgB,GAAG,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,oBAAoB,CAAC,CAAA;IACnE,MAAM,eAAe,GAAG,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,mBAAmB,CAAC,CAAA;IAEjE,+CAA+C;IAC/C,MAAM,eAAe,GAAG,IAAI,CAAC,OAAO,CAAC,SAAS,EAAE,aAAa,CAAC,OAAO,CAAC,CAAA;IACtE,aAAa,CAAC,OAAO,GAAG,eAAe,CAAA;IAEvC,uDAAuD;IACvD,IAAI,aAAa,CAAC,OAAO,EAAE,CAAC;QAC1B,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC,eAAe,EAAE,aAAa,CAAC,OAAO,CAAC,CAAA;QACpE,UAAU,CAAC,OAAO,CAAC,CAAA;QACnB,GAAG,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,OAAO,EAAE,EAAE,sBAAsB,CAAC,CAAA;IACxD,CAAC;IAED,IAAI,eAA4C,CAAA;IAChD,IAAI,eAA2D,CAAA;IAC/D,MAAM,SAAS,GAAoB,EAAE,CAAA;IAErC,gDAAgD;IAChD,IAAI,EAAE,CAAC,UAAU,CAAC,WAAW,CAAC,IAAI,EAAE,CAAC,UAAU,CAAC,gBAAgB,CAAC,EAAE,CAAC;QAClE,MAAM,EAAE,GAAG,WAAW,CAAC,aAAa,CAAC,OAAO,CAAC,CAAA;QAC7C,MAAM,aAAa,GAAG,mBAAmB,CAAC,EAAE,CAAC,CAAA;QAC7C,MAAM,QAAQ,GAAG,cAAc,CAAC,EAAE,CAAC,CAAA;QACnC,MAAM,WAAW,GAAG,iBAAiB,CAAC,WAAW,CAAC,CAAA;QAClD,MAAM,iBAAiB,GAAG,uBAAuB,CAAC,gBAAgB,CAAC,CAAA;QACnE,MAAM,YAAY,GAAG,yBAAyB,EAAE,CAAA;QAEhD,eAAe,GAAG,mBAAmB,CACnC,EAAE,GAAG,EAAE,YAAY,EAAE,aAAa,EAAE,QAAQ,EAAE,aAAa,EAAE,EAC7D,OAAO,CAAC,WAAW,IAAI,KAAK,EAC5B,OAAO,CAAC,eAAe,CACxB,CAAA;QAED,qBAAqB,CAAC;YACpB,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,aAAa,EAAE,WAAW,EAAE,iBAAiB;YAClE,aAAa,EAAE,YAAY,EAAE,QAAQ,EAAE,eAAe;SACvD,CAAC,CAAA;QAEF,qEAAqE;QACrE,eAAe,GAAG,WAAW,CAAC,GAAG,EAAE;YACjC,aAAa,CAAC,aAAa,EAAE,CAAA;YAC7B,YAAY,CAAC,OAAO,CAAC,aAAa,CAAC,sBAAsB,GAAG,IAAI,CAAC,CAAA;QACnE,CAAC,EAAE,MAAM,CAAC,CAAA;QAEV,oEAAoE;QACpE,yDAAyD;QACzD,SAAS,CAAC,cAAc,GAAG,yBAAyB,CAAC,WAAW,CAAC,CAAA;QACjE,SAAS,CAAC,iBAAiB,GAAG,4BAA4B,CAAC,eAAe,EAAE,aAAa,CAAC,sBAAsB,CAAC,CAAA;QACjH,SAAS,CAAC,SAAS,GAAG,oBAAoB,CAAC,QAAQ,CAAC,CAAA;QAEpD,GAAG,CAAC,IAAI,CAAC,6BAA6B,CAAC,CAAA;IACzC,CAAC;SAAM,CAAC;QACN,GAAG,CAAC,IAAI,CAAC,EAAE,WAAW,EAAE,gBAAgB,EAAE,EAAE,6EAA6E,CAAC,CAAA;IAC5H,CAAC;IAED,cAAc;IACd,IAAI,OAAO,CAAC,GAAG,CAAC,QAAQ,KAAK,YAAY,EAAE,CAAC;QAC1C,GAAG,CAAC,IAAI,CAAC,iFAAiF,CAAC,CAAA;IAC7F,CAAC;IAED,yEAAyE;IACzE,IAAI,YAAsC,CAAA;IAC1C,MAAM,WAAW,GAAG,eAAe,CAAC,eAAe,CAAC,CAAA;IACpD,IAAI,WAAW,IAAI,WAAW,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAClD,kBAAkB,CAAC,WAAW,CAAC,OAAO,EAAE,aAAa,CAAC,IAAI,CAAC,CAAA;QAC3D,YAAY,GAAG,kBAAkB,CAAC,WAAW,CAAC,OAAO,EAAE,SAAS,CAAC,CAAA;QACjE,GAAG,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,WAAW,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,uCAAuC,CAAC,CAAA;IAC1F,CAAC;IAED,KAAK,UAAU,KAAK;QAClB,qEAAqE;QACrE,sEAAsE;QACtE,wCAAwC;QACxC,MAAM,OAAO,GAA+B,EAAE,CAAA;QAC9C,IAAI,CAAC;YACH,IAAI,eAAe,EAAE,CAAC;gBACpB,MAAM,eAAe,CAAC,KAAK,EAAE,CAAA;gBAC7B,OAAO,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,eAAgB,CAAC,IAAI,EAAE,CAAC,CAAA;YAC7C,CAAC;YACD,IAAI,YAAY,EAAE,CAAC;gBACjB,MAAM,YAAY,CAAC,KAAK,EAAE,CAAA;gBAC1B,OAAO,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,YAAa,CAAC,IAAI,EAAE,CAAC,CAAA;YAC1C,CAAC;QACH,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,KAAK,MAAM,QAAQ,IAAI,OAAO,CAAC,OAAO,EAAE,EAAE,CAAC;gBACzC,IAAI,CAAC;oBAAC,MAAM,QAAQ,EAAE,CAAA;gBAAC,CAAC;gBAAC,OAAO,WAAW,EAAE,CAAC;oBAC5C,GAAG,CAAC,IAAI,CAAC,EAAE,GAAG,EAAE,WAAW,EAAE,EAAE,oCAAoC,CAAC,CAAA;gBACtE,CAAC;YACH,CAAC;YACD,MAAM,GAAG,CAAA;QACX,CAAC;IACH,CAAC;IAED,KAAK,UAAU,IAAI;QACjB,IAAI,eAAe;YAAE,aAAa,CAAC,eAAe,CAAC,CAAA;QACnD,IAAI,eAAe,EAAE,CAAC;YACpB,IAAI,CAAC;gBAAC,MAAM,eAAe,CAAC,IAAI,EAAE,CAAA;YAAC,CAAC;YAAC,OAAO,GAAG,EAAE,CAAC;gBAChD,GAAG,CAAC,IAAI,CAAC,EAAE,GAAG,EAAE,EAAE,iCAAiC,CAAC,CAAA;YACtD,CAAC;QACH,CAAC;QACD,IAAI,YAAY,EAAE,CAAC;YACjB,IAAI,CAAC;gBAAC,MAAM,YAAY,CAAC,IAAI,EAAE,CAAA;YAAC,CAAC;YAAC,OAAO,GAAG,EAAE,CAAC;gBAC7C,GAAG,CAAC,IAAI,CAAC,EAAE,GAAG,EAAE,EAAE,8BAA8B,CAAC,CAAA;YACnD,CAAC;QACH,CAAC;QACD,aAAa,EAAE,CAAA;IACjB,CAAC;IAED,OAAO,EAAE,GAAG,EAAE,MAAM,EAAE,YAAY,EAAE,aAAa,EAAE,KAAK,EAAE,IAAI,EAAE,CAAA;AAClE,CAAC"}
|
|
@@ -20,6 +20,9 @@ function isValidHeaders(value) {
|
|
|
20
20
|
return false;
|
|
21
21
|
return Object.values(value).every((v) => typeof v === 'string');
|
|
22
22
|
}
|
|
23
|
+
function isValidAuthMode(value) {
|
|
24
|
+
return value === 'none' || value === 'api-key' || value === 'api-key-telegram';
|
|
25
|
+
}
|
|
23
26
|
function isProxyMapping(value) {
|
|
24
27
|
if (typeof value !== 'object' || value === null)
|
|
25
28
|
return false;
|
|
@@ -32,6 +35,24 @@ function isProxyMapping(value) {
|
|
|
32
35
|
return false;
|
|
33
36
|
if (m.host !== undefined && (typeof m.host !== 'string' || m.host.length === 0))
|
|
34
37
|
return false;
|
|
38
|
+
if (m.authMode !== undefined && !isValidAuthMode(m.authMode))
|
|
39
|
+
return false;
|
|
40
|
+
if (m.apiKeyHeader !== undefined && (typeof m.apiKeyHeader !== 'string' || m.apiKeyHeader.length === 0))
|
|
41
|
+
return false;
|
|
42
|
+
if (m.apiKeyPrefix !== undefined && typeof m.apiKeyPrefix !== 'string')
|
|
43
|
+
return false;
|
|
44
|
+
if (m.telegramApprovalTtlSeconds !== undefined &&
|
|
45
|
+
(typeof m.telegramApprovalTtlSeconds !== 'number'
|
|
46
|
+
|| !Number.isInteger(m.telegramApprovalTtlSeconds)
|
|
47
|
+
|| m.telegramApprovalTtlSeconds < 0)) {
|
|
48
|
+
return false;
|
|
49
|
+
}
|
|
50
|
+
// When auth is required, the caller header name is mandatory. Fail fast at
|
|
51
|
+
// load time rather than at the first request — the operator wants a
|
|
52
|
+
// descriptive startup error, not a 500 later.
|
|
53
|
+
if (m.authMode !== undefined && m.authMode !== 'none' && m.apiKeyHeader === undefined) {
|
|
54
|
+
return false;
|
|
55
|
+
}
|
|
35
56
|
return true;
|
|
36
57
|
}
|
|
37
58
|
function isProxyConfig(value) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"proxy_config.js","sourceRoot":"","sources":["../../../../../server/src/domains/request-proxy/config/proxy_config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACrC,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAEpC,OAAO,EAAE,cAAc,EAAE,MAAM,oCAAoC,CAAC;AAEpE,SAAS,WAAW,CAAC,KAAc;IACjC,OAAO,OAAO,KAAK,KAAK,QAAQ,IAAI,MAAM,CAAC,SAAS,CAAC,KAAK,CAAC,IAAI,KAAK,IAAI,CAAC,IAAI,KAAK,IAAI,KAAK,CAAC;AAC9F,CAAC;AAED,SAAS,cAAc,CAAC,KAAc;IACpC,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,KAAK,CAAC;IAClE,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,KAAK,CAAC,CAAC;QAC3B,OAAO,GAAG,CAAC,QAAQ,KAAK,OAAO,IAAI,GAAG,CAAC,QAAQ,KAAK,QAAQ,CAAC;IAC/D,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC;AAED,SAAS,cAAc,CAAC,KAAc;IACpC,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC;QAAE,OAAO,KAAK,CAAC;IACtF,OAAO,MAAM,CAAC,MAAM,CAAC,KAAgC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC,KAAK,QAAQ,CAAC,CAAC;AAC7F,CAAC;AAED,SAAS,cAAc,CAAC,KAAc;IACpC,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI;QAAE,OAAO,KAAK,CAAC;IAC9D,MAAM,CAAC,GAAG,KAAgC,CAAC;IAC3C,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC,IAAI,CAAC;QAAE,OAAO,KAAK,CAAC;IACvC,IAAI,CAAC,cAAc,CAAC,CAAC,CAAC,OAAO,CAAC;QAAE,OAAO,KAAK,CAAC;IAC7C,IAAI,CAAC,CAAC,OAAO,KAAK,SAAS,IAAI,CAAC,cAAc,CAAC,CAAC,CAAC,OAAO,CAAC;QAAE,OAAO,KAAK,CAAC;IACxE,IAAI,CAAC,CAAC,IAAI,KAAK,SAAS,IAAI,CAAC,OAAO,CAAC,CAAC,IAAI,KAAK,QAAQ,IAAI,CAAC,CAAC,IAAI,CAAC,MAAM,KAAK,CAAC,CAAC;QAAE,OAAO,KAAK,CAAC;
|
|
1
|
+
{"version":3,"file":"proxy_config.js","sourceRoot":"","sources":["../../../../../server/src/domains/request-proxy/config/proxy_config.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* In-memory TTL cache for "approved" proxy decisions, keyed by the tuple
|
|
3
|
+
* `(api-key-id, port)`. A cache hit means the token-holder has an
|
|
4
|
+
* unexpired Telegram approval for this specific proxy listener, so the
|
|
5
|
+
* next request is forwarded without asking the approver again.
|
|
6
|
+
*
|
|
7
|
+
* Why in-memory (and not SQLite, like command approvals): proxy traffic is
|
|
8
|
+
* expected to be high-volume and the approval is scoped to a running agent
|
|
9
|
+
* session. Survival across restarts is a non-goal for v1 — an operator
|
|
10
|
+
* restart should re-prompt, which is the conservative default. Persisting
|
|
11
|
+
* proxy approvals can be added later without changing the cache API.
|
|
12
|
+
*/
|
|
13
|
+
/**
|
|
14
|
+
* Construct a cache. `now` is injectable so tests can advance time
|
|
15
|
+
* without using real timers.
|
|
16
|
+
*/
|
|
17
|
+
export function createProxyApprovalCache(now = Date.now) {
|
|
18
|
+
const entries = new Map();
|
|
19
|
+
function cacheKey(key) {
|
|
20
|
+
return `${key.keyId}::${key.port}`;
|
|
21
|
+
}
|
|
22
|
+
return {
|
|
23
|
+
has(key) {
|
|
24
|
+
const expiresAt = entries.get(cacheKey(key));
|
|
25
|
+
if (expiresAt === undefined)
|
|
26
|
+
return false;
|
|
27
|
+
if (expiresAt <= now()) {
|
|
28
|
+
entries.delete(cacheKey(key));
|
|
29
|
+
return false;
|
|
30
|
+
}
|
|
31
|
+
return true;
|
|
32
|
+
},
|
|
33
|
+
set(key, ttlSeconds) {
|
|
34
|
+
if (ttlSeconds <= 0) {
|
|
35
|
+
// A zero/negative TTL means "do not cache". Dropping the write is
|
|
36
|
+
// simpler than surfacing an error — callers disable caching by
|
|
37
|
+
// setting the config value to 0.
|
|
38
|
+
entries.delete(cacheKey(key));
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
entries.set(cacheKey(key), now() + ttlSeconds * 1000);
|
|
42
|
+
},
|
|
43
|
+
clear() {
|
|
44
|
+
entries.clear();
|
|
45
|
+
},
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
//# sourceMappingURL=proxy_approval_cache.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"proxy_approval_cache.js","sourceRoot":"","sources":["../../../../../server/src/domains/request-proxy/service/proxy_approval_cache.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAgBH;;;GAGG;AACH,MAAM,UAAU,wBAAwB,CAAC,MAAoB,IAAI,CAAC,GAAG;IACnE,MAAM,OAAO,GAAG,IAAI,GAAG,EAAkB,CAAC;IAE1C,SAAS,QAAQ,CAAC,GAA0B;QAC1C,OAAO,GAAG,GAAG,CAAC,KAAK,KAAK,GAAG,CAAC,IAAI,EAAE,CAAC;IACrC,CAAC;IAED,OAAO;QACL,GAAG,CAAC,GAA0B;YAC5B,MAAM,SAAS,GAAG,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC;YAC7C,IAAI,SAAS,KAAK,SAAS;gBAAE,OAAO,KAAK,CAAC;YAC1C,IAAI,SAAS,IAAI,GAAG,EAAE,EAAE,CAAC;gBACvB,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC;gBAC9B,OAAO,KAAK,CAAC;YACf,CAAC;YACD,OAAO,IAAI,CAAC;QACd,CAAC;QAED,GAAG,CAAC,GAA0B,EAAE,UAAkB;YAChD,IAAI,UAAU,IAAI,CAAC,EAAE,CAAC;gBACpB,kEAAkE;gBAClE,+DAA+D;gBAC/D,iCAAiC;gBACjC,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC;gBAC9B,OAAO;YACT,CAAC;YACD,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,GAAG,EAAE,GAAG,UAAU,GAAG,IAAI,CAAC,CAAC;QACxD,CAAC;QAED,KAAK;YACH,OAAO,CAAC,KAAK,EAAE,CAAC;QAClB,CAAC;KACF,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,204 @@
|
|
|
1
|
+
import { randomUUID } from 'node:crypto';
|
|
2
|
+
import { DEFAULT_PROXY_APPROVAL_TTL_SECONDS } from '../types/proxy_types.js';
|
|
3
|
+
import { createChildLogger } from '../../../lib/logger.js';
|
|
4
|
+
const log = createChildLogger('proxy-auth');
|
|
5
|
+
/**
|
|
6
|
+
* Authenticate and (optionally) request approval for a single proxy request.
|
|
7
|
+
*
|
|
8
|
+
* Pure logic — takes the incoming request and the per-mapping dependencies,
|
|
9
|
+
* returns a decision. The proxy server is responsible for writing the 401/403
|
|
10
|
+
* response and for deleting the caller's auth header from the forwarded
|
|
11
|
+
* request when the decision is `pass`.
|
|
12
|
+
*/
|
|
13
|
+
export async function authorizeProxyRequest(req, deps) {
|
|
14
|
+
const { mapping, validator, approvalRequester, cache, audit, generateRequestId } = deps;
|
|
15
|
+
const requestId = generateRequestId ? generateRequestId() : randomUUID();
|
|
16
|
+
const authMode = mapping.authMode ?? 'none';
|
|
17
|
+
if (authMode === 'none') {
|
|
18
|
+
return { kind: 'pass', requestId };
|
|
19
|
+
}
|
|
20
|
+
if (mapping.apiKeyHeader === undefined) {
|
|
21
|
+
// Config loader should reject this, but fail closed if we ever see it.
|
|
22
|
+
recordAudit(audit, {
|
|
23
|
+
type: 'proxy_auth_denied', requestId, mapping, req,
|
|
24
|
+
reason: 'apiKeyHeader not configured',
|
|
25
|
+
});
|
|
26
|
+
return {
|
|
27
|
+
kind: 'reject', requestId,
|
|
28
|
+
status: 500, code: 'misconfigured',
|
|
29
|
+
message: 'Proxy mapping is misconfigured (apiKeyHeader missing).',
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
if (!validator) {
|
|
33
|
+
recordAudit(audit, {
|
|
34
|
+
type: 'proxy_auth_denied', requestId, mapping, req,
|
|
35
|
+
reason: 'no validator wired',
|
|
36
|
+
});
|
|
37
|
+
return {
|
|
38
|
+
kind: 'reject', requestId,
|
|
39
|
+
status: 500, code: 'misconfigured',
|
|
40
|
+
message: 'Proxy auth is configured but no token validator is available.',
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
const rawToken = extractToken(req, mapping.apiKeyHeader, mapping.apiKeyPrefix);
|
|
44
|
+
if (rawToken === undefined) {
|
|
45
|
+
recordAudit(audit, {
|
|
46
|
+
type: 'proxy_auth_denied', requestId, mapping, req,
|
|
47
|
+
reason: 'missing or malformed header',
|
|
48
|
+
});
|
|
49
|
+
return {
|
|
50
|
+
kind: 'reject', requestId,
|
|
51
|
+
status: 401, code: 'unauthorized',
|
|
52
|
+
message: 'Missing or malformed authentication header.',
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
const identity = validator.validate(rawToken);
|
|
56
|
+
if (!identity) {
|
|
57
|
+
recordAudit(audit, {
|
|
58
|
+
type: 'proxy_auth_denied', requestId, mapping, req,
|
|
59
|
+
reason: 'invalid token',
|
|
60
|
+
});
|
|
61
|
+
return {
|
|
62
|
+
kind: 'reject', requestId,
|
|
63
|
+
status: 401, code: 'unauthorized',
|
|
64
|
+
message: 'Invalid authentication token.',
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
if (authMode === 'api-key') {
|
|
68
|
+
recordAudit(audit, {
|
|
69
|
+
type: 'proxy_auth_ok', requestId, mapping, req, identity,
|
|
70
|
+
});
|
|
71
|
+
return { kind: 'pass', requestId, keyId: identity.keyId, keyName: identity.keyName };
|
|
72
|
+
}
|
|
73
|
+
// authMode === 'api-key-telegram'
|
|
74
|
+
if (!approvalRequester) {
|
|
75
|
+
recordAudit(audit, {
|
|
76
|
+
type: 'proxy_approval_error', requestId, mapping, req, identity,
|
|
77
|
+
reason: 'no approval requester wired',
|
|
78
|
+
});
|
|
79
|
+
return {
|
|
80
|
+
kind: 'reject', requestId,
|
|
81
|
+
status: 500, code: 'misconfigured',
|
|
82
|
+
message: 'Telegram approval is configured but no approval channel is available.',
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
const cacheKey = { keyId: identity.keyId, port: mapping.port };
|
|
86
|
+
if (cache?.has(cacheKey)) {
|
|
87
|
+
recordAudit(audit, {
|
|
88
|
+
type: 'proxy_approval_approved', requestId, mapping, req, identity, source: 'cache',
|
|
89
|
+
});
|
|
90
|
+
return { kind: 'pass', requestId, keyId: identity.keyId, keyName: identity.keyName };
|
|
91
|
+
}
|
|
92
|
+
const approvalCtx = {
|
|
93
|
+
port: mapping.port,
|
|
94
|
+
baseUrl: mapping.baseUrl,
|
|
95
|
+
method: req.method ?? 'GET',
|
|
96
|
+
path: req.url ?? '/',
|
|
97
|
+
keyId: identity.keyId,
|
|
98
|
+
keyName: identity.keyName,
|
|
99
|
+
ip: callerIp(req),
|
|
100
|
+
requestId,
|
|
101
|
+
};
|
|
102
|
+
recordAudit(audit, { type: 'proxy_approval_requested', requestId, mapping, req, identity });
|
|
103
|
+
let outcome;
|
|
104
|
+
try {
|
|
105
|
+
outcome = await approvalRequester.request(approvalCtx);
|
|
106
|
+
}
|
|
107
|
+
catch (err) {
|
|
108
|
+
log.error({ err, requestId, port: mapping.port }, 'Approval requester threw');
|
|
109
|
+
recordAudit(audit, {
|
|
110
|
+
type: 'proxy_approval_error', requestId, mapping, req, identity,
|
|
111
|
+
reason: err instanceof Error ? err.message : 'approval error',
|
|
112
|
+
});
|
|
113
|
+
return {
|
|
114
|
+
kind: 'reject', requestId,
|
|
115
|
+
status: 503, code: 'approval_error',
|
|
116
|
+
message: 'Approval channel failed.',
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
if (outcome === 'approved') {
|
|
120
|
+
const ttl = mapping.telegramApprovalTtlSeconds ?? DEFAULT_PROXY_APPROVAL_TTL_SECONDS;
|
|
121
|
+
cache?.set(cacheKey, ttl);
|
|
122
|
+
recordAudit(audit, {
|
|
123
|
+
type: 'proxy_approval_approved', requestId, mapping, req, identity, source: 'telegram',
|
|
124
|
+
});
|
|
125
|
+
return { kind: 'pass', requestId, keyId: identity.keyId, keyName: identity.keyName };
|
|
126
|
+
}
|
|
127
|
+
if (outcome === 'timeout') {
|
|
128
|
+
recordAudit(audit, { type: 'proxy_approval_timeout', requestId, mapping, req, identity });
|
|
129
|
+
return {
|
|
130
|
+
kind: 'reject', requestId,
|
|
131
|
+
status: 408, code: 'approval_timeout',
|
|
132
|
+
message: 'Approval timed out.',
|
|
133
|
+
};
|
|
134
|
+
}
|
|
135
|
+
if (outcome === 'error') {
|
|
136
|
+
recordAudit(audit, {
|
|
137
|
+
type: 'proxy_approval_error', requestId, mapping, req, identity,
|
|
138
|
+
reason: 'approval channel error',
|
|
139
|
+
});
|
|
140
|
+
return {
|
|
141
|
+
kind: 'reject', requestId,
|
|
142
|
+
status: 503, code: 'approval_error',
|
|
143
|
+
message: 'Approval channel failed.',
|
|
144
|
+
};
|
|
145
|
+
}
|
|
146
|
+
// outcome === 'denied'
|
|
147
|
+
recordAudit(audit, { type: 'proxy_approval_denied', requestId, mapping, req, identity });
|
|
148
|
+
return {
|
|
149
|
+
kind: 'reject', requestId,
|
|
150
|
+
status: 403, code: 'forbidden',
|
|
151
|
+
message: 'Approval denied.',
|
|
152
|
+
};
|
|
153
|
+
}
|
|
154
|
+
/**
|
|
155
|
+
* Extract the token value from the configured header (case-insensitive).
|
|
156
|
+
* Returns `undefined` when missing, empty, or when a required prefix is
|
|
157
|
+
* not present.
|
|
158
|
+
*/
|
|
159
|
+
function extractToken(req, headerName, prefix) {
|
|
160
|
+
const lower = headerName.toLowerCase();
|
|
161
|
+
const raw = req.headers[lower];
|
|
162
|
+
const value = Array.isArray(raw) ? raw[0] : raw;
|
|
163
|
+
if (typeof value !== 'string' || value.length === 0)
|
|
164
|
+
return undefined;
|
|
165
|
+
if (prefix !== undefined && prefix.length > 0) {
|
|
166
|
+
if (!value.startsWith(prefix))
|
|
167
|
+
return undefined;
|
|
168
|
+
const stripped = value.slice(prefix.length);
|
|
169
|
+
return stripped.length > 0 ? stripped : undefined;
|
|
170
|
+
}
|
|
171
|
+
return value;
|
|
172
|
+
}
|
|
173
|
+
/**
|
|
174
|
+
* Best-effort remote address extraction. The proxy listeners bind to loopback
|
|
175
|
+
* by default, so in production this is primarily used for audit context
|
|
176
|
+
* rather than authorization.
|
|
177
|
+
*/
|
|
178
|
+
function callerIp(req) {
|
|
179
|
+
return req.socket?.remoteAddress ?? 'unknown';
|
|
180
|
+
}
|
|
181
|
+
function recordAudit(sink, args) {
|
|
182
|
+
if (!sink)
|
|
183
|
+
return;
|
|
184
|
+
const event = {
|
|
185
|
+
type: args.type,
|
|
186
|
+
ts: new Date().toISOString(),
|
|
187
|
+
requestId: args.requestId,
|
|
188
|
+
port: args.mapping.port,
|
|
189
|
+
method: args.req.method ?? 'GET',
|
|
190
|
+
path: args.req.url ?? '/',
|
|
191
|
+
keyId: args.identity?.keyId,
|
|
192
|
+
keyName: args.identity?.keyName,
|
|
193
|
+
ip: callerIp(args.req),
|
|
194
|
+
reason: args.reason,
|
|
195
|
+
source: args.source,
|
|
196
|
+
};
|
|
197
|
+
try {
|
|
198
|
+
sink.record(event);
|
|
199
|
+
}
|
|
200
|
+
catch (err) {
|
|
201
|
+
log.warn({ err, requestId: args.requestId }, 'Proxy audit sink threw; continuing');
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
//# sourceMappingURL=proxy_auth.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"proxy_auth.js","sourceRoot":"","sources":["../../../../../server/src/domains/request-proxy/service/proxy_auth.ts"],"names":[],"mappings":"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"}
|
|
@@ -2,14 +2,29 @@ import http from 'node:http';
|
|
|
2
2
|
import { createProxyMiddleware } from 'http-proxy-middleware';
|
|
3
3
|
import { DEFAULT_PROXY_HOST } from '../types/proxy_types.js';
|
|
4
4
|
import { createChildLogger } from '../../../lib/logger.js';
|
|
5
|
+
import { authorizeProxyRequest } from './proxy_auth.js';
|
|
6
|
+
import { createProxyApprovalCache } from './proxy_approval_cache.js';
|
|
5
7
|
const log = createChildLogger('proxy');
|
|
6
|
-
function
|
|
8
|
+
function writeJsonError(res, status, code, message) {
|
|
9
|
+
if (res.headersSent)
|
|
10
|
+
return;
|
|
11
|
+
res.writeHead(status, { 'Content-Type': 'application/json' });
|
|
12
|
+
res.end(JSON.stringify({ error: code, message }));
|
|
13
|
+
}
|
|
14
|
+
function buildProxyServer(mapping, deps, cache) {
|
|
7
15
|
const middleware = createProxyMiddleware({
|
|
8
16
|
target: mapping.baseUrl,
|
|
9
17
|
changeOrigin: true,
|
|
10
18
|
logger: log,
|
|
11
19
|
on: {
|
|
12
20
|
proxyReq: (proxyReq) => {
|
|
21
|
+
// Defense-in-depth: also strip the caller's auth header from the
|
|
22
|
+
// outgoing request. The incoming req.headers has already been
|
|
23
|
+
// mutated (see handler below), but proxyReq.removeHeader is the
|
|
24
|
+
// authoritative write onto the outgoing socket.
|
|
25
|
+
if (mapping.authMode && mapping.authMode !== 'none' && mapping.apiKeyHeader) {
|
|
26
|
+
proxyReq.removeHeader(mapping.apiKeyHeader);
|
|
27
|
+
}
|
|
13
28
|
if (!mapping.headers)
|
|
14
29
|
return;
|
|
15
30
|
for (const [name, value] of Object.entries(mapping.headers)) {
|
|
@@ -28,12 +43,34 @@ function buildProxyServer(mapping) {
|
|
|
28
43
|
},
|
|
29
44
|
});
|
|
30
45
|
return http.createServer((req, res) => {
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
46
|
+
authorizeProxyRequest(req, {
|
|
47
|
+
mapping,
|
|
48
|
+
validator: deps.tokenValidator,
|
|
49
|
+
approvalRequester: deps.approvalRequester,
|
|
50
|
+
cache,
|
|
51
|
+
audit: deps.auditSink,
|
|
52
|
+
})
|
|
53
|
+
.then((decision) => {
|
|
54
|
+
if (decision.kind === 'reject') {
|
|
55
|
+
writeJsonError(res, decision.status, decision.code, decision.message);
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
// Strip the caller's auth header from req.headers before the proxy
|
|
59
|
+
// middleware forwards it, so the lucifer-gate token does not leak
|
|
60
|
+
// upstream. The proxyReq handler also removes it on the outgoing
|
|
61
|
+
// socket (belt and braces).
|
|
62
|
+
if (mapping.authMode && mapping.authMode !== 'none' && mapping.apiKeyHeader) {
|
|
63
|
+
delete req.headers[mapping.apiKeyHeader.toLowerCase()];
|
|
36
64
|
}
|
|
65
|
+
middleware(req, res).catch((err) => {
|
|
66
|
+
log.error({ err, port: mapping.port }, 'Proxy middleware threw');
|
|
67
|
+
writeJsonError(res, 502, 'bad_gateway', 'Proxy handler failed');
|
|
68
|
+
});
|
|
69
|
+
})
|
|
70
|
+
.catch((err) => {
|
|
71
|
+
// authorizeProxyRequest never rejects, but guard just in case.
|
|
72
|
+
log.error({ err, port: mapping.port }, 'Proxy auth threw unexpectedly');
|
|
73
|
+
writeJsonError(res, 500, 'internal_error', 'Proxy authorization failed');
|
|
37
74
|
});
|
|
38
75
|
});
|
|
39
76
|
}
|
|
@@ -69,6 +106,26 @@ async function bestEffortClose(server) {
|
|
|
69
106
|
log.warn({ err }, 'Error while closing proxy listener');
|
|
70
107
|
}
|
|
71
108
|
}
|
|
109
|
+
/**
|
|
110
|
+
* Validate that every mapping with a non-`none` authMode has the runtime
|
|
111
|
+
* deps it needs. Called at startup so operators get a descriptive error
|
|
112
|
+
* rather than a confusing 500 on the first request.
|
|
113
|
+
*/
|
|
114
|
+
function validateMappingDeps(mappings, deps) {
|
|
115
|
+
for (const [index, m] of mappings.entries()) {
|
|
116
|
+
const mode = m.authMode ?? 'none';
|
|
117
|
+
if (mode === 'none')
|
|
118
|
+
continue;
|
|
119
|
+
if (!deps.tokenValidator) {
|
|
120
|
+
throw new Error(`Proxy mapping proxies[${index}] (port ${m.port}) has authMode='${mode}' but no token validator is wired. ` +
|
|
121
|
+
`Ensure api-keys.json is present so the gateway is initialized before the proxy.`);
|
|
122
|
+
}
|
|
123
|
+
if (mode === 'api-key-telegram' && !deps.approvalRequester) {
|
|
124
|
+
throw new Error(`Proxy mapping proxies[${index}] (port ${m.port}) has authMode='api-key-telegram' but no approval channel is wired. ` +
|
|
125
|
+
`Configure Telegram (LUCIFER_TELEGRAM_TOKEN + chat id) or the web approval UI.`);
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
}
|
|
72
129
|
/**
|
|
73
130
|
* Build proxy servers for a set of mappings. Listeners are NOT bound until
|
|
74
131
|
* `start()` is called so that `createApp()` stays synchronous and config
|
|
@@ -78,11 +135,17 @@ async function bestEffortClose(server) {
|
|
|
78
135
|
* started listeners are closed before the error is rethrown, so the caller
|
|
79
136
|
* never observes a partially-started set.
|
|
80
137
|
*/
|
|
81
|
-
export function createProxyServers(mappings) {
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
138
|
+
export function createProxyServers(mappings, deps = {}) {
|
|
139
|
+
validateMappingDeps(mappings, deps);
|
|
140
|
+
const cacheFactory = deps.approvalCacheFactory ?? (() => createProxyApprovalCache());
|
|
141
|
+
const running = mappings.map((mapping) => {
|
|
142
|
+
const cache = cacheFactory();
|
|
143
|
+
return {
|
|
144
|
+
mapping,
|
|
145
|
+
cache,
|
|
146
|
+
server: buildProxyServer(mapping, deps, cache),
|
|
147
|
+
};
|
|
148
|
+
});
|
|
86
149
|
async function start() {
|
|
87
150
|
const started = [];
|
|
88
151
|
try {
|
|
@@ -90,7 +153,7 @@ export function createProxyServers(mappings) {
|
|
|
90
153
|
const host = entry.mapping.host ?? DEFAULT_PROXY_HOST;
|
|
91
154
|
await listenAsync(entry.server, entry.mapping.port, host);
|
|
92
155
|
started.push(entry);
|
|
93
|
-
log.info({ port: entry.mapping.port, host, baseUrl: entry.mapping.baseUrl }, 'Proxy listening');
|
|
156
|
+
log.info({ port: entry.mapping.port, host, baseUrl: entry.mapping.baseUrl, authMode: entry.mapping.authMode ?? 'none' }, 'Proxy listening');
|
|
94
157
|
}
|
|
95
158
|
}
|
|
96
159
|
catch (err) {
|
|
@@ -103,7 +166,10 @@ export function createProxyServers(mappings) {
|
|
|
103
166
|
async function stop() {
|
|
104
167
|
// Best-effort close: a listener that never bound (e.g. because start()
|
|
105
168
|
// failed partway) must not prevent cleanup of the rest.
|
|
106
|
-
await Promise.all(running.map(({ server }) =>
|
|
169
|
+
await Promise.all(running.map(({ server, cache }) => {
|
|
170
|
+
cache.clear();
|
|
171
|
+
return bestEffortClose(server);
|
|
172
|
+
}));
|
|
107
173
|
}
|
|
108
174
|
return { start, stop };
|
|
109
175
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"proxy_server.js","sourceRoot":"","sources":["../../../../../server/src/domains/request-proxy/service/proxy_server.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,qBAAqB,EAAE,MAAM,uBAAuB,CAAC;
|
|
1
|
+
{"version":3,"file":"proxy_server.js","sourceRoot":"","sources":["../../../../../server/src/domains/request-proxy/service/proxy_server.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"proxy_types.js","sourceRoot":"","sources":["../../../../../server/src/domains/request-proxy/types/proxy_types.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"proxy_types.js","sourceRoot":"","sources":["../../../../../server/src/domains/request-proxy/types/proxy_types.ts"],"names":[],"mappings":"AA0BA,MAAM,CAAC,MAAM,uBAAuB,GAAkB,MAAM,CAAC;AAC7D,MAAM,CAAC,MAAM,kCAAkC,GAAG,IAAI,CAAC;AAavD,MAAM,CAAC,MAAM,kBAAkB,GAAG,WAAW,CAAC"}
|
|
@@ -17,7 +17,9 @@ export function createTestAppContext(label, options) {
|
|
|
17
17
|
approvalTimeoutSeconds: 5,
|
|
18
18
|
executionTimeoutSeconds: 10,
|
|
19
19
|
maxConcurrentExecutions: 3,
|
|
20
|
-
|
|
20
|
+
// Integration tests run real commands against the repo (e.g. `git status`),
|
|
21
|
+
// so this needs to accommodate a growing working tree. 1 KiB was brittle.
|
|
22
|
+
maxOutputBytes: 65536,
|
|
21
23
|
rateLimitPerMinute: 100,
|
|
22
24
|
onApprovalTimeout: 'deny',
|
|
23
25
|
dataDir: '../data',
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"integration-setup.js","sourceRoot":"","sources":["../../../server/src/test/integration-setup.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AAC3D,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAC7C,OAAO,EAAE,UAAU,EAAE,MAAM,wDAAwD,CAAC;AAUpF,MAAM,UAAU,oBAAoB,CAClC,KAAa,EACb,OAGC;IAED,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,SAAS,KAAK,EAAE,CAAC,CAAC;IACtD,MAAM,SAAS,GAAG,IAAI,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC;IAC1C,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;IAEtC,MAAM,OAAO,GAAG,OAAO,KAAK,QAAQ,CAAC;IACrC,MAAM,QAAQ,GAAG,GAAG,KAAK,eAAe,CAAC;IACzC,MAAM,QAAQ,GAAG,UAAU,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC;IAE/C,SAAS,CAAC,SAAS,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAC1C,SAAS,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAExC,MAAM,UAAU,GAAG,IAAI,CAAC,SAAS,EAAE,cAAc,CAAC,CAAC;IAEnD,aAAa,CAAC,UAAU,EAAE,IAAI,CAAC,SAAS,CAAC;QACvC,IAAI,EAAE,CAAC;QACP,sBAAsB,EAAE,CAAC;QACzB,uBAAuB,EAAE,EAAE;QAC3B,uBAAuB,EAAE,CAAC;QAC1B,cAAc,EAAE,
|
|
1
|
+
{"version":3,"file":"integration-setup.js","sourceRoot":"","sources":["../../../server/src/test/integration-setup.ts"],"names":[],"mappings":"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"}
|