[IMP] web_editor: do not alter code pasted from editor
Purpose Allow users to copy/paste specific elements that are generated by Odoo instead of sanitizing it on paste. It allows to keep structured data in DOM. Prepares Task-2796156 Prepares odoo/enterprise#29423 X-original-commit: 36ed4db2b378543d51e6e3eb03962707dbf15b1d Part-of: odoo/odoo#101694
This commit is contained in:
committed by
Thibault Delavallée
parent
1f6005070f
commit
d8cf028714
@@ -589,6 +589,7 @@ export class OdooEditor extends EventTarget {
|
||||
this.addDomListener(this.editable, 'paste', this._onPaste);
|
||||
this.addDomListener(this.editable, 'drop', this._onDrop);
|
||||
|
||||
this.addDomListener(this.document, 'copy', this._onClipboardCopy);
|
||||
this.addDomListener(this.document, 'selectionchange', this._onSelectionChange);
|
||||
this.addDomListener(this.document, 'selectionchange', this._handleCommandHint);
|
||||
this.addDomListener(this.document, 'keydown', this._onDocumentKeydown);
|
||||
@@ -3081,6 +3082,26 @@ export class OdooEditor extends EventTarget {
|
||||
}
|
||||
}
|
||||
|
||||
_onClipboardCopy(clipboardEvent) {
|
||||
if (this.isSelectionInEditable()) {
|
||||
clipboardEvent.preventDefault();
|
||||
const selection = this.document.getSelection();
|
||||
const range = selection.getRangeAt(0);
|
||||
const rangeContent = range.cloneContents();
|
||||
|
||||
const dataHtmlElement = document.createElement('data');
|
||||
dataHtmlElement.append(rangeContent);
|
||||
const odooHtml = dataHtmlElement.innerHTML;
|
||||
const odooText = dataHtmlElement.innerText;
|
||||
if (!clipboardEvent.clipboardData.getData('text/plain')) {
|
||||
clipboardEvent.clipboardData.setData('text/plain', odooText);
|
||||
}
|
||||
if (!clipboardEvent.clipboardData.getData('text/html')) {
|
||||
clipboardEvent.clipboardData.setData('text/html', odooHtml);
|
||||
}
|
||||
clipboardEvent.clipboardData.setData('text/odoo-editor', odooHtml);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
@@ -3882,8 +3903,15 @@ export class OdooEditor extends EventTarget {
|
||||
ev.preventDefault();
|
||||
const sel = this.document.getSelection();
|
||||
const files = getImageFiles(ev.clipboardData);
|
||||
const odooEditorHtml = ev.clipboardData.getData('text/odoo-editor');
|
||||
const clipboardHtml = ev.clipboardData.getData('text/html');
|
||||
if (clipboardHtml) {
|
||||
if (odooEditorHtml) {
|
||||
const fragment = parseHTML(odooEditorHtml);
|
||||
DOMPurify.sanitize(fragment, { IN_PLACE: true });
|
||||
if (fragment.hasChildNodes()) {
|
||||
this.execCommand('insert', fragment);
|
||||
}
|
||||
} else if (clipboardHtml) {
|
||||
this.execCommand('insert', this._prepareClipboardData(clipboardHtml));
|
||||
} else if (files.length) {
|
||||
this.addImagesFiles(files);
|
||||
|
||||
@@ -21,6 +21,7 @@ const pasteData = async function (editor, text, type) {
|
||||
|
||||
const pasteText = async (editor, text) => pasteData(editor, text, 'text/plain');
|
||||
const pasteHtml = async (editor, html) => pasteData(editor, html, 'text/html');
|
||||
const pasteOdooEditorHtml = async (editor, html) => pasteData(editor, html, 'text/odoo-editor');
|
||||
|
||||
describe('Copy and paste', () => {
|
||||
describe('Html Paste cleaning', () => {
|
||||
@@ -1479,4 +1480,24 @@ describe('Copy and paste', () => {
|
||||
});
|
||||
});
|
||||
});
|
||||
describe('Odoo editor own html', () => {
|
||||
it('should paste html as is', async () => {
|
||||
await testEditor(BasicEditor, {
|
||||
contentBefore: '<p>a[]b</p>',
|
||||
stepFunction: async editor => {
|
||||
await pasteOdooEditorHtml(editor, '<div class="custom-paste">b</div>');
|
||||
},
|
||||
contentAfter: '<p>a</p><div class="custom-paste">b</div>[]<p>b</p>',
|
||||
});
|
||||
});
|
||||
it('should not paste unsafe content', async () => {
|
||||
await testEditor(BasicEditor, {
|
||||
contentBefore: '<p>a[]b</p>',
|
||||
stepFunction: async editor => {
|
||||
await pasteOdooEditorHtml(editor, `<script>console.log('xss attack')</script>`);
|
||||
},
|
||||
contentAfter: '<p>a[]b</p>',
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user