Files
openclaw/src/gateway/http-endpoint-helpers.ts
Jacob Tomlinson f0af186726 gateway: ignore bearer-declared HTTP operator scopes (#57783)
* gateway: ignore bearer-declared HTTP operator scopes

* gateway: key HTTP bearer guards to auth mode

* gateway: refresh rebased HTTP regression expectations

* gateway: honor resolved HTTP auth method

* gateway: remove duplicate openresponses owner flags
2026-03-30 20:04:33 +01:00

72 lines
2.1 KiB
TypeScript

import type { IncomingMessage, ServerResponse } from "node:http";
import type { AuthRateLimiter } from "./auth-rate-limit.js";
import type { ResolvedGatewayAuth } from "./auth.js";
import { readJsonBodyOrError, sendJson, sendMethodNotAllowed } from "./http-common.js";
import {
authorizeGatewayHttpRequestOrReply,
type AuthorizedGatewayHttpRequest,
resolveTrustedHttpOperatorScopes,
} from "./http-utils.js";
import { authorizeOperatorScopesForMethod } from "./method-scopes.js";
export async function handleGatewayPostJsonEndpoint(
req: IncomingMessage,
res: ServerResponse,
opts: {
pathname: string;
auth: ResolvedGatewayAuth;
maxBodyBytes: number;
trustedProxies?: string[];
allowRealIpFallback?: boolean;
rateLimiter?: AuthRateLimiter;
requiredOperatorMethod?: "chat.send" | (string & Record<never, never>);
},
): Promise<false | { body: unknown; requestAuth: AuthorizedGatewayHttpRequest } | undefined> {
const url = new URL(req.url ?? "/", `http://${req.headers.host || "localhost"}`);
if (url.pathname !== opts.pathname) {
return false;
}
if (req.method !== "POST") {
sendMethodNotAllowed(res);
return undefined;
}
const requestAuth = await authorizeGatewayHttpRequestOrReply({
req,
res,
auth: opts.auth,
trustedProxies: opts.trustedProxies,
allowRealIpFallback: opts.allowRealIpFallback,
rateLimiter: opts.rateLimiter,
});
if (!requestAuth) {
return undefined;
}
if (opts.requiredOperatorMethod) {
const requestedScopes = resolveTrustedHttpOperatorScopes(req, requestAuth);
const scopeAuth = authorizeOperatorScopesForMethod(
opts.requiredOperatorMethod,
requestedScopes,
);
if (!scopeAuth.allowed) {
sendJson(res, 403, {
ok: false,
error: {
type: "forbidden",
message: `missing scope: ${scopeAuth.missingScope}`,
},
});
return undefined;
}
}
const body = await readJsonBodyOrError(req, res, opts.maxBodyBytes);
if (body === undefined) {
return undefined;
}
return { body, requestAuth };
}