mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-19 00:34:46 +00:00
fix(file-transfer): validate inline write base64
This commit is contained in:
@@ -36,6 +36,7 @@ Docs: https://docs.openclaw.ai
|
||||
- Gateway HTTP: match models, session kill, and session history route paths without trusting malformed Host headers, avoiding pre-auth 500s on those endpoints.
|
||||
- Google Meet/Codex: report malformed node proxy `payloadJSON` responses with plugin-owned errors instead of leaking raw JSON parser failures.
|
||||
- Debug proxy: reject malformed relative-form proxy targets with a controlled 400 response instead of letting URL parsing escape the request handler.
|
||||
- File transfer: reject malformed inline `file_write` base64 before computing hashes or invoking paired nodes, avoiding Node's lenient base64 decoder.
|
||||
- Models config/auth: stop inferring provider env-var markers from broad `^[A-Z_][A-Z0-9_]*$` strings, and resolve config-backed provider `apiKey` values only through structured env SecretRefs (`secrets.providers[id]` / `secrets.defaults`), so unrelated env vars cannot accidentally become provider credentials. Thanks @sallyom.
|
||||
- Media fetch: skip allocating and buffering the response body for bodyless media responses (HEAD probes and 204-style empty bodies), avoiding wasted heap on streams that carry no payload. Thanks @shakkernerd.
|
||||
- CLI/onboarding: forward provider-specific auth flags (e.g. `--openai-api-key`) through the onboarding wizard so they reach provider auth methods via `ctx.opts`, letting `--openai-api-key "$OPENAI_API_KEY"` skip the redundant "use existing env var?" prompt in non-interactive harnesses. (#81669) Thanks @sjf.
|
||||
|
||||
29
extensions/file-transfer/src/tools/file-write-tool.test.ts
Normal file
29
extensions/file-transfer/src/tools/file-write-tool.test.ts
Normal file
@@ -0,0 +1,29 @@
|
||||
import { callGatewayTool } from "openclaw/plugin-sdk/agent-harness-runtime";
|
||||
import { describe, expect, it, vi } from "vitest";
|
||||
import { createFileWriteTool } from "./file-write-tool.js";
|
||||
|
||||
vi.mock("openclaw/plugin-sdk/agent-harness-runtime", () => ({
|
||||
callGatewayTool: vi.fn(),
|
||||
listNodes: vi.fn(),
|
||||
resolveNodeIdFromList: vi.fn(),
|
||||
}));
|
||||
|
||||
vi.mock("openclaw/plugin-sdk/media-store", () => ({
|
||||
readMediaBuffer: vi.fn(),
|
||||
}));
|
||||
|
||||
describe("file_write tool", () => {
|
||||
it("rejects malformed inline base64 before invoking the node", async () => {
|
||||
const tool = createFileWriteTool();
|
||||
|
||||
await expect(
|
||||
tool.execute("tool-call-1", {
|
||||
node: "node-1",
|
||||
path: "/tmp/out.txt",
|
||||
contentBase64: "AAA@@@",
|
||||
}),
|
||||
).rejects.toThrow("contentBase64 is not valid base64");
|
||||
|
||||
expect(callGatewayTool).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
@@ -21,6 +21,18 @@ import {
|
||||
FILE_WRITE_TOOL_DESCRIPTOR,
|
||||
} from "./descriptors.js";
|
||||
|
||||
function normalizeBase64ForCompare(value: string): string {
|
||||
return value.replace(/=+$/u, "").replace(/-/gu, "+").replace(/_/gu, "/");
|
||||
}
|
||||
|
||||
function decodeStrictBase64(value: string): Buffer {
|
||||
const buffer = Buffer.from(value, "base64");
|
||||
if (normalizeBase64ForCompare(buffer.toString("base64")) !== normalizeBase64ForCompare(value)) {
|
||||
throw new Error("contentBase64 is not valid base64");
|
||||
}
|
||||
return buffer;
|
||||
}
|
||||
|
||||
async function readSourceBytes(input: {
|
||||
contentBase64?: string;
|
||||
sourceMediaId?: string;
|
||||
@@ -37,7 +49,7 @@ async function readSourceBytes(input: {
|
||||
if (input.contentBase64 === undefined) {
|
||||
throw new Error("contentBase64 or sourceMediaId required");
|
||||
}
|
||||
const buffer = Buffer.from(input.contentBase64, "base64");
|
||||
const buffer = decodeStrictBase64(input.contentBase64);
|
||||
return { buffer, contentBase64: input.contentBase64, source: "inline" };
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user