99use BookStack \Theming \ThemeEvents ;
1010use BookStack \Uploads \ImageRepo ;
1111use BookStack \Uploads \ImageService ;
12+ use BookStack \Users \Models \User ;
1213use BookStack \Util \HtmlContentFilter ;
14+ use BookStack \Util \WebSafeMimeSniffer ;
1315use DOMDocument ;
1416use DOMElement ;
1517use DOMNode ;
@@ -27,9 +29,9 @@ public function __construct(
2729 /**
2830 * Update the content of the page with new provided HTML.
2931 */
30- public function setNewHTML (string $ html ): void
32+ public function setNewHTML (string $ html, User $ updater ): void
3133 {
32- $ html = $ this ->extractBase64ImagesFromHtml ($ html );
34+ $ html = $ this ->extractBase64ImagesFromHtml ($ html, $ updater );
3335 $ this ->page ->html = $ this ->formatHtml ($ html );
3436 $ this ->page ->text = $ this ->toPlainText ();
3537 $ this ->page ->markdown = '' ;
@@ -38,9 +40,9 @@ public function setNewHTML(string $html): void
3840 /**
3941 * Update the content of the page with new provided Markdown content.
4042 */
41- public function setNewMarkdown (string $ markdown ): void
43+ public function setNewMarkdown (string $ markdown, User $ updater ): void
4244 {
43- $ markdown = $ this ->extractBase64ImagesFromMarkdown ($ markdown );
45+ $ markdown = $ this ->extractBase64ImagesFromMarkdown ($ markdown, $ updater );
4446 $ this ->page ->markdown = $ markdown ;
4547 $ html = (new MarkdownToHtml ($ markdown ))->convert ();
4648 $ this ->page ->html = $ this ->formatHtml ($ html );
@@ -50,7 +52,7 @@ public function setNewMarkdown(string $markdown): void
5052 /**
5153 * Convert all base64 image data to saved images.
5254 */
53- protected function extractBase64ImagesFromHtml (string $ htmlText ): string
55+ protected function extractBase64ImagesFromHtml (string $ htmlText, User $ updater ): string
5456 {
5557 if (empty ($ htmlText ) || !str_contains ($ htmlText , 'data:image ' )) {
5658 return $ htmlText ;
@@ -66,7 +68,7 @@ protected function extractBase64ImagesFromHtml(string $htmlText): string
6668 $ imageNodes = $ xPath ->query ('//img[contains(@src, \'data:image \')] ' );
6769 foreach ($ imageNodes as $ imageNode ) {
6870 $ imageSrc = $ imageNode ->getAttribute ('src ' );
69- $ newUrl = $ this ->base64ImageUriToUploadedImageUrl ($ imageSrc );
71+ $ newUrl = $ this ->base64ImageUriToUploadedImageUrl ($ imageSrc, $ updater );
7072 $ imageNode ->setAttribute ('src ' , $ newUrl );
7173 }
7274
@@ -86,7 +88,7 @@ protected function extractBase64ImagesFromHtml(string $htmlText): string
8688 * Attempting to capture the whole data uri using regex can cause PHP
8789 * PCRE limits to be hit with larger, multi-MB, files.
8890 */
89- protected function extractBase64ImagesFromMarkdown (string $ markdown ): string
91+ protected function extractBase64ImagesFromMarkdown (string $ markdown, User $ updater ): string
9092 {
9193 $ matches = [];
9294 $ contentLength = strlen ($ markdown );
@@ -104,7 +106,7 @@ protected function extractBase64ImagesFromMarkdown(string $markdown): string
104106 $ dataUri .= $ char ;
105107 }
106108
107- $ newUrl = $ this ->base64ImageUriToUploadedImageUrl ($ dataUri );
109+ $ newUrl = $ this ->base64ImageUriToUploadedImageUrl ($ dataUri, $ updater );
108110 $ replacements [] = [$ dataUri , $ newUrl ];
109111 }
110112
@@ -119,16 +121,28 @@ protected function extractBase64ImagesFromMarkdown(string $markdown): string
119121 * Parse the given base64 image URI and return the URL to the created image instance.
120122 * Returns an empty string if the parsed URI is invalid or causes an error upon upload.
121123 */
122- protected function base64ImageUriToUploadedImageUrl (string $ uri ): string
124+ protected function base64ImageUriToUploadedImageUrl (string $ uri, User $ updater ): string
123125 {
124126 $ imageRepo = app ()->make (ImageRepo::class);
125127 $ imageInfo = $ this ->parseBase64ImageUri ($ uri );
126128
129+ // Validate user has permission to create images
130+ if (!$ updater ->can ('image-create-all ' )) {
131+ return '' ;
132+ }
133+
127134 // Validate extension and content
128135 if (empty ($ imageInfo ['data ' ]) || !ImageService::isExtensionSupported ($ imageInfo ['extension ' ])) {
129136 return '' ;
130137 }
131138
139+ // Validate content looks like an image via sniffing mime type
140+ $ mimeSniffer = new WebSafeMimeSniffer ();
141+ $ mime = $ mimeSniffer ->sniff ($ imageInfo ['data ' ]);
142+ if (!str_starts_with ($ mime , 'image/ ' )) {
143+ return '' ;
144+ }
145+
132146 // Validate that the content is not over our upload limit
133147 $ uploadLimitBytes = (config ('app.upload_limit ' ) * 1000000 );
134148 if (strlen ($ imageInfo ['data ' ]) > $ uploadLimitBytes ) {
0 commit comments