@cat-factory/server 0.202.0 → 0.204.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/dist/agents/modelProviderResolver.d.ts +11 -9
- package/dist/agents/modelProviderResolver.d.ts.map +1 -1
- package/dist/agents/modelProviderResolver.js +8 -8
- package/dist/agents/modelProviderResolver.js.map +1 -1
- package/dist/auth/machineGate.d.ts +21 -0
- package/dist/auth/machineGate.d.ts.map +1 -0
- package/dist/auth/machineGate.js +32 -0
- package/dist/auth/machineGate.js.map +1 -0
- package/dist/config/platformAlerts.d.ts +8 -3
- package/dist/config/platformAlerts.d.ts.map +1 -1
- package/dist/config/platformAlerts.js +6 -1
- package/dist/config/platformAlerts.js.map +1 -1
- package/dist/config/types.d.ts +43 -3
- package/dist/config/types.d.ts.map +1 -1
- package/dist/events/machineSubscribe.d.ts +17 -1
- package/dist/events/machineSubscribe.d.ts.map +1 -1
- package/dist/events/machineSubscribe.js +30 -0
- package/dist/events/machineSubscribe.js.map +1 -1
- package/dist/http/clientAddress.d.ts +40 -0
- package/dist/http/clientAddress.d.ts.map +1 -0
- package/dist/http/clientAddress.js +140 -0
- package/dist/http/clientAddress.js.map +1 -0
- package/dist/http/env.d.ts +26 -1
- package/dist/http/env.d.ts.map +1 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -1
- package/dist/index.js.map +1 -1
- package/dist/modules/auth/AuthController.d.ts.map +1 -1
- package/dist/modules/auth/AuthController.js +87 -41
- package/dist/modules/auth/AuthController.js.map +1 -1
- package/dist/modules/auth/authThrottle.d.ts +18 -0
- package/dist/modules/auth/authThrottle.d.ts.map +1 -0
- package/dist/modules/auth/authThrottle.js +118 -0
- package/dist/modules/auth/authThrottle.js.map +1 -0
- package/dist/modules/binaryGenerators/BinaryGeneratorsController.d.ts.map +1 -1
- package/dist/modules/binaryGenerators/BinaryGeneratorsController.js +2 -8
- package/dist/modules/binaryGenerators/BinaryGeneratorsController.js.map +1 -1
- package/dist/modules/bugHunt/BugHuntController.d.ts.map +1 -1
- package/dist/modules/bugHunt/BugHuntController.js +6 -2
- package/dist/modules/bugHunt/BugHuntController.js.map +1 -1
- package/dist/modules/events/EventsRelayController.d.ts.map +1 -1
- package/dist/modules/events/EventsRelayController.js +10 -11
- package/dist/modules/events/EventsRelayController.js.map +1 -1
- package/dist/modules/foundationalServices/FoundationalBuiltinsController.d.ts.map +1 -1
- package/dist/modules/foundationalServices/FoundationalBuiltinsController.js +2 -8
- package/dist/modules/foundationalServices/FoundationalBuiltinsController.js.map +1 -1
- package/dist/modules/llmProxy/LlmProxyController.d.ts.map +1 -1
- package/dist/modules/llmProxy/LlmProxyController.js +38 -17
- package/dist/modules/llmProxy/LlmProxyController.js.map +1 -1
- package/dist/modules/notifications/NotificationRelayController.d.ts.map +1 -1
- package/dist/modules/notifications/NotificationRelayController.js +2 -6
- package/dist/modules/notifications/NotificationRelayController.js.map +1 -1
- package/dist/modules/persistence/GitHubDelegationController.d.ts.map +1 -1
- package/dist/modules/persistence/GitHubDelegationController.js +2 -6
- package/dist/modules/persistence/GitHubDelegationController.js.map +1 -1
- package/dist/modules/persistence/PersistenceController.d.ts.map +1 -1
- package/dist/modules/persistence/PersistenceController.js +3 -6
- package/dist/modules/persistence/PersistenceController.js.map +1 -1
- package/dist/modules/tasks/TaskSourceController.d.ts.map +1 -1
- package/dist/modules/tasks/TaskSourceController.js +11 -3
- package/dist/modules/tasks/TaskSourceController.js.map +1 -1
- package/dist/modules/tasks/TaskWebhookController.d.ts +1 -1
- package/dist/modules/tasks/TaskWebhookController.js +1 -1
- package/dist/modules/telemetry/TelemetryIngestController.d.ts.map +1 -1
- package/dist/modules/telemetry/TelemetryIngestController.js +2 -6
- package/dist/modules/telemetry/TelemetryIngestController.js.map +1 -1
- package/dist/modules/telemetry/TelemetryReadController.d.ts.map +1 -1
- package/dist/modules/telemetry/TelemetryReadController.js +2 -6
- package/dist/modules/telemetry/TelemetryReadController.js.map +1 -1
- package/dist/persistence/rpc-allowlist.d.ts.map +1 -1
- package/dist/persistence/rpc-allowlist.js +18 -0
- package/dist/persistence/rpc-allowlist.js.map +1 -1
- package/dist/runtime/platformHealth.d.ts.map +1 -1
- package/dist/runtime/platformHealth.js +130 -19
- package/dist/runtime/platformHealth.js.map +1 -1
- package/package.json +8 -8
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { type ProviderRegistry, type VendorConcurrencyLimiter, type WorkspaceBodiesGate } from '@cat-factory/agents';
|
|
2
|
-
import {
|
|
2
|
+
import type { ApiKeyService, LocalModelEndpointService } from '@cat-factory/integrations';
|
|
3
3
|
import type { InlineLlmCallRecorder, LlmTraceSink, ModelProviderResolver } from '@cat-factory/kernel';
|
|
4
4
|
export interface ScopedModelProviderOptions {
|
|
5
5
|
/**
|
|
@@ -13,16 +13,18 @@ export interface ScopedModelProviderOptions {
|
|
|
13
13
|
/** Opt-in registries that need no DB key — the Cloudflare lib + Bedrock. */
|
|
14
14
|
extraRegistries?: ProviderRegistry[];
|
|
15
15
|
/**
|
|
16
|
-
*
|
|
17
|
-
* calls reach them like the proxied path. Keyless by design (the endpoint carries an
|
|
16
|
+
* The initiating user's locally-run model endpoints (Ollama / LM Studio / …) so inline
|
|
17
|
+
* LLM calls reach them like the proxied path. Keyless by design (the endpoint carries an
|
|
18
18
|
* optional key), so these register into the per-scope registry directly rather than via
|
|
19
|
-
* the DB API-key pool.
|
|
19
|
+
* the DB API-key pool.
|
|
20
|
+
*
|
|
21
|
+
* Typed as the SERVICE's own methods, not as a pair of callbacks: the read and the
|
|
22
|
+
* transport must come from ONE instance, because that instance is what binds the
|
|
23
|
+
* deployment's loopback/LAN policy (SSRF re-validation on every redirect hop). A
|
|
24
|
+
* structural `{ endpointsFor, fetch }` pair still typechecked when a facade passed the
|
|
25
|
+
* global `fetch`, which is the wrong-policy wiring this option exists to prevent.
|
|
20
26
|
*/
|
|
21
|
-
|
|
22
|
-
provider: string;
|
|
23
|
-
baseUrl: string;
|
|
24
|
-
apiKey: string | null;
|
|
25
|
-
}[]>;
|
|
27
|
+
localRunners?: Pick<LocalModelEndpointService, 'listResolved' | 'fetchRunner'>;
|
|
26
28
|
}
|
|
27
29
|
/**
|
|
28
30
|
* How inline calls are observed: persisted to `llm_call_metrics` via {@link recordCall}, and/or
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"modelProviderResolver.d.ts","sourceRoot":"","sources":["../../src/agents/modelProviderResolver.ts"],"names":[],"mappings":"AAAA,OAAO,EAIL,KAAK,gBAAgB,EACrB,KAAK,wBAAwB,EAC7B,KAAK,mBAAmB,EAKzB,MAAM,qBAAqB,CAAA;AAC5B,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"modelProviderResolver.d.ts","sourceRoot":"","sources":["../../src/agents/modelProviderResolver.ts"],"names":[],"mappings":"AAAA,OAAO,EAIL,KAAK,gBAAgB,EACrB,KAAK,wBAAwB,EAC7B,KAAK,mBAAmB,EAKzB,MAAM,qBAAqB,CAAA;AAC5B,OAAO,KAAK,EAAE,aAAa,EAAE,yBAAyB,EAAE,MAAM,2BAA2B,CAAA;AACzF,OAAO,KAAK,EACV,qBAAqB,EACrB,YAAY,EAEZ,qBAAqB,EAEtB,MAAM,qBAAqB,CAAA;AAe5B,MAAM,WAAW,0BAA0B;IACzC;;;;OAIG;IACH,OAAO,CAAC,EAAE,aAAa,CAAA;IACvB,qFAAqF;IACrF,UAAU,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,MAAM,GAAG,SAAS,CAAA;IACpD,4EAA4E;IAC5E,eAAe,CAAC,EAAE,gBAAgB,EAAE,CAAA;IACpC;;;;;;;;;;;OAWG;IACH,YAAY,CAAC,EAAE,IAAI,CAAC,yBAAyB,EAAE,cAAc,GAAG,aAAa,CAAC,CAAA;CAC/E;AAED;;;;;GAKG;AACH,MAAM,WAAW,qBAAqB;IACpC;;;;;OAKG;IACH,SAAS,CAAC,EAAE,YAAY,CAAA;IACxB;;;;OAIG;IACH,UAAU,CAAC,EAAE,qBAAqB,CAAA;IAClC,aAAa,CAAC,EAAE,OAAO,CAAA;IACvB;;;;;;;OAOG;IACH,sBAAsB,EAAE,mBAAmB,CAAA;CAC5C;AAED,wBAAgB,iCAAiC,CAC/C,IAAI,EAAE,0BAA0B,GAC/B,qBAAqB,CA4CvB;AAuDD,MAAM,WAAW,sBAAsB;IACrC;;;OAGG;IACH,UAAU,CAAC,EAAE,qBAAqB,CAAA;IAClC,2GAA2G;IAC3G,OAAO,EAAE,wBAAwB,CAAA;CAClC;AAED;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,wBAAgB,yBAAyB,CACvC,QAAQ,EAAE,qBAAqB,EAC/B,KAAK,EAAE,sBAAsB,GAC5B,qBAAqB,CAKvB"}
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { CompositeModelProvider, InstrumentedModelProvider, anthropicResolver, limitModelProvider, openAiCompatibleResolver, openAiResolver, } from '@cat-factory/agents';
|
|
2
|
-
import { fetchLocalRunner } from '@cat-factory/integrations';
|
|
3
2
|
import { logger } from '../observability/logger.js';
|
|
4
3
|
import { openAiCompatibleBaseUrlError } from './providerErrors.js';
|
|
5
4
|
export function createScopedModelProviderResolver(opts) {
|
|
@@ -25,17 +24,18 @@ export function createScopedModelProviderResolver(opts) {
|
|
|
25
24
|
}
|
|
26
25
|
}
|
|
27
26
|
// The initiating user's locally-run runners (keyless OpenAI-compatible endpoints).
|
|
28
|
-
// Route their transport through
|
|
29
|
-
// SSRF allow-list on EVERY redirect hop
|
|
30
|
-
// it the AI-SDK default fetch would silently follow a
|
|
31
|
-
// cloud-metadata endpoint (SEC-2).
|
|
32
|
-
|
|
33
|
-
|
|
27
|
+
// Route their transport through the facade's policy-bound runner fetch so the inline
|
|
28
|
+
// path re-validates the SSRF allow-list on EVERY redirect hop, the same guard the
|
|
29
|
+
// proxy path applies. Without it the AI-SDK default fetch would silently follow a
|
|
30
|
+
// local runner's 302 to the cloud-metadata endpoint (SEC-2/SEC-3).
|
|
31
|
+
const runners = opts.localRunners;
|
|
32
|
+
if (scope.userId && runners) {
|
|
33
|
+
for (const ep of await runners.listResolved(scope.userId)) {
|
|
34
34
|
registry[ep.provider] = openAiCompatibleResolver({
|
|
35
35
|
name: ep.provider,
|
|
36
36
|
apiKey: ep.apiKey || 'local',
|
|
37
37
|
baseURL: ep.baseUrl,
|
|
38
|
-
fetch: (url, init) =>
|
|
38
|
+
fetch: (url, init) => runners.fetchRunner(String(url), init ?? {}),
|
|
39
39
|
});
|
|
40
40
|
}
|
|
41
41
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"modelProviderResolver.js","sourceRoot":"","sources":["../../src/agents/modelProviderResolver.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,sBAAsB,EACtB,yBAAyB,EAKzB,iBAAiB,EACjB,kBAAkB,EAClB,wBAAwB,EACxB,cAAc,GACf,MAAM,qBAAqB,CAAA;
|
|
1
|
+
{"version":3,"file":"modelProviderResolver.js","sourceRoot":"","sources":["../../src/agents/modelProviderResolver.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { Context } from 'hono';
|
|
2
|
+
import type { AppEnv } from '../http/env.js';
|
|
3
|
+
import { type MachinePayload } from './signing.js';
|
|
4
|
+
/**
|
|
5
|
+
* The ONE machine-token gate for every `/internal/*` machine endpoint: verify the
|
|
6
|
+
* `machine`-audience token, then consult the machine-node roster so a REVOKED node is
|
|
7
|
+
* refused everywhere at once (SEC-5). Before this helper each controller inlined the same
|
|
8
|
+
* six verify lines, which is exactly how a revocation check would have landed on some
|
|
9
|
+
* endpoints and not others.
|
|
10
|
+
*
|
|
11
|
+
* Returns the verified payload, or null when the request must be refused; each controller
|
|
12
|
+
* keeps its own refusal envelope (the relay controllers' `{ ok: false }` shape and the
|
|
13
|
+
* plain `{ error }` shape both stay where they are). A revoked node gets the same 403 as
|
|
14
|
+
* an invalid token: the caller holds the token either way, so there is no oracle to
|
|
15
|
+
* protect, and the reconnect flow is the remedy for both.
|
|
16
|
+
*
|
|
17
|
+
* A roster read that THROWS propagates (a 500, retried by the machine clients), because
|
|
18
|
+
* an unreadable roster is not consent to serve a possibly-revoked node.
|
|
19
|
+
*/
|
|
20
|
+
export declare function verifyMachineRequest(c: Context<AppEnv>): Promise<MachinePayload | null>;
|
|
21
|
+
//# sourceMappingURL=machineGate.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"machineGate.d.ts","sourceRoot":"","sources":["../../src/auth/machineGate.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,MAAM,CAAA;AACnC,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,gBAAgB,CAAA;AAC5C,OAAO,EAAE,KAAK,cAAc,EAA6B,MAAM,cAAc,CAAA;AAE7E;;;;;;;;;;;;;;;GAeG;AACH,wBAAsB,oBAAoB,CAAC,CAAC,EAAE,OAAO,CAAC,MAAM,CAAC,GAAG,OAAO,CAAC,cAAc,GAAG,IAAI,CAAC,CAW7F"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { TOKEN_AUDIENCE, signerFor } from './signing.js';
|
|
2
|
+
/**
|
|
3
|
+
* The ONE machine-token gate for every `/internal/*` machine endpoint: verify the
|
|
4
|
+
* `machine`-audience token, then consult the machine-node roster so a REVOKED node is
|
|
5
|
+
* refused everywhere at once (SEC-5). Before this helper each controller inlined the same
|
|
6
|
+
* six verify lines, which is exactly how a revocation check would have landed on some
|
|
7
|
+
* endpoints and not others.
|
|
8
|
+
*
|
|
9
|
+
* Returns the verified payload, or null when the request must be refused; each controller
|
|
10
|
+
* keeps its own refusal envelope (the relay controllers' `{ ok: false }` shape and the
|
|
11
|
+
* plain `{ error }` shape both stay where they are). A revoked node gets the same 403 as
|
|
12
|
+
* an invalid token: the caller holds the token either way, so there is no oracle to
|
|
13
|
+
* protect, and the reconnect flow is the remedy for both.
|
|
14
|
+
*
|
|
15
|
+
* A roster read that THROWS propagates (a 500, retried by the machine clients), because
|
|
16
|
+
* an unreadable roster is not consent to serve a possibly-revoked node.
|
|
17
|
+
*/
|
|
18
|
+
export async function verifyMachineRequest(c) {
|
|
19
|
+
const container = c.get('container');
|
|
20
|
+
const secret = container.config.auth.sessionSecret;
|
|
21
|
+
const token = c.req.header('authorization')?.replace(/^Bearer\s+/i, '');
|
|
22
|
+
const payload = secret
|
|
23
|
+
? await signerFor(secret).verify(token, { aud: TOKEN_AUDIENCE.machine })
|
|
24
|
+
: null;
|
|
25
|
+
if (!payload)
|
|
26
|
+
return null;
|
|
27
|
+
const nodes = container.machineNodeRepository;
|
|
28
|
+
if (nodes && (await nodes.isRevoked(payload.nodeId)))
|
|
29
|
+
return null;
|
|
30
|
+
return payload;
|
|
31
|
+
}
|
|
32
|
+
//# sourceMappingURL=machineGate.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"machineGate.js","sourceRoot":"","sources":["../../src/auth/machineGate.ts"],"names":[],"mappings":"AAEA,OAAO,EAAuB,cAAc,EAAE,SAAS,EAAE,MAAM,cAAc,CAAA;AAE7E;;;;;;;;;;;;;;;GAeG;AACH,MAAM,CAAC,KAAK,UAAU,oBAAoB,CAAC,CAAkB;IAC3D,MAAM,SAAS,GAAG,CAAC,CAAC,GAAG,CAAC,WAAW,CAAC,CAAA;IACpC,MAAM,MAAM,GAAG,SAAS,CAAC,MAAM,CAAC,IAAI,CAAC,aAAa,CAAA;IAClD,MAAM,KAAK,GAAG,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,eAAe,CAAC,EAAE,OAAO,CAAC,aAAa,EAAE,EAAE,CAAC,CAAA;IACvE,MAAM,OAAO,GAAG,MAAM;QACpB,CAAC,CAAC,MAAM,SAAS,CAAC,MAAM,CAAC,CAAC,MAAM,CAAiB,KAAK,EAAE,EAAE,GAAG,EAAE,cAAc,CAAC,OAAO,EAAE,CAAC;QACxF,CAAC,CAAC,IAAI,CAAA;IACR,IAAI,CAAC,OAAO;QAAE,OAAO,IAAI,CAAA;IACzB,MAAM,KAAK,GAAG,SAAS,CAAC,qBAAqB,CAAA;IAC7C,IAAI,KAAK,IAAI,CAAC,MAAM,KAAK,CAAC,SAAS,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;QAAE,OAAO,IAAI,CAAA;IACjE,OAAO,OAAO,CAAA;AAChB,CAAC"}
|
|
@@ -1,7 +1,12 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { PlatformAlertWindow } from '@cat-factory/contracts';
|
|
2
2
|
import type { PlatformAlertConfig } from './types.js';
|
|
3
|
-
/**
|
|
4
|
-
|
|
3
|
+
/**
|
|
4
|
+
* Parse the `1h`/`24h`/`7d` alert window, defaulting to the most operationally useful `1h`.
|
|
5
|
+
* The dashboard's rollup-backed `30d`/`90d` windows are deliberately not accepted here (see
|
|
6
|
+
* `platformAlertWindowSchema`), so naming one falls back to `1h` rather than quietly
|
|
7
|
+
* evaluating an alert against a table materialised at best hourly.
|
|
8
|
+
*/
|
|
9
|
+
export declare function parsePlatformObservabilityWindow(raw: string | undefined): PlatformAlertWindow;
|
|
5
10
|
/** The raw env strings each facade feeds the parser (already extracted from its env source). */
|
|
6
11
|
export interface PlatformAlertEnvInput {
|
|
7
12
|
/** Whether `PLATFORM_ALERTS` opted the sweep in. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"platformAlerts.d.ts","sourceRoot":"","sources":["../../src/config/platformAlerts.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,
|
|
1
|
+
{"version":3,"file":"platformAlerts.d.ts","sourceRoot":"","sources":["../../src/config/platformAlerts.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,wBAAwB,CAAA;AAEjE,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAA;AAcrD;;;;;GAKG;AACH,wBAAgB,gCAAgC,CAAC,GAAG,EAAE,MAAM,GAAG,SAAS,GAAG,mBAAmB,CAG7F;AAED,gGAAgG;AAChG,MAAM,WAAW,qBAAqB;IACpC,oDAAoD;IACpD,OAAO,EAAE,OAAO,CAAA;IAChB,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,cAAc,CAAC,EAAE,MAAM,CAAA;IACvB,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,cAAc,CAAC,EAAE,MAAM,CAAA;IACvB,mBAAmB,CAAC,EAAE,MAAM,CAAA;IAC5B,mBAAmB,CAAC,EAAE,MAAM,CAAA;IAC5B,gBAAgB,CAAC,EAAE,MAAM,CAAA;CAC1B;AAED;;;;;GAKG;AACH,wBAAgB,0BAA0B,CAAC,GAAG,EAAE,qBAAqB,GAAG,mBAAmB,CA8D1F"}
|
|
@@ -9,7 +9,12 @@ import { parseNumericEnv } from './numeric.js';
|
|
|
9
9
|
const DEFAULT_PLATFORM_ALERT_INTERVAL_MS = 5 * 60_000;
|
|
10
10
|
/** Floor the interval so a `0`/tiny override can't turn the sweep into a busy-loop. */
|
|
11
11
|
const MIN_PLATFORM_ALERT_INTERVAL_MS = 10_000;
|
|
12
|
-
/**
|
|
12
|
+
/**
|
|
13
|
+
* Parse the `1h`/`24h`/`7d` alert window, defaulting to the most operationally useful `1h`.
|
|
14
|
+
* The dashboard's rollup-backed `30d`/`90d` windows are deliberately not accepted here (see
|
|
15
|
+
* `platformAlertWindowSchema`), so naming one falls back to `1h` rather than quietly
|
|
16
|
+
* evaluating an alert against a table materialised at best hourly.
|
|
17
|
+
*/
|
|
13
18
|
export function parsePlatformObservabilityWindow(raw) {
|
|
14
19
|
const v = raw?.trim();
|
|
15
20
|
return v === '24h' || v === '7d' ? v : '1h';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"platformAlerts.js","sourceRoot":"","sources":["../../src/config/platformAlerts.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,iCAAiC,EAAE,MAAM,4BAA4B,CAAA;AAE9E,OAAO,EAAE,eAAe,EAAE,MAAM,cAAc,CAAA;AAE9C,uFAAuF;AACvF,6FAA6F;AAC7F,4FAA4F;AAC5F,2FAA2F;AAC3F,gEAAgE;AAEhE,6FAA6F;AAC7F,MAAM,kCAAkC,GAAG,CAAC,GAAG,MAAM,CAAA;AACrD,uFAAuF;AACvF,MAAM,8BAA8B,GAAG,MAAM,CAAA;AAE7C
|
|
1
|
+
{"version":3,"file":"platformAlerts.js","sourceRoot":"","sources":["../../src/config/platformAlerts.ts"],"names":[],"mappings":"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"}
|
package/dist/config/types.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { AgentRouting } from '@cat-factory/agents';
|
|
2
|
-
import type { InfrastructureCapabilities, LocalModeConfig, ModelOption, PlatformObservabilityWindow } from '@cat-factory/contracts';
|
|
2
|
+
import type { InfrastructureCapabilities, LocalModeConfig, ModelOption, PlatformAlertWindow, PlatformObservabilityWindow } from '@cat-factory/contracts';
|
|
3
3
|
import type { DetectionConventions } from '@cat-factory/integrations';
|
|
4
4
|
import type { DocumentSourceKind, HarnessKind, ModelRef } from '@cat-factory/kernel';
|
|
5
5
|
import type { PlatformAlertThresholds } from '@cat-factory/orchestration';
|
|
@@ -120,6 +120,27 @@ export interface AuthConfig {
|
|
|
120
120
|
* invite. Empty ⇒ new-user creation is invite-only (the default, fail-closed).
|
|
121
121
|
*/
|
|
122
122
|
allowedEmailDomains: string[];
|
|
123
|
+
/**
|
|
124
|
+
* Whether a proxy in front of this process may be believed about the client address.
|
|
125
|
+
* OFF by default on Node: `x-forwarded-for` is attacker-supplied on a bare deployment,
|
|
126
|
+
* and a client-chosen address hands the attacker unlimited fresh throttle buckets plus
|
|
127
|
+
* the ability to pin someone else's (SEC-4). Node deployments behind a proxy opt in with
|
|
128
|
+
* `AUTH_TRUST_PROXY=true`; the Worker hardcodes it on because the Cloudflare edge injects
|
|
129
|
+
* and overwrites `cf-connecting-ip`.
|
|
130
|
+
*
|
|
131
|
+
* WHICH header is consulted is the facade's decision, not this flag's: see each facade's
|
|
132
|
+
* `resolveClientAddress`.
|
|
133
|
+
*/
|
|
134
|
+
trustProxyHeaders: boolean;
|
|
135
|
+
/**
|
|
136
|
+
* How many trusted proxies sit in front of this process, used to pick the client hop out
|
|
137
|
+
* of an `x-forwarded-for` chain (`AUTH_TRUST_PROXY_HOPS`, default 1). The rightmost entry
|
|
138
|
+
* was appended by the nearest proxy, so with a single proxy the client is last; behind a
|
|
139
|
+
* CDN plus a load balancer it is two from the end. Getting it wrong over-counts (several
|
|
140
|
+
* clients share a bucket) rather than under-counting, because a chain shorter than the
|
|
141
|
+
* declared topology is discarded in favour of the socket peer.
|
|
142
|
+
*/
|
|
143
|
+
trustedProxyHops: number;
|
|
123
144
|
}
|
|
124
145
|
export interface EmailConfig {
|
|
125
146
|
/**
|
|
@@ -272,6 +293,21 @@ export interface RetentionConfig {
|
|
|
272
293
|
* intact. 0 disables.
|
|
273
294
|
*/
|
|
274
295
|
notificationsMs: number;
|
|
296
|
+
/**
|
|
297
|
+
* The settled-gate projection (`gate_outcomes`) behind the operator dashboard's gate /
|
|
298
|
+
* CI-fixer attempt statistics. One row per settled gate, so it grows far slower than the
|
|
299
|
+
* call telemetry, but it is still unbounded: pruned on a generous window (default 90 days,
|
|
300
|
+
* matching the longest dashboard window plus room to spare). 0 disables.
|
|
301
|
+
*/
|
|
302
|
+
gateOutcomesMs: number;
|
|
303
|
+
/**
|
|
304
|
+
* The daily run rollup (`platform_run_days`) behind the `30d` / `90d` dashboard windows.
|
|
305
|
+
* Deliberately the LONGEST window of the lot (default 400 days): a rolled-up day is a
|
|
306
|
+
* handful of tiny rows, and the whole point of the table is answering questions the raw
|
|
307
|
+
* scan is too expensive for, which is exactly what a short retention would take away.
|
|
308
|
+
* 0 disables.
|
|
309
|
+
*/
|
|
310
|
+
runDaysMs: number;
|
|
275
311
|
}
|
|
276
312
|
export interface FragmentLibraryConfig {
|
|
277
313
|
/** Opt-in flag (`PROMPT_LIBRARY_ENABLED=true`); needs no encryption key. */
|
|
@@ -354,8 +390,12 @@ export interface OtelPlatformMetricsConfig {
|
|
|
354
390
|
export interface PlatformAlertConfig {
|
|
355
391
|
/** Opt-in flag (`PLATFORM_ALERTS=true`). */
|
|
356
392
|
enabled: boolean;
|
|
357
|
-
/**
|
|
358
|
-
|
|
393
|
+
/**
|
|
394
|
+
* The trailing window each evaluation aggregates over (default `1h`). Deliberately the
|
|
395
|
+
* live-scanned subset of the dashboard's windows: an alert is a statement about NOW, and the
|
|
396
|
+
* `30d`/`90d` windows read a table materialised at best hourly.
|
|
397
|
+
*/
|
|
398
|
+
window: PlatformAlertWindow;
|
|
359
399
|
/**
|
|
360
400
|
* How often the sweep runs (ms). Node reads `PLATFORM_ALERTS_INTERVAL_MS` (default 5min);
|
|
361
401
|
* the Worker is cron-driven (its 2-minute `scheduled` tick) and ignores this.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/config/types.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/config/types.ts"],"names":[],"mappings":"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"}
|
|
@@ -19,9 +19,18 @@ export type MachineSubscribeAuth = {
|
|
|
19
19
|
payload: MachinePayload;
|
|
20
20
|
} | {
|
|
21
21
|
ok: false;
|
|
22
|
-
status:
|
|
22
|
+
status: MachineSubscribeRefusalStatus;
|
|
23
23
|
message: string;
|
|
24
24
|
};
|
|
25
|
+
/** The statuses a refused handshake can carry. */
|
|
26
|
+
export type MachineSubscribeRefusalStatus = 403 | 404 | 503;
|
|
27
|
+
/**
|
|
28
|
+
* The `{ ok: false }` code each refusal status reports to a machine client. An exhaustive
|
|
29
|
+
* `Record`, so adding a status forces a decision here rather than silently collapsing onto
|
|
30
|
+
* `forbidden`: a node RETRIES an `unavailable` (we could not read the roster) and reconnects
|
|
31
|
+
* for a fresh node id on a `forbidden`, so the two must stay distinguishable.
|
|
32
|
+
*/
|
|
33
|
+
export declare const MACHINE_SUBSCRIBE_ERROR_CODE: Record<MachineSubscribeRefusalStatus, string>;
|
|
25
34
|
/** Resolves a workspace to its owning account — the mothership's own `workspaceRepository`. */
|
|
26
35
|
export type AccountOfWorkspace = (workspaceId: string) => Promise<string | null | undefined> | string | null | undefined;
|
|
27
36
|
/**
|
|
@@ -50,6 +59,13 @@ export declare function authorizeMachineSubscribe(opts: {
|
|
|
50
59
|
workspaceId: string;
|
|
51
60
|
/** The mothership's workspace → account resolver; absent ⇒ this facade is not a mothership. */
|
|
52
61
|
accountOf: AccountOfWorkspace | undefined;
|
|
62
|
+
/**
|
|
63
|
+
* The machine-node roster's revocation read (SEC-5), threaded from the facade's
|
|
64
|
+
* `machineNodeRepository`; absent ⇒ no roster is wired and no revocation check runs.
|
|
65
|
+
* This handshake cannot go through the shared HTTP gate (it rides a WS upgrade, not a
|
|
66
|
+
* Hono context), so it takes the same check as an input instead.
|
|
67
|
+
*/
|
|
68
|
+
isRevoked?: (nodeId: string) => Promise<boolean>;
|
|
53
69
|
}): Promise<MachineSubscribeAuth>;
|
|
54
70
|
/** Accepts either a raw token or a full `Authorization: Bearer …` header value. */
|
|
55
71
|
export declare function stripBearer(value: string | undefined): string | undefined;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"machineSubscribe.d.ts","sourceRoot":"","sources":["../../src/events/machineSubscribe.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAA;AACpD,OAAO,EAAE,KAAK,cAAc,EAA6B,MAAM,oBAAoB,CAAA;AAwBnF;;;;;GAKG;AACH,eAAO,MAAM,6BAA6B,+BAA+B,CAAA;AAEzE,4FAA4F;AAC5F,eAAO,MAAM,gCAAgC,QAA6C,CAAA;AAE1F;;;;GAIG;AACH,MAAM,MAAM,oBAAoB,GAC5B;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,OAAO,EAAE,cAAc,CAAA;CAAE,GACrC;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,MAAM,EAAE,GAAG,GAAG,GAAG,GAAG,GAAG,
|
|
1
|
+
{"version":3,"file":"machineSubscribe.d.ts","sourceRoot":"","sources":["../../src/events/machineSubscribe.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAA;AACpD,OAAO,EAAE,KAAK,cAAc,EAA6B,MAAM,oBAAoB,CAAA;AAwBnF;;;;;GAKG;AACH,eAAO,MAAM,6BAA6B,+BAA+B,CAAA;AAEzE,4FAA4F;AAC5F,eAAO,MAAM,gCAAgC,QAA6C,CAAA;AAE1F;;;;GAIG;AACH,MAAM,MAAM,oBAAoB,GAC5B;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,OAAO,EAAE,cAAc,CAAA;CAAE,GACrC;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,MAAM,EAAE,6BAA6B,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAA;AAEzE,kDAAkD;AAClD,MAAM,MAAM,6BAA6B,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,CAAA;AAE3D;;;;;GAKG;AACH,eAAO,MAAM,4BAA4B,EAAE,MAAM,CAAC,6BAA6B,EAAE,MAAM,CAItF,CAAA;AAED,+FAA+F;AAC/F,MAAM,MAAM,kBAAkB,GAAG,CAC/B,WAAW,EAAE,MAAM,KAChB,OAAO,CAAC,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC,GAAG,MAAM,GAAG,IAAI,GAAG,SAAS,CAAA;AAEnE;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAsB,yBAAyB,CAAC,IAAI,EAAE;IACpD,IAAI,EAAE,UAAU,CAAA;IAChB,+FAA+F;IAC/F,KAAK,EAAE,MAAM,GAAG,SAAS,CAAA;IACzB,WAAW,EAAE,MAAM,CAAA;IACnB,+FAA+F;IAC/F,SAAS,EAAE,kBAAkB,GAAG,SAAS,CAAA;IACzC;;;;;OAKG;IACH,SAAS,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAC,CAAA;CACjD,GAAG,OAAO,CAAC,oBAAoB,CAAC,CAqChC;AAED,mFAAmF;AACnF,wBAAgB,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,GAAG,SAAS,CAEzE"}
|
|
@@ -29,6 +29,17 @@ import { TOKEN_AUDIENCE, signerFor } from '../auth/signing.js';
|
|
|
29
29
|
export const MACHINE_EVENTS_SUBSCRIBE_PATH = '/internal/events/subscribe';
|
|
30
30
|
/** Matches `/internal/events/subscribe/<workspaceId>`, capturing the (still-encoded) id. */
|
|
31
31
|
export const MACHINE_EVENTS_SUBSCRIBE_PATTERN = /^\/internal\/events\/subscribe\/([^/]+)$/;
|
|
32
|
+
/**
|
|
33
|
+
* The `{ ok: false }` code each refusal status reports to a machine client. An exhaustive
|
|
34
|
+
* `Record`, so adding a status forces a decision here rather than silently collapsing onto
|
|
35
|
+
* `forbidden`: a node RETRIES an `unavailable` (we could not read the roster) and reconnects
|
|
36
|
+
* for a fresh node id on a `forbidden`, so the two must stay distinguishable.
|
|
37
|
+
*/
|
|
38
|
+
export const MACHINE_SUBSCRIBE_ERROR_CODE = {
|
|
39
|
+
403: 'forbidden',
|
|
40
|
+
404: 'not_found',
|
|
41
|
+
503: 'unavailable',
|
|
42
|
+
};
|
|
32
43
|
/**
|
|
33
44
|
* Authorise a machine subscribe handshake for `workspaceId`.
|
|
34
45
|
*
|
|
@@ -57,6 +68,25 @@ export async function authorizeMachineSubscribe(opts) {
|
|
|
57
68
|
: null;
|
|
58
69
|
if (!payload)
|
|
59
70
|
return { ok: false, status: 403, message: 'invalid machine token' };
|
|
71
|
+
if (opts.isRevoked) {
|
|
72
|
+
// An unreadable roster is not consent to serve a possibly-revoked node, so a throwing
|
|
73
|
+
// read REFUSES rather than propagating: unlike the HTTP gate (whose throw becomes a 500
|
|
74
|
+
// through `handleError`), this runs on a WebSocket upgrade where the only caller can do
|
|
75
|
+
// nothing with a rejected promise but crash the process and leave the socket dangling.
|
|
76
|
+
// 503 rather than 403, because "we could not check" and "you are revoked" need different
|
|
77
|
+
// reactions from the node: retry the connection, versus reconnect for a fresh id.
|
|
78
|
+
let revoked;
|
|
79
|
+
try {
|
|
80
|
+
revoked = await opts.isRevoked(payload.nodeId);
|
|
81
|
+
}
|
|
82
|
+
catch {
|
|
83
|
+
return { ok: false, status: 503, message: 'machine node state is unavailable' };
|
|
84
|
+
}
|
|
85
|
+
// Same 403 as an invalid token: the caller holds the token, so there is no oracle to
|
|
86
|
+
// protect, and reconnecting (which mints a fresh node) is the remedy for both.
|
|
87
|
+
if (revoked)
|
|
88
|
+
return { ok: false, status: 403, message: 'invalid machine token' };
|
|
89
|
+
}
|
|
60
90
|
if (!opts.accountOf) {
|
|
61
91
|
return { ok: false, status: 503, message: 'event subscription is not enabled' };
|
|
62
92
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"machineSubscribe.js","sourceRoot":"","sources":["../../src/events/machineSubscribe.ts"],"names":[],"mappings":"AACA,OAAO,EAAuB,cAAc,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAA;AAEnF,2FAA2F;AAC3F,EAAE;AACF,gGAAgG;AAChG,gGAAgG;AAChG,mGAAmG;AACnG,+FAA+F;AAC/F,uEAAuE;AACvE,EAAE;AACF,4FAA4F;AAC5F,wFAAwF;AACxF,kGAAkG;AAClG,iGAAiG;AACjG,8FAA8F;AAC9F,8CAA8C;AAC9C,EAAE;AACF,8FAA8F;AAC9F,6FAA6F;AAC7F,iGAAiG;AACjG,+FAA+F;AAC/F,qFAAqF;AACrF,mEAAmE;AAEnE;;;;;GAKG;AACH,MAAM,CAAC,MAAM,6BAA6B,GAAG,4BAA4B,CAAA;AAEzE,4FAA4F;AAC5F,MAAM,CAAC,MAAM,gCAAgC,GAAG,0CAA0C,CAAA;
|
|
1
|
+
{"version":3,"file":"machineSubscribe.js","sourceRoot":"","sources":["../../src/events/machineSubscribe.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* How many trusted proxies sit in front of this process (`AUTH_TRUST_PROXY_HOPS`).
|
|
3
|
+
*
|
|
4
|
+
* Defaults to 1, the single-reverse-proxy shape, and clamps to at least 1: a 0 would mean
|
|
5
|
+
* "believe the leftmost entry", which is the client-controlled end of the chain and the very
|
|
6
|
+
* spoof this setting exists to close. An unparseable value takes the default rather than
|
|
7
|
+
* failing boot, matching how every other numeric knob here degrades.
|
|
8
|
+
*/
|
|
9
|
+
export declare function resolveTrustedProxyHops(raw: string | undefined): number;
|
|
10
|
+
/**
|
|
11
|
+
* Pick the client hop out of an `x-forwarded-for` chain, given how many trusted proxies
|
|
12
|
+
* sit in front of this process.
|
|
13
|
+
*
|
|
14
|
+
* The chain grows left to right as a request traverses proxies, so the RIGHTMOST entry was
|
|
15
|
+
* appended by our nearest proxy and is the address that actually connected to it. That
|
|
16
|
+
* makes rightmost correct under BOTH common configurations (nginx's appending
|
|
17
|
+
* `proxy_add_x_forwarded_for` and an overwriting `proxy_set_header`), where leftmost is
|
|
18
|
+
* correct only under the second and is otherwise whatever the client typed. With `n`
|
|
19
|
+
* trusted proxies the client sits `n` from the end.
|
|
20
|
+
*
|
|
21
|
+
* Returns `null` when the header is absent, unparseable, or SHORTER than the configured
|
|
22
|
+
* chain: a chain that does not look like the declared topology is not evidence about the
|
|
23
|
+
* client, so the caller falls back to the socket peer rather than trusting a guess.
|
|
24
|
+
*/
|
|
25
|
+
export declare function forwardedClientAddress(header: string | undefined, trustedHops: number): string | null;
|
|
26
|
+
/**
|
|
27
|
+
* Normalise one address into the form the throttle keys on, or `null` when it is not an
|
|
28
|
+
* address at all.
|
|
29
|
+
*
|
|
30
|
+
* Two things happen here, both load-bearing:
|
|
31
|
+
*
|
|
32
|
+
* - Anything not IP-shaped is REFUSED rather than passed through. A proxy that appends
|
|
33
|
+
* `ip:port` per connection, or an attacker sending free text, would otherwise mint a
|
|
34
|
+
* distinct bucket per request and land unbounded strings in the ledger's key column.
|
|
35
|
+
* - An IPv6 address is bucketed to its /64. A single residential or hosting allocation is
|
|
36
|
+
* routinely a /64 or larger, so keying on the full address gives an attacker 2^64
|
|
37
|
+
* buckets, which is the same hole as trusting a spoofable header.
|
|
38
|
+
*/
|
|
39
|
+
export declare function normalizeClientAddress(raw: string): string | null;
|
|
40
|
+
//# sourceMappingURL=clientAddress.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"clientAddress.d.ts","sourceRoot":"","sources":["../../src/http/clientAddress.ts"],"names":[],"mappings":"AAkBA;;;;;;;GAOG;AACH,wBAAgB,uBAAuB,CAAC,GAAG,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,CAGvE;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,sBAAsB,CACpC,MAAM,EAAE,MAAM,GAAG,SAAS,EAC1B,WAAW,EAAE,MAAM,GAClB,MAAM,GAAG,IAAI,CAUf;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,sBAAsB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAgBjE"}
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
// ---------------------------------------------------------------------------
|
|
2
|
+
// Client-address resolution for the password throttle (SEC-4).
|
|
3
|
+
//
|
|
4
|
+
// The throttle's whole value rests on the address being one the CLIENT cannot choose:
|
|
5
|
+
// a spoofable value is unlimited fresh buckets (and, worse, the ability to pin a
|
|
6
|
+
// victim's bucket). Which header carries that address is a property of the FACADE's
|
|
7
|
+
// topology, not of the throttle, so the facade resolves it (`resolveClientAddress`) and
|
|
8
|
+
// only the normalisation below is shared:
|
|
9
|
+
//
|
|
10
|
+
// - The Worker reads `cf-connecting-ip`. That header is authentic on that facade alone,
|
|
11
|
+
// because the Cloudflare edge injects it and overwrites whatever the client sent.
|
|
12
|
+
// - Node reads the socket peer by default, and `x-forwarded-for` only when
|
|
13
|
+
// `AUTH_TRUST_PROXY=true`. It must NOT consult `cf-connecting-ip`: nginx / Caddy /
|
|
14
|
+
// ALB / HAProxy rewrite `x-forwarded-for` and pass every other header through
|
|
15
|
+
// untouched, so trusting a Cloudflare-specific header on a generic proxy leaves it
|
|
16
|
+
// fully client-controlled.
|
|
17
|
+
// ---------------------------------------------------------------------------
|
|
18
|
+
/**
|
|
19
|
+
* How many trusted proxies sit in front of this process (`AUTH_TRUST_PROXY_HOPS`).
|
|
20
|
+
*
|
|
21
|
+
* Defaults to 1, the single-reverse-proxy shape, and clamps to at least 1: a 0 would mean
|
|
22
|
+
* "believe the leftmost entry", which is the client-controlled end of the chain and the very
|
|
23
|
+
* spoof this setting exists to close. An unparseable value takes the default rather than
|
|
24
|
+
* failing boot, matching how every other numeric knob here degrades.
|
|
25
|
+
*/
|
|
26
|
+
export function resolveTrustedProxyHops(raw) {
|
|
27
|
+
const parsed = Number.parseInt(raw?.trim() ?? '', 10);
|
|
28
|
+
return Number.isFinite(parsed) && parsed >= 1 ? parsed : 1;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Pick the client hop out of an `x-forwarded-for` chain, given how many trusted proxies
|
|
32
|
+
* sit in front of this process.
|
|
33
|
+
*
|
|
34
|
+
* The chain grows left to right as a request traverses proxies, so the RIGHTMOST entry was
|
|
35
|
+
* appended by our nearest proxy and is the address that actually connected to it. That
|
|
36
|
+
* makes rightmost correct under BOTH common configurations (nginx's appending
|
|
37
|
+
* `proxy_add_x_forwarded_for` and an overwriting `proxy_set_header`), where leftmost is
|
|
38
|
+
* correct only under the second and is otherwise whatever the client typed. With `n`
|
|
39
|
+
* trusted proxies the client sits `n` from the end.
|
|
40
|
+
*
|
|
41
|
+
* Returns `null` when the header is absent, unparseable, or SHORTER than the configured
|
|
42
|
+
* chain: a chain that does not look like the declared topology is not evidence about the
|
|
43
|
+
* client, so the caller falls back to the socket peer rather than trusting a guess.
|
|
44
|
+
*/
|
|
45
|
+
export function forwardedClientAddress(header, trustedHops) {
|
|
46
|
+
if (!header)
|
|
47
|
+
return null;
|
|
48
|
+
const hops = Math.max(1, Math.trunc(trustedHops));
|
|
49
|
+
const entries = header
|
|
50
|
+
.split(',')
|
|
51
|
+
.map((part) => part.trim())
|
|
52
|
+
.filter(Boolean);
|
|
53
|
+
const candidate = entries[entries.length - hops];
|
|
54
|
+
if (!candidate)
|
|
55
|
+
return null;
|
|
56
|
+
return normalizeClientAddress(candidate);
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Normalise one address into the form the throttle keys on, or `null` when it is not an
|
|
60
|
+
* address at all.
|
|
61
|
+
*
|
|
62
|
+
* Two things happen here, both load-bearing:
|
|
63
|
+
*
|
|
64
|
+
* - Anything not IP-shaped is REFUSED rather than passed through. A proxy that appends
|
|
65
|
+
* `ip:port` per connection, or an attacker sending free text, would otherwise mint a
|
|
66
|
+
* distinct bucket per request and land unbounded strings in the ledger's key column.
|
|
67
|
+
* - An IPv6 address is bucketed to its /64. A single residential or hosting allocation is
|
|
68
|
+
* routinely a /64 or larger, so keying on the full address gives an attacker 2^64
|
|
69
|
+
* buckets, which is the same hole as trusting a spoofable header.
|
|
70
|
+
*/
|
|
71
|
+
export function normalizeClientAddress(raw) {
|
|
72
|
+
let value = raw.trim().toLowerCase();
|
|
73
|
+
if (!value)
|
|
74
|
+
return null;
|
|
75
|
+
// `[2001:db8::1]:443` and `[2001:db8::1]` both carry a bracketed v6 literal.
|
|
76
|
+
const bracketed = /^\[([^\]]+)\](?::\d+)?$/.exec(value);
|
|
77
|
+
if (bracketed?.[1])
|
|
78
|
+
value = bracketed[1];
|
|
79
|
+
// A bare `1.2.3.4:443` from a port-appending proxy; a v6 literal has >1 colon so it is
|
|
80
|
+
// never mistaken for one.
|
|
81
|
+
else if ((value.match(/:/g) ?? []).length === 1)
|
|
82
|
+
value = value.split(':')[0] ?? value;
|
|
83
|
+
// Drop an IPv6 zone index (`fe80::1%eth0`), which is host-local decoration.
|
|
84
|
+
const zone = value.indexOf('%');
|
|
85
|
+
if (zone >= 0)
|
|
86
|
+
value = value.slice(0, zone);
|
|
87
|
+
if (isIpv4(value))
|
|
88
|
+
return value;
|
|
89
|
+
const groups = expandIpv6(value);
|
|
90
|
+
// The /64 is the routable unit; the interface half is the attacker's to vary freely.
|
|
91
|
+
return groups ? `${groups.slice(0, 4).join(':')}::/64` : null;
|
|
92
|
+
}
|
|
93
|
+
function isIpv4(value) {
|
|
94
|
+
const parts = value.split('.');
|
|
95
|
+
return (parts.length === 4 &&
|
|
96
|
+
parts.every((p) => /^\d{1,3}$/.test(p) && Number(p) <= 255 && (p === '0' || !p.startsWith('0'))));
|
|
97
|
+
}
|
|
98
|
+
/** Expand an IPv6 literal to its eight 16-bit groups, or `null` if it is not one. */
|
|
99
|
+
function expandIpv6(value) {
|
|
100
|
+
if (!value.includes(':'))
|
|
101
|
+
return null;
|
|
102
|
+
const halves = value.split('::');
|
|
103
|
+
if (halves.length > 2)
|
|
104
|
+
return null;
|
|
105
|
+
const parse = (part) => {
|
|
106
|
+
if (!part)
|
|
107
|
+
return [];
|
|
108
|
+
const out = [];
|
|
109
|
+
for (const group of part.split(':')) {
|
|
110
|
+
// A trailing dotted-quad (`::ffff:127.0.0.1`) occupies two groups.
|
|
111
|
+
if (group.includes('.')) {
|
|
112
|
+
if (!isIpv4(group))
|
|
113
|
+
return null;
|
|
114
|
+
const [a, b, c, d] = group.split('.').map(Number);
|
|
115
|
+
out.push(hex((a << 8) | b), hex((c << 8) | d));
|
|
116
|
+
continue;
|
|
117
|
+
}
|
|
118
|
+
if (!/^[0-9a-f]{1,4}$/.test(group))
|
|
119
|
+
return null;
|
|
120
|
+
out.push(group);
|
|
121
|
+
}
|
|
122
|
+
return out;
|
|
123
|
+
};
|
|
124
|
+
const head = parse(halves[0] ?? '');
|
|
125
|
+
const tail = halves.length === 2 ? parse(halves[1] ?? '') : null;
|
|
126
|
+
if (!head)
|
|
127
|
+
return null;
|
|
128
|
+
if (halves.length === 1)
|
|
129
|
+
return head.length === 8 ? head : null;
|
|
130
|
+
if (!tail)
|
|
131
|
+
return null;
|
|
132
|
+
const fill = 8 - head.length - tail.length;
|
|
133
|
+
if (fill < 1)
|
|
134
|
+
return null;
|
|
135
|
+
return [...head, ...Array.from({ length: fill }, () => '0'), ...tail];
|
|
136
|
+
}
|
|
137
|
+
function hex(n) {
|
|
138
|
+
return n.toString(16);
|
|
139
|
+
}
|
|
140
|
+
//# sourceMappingURL=clientAddress.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"clientAddress.js","sourceRoot":"","sources":["../../src/http/clientAddress.ts"],"names":[],"mappings":"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"}
|