From 8f6cba262ff1b2d26f1aaf9f65c66aae872a7a22 Mon Sep 17 00:00:00 2001 From: NGPixel Date: Sat, 12 Sep 2020 14:05:24 -0400 Subject: [PATCH] fix: draw.io svgs are no longer removed with linebreaks (#2415) --- client/components/editor/editor-markdown.vue | 19 ++++++++- package.json | 36 +++++++++--------- .../rendering/html-security/definition.yml | 8 +++- .../rendering/html-security/renderer.js | 17 +++++++++ yarn.lock | Bin 826232 -> 832616 bytes 5 files changed, 60 insertions(+), 20 deletions(-) diff --git a/client/components/editor/editor-markdown.vue b/client/components/editor/editor-markdown.vue index 3e23655b..5e124e96 100644 --- a/client/components/editor/editor-markdown.vue +++ b/client/components/editor/editor-markdown.vue @@ -300,6 +300,21 @@ const md = new MarkdownIt({ .use(mdFootnote) .use(mdImsize) +// DOMPurify fix for draw.io +DOMPurify.addHook('uponSanitizeElement', (elm) => { + if (elm.querySelectorAll) { + const breaks = elm.querySelectorAll('foreignObject br, foreignObject p') + if (breaks && breaks.length) { + for (let i = 0; i < breaks.length; i++) { + breaks[i].parentNode.replaceChild( + document.createElement('div'), + breaks[i] + ) + } + } + } +}) + // ======================================== // HELPER FUNCTIONS // ======================================== @@ -459,7 +474,9 @@ export default { linesMap = [] // this.$store.set('editor/content', newContent) this.processMarkers(this.cm.firstLine(), this.cm.lastLine()) - this.previewHTML = DOMPurify.sanitize(md.render(newContent)) + this.previewHTML = DOMPurify.sanitize(md.render(newContent), { + ADD_TAGS: ['foreignObject'] + }) this.$nextTick(() => { tabsetHelper.format() this.renderMermaidDiagrams() diff --git a/package.json b/package.json index ec2fdede..3ca42c3a 100644 --- a/package.json +++ b/package.json @@ -37,8 +37,8 @@ }, "dependencies": { "@aoberoi/passport-slack": "1.0.5", - "@azure/storage-blob": "12.1.2", - "@bugsnag/js": "7.3.3", + "@azure/storage-blob": "12.2.0", + "@bugsnag/js": "7.3.4", "@exlinc/keycloak-passport": "1.0.2", "@root/csr": "0.8.1", "@root/keypairs": "0.10.1", @@ -50,7 +50,7 @@ "apollo-server": "2.17.0", "apollo-server-express": "2.17.0", "auto-load": "3.0.4", - "aws-sdk": "2.746.0", + "aws-sdk": "2.751.0", "azure-search-client": "3.1.5", "bcryptjs-then": "1.0.1", "bluebird": "3.7.2", @@ -69,7 +69,7 @@ "custom-error-instance": "2.1.2", "dependency-graph": "0.9.0", "diff": "4.0.2", - "diff2html": "3.1.12", + "diff2html": "3.1.13", "dompurify": "2.0.15", "dotize": "0.3.0", "elasticsearch6": "npm:@elastic/elasticsearch@6", @@ -87,9 +87,9 @@ "graphql-list-fields": "2.0.2", "graphql-rate-limit-directive": "1.2.1", "graphql-subscriptions": "1.1.0", - "graphql-tools": "6.2.0", + "graphql-tools": "6.2.1", "he": "1.2.0", - "highlight.js": "10.1.2", + "highlight.js": "10.2.0", "i18next": "19.7.0", "i18next-express-middleware": "2.0.0", "i18next-node-fs-backend": "2.1.3", @@ -122,7 +122,7 @@ "mime-types": "2.1.27", "moment": "2.27.0", "moment-timezone": "0.5.31", - "mongodb": "3.6.1", + "mongodb": "3.6.2", "ms": "2.1.2", "mssql": "6.2.1", "multer": "1.4.2", @@ -134,7 +134,7 @@ "objection": "2.2.3", "passport": "0.4.1", "passport-auth0": "1.3.3", - "passport-azure-ad": "4.2.1", + "passport-azure-ad": "4.3.0", "passport-cas": "0.1.1", "passport-discord": "0.1.4", "passport-dropbox-oauth2": "1.1.0", @@ -183,7 +183,7 @@ "validate.js": "0.13.1", "winston": "3.3.3", "xss": "1.0.8", - "yargs": "15.4.1" + "yargs": "16.0.3" }, "devDependencies": { "@babel/cli": "^7.11.6", @@ -202,7 +202,7 @@ "@mdi/font": "5.5.55", "@panter/vue-i18next": "0.15.2", "@requarks/ckeditor5": "19.0.1-wiki.2", - "@vue/babel-preset-app": "4.5.4", + "@vue/babel-preset-app": "4.5.6", "animate-sass": "0.8.2", "animated-number-vue": "1.0.0", "apollo-cache-inmemory": "1.6.6", @@ -231,7 +231,7 @@ "codemirror": "5.57.0", "copy-webpack-plugin": "6.1.0", "core-js": "3.6.5", - "css-loader": "4.2.2", + "css-loader": "4.3.0", "cssnano": "4.1.10", "cypress": "5.1.0", "d3": "6.1.1", @@ -263,8 +263,8 @@ "jest": "26.4.2", "js-beautify": "1.13.0", "js-cookie": "2.2.1", - "mermaid": "8.7.0", - "mini-css-extract-plugin": "0.11.0", + "mermaid": "8.8.0", + "mini-css-extract-plugin": "0.11.1", "moment-duration-format": "2.3.2", "moment-timezone-data-webpack-plugin": "1.3.0", "offline-plugin": "5.0.7", @@ -289,7 +289,7 @@ "script-ext-html-webpack-plugin": "2.1.4", "simple-progress-webpack-plugin": "1.1.2", "style-loader": "1.2.1", - "terser": "5.3.0", + "terser": "5.3.1", "twemoji-awesome": "1.0.6", "url-loader": "4.1.0", "velocity-animate": "1.5.2", @@ -298,7 +298,7 @@ "vue-apollo": "3.0.4", "vue-chartjs": "3.5.1", "vue-clipboards": "1.3.0", - "vue-filepond": "6.0.2", + "vue-filepond": "6.0.3", "vue-hot-reload-api": "2.3.4", "vue-loader": "15.9.3", "vue-moment": "4.1.0", @@ -318,13 +318,13 @@ "webpack-cli": "3.3.12", "webpack-dev-middleware": "3.7.2", "webpack-hot-middleware": "2.25.0", - "webpack-merge": "5.1.3", + "webpack-merge": "5.1.4", "webpack-modernizr-loader": "5.0.0", "webpack-subresource-integrity": "1.4.1", "webpackbar": "4.0.0", - "whatwg-fetch": "3.4.0", + "whatwg-fetch": "3.4.1", "write-file-webpack-plugin": "4.5.1", - "xterm": "4.8.1", + "xterm": "4.9.0", "zxcvbn": "4.4.2" }, "resolutions": { diff --git a/server/modules/rendering/html-security/definition.yml b/server/modules/rendering/html-security/definition.yml index 8fefeda1..04067c58 100644 --- a/server/modules/rendering/html-security/definition.yml +++ b/server/modules/rendering/html-security/definition.yml @@ -14,9 +14,15 @@ props: default: true hint: Sanitize HTML from unsafe attributes and tags that could lead to XSS attacks order: 1 + allowDrawIoUnsafe: + type: Boolean + title: Allow Draw.io Unsafe Elements + default: true + hint: Draw.io diagrams may introduce some elements that are usually filtered. Turning off this option may cause some diagrams to be completely removed during the sanitization process. + order: 2 allowIFrames: type: Boolean title: Allow iframes default: false hint: iframes will not be stripped if enabled. (Not recommended) - order: 2 + order: 3 diff --git a/server/modules/rendering/html-security/renderer.js b/server/modules/rendering/html-security/renderer.js index 9f7484ca..b3233824 100644 --- a/server/modules/rendering/html-security/renderer.js +++ b/server/modules/rendering/html-security/renderer.js @@ -10,6 +10,23 @@ module.exports = { const allowedAttrs = ['v-pre', 'v-slot:tabs', 'v-slot:content', 'target'] const allowedTags = ['tabset', 'template'] + if (config.allowDrawIoUnsafe) { + allowedTags.push('foreignObject') + DOMPurify.addHook('uponSanitizeElement', (elm) => { + if (elm.querySelectorAll) { + const breaks = elm.querySelectorAll('foreignObject br, foreignObject p') + if (breaks && breaks.length) { + for (let i = 0; i < breaks.length; i++) { + breaks[i].parentNode.replaceChild( + window.document.createElement('div'), + breaks[i] + ) + } + } + } + }) + } + if (config.allowIFrames) { allowedTags.push('iframe') } diff --git a/yarn.lock b/yarn.lock index b41488705e29a3069819b0c31abd074918c1e82d..67e6be13b34a89f929c33f9db72140a7a81ca54b 100644 GIT binary patch delta 13607 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 V0tkI*zO%P+coPSM_w8()`oF{s28{p! delta 9911 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 asZiMeN#e}>p^t4GCkSS)Kee%P^Zy4=YJDUC