From e5e0bfac3e92043ca36d74eb716b90661babf745 Mon Sep 17 00:00:00 2001 From: bfs2021 <101915083+bfs2021@users.noreply.github.com> Date: Fri, 6 Nov 2026 05:40:00 +0000 Subject: [PATCH] fix: refuse unparseable https preview URLs instead of crashing validate checkPreviewField called new URL(v) on values safeImageUrl had already rejected as unparseable, so a typo like https://[bad aborted the whole validate run with a stack trace instead of reporting the field error. Parse defensively and report the normal public-host error. --- site/checks.mjs | 12 ++++++++++-- site/checks.test.mjs | 2 ++ 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/site/checks.mjs b/site/checks.mjs index 8c98786..56d1365 100644 --- a/site/checks.mjs +++ b/site/checks.mjs @@ -1063,8 +1063,16 @@ export function checkPreviewField(rel, meta) { if (meta.preview === undefined || meta.preview === null || meta.preview === "") return []; const v = String(meta.preview); if (v === "none") return []; - if (/^https:\/\/\S+$/.test(v) && safeImageUrl(v) === new URL(v).href) return []; - if (/^https:\/\/\S+$/.test(v)) return [`${rel} preview must be an https:// image URL on a public host`]; + if (/^https:\/\/\S+$/.test(v)) { + let href = null; + try { + href = new URL(v).href; + } catch { + href = null; + } + if (href !== null && safeImageUrl(v) === href) return []; + return [`${rel} preview must be an https:// image URL on a public host`]; + } return [`${rel} preview must be "none" or an https:// image URL`]; } diff --git a/site/checks.test.mjs b/site/checks.test.mjs index 9f11841..f6ccdf6 100644 --- a/site/checks.test.mjs +++ b/site/checks.test.mjs @@ -828,6 +828,8 @@ accepts("preview field: https url", checkPreviewField("ok.md", { preview: "https rejects("preview field: http refused", checkPreviewField("bad.md", { preview: "http://a/b.png" }), 'bad.md preview must be "none" or an https:// image URL'); rejects("preview field: loopback refused", checkPreviewField("bad.md", { preview: "https://127.0.0.1/a.png" }), "bad.md preview must be an https:// image URL on a public host"); rejects("preview field: word refused", checkPreviewField("bad.md", { preview: "yes" }), 'bad.md preview must be "none" or an https:// image URL'); +rejects("preview field: unparseable https url refused", checkPreviewField("bad.md", { preview: "https://[bad" }), "bad.md preview must be an https:// image URL on a public host"); +rejects("preview field: userinfo refused", checkPreviewField("bad.md", { preview: "https://u:p@a.example/b.png" }), "bad.md preview must be an https:// image URL on a public host"); /* V30: line endings ------------------------------------------------------ */ accepts("V30 accepts LF-only text", checkLineEndings("ok.md", "---\nid: a\n---\n\nBody\n"));