From 48bddaa1536cf6bc592cda911a1e2bf8b60d3c18 Mon Sep 17 00:00:00 2001 From: "Garrett W." Date: Tue, 4 Aug 2026 02:06:48 +0000 Subject: [PATCH] fix: video embed of stream/playlist URL --- src/Service/VideoManager.php | 13 +++++++++++++ src/Utils/Embed.php | 15 +++++++++++++++ tests/Unit/Utils/EmbedTest.php | 30 ++++++++++++++++++++++++++++++ 3 files changed, 58 insertions(+) diff --git a/src/Service/VideoManager.php b/src/Service/VideoManager.php index 005947425..31a30567d 100644 --- a/src/Service/VideoManager.php +++ b/src/Service/VideoManager.php @@ -7,6 +7,7 @@ class VideoManager { public const VIDEO_MIMETYPES = ['video/mp4', 'video/webm']; + public const UNSUPPORTED_STREAM_EXTENSIONS = ['m3u8', 'm3u', 'mpd', 'ism', 'isml']; public static function isVideoUrl(string $url): bool { @@ -22,6 +23,18 @@ public static function isVideoUrl(string $url): bool return \in_array($urlExt, $types, false); } + public static function isUnsupportedStreamUrl(string $url): bool + { + if (str_starts_with($url, 'data:')) { + return false; + } + + $path = (string) parse_url($url, PHP_URL_PATH); + $urlExt = strtolower(pathinfo($path, PATHINFO_EXTENSION)); + + return \in_array($urlExt, self::UNSUPPORTED_STREAM_EXTENSIONS, true); + } + public static function isSupportedVideoMimeType(?string $mimeType): bool { if (null === $mimeType || '' === trim($mimeType)) { diff --git a/src/Utils/Embed.php b/src/Utils/Embed.php index 448ab8aea..aa4b11cd4 100644 --- a/src/Utils/Embed.php +++ b/src/Utils/Embed.php @@ -154,6 +154,7 @@ private function cleanIframe(?string $html): ?string libxml_clear_errors(); $videoElements = $dom->getElementsByTagName('video'); + $iframeElements = $dom->getElementsByTagName('iframe'); foreach ($videoElements as $videoElement) { $sourceUrl = $videoElement->getAttribute('src'); @@ -186,6 +187,20 @@ private function cleanIframe(?string $html): ?string } } + foreach ($iframeElements as $iframeElement) { + $iframeSrc = $iframeElement->getAttribute('src'); + + if ( + $iframeSrc + && ( + VideoManager::isVideoUrl($iframeSrc) + || VideoManager::isUnsupportedStreamUrl($iframeSrc) + ) + ) { + return null; + } + } + return $html; } diff --git a/tests/Unit/Utils/EmbedTest.php b/tests/Unit/Utils/EmbedTest.php index b4e698781..77f422123 100644 --- a/tests/Unit/Utils/EmbedTest.php +++ b/tests/Unit/Utils/EmbedTest.php @@ -53,6 +53,36 @@ public function testUnsupportedVideoContentWithOtherMarkupIsRejected(): void self::assertNull($method->invoke($embed, $html)); } + public function testUnsupportedIframeStreamUrlIsRejected(): void + { + $embed = $this->createEmbed(); + $method = new \ReflectionMethod(Embed::class, 'cleanIframe'); + + $html = ''; + + self::assertNull($method->invoke($embed, $html)); + } + + public function testIframeVideoUrlIsRejected(): void + { + $embed = $this->createEmbed(); + $method = new \ReflectionMethod(Embed::class, 'cleanIframe'); + + $html = ''; + + self::assertNull($method->invoke($embed, $html)); + } + + public function testSupportedIframeEmbedUrlIsKept(): void + { + $embed = $this->createEmbed(); + $method = new \ReflectionMethod(Embed::class, 'cleanIframe'); + + $html = ''; + + self::assertSame($html, $method->invoke($embed, $html)); + } + private function createEmbed(): Embed { return new Embed(