Refuse non-media streams and gate video framing

This commit is contained in:
Fisto
2026-09-16 14:04:57 +02:00
parent c100bc269c
commit d522681553
5 changed files with 28 additions and 6 deletions
+11 -4
View File
@@ -424,6 +424,13 @@
media.replaceChildren(el("span", "vk-media-card-kind", item.kind.toUpperCase()));
}
/** Only real video files can be framed; embed pages (YouTube etc.) never are. */
function canFrameVideo(item) {
const direct = /\.(mp4|webm|m4v)(\?|$)/i;
if (item.playUrl && direct.test(item.playUrl)) return true;
return item.source !== "embed" && direct.test(item.url ?? "");
}
function playIcon(item) {
const play = el("span", "vk-media-play", "▶");
play.title = "Play";
@@ -470,7 +477,7 @@
}
media.append(img);
} else if (item.kind === "video") {
} else if (item.kind === "video" && canFrameVideo(item)) {
// No thumbnail: take the first frame through the same-origin stream endpoint,
// which refreshes expired URLs and avoids cross-origin blocking.
const video = document.createElement("video");
@@ -1160,14 +1167,14 @@
);
media.append(
button("Open in new tab", () =>
window.open(directVideo, "_blank", "noreferrer")
window.open(item.playUrl || directVideo, "_blank", "noreferrer")
)
);
},
{ once: true }
);
media.append(video);
} else if (item.kind === "video") {
} else if (item.kind === "video" && canFrameVideo(item)) {
// No still available: show the first frame through the stream endpoint.
const video = document.createElement("video");
video.preload = "metadata";
@@ -1183,7 +1190,7 @@
);
media.append(video);
media.append(viewerPlayIcon(item));
} else if (/^(https?:|\/)/.test(source)) {
} else if ((item.kind === "image" || item.kind === "gif") && /^(https?:|\/)/.test(source)) {
const img = document.createElement("img");
img.src = source;
img.alt = item.kind;
+7
View File
@@ -807,6 +807,13 @@ export function startWebUi(deps: WebUiDeps): WebUiHandle {
throw new HttpError(502, `upstream ${upstream.status}`);
}
// Never pipe a page into a media element: embed URLs that are not direct files
// (YouTube, provider redirectors) answer with HTML.
const upstreamType = upstream.headers.get("content-type") ?? "";
if (!/^(image|video|audio|application\/octet-stream)/i.test(upstreamType)) {
throw new HttpError(415, `not a media resource (${upstreamType || "unknown"})`);
}
res.status(upstream.status);
for (const header of ["content-type", "content-length", "accept-ranges", "content-range"]) {
const value = upstream.headers.get(header);