mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-03 00:40:21 +00:00
Harden dashboard session events and history APIs
This commit is contained in:
@@ -1,15 +1,22 @@
|
||||
import type { IncomingMessage, ServerResponse } from "node:http";
|
||||
import { killSubagentRunAdmin } from "../agents/subagent-control.js";
|
||||
import { loadConfig } from "../config/config.js";
|
||||
import { authorizeHttpGatewayConnect, type ResolvedGatewayAuth } from "./auth.js";
|
||||
import {
|
||||
sendGatewayAuthFailure,
|
||||
sendJson,
|
||||
sendMethodNotAllowed,
|
||||
} from "./http-common.js";
|
||||
killControlledSubagentRun,
|
||||
killSubagentRunAdmin,
|
||||
resolveSubagentController,
|
||||
} from "../agents/subagent-control.js";
|
||||
import { getSubagentRunByChildSessionKey } from "../agents/subagent-registry.js";
|
||||
import { loadConfig } from "../config/config.js";
|
||||
import type { AuthRateLimiter } from "./auth-rate-limit.js";
|
||||
import {
|
||||
authorizeHttpGatewayConnect,
|
||||
isLocalDirectRequest,
|
||||
type ResolvedGatewayAuth,
|
||||
} from "./auth.js";
|
||||
import { sendGatewayAuthFailure, sendJson, sendMethodNotAllowed } from "./http-common.js";
|
||||
import { getBearerToken } from "./http-utils.js";
|
||||
import { loadSessionEntry } from "./session-utils.js";
|
||||
import type { AuthRateLimiter } from "./auth-rate-limit.js";
|
||||
|
||||
const REQUESTER_SESSION_KEY_HEADER = "x-openclaw-requester-session-key";
|
||||
|
||||
function resolveSessionKeyFromPath(pathname: string): string | null {
|
||||
const match = pathname.match(/^\/sessions\/([^/]+)\/kill$/);
|
||||
@@ -60,7 +67,7 @@ export async function handleSessionKillHttpRequest(
|
||||
return true;
|
||||
}
|
||||
|
||||
const { entry } = loadSessionEntry(sessionKey);
|
||||
const { entry, canonicalKey } = loadSessionEntry(sessionKey);
|
||||
if (!entry) {
|
||||
sendJson(res, 404, {
|
||||
ok: false,
|
||||
@@ -72,14 +79,54 @@ export async function handleSessionKillHttpRequest(
|
||||
return true;
|
||||
}
|
||||
|
||||
const result = await killSubagentRunAdmin({
|
||||
cfg,
|
||||
sessionKey,
|
||||
});
|
||||
const trustedProxies = opts.trustedProxies ?? cfg.gateway?.trustedProxies;
|
||||
const allowRealIpFallback = opts.allowRealIpFallback ?? cfg.gateway?.allowRealIpFallback;
|
||||
const requesterSessionKey = req.headers[REQUESTER_SESSION_KEY_HEADER]?.toString().trim();
|
||||
const allowLocalAdminKill = isLocalDirectRequest(req, trustedProxies, allowRealIpFallback);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
let killed = false;
|
||||
if (requesterSessionKey) {
|
||||
const runEntry = getSubagentRunByChildSessionKey(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 {
|
||||
const result = await killSubagentRunAdmin({
|
||||
cfg,
|
||||
sessionKey: canonicalKey,
|
||||
});
|
||||
killed = result.killed;
|
||||
}
|
||||
|
||||
sendJson(res, 200, {
|
||||
ok: true,
|
||||
killed: result.killed,
|
||||
killed,
|
||||
});
|
||||
return true;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user