Skip to content

ROL-2184: Preserve pasted entry images when publishing - #203

Closed
snoopdave wants to merge 1 commit into
masterfrom
fix-inline-entry-images
Closed

snoopdave wants to merge 1 commit into
masterfrom
fix-inline-entry-images

Conversation

@snoopdave

@snoopdave snoopdave commented Oct 3, 2026 •

Copy link
Copy Markdown
Contributor

Fixes ROL-2184.

Summary

Desktop images pasted or dragged into the rich text editor remain visible while editing but disappear from published entries because their data: sources are removed during rendering.

This change converts PNG, JPEG, and GIF data images to Roller media files when uploads are available to the author. If uploads are disabled or the author cannot upload, it keeps validated images inline. Saving an older entry applies the same handling to images already in its text or summary.

It also adds weblog.inlineImages.preferInline for operators who want inline storage even when uploads are available, limits inline content to 60,000 UTF-8 bytes per field, permits validated data images through the HTML sanitizer, and updates bundled theme image policies and the user guide.

Verification

  • mvn -q -pl app -am -DskipTests compile — passed
  • git diff --check — passed
  • Tests and browser verification were not run.

Notes

Custom themes with their own Content Security Policy need data: in img-src to display inline images.

if (html == null) {
return sources;
}
Matcher image = IMAGE_TAG.matcher(html);
@snoopdave snoopdave changed the title Preserve pasted entry images when publishing ROL-2184: Preserve pasted entry images when publishing Oct 3, 2026
@snoopdave snoopdave added the 6.1.7 label Oct 3, 2026

@snoopdave snoopdave left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

PR-Review: 2 inline comments posted.

// MySQL's TEXT column holds 65,535 bytes. Leave room for the rest of an entry.
public static final int MAX_FIELD_BYTES = 60000;

private static final Pattern IMAGE_TAG = Pattern.compile("(?is)<img\\b[^>]*>");

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🐞Claude Issue: Blocking: This is the cause of the failing CodeQL check (high: polynomial regex on user data). [^>]* also matches <, so on text with many <img and no > each find() scans to the end of the input, which is O(n²). Measured with "<img ".repeat(n): 0.44 s at 50 KB, 1.8 s at 100 KB, 7.2 s at 200 KB. Any author can make a save take minutes.

Fix: stop at the next tag start. On the same input this ran in 1–3 ms:

private static final Pattern IMAGE_TAG = Pattern.compile("(?is)<img\\b[^<>]*>");

Add a regression test with a large adversarial input.

public static final int MAX_FIELD_BYTES = 60000;

private static final Pattern IMAGE_TAG = Pattern.compile("(?is)<img\\b[^>]*>");
private static final Pattern SOURCE_ATTRIBUTE = Pattern.compile(

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🐞Claude Issue: Important: SOURCE_ATTRIBUTE can match src= inside another attribute's quoted value. For example, in <img alt='src="data:image/png;base64,..."' src="https://..."> the alt text is treated as the source. That alt text is then rewritten or rejected, and the real src is ignored. Match attributes in sequence instead (name=value pairs from the tag start), or at least skip matches that fall inside an earlier quoted value.

@snoopdave

Copy link
Copy Markdown
Contributor Author

🐞Claude Issue: PR-Review: General Issues

The following issues were found but cannot be attached to a specific line in the diff:

  • Blocking: There are no tests. InlineImageData (parsing, signature checks, size limits, findSources offsets), the HTMLSanitizer change that accepts data URLs, and the EntryEdit paths (keep inline, upload, too large, and cleanup after a failed save) all need coverage. app/src/test/java/.../util/ and .../ui/struts2/editor/EntryEdit*Test.java already follow this pattern. Also add a test that data:image/svg+xml and data:text/html are still stripped by the sanitizer.
  • Blocking: CHANGES.md is not updated. Add a short entry for ROL-2184 that links the JIRA issue and mentions weblog.inlineImages.preferInline and the theme CSP change (img-src * data:).

@snoopdave

Copy link
Copy Markdown
Contributor Author

Closing as superseded by #205. That PR targets roller-6.1.x for 6.1.7 and includes the follow-up fixes and tests. The change can be cherry-picked to master after the 6.1.7 release, as noted on #205.

@snoopdave snoopdave closed this Oct 4, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants