openclaw
Version:
Multi-channel AI gateway with extensible messaging integrations
122 lines (121 loc) • 4.23 kB
JavaScript
import { c as normalizeOptionalString } from "./string-coerce-mnp54Vah.js";
import { o as isLocalDirectRequest } from "./auth-DXSWhsnk.js";
import { i as getRuntimeConfig } from "./io-Gi7-pyU-.js";
import { n as authorizeOperatorScopesForMethod } from "./method-scopes-BtdN3y7s.js";
import { u as loadSessionEntry } from "./session-utils-CHNCuY8a.js";
import { s as getLatestSubagentRunByChildSessionKey } from "./subagent-registry-BeWX0MLH.js";
import { i as killSubagentRunAdmin, o as resolveSubagentController, r as killControlledSubagentRun } from "./subagent-control-DqhkhV-5.js";
import { a as sendJson, i as sendInvalidRequest, o as sendMethodNotAllowed, s as sendMissingScopeForbidden } from "./http-common-DunL6val.js";
import { f as resolveTrustedHttpOperatorScopes, t as authorizeGatewayHttpRequestOrReply } from "./http-auth-utils-Du8mRZIw.js";
import "./http-utils-leZWdpma.js";
//#region src/gateway/session-kill-http.ts
const REQUESTER_SESSION_KEY_HEADER = "x-openclaw-requester-session-key";
function resolveSessionKeyFromPath(pathname) {
const match = pathname.match(/^\/sessions\/([^/]+)\/kill$/);
if (!match) return { matched: false };
try {
const decoded = decodeURIComponent(match[1] ?? "").trim();
if (!decoded) return {
error: "invalid-session-key",
matched: true
};
return {
matched: true,
sessionKey: decoded
};
} catch {
return {
error: "invalid-session-key",
matched: true
};
}
}
async function handleSessionKillHttpRequest(req, res, opts) {
const cfg = getRuntimeConfig();
const sessionKeyResolution = resolveSessionKeyFromPath(new URL(req.url ?? "/", "http://localhost").pathname);
if (!sessionKeyResolution.matched) return false;
if ("error" in sessionKeyResolution) {
sendInvalidRequest(res, "invalid session key");
return true;
}
const { sessionKey } = sessionKeyResolution;
if (req.method !== "POST") {
sendMethodNotAllowed(res, "POST");
return true;
}
const requestAuth = await authorizeGatewayHttpRequestOrReply({
req,
res,
auth: opts.auth,
trustedProxies: opts.trustedProxies ?? cfg.gateway?.trustedProxies,
allowRealIpFallback: opts.allowRealIpFallback ?? cfg.gateway?.allowRealIpFallback,
rateLimiter: opts.rateLimiter
});
if (!requestAuth) return true;
const trustedProxies = opts.trustedProxies ?? cfg.gateway?.trustedProxies;
const allowRealIpFallback = opts.allowRealIpFallback ?? cfg.gateway?.allowRealIpFallback;
const requesterSessionKey = normalizeOptionalString(req.headers[REQUESTER_SESSION_KEY_HEADER]?.toString());
const allowLocalAdminKill = isLocalDirectRequest(req, trustedProxies, allowRealIpFallback);
const requestedScopes = resolveTrustedHttpOperatorScopes(req, requestAuth);
if (!requesterSessionKey && !allowLocalAdminKill) {
sendJson(res, 403, {
ok: false,
error: {
type: "forbidden",
message: "Session kills require a local admin request or requester session ownership."
}
});
return true;
}
const scopeAuth = authorizeOperatorScopesForMethod(requesterSessionKey && !allowLocalAdminKill ? "sessions.abort" : "sessions.delete", requestedScopes);
if (!scopeAuth.allowed) {
sendMissingScopeForbidden(res, scopeAuth.missingScope);
return true;
}
const { entry, canonicalKey } = loadSessionEntry(sessionKey);
if (!entry) {
sendJson(res, 404, {
ok: false,
error: {
type: "not_found",
message: `Session not found: ${sessionKey}`
}
});
return true;
}
let killed = false;
if (!allowLocalAdminKill && requesterSessionKey) {
const runEntry = getLatestSubagentRunByChildSessionKey(canonicalKey);
if (runEntry) {
const result = await killControlledSubagentRun({
cfg,
controller: resolveSubagentController({
cfg,
agentSessionKey: requesterSessionKey
}),
entry: runEntry
});
if (result.status === "forbidden") {
sendJson(res, 403, {
ok: false,
error: {
type: "forbidden",
message: result.error
}
});
return true;
}
killed = result.status === "ok";
}
} else killed = (await killSubagentRunAdmin({
cfg,
sessionKey: canonicalKey
})).killed;
sendJson(res, 200, {
ok: true,
killed
});
return true;
}
//#endregion
export { handleSessionKillHttpRequest };