Repository navigation
Conversation
The RTD imported pasted images by asking the server to fetch their URLs (getImgFromRemoteURL), which let any client make the server fetch arbitrary URLs. The browser now downloads pasted images itself and uploads them through getUploadedFileFinalURL, and the server-side fetch is removed. - data: URLs are decoded directly as the CSP generally blocks fetching them - When 'Copy image' offers both a remote URL and the image file, use the file - Accept png, jpeg, gif, webp and avif, max 20MB, and verify they decode - Upload placeholders take the pasted image's dimensions - Server-side RTD cleanup now properly discards invalid or non-image data: URLs
Member
Author
|
@webharerob decodeImageDataURL is added as internal api - could be moved to @webhare/upload next to getFileAsDataURL and then also used to replace dataURItoBlob in imgeditcontroller.ts. worth it? |
Contributor
There was a problem hiding this comment.
🟡 Changes recommended
The paste handler can discard valid images, retain unused files and object URLs, and buffer oversized downloads before enforcing the size limit.
3 open issues
What changed in this PR
Moves pasted RTD image downloads into the browser and reuses the existing upload service, removing the unauthenticated server-side URL-fetching endpoint that enabled SSRF.
Changes:
- Adds browser-side image validation, direct data URL decoding, and clipboard-file handling.
- Preserves pasted image dimensions during upload and supports WebP/AVIF image-cache URLs.
- Fixes invalid data URL cleanup and adds paste regression tests.
| File | Description |
|---|---|
whtree/modules/webhare_testsuite/tests/tollium/richdoc/teststructured.ts |
Tests rejected images and PNG/WebP clipboard imports. |
whtree/modules/tollium/web/ui/components/richeditor/richeditor.scss |
Prevents upload spinners from stretching. |
whtree/modules/tollium/web/ui/components/richeditor/internal/structurededitor.tsx |
Prefers clipboard image files and preserves styled dimensions. |
whtree/modules/tollium/web/ui/components/richeditor/internal/editorbase.tsx |
Downloads, validates, and uploads pasted images in the browser. |
whtree/modules/publisher/lib/internal/rtd/service.whlib |
Discards invalid and non-image data URLs before storage. |
whtree/modules/publisher/lib/internal/forms/rpc.whlib |
Removes remote fetching and routes WebP/AVIF uploads through the image cache. |
whtree/jssdk/forms/src/formservice.ts |
Removes the remote-image download method from the service interface. |
Review effort: Balanced
Comment on lines
+329
to
+330
| const bytes = match[2] ? Uint8Array.from(atob(decodeURIComponent(match[3])), c => c.charCodeAt(0)) : new TextEncoder().encode(decodeURIComponent(match[3])); | ||
| return new Blob([bytes], { type }); |
| if (contentlength > pastedImageMaxSize) | ||
| throw new Error(`Image is too large (${contentlength} bytes)`); | ||
|
|
||
| return await response.blob(); |
Comment on lines
+2117
to
+2118
| const url = URL.createObjectURL(file); | ||
| this.pastedfiles.set(url, file); |
- Don't crash when clipboardData has no files (fixes testobjects-block/inline) - Percent-decode non-base64 data: URLs directly into bytes instead of through decodeURIComponent, which rejects non-UTF-8 data such as image bytes - Enforce the pasted image size limit while reading the response, as Content-Length may be absent - Release object URLs for clipboard images that weren't imported, and any remaining ones when the editor is destroyed - Move the pasted image helpers to a type-checked utils.ts
There was a problem hiding this comment.
🤖 Auto-Approved: PR author (@unilynx) is an internal organization/repository member.
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.

Why
When content with images is pasted into an RTD, the editor asked the server to download each image URL through
getImgFromRemoteURLon the publisher form service. That service is reachable without authentication, so anyone could make the server fetch arbitrary URLs (SSRF), with only weak port and credential checks in place.What changes
getUploadedFileFinalURL, the same path the image upload button uses.RPC_GetImgFromRemoteURLand its TypeScript interface entry are removed.data:URLs are decoded directly instead of fetched, because CSPconnect-src(eg. in the backend) blocksfetch()ofdata:/blob:.<img>and one image file. This avoids needing CORS on the remote URL.createImageBitmap). Fetches usecredentials: "omit"andreferrerPolicy: "strict-origin".width/heightattributes or pixelstyledimensions. The spinner isn't stretched (object-fit: none).getUploadedFileFinalURLtreats webp/avif as images (image cache URL instead of a file URL).ValidateAndCleanupImage: non-imagedata:URLs were disposed but then still stored, and invaliddata:URLs weren't handled. Both are now discarded.Known limitations
TODOmarks where the editor should tell the user how many images couldn't be copied.connect-src 'self' https://*.googleapis.com, so cross-originhttps:image URLs in pasted HTML will be dropped there unlessconnect-srcis widened. Same-origin images,data:URLs and clipboard image files work.Tests
tollium.richdoc.teststructured: unusable pasted images are rejected (non-imagedata:URL, corrupt png, 404,file:URL), and png and webp clipboard files are imported when the HTML's remote URL can't be fetched.tollium.richdoc.teststructured,tollium.richdoc.testfree,tollium.richdoc.testrteservice,wh.jscomponents.rte.teststructured,wh.jscomponents.rte.teststructured-copypaste,wh.jscomponents.rte.testbase,publisher.forms.testrteandpublisher.forms.testuploadfield.