fix(gateway): land #39064 from @Narcooo

Co-authored-by: Narcooo <Narcooo@users.noreply.github.com>
This commit is contained in:
Peter Steinberger
2026-03-07 18:52:42 +00:00
parent 2ada1b71b6
commit 2f59a3cff3
3 changed files with 14 additions and 4 deletions

View File

@@ -247,6 +247,7 @@ Docs: https://docs.openclaw.ai
- Discord/native slash command auth: honor `commands.allowFrom.discord` (and `commands.allowFrom["*"]`) in guild slash-command pre-dispatch authorization so allowlisted senders are no longer incorrectly rejected as unauthorized. (#38794) Thanks @jskoiz and @thewilloftheshadow.
- Outbound/message target normalization: ignore empty legacy `to`/`channelId` fields when explicit `target` is provided so valid target-based sends no longer fail legacy-param validation; includes regression coverage. (#38944) Thanks @Narcooo.
- Models/auth token prompts: guard cancelled manual token prompts so `Symbol(clack:cancel)` values cannot be persisted into auth profiles; adds regression coverage for cancelled `models auth paste-token`. (#38951) Thanks @MumuTW.
- Gateway/loopback announce URLs: treat `http://` and `https://` aliases with the same loopback/private-network policy as websocket URLs so loopback cron announce delivery no longer fails secure URL validation. (#39064) Thanks @Narcooo.
## 2026.3.2

View File

@@ -439,8 +439,10 @@ describe("isSecureWebSocketUrl", () => {
// invalid URLs
{ input: "not-a-url", expected: false },
{ input: "", expected: false },
{ input: "http://127.0.0.1:18789", expected: false },
{ input: "https://127.0.0.1:18789", expected: false },
{ input: "http://127.0.0.1:18789", expected: true },
{ input: "https://127.0.0.1:18789", expected: true },
{ input: "https://remote.example.com:18789", expected: true },
{ input: "http://remote.example.com:18789", expected: false },
] as const;
for (const testCase of cases) {
@@ -451,6 +453,7 @@ describe("isSecureWebSocketUrl", () => {
it("allows private ws:// only when opt-in is enabled", () => {
const allowedWhenOptedIn = [
"ws://10.0.0.5:18789",
"http://10.0.0.5:18789",
"ws://172.16.0.1:18789",
"ws://192.168.1.100:18789",
"ws://100.64.0.1:18789",

View File

@@ -421,11 +421,17 @@ export function isSecureWebSocketUrl(
return false;
}
if (parsed.protocol === "wss:") {
// Node's ws client accepts http(s) URLs and normalizes them to ws(s).
// Treat those aliases the same way here so loopback cron announce delivery
// and TLS-backed https endpoints follow the same security policy.
const protocol =
parsed.protocol === "https:" ? "wss:" : parsed.protocol === "http:" ? "ws:" : parsed.protocol;
if (protocol === "wss:") {
return true;
}
if (parsed.protocol !== "ws:") {
if (protocol !== "ws:") {
return false;
}