fix(synology-chat): wrap malformed webhook json

This commit is contained in:
Vincent Koc
2026-05-14 19:53:02 +08:00
parent 2d6fd54ebd
commit e692f5c1cf
3 changed files with 30 additions and 1 deletions

View File

@@ -63,6 +63,7 @@ Docs: https://docs.openclaw.ai
- Amazon Bedrock embeddings: report malformed provider response JSON with provider-owned errors instead of leaking raw parser failures.
- QQBot: report malformed access-token JSON with provider-owned errors instead of leaking raw parser failures.
- OpenAI embeddings: report malformed batch output JSONL with provider-owned errors instead of leaking raw parser failures.
- Synology Chat: report malformed JSON webhook payloads with stable channel-owned parser errors.
- 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.

View File

@@ -449,6 +449,29 @@ describe("createWebhookHandler", () => {
expect(message.chatUserId).toBe("123");
});
it("rejects malformed application/json with a stable parser error", async () => {
const deliver = vi.fn().mockResolvedValue(null);
const handler = createWebhookHandler({
account: makeAccount({ accountId: "json-malformed-" + Date.now() }),
deliver,
log,
});
const req = makeReq("POST", "{not json", {
headers: { "content-type": "application/json" },
});
const res = makeRes();
await handler(req, res);
expect(res._status).toBe(400);
expect(res._body).toContain("Invalid request body");
expect(deliver).not.toHaveBeenCalled();
expect(log.warn).toHaveBeenCalledWith(
"Failed to parse webhook payload",
expect.objectContaining({ message: "Invalid JSON body" }),
);
});
it("accepts token from query when body token is absent", async () => {
await expectTokenlessBodyAccepted({
accountIdSuffix: "query-token-test",

View File

@@ -224,7 +224,12 @@ function parseJsonBody(body: string): Record<string, unknown> {
if (!body.trim()) {
return {};
}
const parsed = JSON.parse(body);
let parsed: unknown;
try {
parsed = JSON.parse(body) as unknown;
} catch {
throw new Error("Invalid JSON body");
}
if (!parsed || Array.isArray(parsed) || typeof parsed !== "object") {
throw new Error("Invalid JSON body");
}