fix(mattermost): wrap malformed interaction json · openclaw/openclaw@74dae60
vincentkoc
·
2026-05-14
·
via Recent Commits to openclaw:main
| Original file line number | Diff line number | Diff line change |
|---|
@@ -64,6 +64,7 @@ Docs: https://docs.openclaw.ai
|
64 | 64 | - QQBot: report malformed access-token JSON with provider-owned errors instead of leaking raw parser failures. |
65 | 65 | - OpenAI embeddings: report malformed batch output JSONL with provider-owned errors instead of leaking raw parser failures. |
66 | 66 | - Synology Chat: report malformed JSON webhook payloads with stable channel-owned parser errors. |
| 67 | +- Mattermost: report malformed interaction callback JSON with stable channel-owned parser errors. |
67 | 68 | - 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. |
68 | 69 | - 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. |
69 | 70 | - 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. |
|
| Original file line number | Diff line number | Diff line change |
|---|
@@ -499,7 +499,12 @@ describe("createMattermostInteractionHandler", () => {
|
499 | 499 | remoteAddress?: string; |
500 | 500 | headers?: Record<string, string>; |
501 | 501 | }): IncomingMessage { |
502 | | -const body = params.body === undefined ? "" : JSON.stringify(params.body); |
| 502 | +const body = |
| 503 | +params.body === undefined |
| 504 | + ? "" |
| 505 | + : typeof params.body === "string" |
| 506 | + ? params.body |
| 507 | + : JSON.stringify(params.body); |
503 | 508 | const listeners = new Map<string, Array<(...args: unknown[]) => void>>(); |
504 | 509 | |
505 | 510 | const req = { |
@@ -717,6 +722,26 @@ describe("createMattermostInteractionHandler", () => {
|
717 | 722 | expectSuccessfulApprovalUpdate(res, requestLog); |
718 | 723 | }); |
719 | 724 | |
| 725 | +it("rejects malformed JSON callback requests with a stable parser error", async () => { |
| 726 | +const log = vi.fn(); |
| 727 | +const handler = createMattermostInteractionHandler({ |
| 728 | +client: createMattermostClientMock(async () => { |
| 729 | +throw new Error("unexpected client request"); |
| 730 | +}), |
| 731 | +botUserId: "bot", |
| 732 | +accountId: "acct", |
| 733 | + log, |
| 734 | +}); |
| 735 | + |
| 736 | +const res = await runHandler(handler, { body: "{not json" }); |
| 737 | + |
| 738 | +expect(res.statusCode).toBe(400); |
| 739 | +expect(res.body).toBe(JSON.stringify({ error: "Invalid request body" })); |
| 740 | +expect(log).toHaveBeenCalledWith( |
| 741 | +"mattermost interaction: failed to parse body: Error: Mattermost interaction body was malformed JSON", |
| 742 | +); |
| 743 | +}); |
| 744 | + |
720 | 745 | it("accepts forwarded Mattermost source IPs from a trusted proxy", async () => { |
721 | 746 | const { res } = await runApproveInteraction({ |
722 | 747 | allowedSourceIps: ["198.51.100.8"], |
|
| Original file line number | Diff line number | Diff line change |
|---|
@@ -405,6 +405,14 @@ export function createMattermostInteractionHandler(params: {
|
405 | 405 | const { client, accountId, log } = params; |
406 | 406 | const core = getMattermostRuntime(); |
407 | 407 | |
| 408 | +function parseInteractionPayload(raw: string): MattermostInteractionPayload { |
| 409 | +try { |
| 410 | +return JSON.parse(raw) as MattermostInteractionPayload; |
| 411 | +} catch { |
| 412 | +throw new Error("Mattermost interaction body was malformed JSON"); |
| 413 | +} |
| 414 | +} |
| 415 | + |
408 | 416 | return async (req: IncomingMessage, res: ServerResponse) => { |
409 | 417 | // Only accept POST |
410 | 418 | if (req.method !== "POST") { |
@@ -435,7 +443,7 @@ export function createMattermostInteractionHandler(params: {
|
435 | 443 | let payload: MattermostInteractionPayload; |
436 | 444 | try { |
437 | 445 | const raw = await readInteractionBody(req); |
438 | | -payload = JSON.parse(raw) as MattermostInteractionPayload; |
| 446 | +payload = parseInteractionPayload(raw); |
439 | 447 | } catch (err) { |
440 | 448 | log?.(`mattermost interaction: failed to parse body: ${String(err)}`); |
441 | 449 | res.statusCode = 400; |
|
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。