mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-20 21:25:00 +00:00
fix(slack): merge auth-header forwarding and html media guard
This commit is contained in:
@@ -83,6 +83,7 @@ Docs: https://docs.openclaw.ai
|
||||
### Fixes
|
||||
|
||||
- Slack/Bot attachment-only messages: when `allowBots: true`, bot messages with empty `text` now include non-forwarded attachment `text`/`fallback` content so webhook alerts are not silently dropped. (#27616)
|
||||
- Slack/Inbound media auth + HTML guard: keep Slack auth headers on forwarded shared attachment image downloads, and reject login/error HTML payloads (while allowing expected `.html` uploads) when resolving Slack media so auth failures do not silently pass as files. (#18642)
|
||||
- Slack/Security ingress mismatch guard: drop slash-command and interaction payloads when app/team identifiers do not match the active Slack account context (including nested `team.id` interaction payloads), preventing cross-app or cross-workspace payload injection into system-event handling. (#29091) Thanks @Solvely-Colin.
|
||||
- Cron/Failure alerts: add configurable repeated-failure alerting with per-job overrides and Web UI cron editor support (`inherit|disabled|custom` with threshold/cooldown/channel/target fields). (#24789) Thanks xbrak.
|
||||
- Cron/Isolated model defaults: resolve isolated cron `subagents.model` (including object-form `primary`) through allowlist-aware model selection so isolated cron runs honor subagent model defaults unless explicitly overridden by job payload model. (#11474) Thanks @AnonO6.
|
||||
|
||||
@@ -571,10 +571,11 @@ describe("resolveSlackAttachmentContent", () => {
|
||||
},
|
||||
],
|
||||
});
|
||||
expect(mockFetch).toHaveBeenCalledWith("https://files.slack.com/forwarded.jpg", {
|
||||
headers: { Authorization: "Bearer xoxb-test-token" },
|
||||
redirect: "manual",
|
||||
});
|
||||
const firstCall = mockFetch.mock.calls[0];
|
||||
expect(firstCall?.[0]).toBe("https://files.slack.com/forwarded.jpg");
|
||||
const firstInit = firstCall?.[1];
|
||||
expect(firstInit?.redirect).toBe("manual");
|
||||
expect(new Headers(firstInit?.headers).get("Authorization")).toBe("Bearer xoxb-test-token");
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import type { WebClient as SlackWebClient } from "@slack/web-api";
|
||||
import { normalizeHostname } from "../../infra/net/hostname.js";
|
||||
import type { FetchLike } from "../../media/fetch.js";
|
||||
import { logWarn } from "../../logger.js";
|
||||
import { fetchRemoteMedia } from "../../media/fetch.js";
|
||||
import { saveMediaBuffer } from "../../media/store.js";
|
||||
import type { SlackAttachment, SlackFile } from "../types.js";
|
||||
@@ -70,11 +69,6 @@ function createSlackMediaFetch(token: string): FetchLike {
|
||||
};
|
||||
}
|
||||
|
||||
function looksLikeHtmlBuffer(buffer: Buffer): boolean {
|
||||
const head = buffer.subarray(0, 512).toString("utf-8").replace(/^\s+/, "").toLowerCase();
|
||||
return head.startsWith("<!doctype html") || head.startsWith("<html");
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches a URL with Authorization header, handling cross-origin redirects.
|
||||
* Node.js fetch strips Authorization headers on cross-origin redirects for security.
|
||||
@@ -131,6 +125,11 @@ function resolveSlackMediaMimetype(
|
||||
return mime;
|
||||
}
|
||||
|
||||
function looksLikeHtmlBuffer(buffer: Buffer): boolean {
|
||||
const head = buffer.subarray(0, 512).toString("utf-8").replace(/^\s+/, "").toLowerCase();
|
||||
return head.startsWith("<!doctype html") || head.startsWith("<html");
|
||||
}
|
||||
|
||||
export type SlackMediaResult = {
|
||||
path: string;
|
||||
contentType?: string;
|
||||
@@ -233,10 +232,6 @@ export async function resolveSlackMedia(params: {
|
||||
if (!isExpectedHtml) {
|
||||
const detectedMime = fetched.contentType?.split(";")[0]?.trim().toLowerCase();
|
||||
if (detectedMime === "text/html" || looksLikeHtmlBuffer(fetched.buffer)) {
|
||||
const fileId = file.name ?? file.id ?? "unknown";
|
||||
logWarn(
|
||||
`slack: received HTML instead of media for file ${fileId}; possible auth failure or expired URL`,
|
||||
);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user