diff --git a/js/package.json b/js/package.json index 8799976bf..aa07217b7 100644 --- a/js/package.json +++ b/js/package.json @@ -50,6 +50,7 @@ "p-debounce": "^4.0.0", "phoenix": "^1.6", "register-service-worker": "^1.7.2", + "sanitize-html": "^2.5.3", "tippy.js": "^6.2.3", "unfetch": "^4.2.0", "v-tooltip": "^2.1.3", @@ -74,6 +75,7 @@ "@types/prosemirror-model": "^1.7.2", "@types/prosemirror-state": "^1.2.4", "@types/prosemirror-view": "^1.11.4", + "@types/sanitize-html": "^2.5.0", "@typescript-eslint/eslint-plugin": "^5.3.0", "@typescript-eslint/parser": "^5.3.0", "@vue/cli-plugin-babel": "~5.0.0-rc.0", diff --git a/js/src/components/Editor.vue b/js/src/components/Editor.vue index ebdcf1556..6645de3ac 100644 --- a/js/src/components/Editor.vue +++ b/js/src/components/Editor.vue @@ -212,6 +212,7 @@ import Underline from "@tiptap/extension-underline"; import Link from "@tiptap/extension-link"; import CharacterCount from "@tiptap/extension-character-count"; import { AutoDir } from "./Editor/Autodir"; +import sanitizeHtml from "sanitize-html"; @Component({ components: { EditorContent, BubbleMenu }, @@ -265,6 +266,7 @@ export default class EditorComponent extends Vue { "aria-label": this.ariaLabel, role: "textbox", }, + transformPastedHTML: this.transformPastedHTML, }, extensions: [ StarterKit, @@ -292,6 +294,19 @@ export default class EditorComponent extends Vue { }); } + transformPastedHTML(html: string): string { + // When using comment mode, limit to acceptable tags + if (this.isCommentMode) { + return sanitizeHtml(html, { + allowedTags: ["b", "i", "em", "strong", "a"], + allowedAttributes: { + a: ["href", "rel", "target"], + }, + }); + } + return html; + } + @Watch("value") onValueChanged(val: string): void { if (!this.editor) return; diff --git a/js/yarn.lock b/js/yarn.lock index 1e6849cdd..6014cfd54 100644 --- a/js/yarn.lock +++ b/js/yarn.lock @@ -2034,6 +2034,13 @@ resolved "https://registry.yarnpkg.com/@types/retry/-/retry-0.12.1.tgz#d8f1c0d0dc23afad6dc16a9e993a0865774b4065" integrity sha512-xoDlM2S4ortawSWORYqsdU+2rxdh4LRW9ytc3zmT37RIKQh6IHyKwwtKhKis9ah8ol07DCkZxPt8BBvPjC6v4g== +"@types/sanitize-html@^2.5.0": + version "2.5.0" + resolved "https://registry.yarnpkg.com/@types/sanitize-html/-/sanitize-html-2.5.0.tgz#bfef58fbcf2674b20ffcc23c3506faa68c3a13e3" + integrity sha512-PeFIEZsO9m1+ACJlXUaimgrR+5DEDiIXhz7Hso307jmq5Yz0lb5kDp8LiTr5dMMMliC/jNNx/qds7Zoxa4zexw== + dependencies: + htmlparser2 "^6.0.0" + "@types/serve-index@*": version "1.9.1" resolved "https://registry.yarnpkg.com/@types/serve-index/-/serve-index-1.9.1.tgz#1b5e85370a192c01ec6cec4735cf2917337a6278" @@ -5708,7 +5715,7 @@ html-webpack-plugin@^5.1.0: pretty-error "^4.0.0" tapable "^2.0.0" -htmlparser2@^6.1.0: +htmlparser2@^6.0.0, htmlparser2@^6.1.0: version "6.1.0" resolved "https://registry.yarnpkg.com/htmlparser2/-/htmlparser2-6.1.0.tgz#c4d762b6c3371a05dbe65e94ae43a9f845fb8fb7" integrity sha512-gyyPk6rgonLFEDGoeRgQNaEUvdJ4ktTmmUh/h2t7s+M8oPpIPxgNACWa+6ESR57kXstwqPiCut0V8NRpcwgU7A== @@ -6142,6 +6149,11 @@ is-plain-object@^2.0.4: dependencies: isobject "^3.0.1" +is-plain-object@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/is-plain-object/-/is-plain-object-5.0.0.tgz#4427f50ab3429e9025ea7d52e9043a9ef4159344" + integrity sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q== + is-potential-custom-element-name@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz#171ed6f19e3ac554394edf78caa05784a45bebb5" @@ -7814,6 +7826,11 @@ parse-json@^5.0.0: json-parse-even-better-errors "^2.3.0" lines-and-columns "^1.1.6" +parse-srcset@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/parse-srcset/-/parse-srcset-1.0.2.tgz#f2bd221f6cc970a938d88556abc589caaaa2bde1" + integrity sha1-8r0iH2zJcKk42IVWq8WJyqqiveE= + parse5-htmlparser2-tree-adapter@^6.0.0: version "6.0.1" resolved "https://registry.yarnpkg.com/parse5-htmlparser2-tree-adapter/-/parse5-htmlparser2-tree-adapter-6.0.1.tgz#2cdf9ad823321140370d4dbf5d3e92c7c8ddc6e6" @@ -8220,7 +8237,7 @@ postcss@^7.0.36: picocolors "^0.2.1" source-map "^0.6.1" -postcss@^8.2.15, postcss@^8.2.6, postcss@^8.3.5: +postcss@^8.2.15, postcss@^8.2.6, postcss@^8.3.11, postcss@^8.3.5: version "8.3.11" resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.3.11.tgz#c3beca7ea811cd5e1c4a3ec6d2e7599ef1f8f858" integrity sha512-hCmlUAIlUiav8Xdqw3Io4LcpA1DOt7h3LSTAC4G6JGHFFaWzI6qvFt9oilvl8BmkbBRX1IhM90ZAmpk68zccQA== @@ -8837,6 +8854,18 @@ safe-buffer@>=5.1.0, safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@^5.1.2, resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== +sanitize-html@^2.5.3: + version "2.5.3" + resolved "https://registry.yarnpkg.com/sanitize-html/-/sanitize-html-2.5.3.tgz#91aa3dc760b072cdf92f9c6973747569b1ba1cd8" + integrity sha512-DGATXd1fs/Rm287/i5FBKVYSBBUL0iAaztOA1/RFhEs4yqo39/X52i/q/CwsfCUG5cilmXSBmnQmyWfnKhBlOg== + dependencies: + deepmerge "^4.2.2" + escape-string-regexp "^4.0.0" + htmlparser2 "^6.0.0" + is-plain-object "^5.0.0" + parse-srcset "^1.0.2" + postcss "^8.3.11" + sass-loader@^12.0.0: version "12.3.0" resolved "https://registry.yarnpkg.com/sass-loader/-/sass-loader-12.3.0.tgz#93278981c189c36a58cbfc37d4b9cef0cdc02871"