From abab623240a40ce1ffe03239113a873327dd5b78 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B8rn=20Gustav=20Larsen?= Date: Wed, 12 Nov 2025 12:48:22 +0100 Subject: [PATCH] The sanitising functionality for both html and SVG has been unified into a single file on both the client and server side. Second, a problem with the SVG output from the drawio has also been fixed. Last, it is possible to add a customised path for the drawio web application, which can be used for local hosting the application. --- .gitignore | 2 + client/components/editor/common/sanitize.js | 48 + client/components/editor/editor-asciidoc.vue | 5 +- client/components/editor/editor-markdown.vue | 5 +- .../components/editor/editor-modal-drawio.vue | 33 +- package.json | 4 +- server/app/data.yml | 3 + server/controllers/common.js | 3 + server/helpers/sanitizer.js | 80 + server/jobs/sanitize-svg.js | 11 +- server/modules/comments/default/comment.js | 10 +- .../rendering/html-security/renderer.js | 39 +- yarn.lock | 11342 ++++++---------- 13 files changed, 4604 insertions(+), 6981 deletions(-) create mode 100644 client/components/editor/common/sanitize.js create mode 100644 server/helpers/sanitizer.js diff --git a/.gitignore b/.gitignore index 9e37fa62..8a9f0258 100644 --- a/.gitignore +++ b/.gitignore @@ -15,6 +15,8 @@ npm/node_modules .node_repl_history npm-debug.log* .yarn +package-lock.json +yarn.lock # Generated assets /assets diff --git a/client/components/editor/common/sanitize.js b/client/components/editor/common/sanitize.js new file mode 100644 index 00000000..a0e8df2d --- /dev/null +++ b/client/components/editor/common/sanitize.js @@ -0,0 +1,48 @@ + +import DOMPurify from 'dompurify' + +/* global siteConfig */ +export default function drawioSanitize( + content) { + if (siteConfig.drawio.sanitizing === false) { + return content + } + + console.log('DEBUG: Performing sanitizing ...') + + content = + DOMPurify.sanitize( + content, + { + USE_PROFILES: + { + svg: true, + html: true + }, + HTML_INTEGRATION_POINTS: + { + foreignobject: true + }, + ADD_TAGS: [ + 'div', + 'foreignObject', + 'switch', + 'style', + 'title', + 'desc', + 'metadata'], + ADD_ATTR: [ + 'xmlns', 'xmlns:xlink', 'xlink:href', 'xml:space', 'xml:base', + 'font-family', 'font-size', 'font-style', 'font-weight', + 'alignment-baseline', 'dominant-baseline', 'baseline-shift', + 'vector-effect', 'text-anchor', 'clip-path', 'mask', + 'fill-rule', 'stroke-linejoin', 'stroke-linecap', + 'transform', 'viewBox', 'preserveAspectRatio', + 'overflow', 'filter', 'style', 'data-name', 'aria-label', 'requiredFeatures', 'pointer-events'], + FORBID_TAGS: ['script'], // keep scripting disabled + FORBID_ATTR: ['onload', 'onclick', 'onmouseover'], // prevent XSS + ALLOW_UNKNOWN_PROTOCOLS: true // for xlink:href + }) + + return content +} diff --git a/client/components/editor/editor-asciidoc.vue b/client/components/editor/editor-asciidoc.vue index 296b2414..fcadf96e 100644 --- a/client/components/editor/editor-asciidoc.vue +++ b/client/components/editor/editor-asciidoc.vue @@ -152,6 +152,7 @@ import 'codemirror/addon/fold/foldcode.js' import 'codemirror/addon/fold/foldgutter.js' import 'codemirror/addon/fold/foldgutter.css' import cmFold from './common/cmFold' +import drawioSanitize from './common/sanitize' // ======================================== // INIT @@ -227,9 +228,7 @@ export default { $(elm).parent().replaceWith(`
${diagramContent}`)
       })
 
-      this.previewHTML = DOMPurify.sanitize($.html(), {
-        ADD_TAGS: ['foreignObject']
-      })
+      this.previewHTML = drawioSanitize($.html())
     },
     /**
      * Insert content at cursor
diff --git a/client/components/editor/editor-markdown.vue b/client/components/editor/editor-markdown.vue
index 4ca6e192..722a9480 100644
--- a/client/components/editor/editor-markdown.vue
+++ b/client/components/editor/editor-markdown.vue
@@ -226,6 +226,7 @@ import mermaid from 'mermaid'
 import katexHelper from './common/katex'
 import tabsetHelper from './markdown/tabset'
 import cmFold from './common/cmFold'
+import drawioSanitize from './common/sanitize'
 
 // ========================================
 // INIT
@@ -453,9 +454,7 @@ export default {
       linesMap = []
       // this.$store.set('editor/content', newContent)
       this.processMarkers(this.cm.firstLine(), this.cm.lastLine())
-      this.previewHTML = DOMPurify.sanitize(md.render(newContent), {
-        ADD_TAGS: ['foreignObject']
-      })
+      this.previewHTML = drawioSanitize(md.render(newContent))
       this.$nextTick(() => {
         tabsetHelper.format()
         this.renderMermaidDiagrams()
diff --git a/client/components/editor/editor-modal-drawio.vue b/client/components/editor/editor-modal-drawio.vue
index 9328c45e..f11925ca 100644
--- a/client/components/editor/editor-modal-drawio.vue
+++ b/client/components/editor/editor-modal-drawio.vue
@@ -2,7 +2,7 @@
   v-card.editor-modal-drawio.animated.fadeIn(flat, tile)
     iframe(
       ref='drawio'
-      src='https://embed.diagrams.net/?embed=1&proto=json&spin=1&saveAndExit=1&noSaveBtn=1&noExitBtn=0'
+      :src='drawioBaseUrl'
       frameborder='0'
     )
 
@@ -10,22 +10,6 @@