FIX: avoid ProseMirror handling paste when unauthorized (#35640)

When `authorizesOneOrMoreExtensions` is `false`, we don't call
`ComposerUpload#setup` to add the paste event listener, which originally
handles the `preventDefault`:


https://github.com/discourse/discourse/blob/d1e1c02fcb0cbc6722280afb6e086cb6a8b53882/frontend/discourse/app/components/composer-editor.gjs#L274-L276


https://github.com/discourse/discourse/blob/d1e1c02fcb0cbc6722280afb6e086cb6a8b53882/frontend/discourse/app/lib/uppy/composer-upload.js#L151-L153


https://github.com/discourse/discourse/blob/d1e1c02fcb0cbc6722280afb6e086cb6a8b53882/frontend/discourse/app/lib/uppy/composer-upload.js#L566-L569

This makes it so ProseMirror handles paste events itself, which leads to
base64 data src images. This PR adds a custom paste handler for
`prosemirror-editor` that prevents default in this case.
This commit is contained in:
Renato Atilio
2025-10-28 12:21:04 -03:00
committed by GitHub
parent 118b182dba
commit 052b07a7f0
2 changed files with 38 additions and 0 deletions
@@ -25,6 +25,7 @@ import { EditorView } from "prosemirror-view";
import { getExtensions } from "discourse/lib/composer/rich-editor-extensions";
import { bind } from "discourse/lib/decorators";
import { i18n } from "discourse-i18n";
import { authorizesOneOrMoreExtensions } from "../../../lib/uploads";
import { buildCommands, buildCustomState } from "../core/commands";
import { buildInputRules } from "../core/inputrules";
import { buildKeymap } from "../core/keymap";
@@ -77,6 +78,7 @@ export default class ProsemirrorEditor extends Component {
@service site;
@service siteSettings;
@service appEvents;
@service currentUser;
schema = createSchema(this.extensions, this.args.includeDefault);
view;
@@ -214,6 +216,19 @@ export default class ProsemirrorEditor extends Component {
next(() => this.args.focusOut?.());
return false;
},
paste: (view, event) => {
// When !authorizesOneOrMoreExtensions, we don't ComposerUpload#setup,
// which is originally responsible for preventDefault.
if (
event.clipboardData.files &&
!authorizesOneOrMoreExtensions(
this.currentUser.staff,
this.siteSettings
)
) {
event.preventDefault();
}
},
drop: (view, event) => {
if (
[...event.dataTransfer.items].some((item) => item.kind === "file")
@@ -1136,6 +1136,29 @@ describe "Composer - ProseMirror editor", type: :system do
expect(rich).to have_css("img[alt='img1'][data-orig-src]", count: 2)
end
it "avoids triggering upload when unauthorized" do
SiteSetting.authorized_extensions = ""
valid_png_data_uri =
"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mP8/5+hHgAHggJ/PchI7wAAAABJRU5ErkJggg=="
cdp.allow_clipboard
open_composer
html = <<~HTML
<img src="#{valid_png_data_uri}" alt="img1" width="100" height="100">
HTML
cdp.copy_paste(html, html: true)
expect(rich).to have_no_css("img")
composer.toggle_rich_editor
expect(composer).to have_value("")
end
it "merges text with link marks created from parsing" do
cdp.allow_clipboard
open_composer