mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-07 23:51:23 +00:00
fix(security): centralize WhatsApp outbound auth and return 403 tool auth errors
This commit is contained in:
@@ -57,6 +57,12 @@ vi.mock("../agents/openclaw-tools.js", () => {
|
||||
err.name = "ToolInputError";
|
||||
return err;
|
||||
};
|
||||
const toolAuthorizationError = (message: string) => {
|
||||
const err = new Error(message) as Error & { status?: number };
|
||||
err.name = "ToolAuthorizationError";
|
||||
err.status = 403;
|
||||
return err;
|
||||
};
|
||||
|
||||
const tools = [
|
||||
{
|
||||
@@ -101,6 +107,9 @@ vi.mock("../agents/openclaw-tools.js", () => {
|
||||
if (mode === "input") {
|
||||
throw toolInputError("mode invalid");
|
||||
}
|
||||
if (mode === "auth") {
|
||||
throw toolAuthorizationError("mode forbidden");
|
||||
}
|
||||
if (mode === "crash") {
|
||||
throw new Error("boom");
|
||||
}
|
||||
@@ -453,7 +462,7 @@ describe("POST /tools/invoke", () => {
|
||||
expect(resMain.status).toBe(200);
|
||||
});
|
||||
|
||||
it("maps tool input errors to 400 and unexpected execution errors to 500", async () => {
|
||||
it("maps tool input/auth errors to 400/403 and unexpected execution errors to 500", async () => {
|
||||
cfg = {
|
||||
...cfg,
|
||||
agents: {
|
||||
@@ -472,6 +481,17 @@ describe("POST /tools/invoke", () => {
|
||||
expect(inputBody.error?.type).toBe("tool_error");
|
||||
expect(inputBody.error?.message).toBe("mode invalid");
|
||||
|
||||
const authRes = await invokeToolAuthed({
|
||||
tool: "tools_invoke_test",
|
||||
args: { mode: "auth" },
|
||||
sessionKey: "main",
|
||||
});
|
||||
expect(authRes.status).toBe(403);
|
||||
const authBody = await authRes.json();
|
||||
expect(authBody.ok).toBe(false);
|
||||
expect(authBody.error?.type).toBe("tool_error");
|
||||
expect(authBody.error?.message).toBe("mode forbidden");
|
||||
|
||||
const crashRes = await invokeToolAuthed({
|
||||
tool: "tools_invoke_test",
|
||||
args: { mode: "crash" },
|
||||
|
||||
@@ -112,16 +112,23 @@ function getErrorMessage(err: unknown): string {
|
||||
return String(err);
|
||||
}
|
||||
|
||||
function isToolInputError(err: unknown): boolean {
|
||||
function resolveToolInputErrorStatus(err: unknown): number | null {
|
||||
if (err instanceof ToolInputError) {
|
||||
return true;
|
||||
const status = (err as { status?: unknown }).status;
|
||||
return typeof status === "number" ? status : 400;
|
||||
}
|
||||
return (
|
||||
typeof err === "object" &&
|
||||
err !== null &&
|
||||
"name" in err &&
|
||||
(err as { name?: unknown }).name === "ToolInputError"
|
||||
);
|
||||
if (typeof err !== "object" || err === null || !("name" in err)) {
|
||||
return null;
|
||||
}
|
||||
const name = (err as { name?: unknown }).name;
|
||||
if (name !== "ToolInputError" && name !== "ToolAuthorizationError") {
|
||||
return null;
|
||||
}
|
||||
const status = (err as { status?: unknown }).status;
|
||||
if (typeof status === "number") {
|
||||
return status;
|
||||
}
|
||||
return name === "ToolAuthorizationError" ? 403 : 400;
|
||||
}
|
||||
|
||||
export async function handleToolsInvokeHttpRequest(
|
||||
@@ -308,8 +315,9 @@ export async function handleToolsInvokeHttpRequest(
|
||||
const result = await (tool as any).execute?.(`http-${Date.now()}`, toolArgs);
|
||||
sendJson(res, 200, { ok: true, result });
|
||||
} catch (err) {
|
||||
if (isToolInputError(err)) {
|
||||
sendJson(res, 400, {
|
||||
const inputStatus = resolveToolInputErrorStatus(err);
|
||||
if (inputStatus !== null) {
|
||||
sendJson(res, inputStatus, {
|
||||
ok: false,
|
||||
error: { type: "tool_error", message: getErrorMessage(err) || "invalid tool arguments" },
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user