]> BookStack Code Mirror - bookstack/commitdiff
Added embed support for contained HTML exports
authorDan Brown <redacted>
Mon, 23 May 2022 15:11:28 +0000 (16:11 +0100)
committerDan Brown <redacted>
Mon, 23 May 2022 15:11:28 +0000 (16:11 +0100)
Unfortunately CSP rules will block embeds anyway.
Need to either relax CSP rules on exports, or instead convert to img
tags?

Also cleaned up existing regexes.

app/Entities/Tools/ExportFormatter.php
tests/Entity/ExportTest.php

index 99aa4536f52bef1ec985c2b46aace5ed5c0f2669..ed3e8d326f693c290eafba1c387b06b0abc27e55 100644 (file)
@@ -215,14 +215,13 @@ class ExportFormatter
      */
     protected function containHtml(string $htmlContent): string
     {
+        // Replace image & embed src attributes with base64 encoded data strings
         $imageTagsOutput = [];
-        preg_match_all("/\<img.*?src\=(\'|\")(.*?)(\'|\").*?\>/i", $htmlContent, $imageTagsOutput);
-
-        // Replace image src with base64 encoded image strings
+        preg_match_all("/<(?:img|embed) .*?src=['\"](.*?)['\"].*?>/i", $htmlContent, $imageTagsOutput);
         if (isset($imageTagsOutput[0]) && count($imageTagsOutput[0]) > 0) {
             foreach ($imageTagsOutput[0] as $index => $imgMatch) {
                 $oldImgTagString = $imgMatch;
-                $srcString = $imageTagsOutput[2][$index];
+                $srcString = $imageTagsOutput[1][$index];
                 $imageEncoded = $this->imageService->imageUriToBase64($srcString);
                 if ($imageEncoded === null) {
                     $imageEncoded = $srcString;
@@ -232,14 +231,13 @@ class ExportFormatter
             }
         }
 
+        // Replace any relative links with full system URL
         $linksOutput = [];
-        preg_match_all("/\<a.*href\=(\'|\")(.*?)(\'|\").*?\>/i", $htmlContent, $linksOutput);
-
-        // Replace image src with base64 encoded image strings
+        preg_match_all("/<a .*href=['\"](.*?)['\"].*?>/i", $htmlContent, $linksOutput);
         if (isset($linksOutput[0]) && count($linksOutput[0]) > 0) {
             foreach ($linksOutput[0] as $index => $linkMatch) {
                 $oldLinkString = $linkMatch;
-                $srcString = $linksOutput[2][$index];
+                $srcString = $linksOutput[1][$index];
                 if (strpos(trim($srcString), 'http') !== 0) {
                     $newSrcString = url($srcString);
                     $newLinkString = str_replace($srcString, $newSrcString, $oldLinkString);
@@ -248,7 +246,6 @@ class ExportFormatter
             }
         }
 
-        // Replace any relative links with system domain
         return $htmlContent;
     }
 
index 08d0921111fdb88a908867af8f228a9c1280e175..9debec12bdc3b9c9980853548ae8555436eaced1 100644 (file)
@@ -258,6 +258,24 @@ class ExportTest extends TestCase
         unlink($testFilePath);
     }
 
+    public function test_page_export_contained_html_embed_element_srcs_are_inlined()
+    {
+        $page = Page::query()->first();
+        $page->html = '<embed src="http://localhost/uploads/images/gallery/svg_test.svg"/>';
+        $page->save();
+
+        $storageDisk = Storage::disk('local');
+        $storageDisk->makeDirectory('uploads/images/gallery');
+        $storageDisk->put('uploads/images/gallery/svg_test.svg', '<svg>good</svg>');
+
+        $resp = $this->asEditor()->get($page->getUrl('/export/html'));
+
+        $storageDisk->delete('uploads/images/gallery/svg_test.svg');
+
+        $resp->assertDontSee('http://localhost/uploads/images/gallery/svg_test.svg', false);
+        $resp->assertSee('<embed src="data:image/svg+xml;base64,PHN2Zz5nb29kPC9zdmc+">', false);
+    }
+
     public function test_exports_removes_scripts_from_custom_head()
     {
         $entities = [