From cf8ce23513a2e3cddbc7321e6b890447c4f3085c Mon Sep 17 00:00:00 2001 From: Yuriy Demidov Date: Tue, 4 Oct 2022 15:04:22 +0300 Subject: [PATCH] feat(Html): use html sanitizer from yfm-transform (#14) --- package-lock.json | 60 +-- package.json | 8 +- src/extensions/markdown/Html/sanitize.tsx | 486 ---------------------- src/extensions/markdown/Html/spec.ts | 2 +- 4 files changed, 36 insertions(+), 520 deletions(-) delete mode 100644 src/extensions/markdown/Html/sanitize.tsx diff --git a/package-lock.json b/package-lock.json index 3b16e66b..263ac9ce 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1487,11 +1487,12 @@ "dev": true }, "@doc-tools/transform": { - "version": "2.11.0", - "resolved": "https://registry.npmjs.org/@doc-tools/transform/-/transform-2.11.0.tgz", - "integrity": "sha512-DGCWi2F3EjKJdKTq9sXbz4HJTwmEMeXFICPXa0iAQawCdNVlAItBGaamTPdCyJpnN9VqrHywzDSi1nRecLyjBA==", + "version": "2.14.0", + "resolved": "https://registry.npmjs.org/@doc-tools/transform/-/transform-2.14.0.tgz", + "integrity": "sha512-6htVwBL1XoPZmXFDqj+PpCkToAn5ZCvx+lJclh/6MP/U9h6B2cql//k9cRezkTVLb963PJ9qhgXPiI1P0dxNng==", "dev": true, "requires": { + "@types/sanitize-html": "^2.6.2", "chalk": "4.1.2", "get-root-node-polyfill": "1.0.0", "github-slugger": "1.4.0", @@ -1504,20 +1505,8 @@ "markdownlint": "^0.25.1", "markdownlint-rule-helpers": "0.17.2", "postcss": "8.4.16", + "sanitize-html": "^2.7.1", "slugify": "1.6.5" - }, - "dependencies": { - "postcss": { - "version": "8.4.16", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.16.tgz", - "integrity": "sha512-ipHE1XBvKzm5xI7hiHCZJCSugxvsdq2mPnsq5+UF+VHCjiBvtDrlxJfMBToWaP9D5XlgNmcFGqoHmUn0EYEaRQ==", - "dev": true, - "requires": { - "nanoid": "^3.3.4", - "picocolors": "^1.0.0", - "source-map-js": "^1.0.2" - } - } } }, "@eslint/eslintrc": { @@ -7912,7 +7901,8 @@ "deepmerge": { "version": "4.2.2", "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.2.2.tgz", - "integrity": "sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg==" + "integrity": "sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg==", + "dev": true }, "default-browser-id": { "version": "1.0.4", @@ -8251,6 +8241,7 @@ "version": "1.4.1", "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.4.1.tgz", "integrity": "sha512-VHwB3KfrcOOkelEG2ZOfxqLZdfkil8PtJi4P8N2MMXucZq2yLp75ClViUlOVwyoHEDjYU433Aq+5zWP61+RGag==", + "dev": true, "requires": { "domelementtype": "^2.0.1", "domhandler": "^4.2.0", @@ -8272,7 +8263,8 @@ "domelementtype": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz", - "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==" + "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==", + "dev": true }, "domexception": { "version": "2.0.1", @@ -8295,6 +8287,7 @@ "version": "4.3.1", "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.3.1.tgz", "integrity": "sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ==", + "dev": true, "requires": { "domelementtype": "^2.2.0" } @@ -8309,6 +8302,7 @@ "version": "2.8.0", "resolved": "https://registry.npmjs.org/domutils/-/domutils-2.8.0.tgz", "integrity": "sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==", + "dev": true, "requires": { "dom-serializer": "^1.0.1", "domelementtype": "^2.2.0", @@ -8525,7 +8519,8 @@ "entities": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz", - "integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==" + "integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==", + "dev": true }, "errno": { "version": "0.1.8", @@ -8705,7 +8700,8 @@ "escape-string-regexp": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", - "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==" + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true }, "escodegen": { "version": "2.0.0", @@ -11449,6 +11445,7 @@ "version": "6.1.0", "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-6.1.0.tgz", "integrity": "sha512-gyyPk6rgonLFEDGoeRgQNaEUvdJ4ktTmmUh/h2t7s+M8oPpIPxgNACWa+6ESR57kXstwqPiCut0V8NRpcwgU7A==", + "dev": true, "requires": { "domelementtype": "^2.0.1", "domhandler": "^4.0.0", @@ -12020,7 +12017,8 @@ "is-plain-object": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-5.0.0.tgz", - "integrity": "sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==" + "integrity": "sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==", + "dev": true }, "is-potential-custom-element-name": { "version": "1.0.1", @@ -15377,7 +15375,8 @@ "nanoid": { "version": "3.3.4", "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.4.tgz", - "integrity": "sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==" + "integrity": "sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==", + "dev": true }, "nanomatch": { "version": "1.2.13", @@ -16278,7 +16277,8 @@ "parse-srcset": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/parse-srcset/-/parse-srcset-1.0.2.tgz", - "integrity": "sha512-/2qh0lav6CmI15FzA3i/2Bzk2zCgQhGMkvhOhKNcBVQ1ldgpbfiNTVslmooUmWJcADi1f1kIeynbDRVzNlfR6Q==" + "integrity": "sha512-/2qh0lav6CmI15FzA3i/2Bzk2zCgQhGMkvhOhKNcBVQ1ldgpbfiNTVslmooUmWJcADi1f1kIeynbDRVzNlfR6Q==", + "dev": true }, "parse5": { "version": "6.0.1", @@ -16387,7 +16387,8 @@ "picocolors": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", - "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==" + "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", + "dev": true }, "picomatch": { "version": "2.3.1", @@ -16524,9 +16525,10 @@ "dev": true }, "postcss": { - "version": "8.4.17", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.17.tgz", - "integrity": "sha512-UNxNOLQydcOFi41yHNMcKRZ39NeXlr8AxGuZJsdub8vIb12fHzcq37DTU/QtbI6WLxNg2gF9Z+8qtRwTj1UI1Q==", + "version": "8.4.16", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.16.tgz", + "integrity": "sha512-ipHE1XBvKzm5xI7hiHCZJCSugxvsdq2mPnsq5+UF+VHCjiBvtDrlxJfMBToWaP9D5XlgNmcFGqoHmUn0EYEaRQ==", + "dev": true, "requires": { "nanoid": "^3.3.4", "picocolors": "^1.0.0", @@ -18217,6 +18219,7 @@ "version": "2.7.2", "resolved": "https://registry.npmjs.org/sanitize-html/-/sanitize-html-2.7.2.tgz", "integrity": "sha512-DggSTe7MviO+K4YTCwprG6W1vsG+IIX67yp/QY55yQqKCJYSWzCA1rZbaXzkjoKeL9+jqwm56wD6srYLtUNivg==", + "dev": true, "requires": { "deepmerge": "^4.2.2", "escape-string-regexp": "^4.0.0", @@ -18693,7 +18696,8 @@ "source-map-js": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", - "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==" + "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==", + "dev": true }, "source-map-resolve": { "version": "0.5.3", diff --git a/package.json b/package.json index b1c8f161..42ad0998 100644 --- a/package.json +++ b/package.json @@ -58,11 +58,10 @@ "prosemirror-utils": "1.0.0-0", "prosemirror-view": "1.26.2", "react-use": "^17.3.2", - "sanitize-html": "^2.7.0", "tslib": "^2.3.1" }, "devDependencies": { - "@doc-tools/transform": "2.11.0", + "@doc-tools/transform": "2.14.0", "@gravity-ui/eslint-config": "1.0.2", "@gravity-ui/prettier-config": "1.0.1", "@gravity-ui/stylelint-config": "1.0.1", @@ -79,7 +78,6 @@ "@types/react": "17.0.50", "@types/react-dom": "17.0.17", "@types/rimraf": "3.0.2", - "@types/sanitize-html": "^2.6.2", "eslint": "8.24.0", "gulp": "4.0.2", "gulp-cli": "2.3.0", @@ -92,7 +90,7 @@ "jest-css-modules": "^2.1.0", "markdown-it-testgen": "^0.1.6", "npm-run-all": "^4.1.5", - "postcss": "8.4.17", + "postcss": "8.4.16", "prettier": "2.7.1", "prosemirror-test-builder": "1.1.0", "react": "17.0.2", @@ -106,7 +104,7 @@ "typescript": "^4.5.2" }, "peerDependencies": { - "@doc-tools/transform": "^2.11.0", + "@doc-tools/transform": "^2.14.0", "@gravity-ui/uikit": "^3.0.0", "lodash": "^4.17.20", "react": "^16.8.0 || ^17.0.0", diff --git a/src/extensions/markdown/Html/sanitize.tsx b/src/extensions/markdown/Html/sanitize.tsx deleted file mode 100644 index 22eb73ae..00000000 --- a/src/extensions/markdown/Html/sanitize.tsx +++ /dev/null @@ -1,486 +0,0 @@ -import sanitizeHtml from 'sanitize-html'; - -const htmlTags = [ - 'a', - 'abbr', - 'acronym', - 'address', - 'area', - 'article', - 'aside', - 'audio', - 'b', - 'bdi', - 'bdo', - 'big', - 'blink', - 'blockquote', - 'body', - 'br', - 'button', - 'canvas', - 'caption', - 'center', - 'cite', - 'code', - 'col', - 'colgroup', - 'content', - 'data', - 'datalist', - 'dd', - 'decorator', - 'del', - 'details', - 'dfn', - 'dialog', - 'dir', - 'div', - 'dl', - 'dt', - 'element', - 'em', - 'fieldset', - 'figcaption', - 'figure', - 'font', - 'footer', - 'form', - 'h1', - 'h2', - 'h3', - 'h4', - 'h5', - 'h6', - 'head', - 'header', - 'hgroup', - 'hr', - 'html', - 'i', - 'img', - 'input', - 'ins', - 'kbd', - 'label', - 'legend', - 'li', - 'main', - 'map', - 'mark', - 'marquee', - 'menu', - 'menuitem', - 'meter', - 'nav', - 'nobr', - 'ol', - 'optgroup', - 'option', - 'output', - 'p', - 'picture', - 'pre', - 'progress', - 'q', - 'rp', - 'rt', - 'ruby', - 's', - 'samp', - 'section', - 'select', - 'shadow', - 'small', - 'source', - 'spacer', - 'span', - 'strike', - 'strong', - 'sub', - 'summary', - 'sup', - 'table', - 'tbody', - 'td', - 'template', - 'textarea', - 'tfoot', - 'th', - 'thead', - 'time', - 'tr', - 'track', - 'tt', - 'u', - 'ul', - 'var', - 'video', - 'wbr', - 'iframe', -]; - -const svgTags = [ - 'svg', - 'altglyph', - 'altglyphdef', - 'altglyphitem', - 'animatecolor', - 'animatemotion', - 'animatetransform', - 'circle', - 'clippath', - 'defs', - 'desc', - 'ellipse', - 'filter', - 'font', - 'g', - 'glyph', - 'glyphref', - 'hkern', - 'image', - 'line', - 'lineargradient', - 'marker', - 'mask', - 'metadata', - 'mpath', - 'path', - 'pattern', - 'polygon', - 'polyline', - 'radialgradient', - 'rect', - 'stop', - 'switch', - 'symbol', - 'text', - 'textpath', - 'title', - 'tref', - 'tspan', - 'view', - 'vkern', - 'animate', -]; - -const htmlAttrs = [ - 'accept', - 'action', - 'align', - 'alt', - 'autocapitalize', - 'autocomplete', - 'autopictureinpicture', - 'autoplay', - 'background', - 'bgcolor', - 'border', - 'capture', - 'cellpadding', - 'cellspacing', - 'checked', - 'cite', - 'class', - 'clear', - 'color', - 'cols', - 'colspan', - 'controls', - 'controlslist', - 'coords', - 'crossorigin', - 'datetime', - 'decoding', - 'default', - 'dir', - 'disabled', - 'disablepictureinpicture', - 'disableremoteplayback', - 'download', - 'draggable', - 'enctype', - 'enterkeyhint', - 'face', - 'for', - 'headers', - 'height', - 'hidden', - 'high', - 'href', - 'hreflang', - 'id', - 'inputmode', - 'integrity', - 'ismap', - 'kind', - 'label', - 'lang', - 'list', - 'loading', - 'loop', - 'low', - 'max', - 'maxlength', - 'media', - 'method', - 'min', - 'minlength', - 'multiple', - 'muted', - 'name', - 'nonce', - 'noshade', - 'novalidate', - 'nowrap', - 'open', - 'optimum', - 'pattern', - 'placeholder', - 'playsinline', - 'poster', - 'preload', - 'pubdate', - 'radiogroup', - 'readonly', - 'rel', - 'required', - 'rev', - 'reversed', - 'role', - 'rows', - 'rowspan', - 'spellcheck', - 'scope', - 'selected', - 'shape', - 'size', - 'sizes', - 'span', - 'srclang', - 'start', - 'src', - 'srcset', - 'step', - 'style', - 'summary', - 'tabindex', - 'title', - 'translate', - 'type', - 'usemap', - 'valign', - 'value', - 'width', - 'xmlns', - 'slot', - 'frameborder', - 'scrolling', - 'target', - 'data-*', -]; - -const svgAttrs = [ - 'accent-height', - 'accumulate', - 'additive', - 'alignment-baseline', - 'ascent', - 'attributename', - 'attributetype', - 'azimuth', - 'basefrequency', - 'baseline-shift', - 'begin', - 'bias', - 'by', - 'class', - 'clip', - 'clippathunits', - 'clip-path', - 'clip-rule', - 'color', - 'color-interpolation', - 'color-interpolation-filters', - 'color-profile', - 'color-rendering', - 'cx', - 'cy', - 'd', - 'dx', - 'dy', - 'diffuseconstant', - 'direction', - 'display', - 'divisor', - 'dur', - 'edgemode', - 'elevation', - 'end', - 'fill', - 'fill-opacity', - 'fill-rule', - 'filter', - 'filterunits', - 'flood-color', - 'flood-opacity', - 'font-family', - 'font-size', - 'font-size-adjust', - 'font-stretch', - 'font-style', - 'font-variant', - 'font-weight', - 'fx', - 'fy', - 'g1', - 'g2', - 'glyph-name', - 'glyphref', - 'gradientunits', - 'gradienttransform', - 'height', - 'href', - 'id', - 'image-rendering', - 'in', - 'in2', - 'k', - 'k1', - 'k2', - 'k3', - 'k4', - 'kerning', - 'keypoints', - 'keysplines', - 'keytimes', - 'lang', - 'lengthadjust', - 'letter-spacing', - 'kernelmatrix', - 'kernelunitlength', - 'lighting-color', - 'local', - 'marker-end', - 'marker-mid', - 'marker-start', - 'markerheight', - 'markerunits', - 'markerwidth', - 'maskcontentunits', - 'maskunits', - 'max', - 'mask', - 'media', - 'method', - 'mode', - 'min', - 'name', - 'numoctaves', - 'offset', - 'operator', - 'opacity', - 'order', - 'orient', - 'orientation', - 'origin', - 'overflow', - 'paint-order', - 'path', - 'pathlength', - 'patterncontentunits', - 'patterntransform', - 'patternunits', - 'points', - 'preservealpha', - 'preserveaspectratio', - 'primitiveunits', - 'r', - 'rx', - 'ry', - 'radius', - 'refx', - 'refy', - 'repeatcount', - 'repeatdur', - 'restart', - 'result', - 'rotate', - 'scale', - 'seed', - 'shape-rendering', - 'specularconstant', - 'specularexponent', - 'spreadmethod', - 'startoffset', - 'stddeviation', - 'stitchtiles', - 'stop-color', - 'stop-opacity', - 'stroke-dasharray', - 'stroke-dashoffset', - 'stroke-linecap', - 'stroke-linejoin', - 'stroke-miterlimit', - 'stroke-opacity', - 'stroke', - 'stroke-width', - 'style', - 'surfacescale', - 'systemlanguage', - 'tabindex', - 'targetx', - 'targety', - 'transform', - 'text-anchor', - 'text-decoration', - 'text-rendering', - 'textlength', - 'type', - 'u1', - 'u2', - 'unicode', - 'values', - 'viewbox', - 'visibility', - 'version', - 'vert-adv-y', - 'vert-origin-x', - 'vert-origin-y', - 'width', - 'word-spacing', - 'wrap', - 'writing-mode', - 'xchannelselector', - 'ychannelselector', - 'x', - 'x1', - 'x2', - 'xmlns', - 'y', - 'y1', - 'y2', - 'z', - 'zoomandpan', - 'from', - 'to', -]; - -const allowedTags = Array.from( - new Set([...htmlTags, ...svgTags, ...sanitizeHtml.defaults.allowedTags]), -); - -const allowedAttributes = Array.from(new Set([...htmlAttrs, ...svgAttrs])); -const allowedSchemes = ['conisio', 'jamfselfservice', 'softwarecenter']; - -export function sanitize(html: string) { - return sanitizeHtml(html, { - allowedTags, - allowedAttributes: { - ...sanitizeHtml.defaults.allowedAttributes, - '*': allowedAttributes, - }, - allowedSchemes: [...sanitizeHtml.defaults.allowedSchemes, ...allowedSchemes], - }); -} diff --git a/src/extensions/markdown/Html/spec.ts b/src/extensions/markdown/Html/spec.ts index dbb5f75f..df74f47b 100644 --- a/src/extensions/markdown/Html/spec.ts +++ b/src/extensions/markdown/Html/spec.ts @@ -1,6 +1,6 @@ +import sanitize from '@doc-tools/transform/lib/sanitize'; import type {NodeSpec} from 'prosemirror-model'; import {HtmlAttr, HtmlNode} from './const'; -import {sanitize} from './sanitize'; enum DomAttr { Html = 'data-html',