|
|
@@ -44,6 +44,11 @@ export class ProsemirrorService {
|
|
|
marks: schema.spec.marks,
|
|
|
});
|
|
|
private enabled = true;
|
|
|
+ /**
|
|
|
+ * This is a Document used for processing incoming text. It ensures that malicious HTML is not executed by the
|
|
|
+ * actual document that is attached to the browser DOM, which could cause XSS attacks.
|
|
|
+ */
|
|
|
+ private detachedDoc: Document | null = null;
|
|
|
|
|
|
constructor(private injector: Injector, private contextMenuService: ContextMenuService) {}
|
|
|
|
|
|
@@ -110,7 +115,8 @@ export class ProsemirrorService {
|
|
|
}
|
|
|
|
|
|
private getStateFromText(text: string | null | undefined): EditorState {
|
|
|
- const div = document.createElement('div');
|
|
|
+ const doc = this.getDetachedDoc();
|
|
|
+ const div = doc.createElement('div');
|
|
|
div.innerHTML = text ?? '';
|
|
|
return EditorState.create({
|
|
|
doc: DOMParser.fromSchema(this.mySchema).parse(div),
|
|
|
@@ -119,7 +125,8 @@ export class ProsemirrorService {
|
|
|
}
|
|
|
|
|
|
private getTextFromState(state: EditorState): string {
|
|
|
- const div = document.createElement('div');
|
|
|
+ const doc = this.getDetachedDoc();
|
|
|
+ const div = doc.createElement('div');
|
|
|
const fragment = DOMSerializer.fromSchema(this.mySchema).serializeFragment(state.doc.content);
|
|
|
|
|
|
div.appendChild(fragment);
|
|
|
@@ -158,4 +165,11 @@ export class ProsemirrorService {
|
|
|
}),
|
|
|
);
|
|
|
}
|
|
|
+
|
|
|
+ private getDetachedDoc() {
|
|
|
+ if (!this.detachedDoc) {
|
|
|
+ this.detachedDoc = document.implementation.createHTMLDocument();
|
|
|
+ }
|
|
|
+ return this.detachedDoc;
|
|
|
+ }
|
|
|
}
|