mirror of
https://github.com/hedgedoc/hedgedoc.git
synced 2024-11-29 03:54:26 -05:00
Add dom purify (#1609)
Signed-off-by: Tilman Vatteroth <git@tilmanvatteroth.de>
This commit is contained in:
parent
994d22eb35
commit
84ee1d9cd9
9 changed files with 103 additions and 81 deletions
|
@ -20,30 +20,22 @@ describe('markdown formatted links to', () => {
|
||||||
|
|
||||||
it('note anchor references render as anchor link', () => {
|
it('note anchor references render as anchor link', () => {
|
||||||
cy.setCodemirrorContent('[anchor](#anchor)')
|
cy.setCodemirrorContent('[anchor](#anchor)')
|
||||||
cy.getMarkdownBody()
|
cy.getMarkdownBody().find('a').should('have.attr', 'href', 'http://127.0.0.1:3001/n/test#anchor')
|
||||||
.find('a')
|
|
||||||
.should('have.attr', 'href', 'http://127.0.0.1:3001/n/test#anchor')
|
|
||||||
})
|
})
|
||||||
|
|
||||||
it('internal pages render as internal link', () => {
|
it('internal pages render as internal link', () => {
|
||||||
cy.setCodemirrorContent('[internal](other-note)')
|
cy.setCodemirrorContent('[internal](other-note)')
|
||||||
cy.getMarkdownBody()
|
cy.getMarkdownBody().find('a').should('have.attr', 'href', 'http://127.0.0.1:3001/n/other-note')
|
||||||
.find('a')
|
|
||||||
.should('have.attr', 'href', 'http://127.0.0.1:3001/n/other-note')
|
|
||||||
})
|
})
|
||||||
|
|
||||||
it('data URIs do not render', () => {
|
it('data URIs do not render', () => {
|
||||||
cy.setCodemirrorContent('[data](data:text/plain,evil)')
|
cy.setCodemirrorContent('[data](data:text/plain,evil)')
|
||||||
cy.getMarkdownBody()
|
cy.getMarkdownBody().find('a').should('not.exist')
|
||||||
.find('a')
|
|
||||||
.should('not.exist')
|
|
||||||
})
|
})
|
||||||
|
|
||||||
it('javascript URIs do not render', () => {
|
it('javascript URIs do not render', () => {
|
||||||
cy.setCodemirrorContent('[js](javascript:alert("evil"))')
|
cy.setCodemirrorContent('[js](javascript:alert("evil"))')
|
||||||
cy.getMarkdownBody()
|
cy.getMarkdownBody().find('a').should('not.exist')
|
||||||
.find('a')
|
|
||||||
.should('not.exist')
|
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -63,29 +55,21 @@ describe('HTML anchor element links to', () => {
|
||||||
|
|
||||||
it('note anchor references render as anchor link', () => {
|
it('note anchor references render as anchor link', () => {
|
||||||
cy.setCodemirrorContent('<a href="#anchor">anchor</a>')
|
cy.setCodemirrorContent('<a href="#anchor">anchor</a>')
|
||||||
cy.getMarkdownBody()
|
cy.getMarkdownBody().find('a').should('have.attr', 'href', 'http://127.0.0.1:3001/n/test#anchor')
|
||||||
.find('a')
|
|
||||||
.should('have.attr', 'href', 'http://127.0.0.1:3001/n/test#anchor')
|
|
||||||
})
|
})
|
||||||
|
|
||||||
it('internal pages render as internal link', () => {
|
it('internal pages render as internal link', () => {
|
||||||
cy.setCodemirrorContent('<a href="other-note">internal</a>')
|
cy.setCodemirrorContent('<a href="other-note">internal</a>')
|
||||||
cy.getMarkdownBody()
|
cy.getMarkdownBody().find('a').should('have.attr', 'href', 'http://127.0.0.1:3001/n/other-note')
|
||||||
.find('a')
|
|
||||||
.should('have.attr', 'href', 'http://127.0.0.1:3001/n/other-note')
|
|
||||||
})
|
})
|
||||||
|
|
||||||
it('data URIs do not render', () => {
|
it('data URIs do not render', () => {
|
||||||
cy.setCodemirrorContent('<a href="data:text/plain,evil">data</a>')
|
cy.setCodemirrorContent('<a href="data:text/plain,evil">data</a>')
|
||||||
cy.getMarkdownBody()
|
cy.getMarkdownBody().find('a').should('not.have.attr', 'href')
|
||||||
.find('a')
|
|
||||||
.should('not.exist')
|
|
||||||
})
|
})
|
||||||
|
|
||||||
it('javascript URIs do not render', () => {
|
it('javascript URIs do not render', () => {
|
||||||
cy.setCodemirrorContent('<a href="javascript:alert(\'evil\')">js</a>')
|
cy.setCodemirrorContent('<a href="javascript:alert(\'evil\')">js</a>')
|
||||||
cy.getMarkdownBody()
|
cy.getMarkdownBody().find('a').should('not.have.attr', 'href')
|
||||||
.find('a')
|
|
||||||
.should('not.exist')
|
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
70
package.json
70
package.json
|
@ -79,18 +79,52 @@
|
||||||
},
|
},
|
||||||
"dependencies": {},
|
"dependencies": {},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
"@craco/craco": "6.4.0",
|
||||||
|
"@cypress/webpack-preprocessor": "5.9.1",
|
||||||
|
"@fontsource/source-sans-pro": "4.5.0",
|
||||||
|
"@hedgedoc/html-to-react": "1.1.0",
|
||||||
|
"@hedgedoc/markdown-it-image-size": "1.0.1",
|
||||||
|
"@hedgedoc/markdown-it-task-lists": "1.0.2",
|
||||||
|
"@matejmazur/react-katex": "3.1.3",
|
||||||
|
"@redux-devtools/core": "3.9.0",
|
||||||
|
"@testing-library/cypress": "8.0.1",
|
||||||
|
"@testing-library/jest-dom": "5.14.1",
|
||||||
|
"@testing-library/react": "12.1.2",
|
||||||
|
"@testing-library/user-event": "13.5.0",
|
||||||
|
"@types/codemirror": "5.60.5",
|
||||||
|
"@types/d3-graphviz": "2.6.7",
|
||||||
|
"@types/diff": "5.0.1",
|
||||||
|
"@types/dompurify": "2.3.1",
|
||||||
|
"@types/jest": "27.0.2",
|
||||||
|
"@types/js-yaml": "4.0.4",
|
||||||
|
"@types/luxon": "2.0.5",
|
||||||
|
"@types/markdown-it": "12.2.3",
|
||||||
|
"@types/markdown-it-container": "2.0.4",
|
||||||
|
"@types/markdown-it-plantuml": "1.4.1",
|
||||||
|
"@types/mermaid": "8.2.7",
|
||||||
|
"@types/node": "16.11.6",
|
||||||
|
"@types/react": "17.0.33",
|
||||||
|
"@types/react-bootstrap-typeahead": "5.1.8",
|
||||||
|
"@types/react-dom": "17.0.10",
|
||||||
|
"@types/react-router": "5.1.17",
|
||||||
|
"@types/react-router-bootstrap": "0.24.5",
|
||||||
|
"@types/react-router-dom": "5.3.2",
|
||||||
|
"@types/redux-devtools": "3.0.47",
|
||||||
|
"@types/sass": "1.43.0",
|
||||||
|
"@types/uuid": "8.3.1",
|
||||||
|
"@typescript-eslint/eslint-plugin": "5.2.0",
|
||||||
|
"@typescript-eslint/parser": "5.2.0",
|
||||||
"abcjs": "6.0.0-beta.33",
|
"abcjs": "6.0.0-beta.33",
|
||||||
"bootstrap": "4.6.1",
|
"bootstrap": "4.6.1",
|
||||||
"codemirror": "5.63.3",
|
"codemirror": "5.63.3",
|
||||||
"copy-webpack-plugin": "6.4.1",
|
"copy-webpack-plugin": "6.4.1",
|
||||||
"@craco/craco": "6.4.0",
|
|
||||||
"cross-env": "7.0.3",
|
"cross-env": "7.0.3",
|
||||||
"cypress": "7.7.0",
|
"cypress": "7.7.0",
|
||||||
"cypress-commands": "1.1.0",
|
"cypress-commands": "1.1.0",
|
||||||
"cypress-file-upload": "5.0.8",
|
"cypress-file-upload": "5.0.8",
|
||||||
"@cypress/webpack-preprocessor": "5.9.1",
|
|
||||||
"d3-graphviz": "3.2.0",
|
"d3-graphviz": "3.2.0",
|
||||||
"diff": "5.0.0",
|
"diff": "5.0.0",
|
||||||
|
"dompurify": "2.3.3",
|
||||||
"emoji-picker-element": "1.8.2",
|
"emoji-picker-element": "1.8.2",
|
||||||
"emoji-picker-element-data": "1.2.0",
|
"emoji-picker-element-data": "1.2.0",
|
||||||
"eslint-config-prettier": "8.3.0",
|
"eslint-config-prettier": "8.3.0",
|
||||||
|
@ -104,11 +138,7 @@
|
||||||
"fast-deep-equal": "3.1.3",
|
"fast-deep-equal": "3.1.3",
|
||||||
"firacode": "5.2.0",
|
"firacode": "5.2.0",
|
||||||
"flowchart.js": "1.17.0",
|
"flowchart.js": "1.17.0",
|
||||||
"@fontsource/source-sans-pro": "4.5.0",
|
|
||||||
"fork-awesome": "1.2.0",
|
"fork-awesome": "1.2.0",
|
||||||
"@hedgedoc/html-to-react": "1.1.0",
|
|
||||||
"@hedgedoc/markdown-it-image-size": "1.0.1",
|
|
||||||
"@hedgedoc/markdown-it-task-lists": "1.0.2",
|
|
||||||
"highlight.js": "11.3.1",
|
"highlight.js": "11.3.1",
|
||||||
"http-server": "14.0.0",
|
"http-server": "14.0.0",
|
||||||
"i18next": "21.3.3",
|
"i18next": "21.3.3",
|
||||||
|
@ -136,7 +166,6 @@
|
||||||
"markmap-common": "0.1.5",
|
"markmap-common": "0.1.5",
|
||||||
"markmap-lib": "0.11.6",
|
"markmap-lib": "0.11.6",
|
||||||
"markmap-view": "0.2.6",
|
"markmap-view": "0.2.6",
|
||||||
"@matejmazur/react-katex": "3.1.3",
|
|
||||||
"mermaid": "8.13.3",
|
"mermaid": "8.13.3",
|
||||||
"optional-js": "2.3.0",
|
"optional-js": "2.3.0",
|
||||||
"prettier": "2.4.1",
|
"prettier": "2.4.1",
|
||||||
|
@ -155,41 +184,14 @@
|
||||||
"react-scripts": "4.0.3",
|
"react-scripts": "4.0.3",
|
||||||
"react-use": "17.3.1",
|
"react-use": "17.3.1",
|
||||||
"redux": "4.1.2",
|
"redux": "4.1.2",
|
||||||
"@redux-devtools/core": "3.9.0",
|
|
||||||
"redux-devtools-extension": "2.13.9",
|
"redux-devtools-extension": "2.13.9",
|
||||||
"reveal.js": "4.1.3",
|
"reveal.js": "4.1.3",
|
||||||
"sanitize-filename": "1.6.3",
|
"sanitize-filename": "1.6.3",
|
||||||
"sass": "1.43.4",
|
"sass": "1.43.4",
|
||||||
"@testing-library/cypress": "8.0.1",
|
|
||||||
"@testing-library/jest-dom": "5.14.1",
|
|
||||||
"@testing-library/react": "12.1.2",
|
|
||||||
"@testing-library/user-event": "13.5.0",
|
|
||||||
"ts-loader": "9.2.6",
|
"ts-loader": "9.2.6",
|
||||||
"ts-mockery": "1.2.0",
|
"ts-mockery": "1.2.0",
|
||||||
"twemoji-colr-font": "0.0.4",
|
"twemoji-colr-font": "0.0.4",
|
||||||
"@types/codemirror": "5.60.5",
|
|
||||||
"typescript": "4.4.4",
|
"typescript": "4.4.4",
|
||||||
"@typescript-eslint/eslint-plugin": "5.2.0",
|
|
||||||
"@typescript-eslint/parser": "5.2.0",
|
|
||||||
"@types/d3-graphviz": "2.6.7",
|
|
||||||
"@types/diff": "5.0.1",
|
|
||||||
"@types/jest": "27.0.2",
|
|
||||||
"@types/js-yaml": "4.0.4",
|
|
||||||
"@types/luxon": "2.0.5",
|
|
||||||
"@types/markdown-it": "12.2.3",
|
|
||||||
"@types/markdown-it-container": "2.0.4",
|
|
||||||
"@types/markdown-it-plantuml": "1.4.1",
|
|
||||||
"@types/mermaid": "8.2.7",
|
|
||||||
"@types/node": "16.11.6",
|
|
||||||
"@types/react": "17.0.33",
|
|
||||||
"@types/react-bootstrap-typeahead": "5.1.8",
|
|
||||||
"@types/react-dom": "17.0.10",
|
|
||||||
"@types/react-router": "5.1.17",
|
|
||||||
"@types/react-router-bootstrap": "0.24.5",
|
|
||||||
"@types/react-router-dom": "5.3.2",
|
|
||||||
"@types/redux-devtools": "3.0.47",
|
|
||||||
"@types/sass": "1.43.0",
|
|
||||||
"@types/uuid": "8.3.1",
|
|
||||||
"use-resize-observer": "8.0.0",
|
"use-resize-observer": "8.0.0",
|
||||||
"uuid": "8.3.2",
|
"uuid": "8.3.2",
|
||||||
"vega": "5.21.0",
|
"vega": "5.21.0",
|
||||||
|
|
|
@ -0,0 +1,25 @@
|
||||||
|
/*
|
||||||
|
* SPDX-FileCopyrightText: 2021 The HedgeDoc developers (see AUTHORS file)
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
*/
|
||||||
|
|
||||||
|
import type { Document } from 'domhandler'
|
||||||
|
import render from 'dom-serializer'
|
||||||
|
import DOMPurify from 'dompurify'
|
||||||
|
import { parseDocument } from 'htmlparser2'
|
||||||
|
|
||||||
|
const customTags = ['app-linemarker', 'app-katex', 'app-gist', 'app-youtube', 'app-vimeo', 'app-asciinema']
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sanitizes the given {@link Document document}.
|
||||||
|
*
|
||||||
|
* @param document The dirty document
|
||||||
|
* @return the sanitized Document
|
||||||
|
*/
|
||||||
|
export const domPurifierNodePreprocessor = (document: Document): Document => {
|
||||||
|
const sanitizedHtml = DOMPurify.sanitize(render(document), {
|
||||||
|
ADD_TAGS: customTags
|
||||||
|
})
|
||||||
|
return parseDocument(sanitizedHtml)
|
||||||
|
}
|
|
@ -11,6 +11,7 @@ import convertHtmlToReact from '@hedgedoc/html-to-react'
|
||||||
import type { Document } from 'domhandler'
|
import type { Document } from 'domhandler'
|
||||||
import { NodeToReactTransformer } from '../utils/node-to-react-transformer'
|
import { NodeToReactTransformer } from '../utils/node-to-react-transformer'
|
||||||
import { LineIdMapper } from '../utils/line-id-mapper'
|
import { LineIdMapper } from '../utils/line-id-mapper'
|
||||||
|
import { domPurifierNodePreprocessor } from './dom-purifier-node-preprocessor'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Renders markdown code into react elements
|
* Renders markdown code into react elements
|
||||||
|
@ -40,9 +41,13 @@ export const useConvertMarkdownToReactDom = (
|
||||||
|
|
||||||
return useMemo(() => {
|
return useMemo(() => {
|
||||||
const html = markdownIt.render(markdownCode)
|
const html = markdownIt.render(markdownCode)
|
||||||
|
|
||||||
return convertHtmlToReact(html, {
|
return convertHtmlToReact(html, {
|
||||||
transform: (node, index) => htmlToReactTransformer.translateNodeToReactElement(node, index),
|
transform: (node, index) => htmlToReactTransformer.translateNodeToReactElement(node, index),
|
||||||
preprocessNodes: preprocessNodes
|
preprocessNodes: (document: Document): Document => {
|
||||||
|
const processedDocument = preprocessNodes ? preprocessNodes(document) : document
|
||||||
|
return domPurifierNodePreprocessor(processedDocument)
|
||||||
|
}
|
||||||
})
|
})
|
||||||
}, [htmlToReactTransformer, markdownCode, markdownIt, preprocessNodes])
|
}, [htmlToReactTransformer, markdownCode, markdownIt, preprocessNodes])
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,7 +9,7 @@ import { Logger } from '../../utils/logger'
|
||||||
|
|
||||||
const log = new Logger('reveal.js > Comment Node Preprocessor')
|
const log = new Logger('reveal.js > Comment Node Preprocessor')
|
||||||
const revealCommandSyntax = /^\s*\.(\w*):(.*)$/g
|
const revealCommandSyntax = /^\s*\.(\w*):(.*)$/g
|
||||||
const dataAttributesSyntax = /\s*([\w-]*)=(?:"((?:[^"\\]|\\"|\\)*)"|'([^']*)')/g
|
const dataAttributesSyntax = /\s*(data-[\w-]*|class)=(?:"((?:[^"\\]|\\"|\\)*)"|'([^']*)')/g
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Travels through the given {@link Document}, searches for reveal command comments and applies them.
|
* Travels through the given {@link Document}, searches for reveal command comments and applies them.
|
||||||
|
|
|
@ -14,7 +14,7 @@ export const legacySlideshareShortCode: MarkdownIt.PluginSimple = (markdownIt) =
|
||||||
name: 'legacy-slideshare-short-code',
|
name: 'legacy-slideshare-short-code',
|
||||||
regex: finalRegex,
|
regex: finalRegex,
|
||||||
replace: (match: string) => {
|
replace: (match: string) => {
|
||||||
return `<a target="_blank" rel="noopener noreferrer" href="https://www.slideshare.net/${match}">https://www.slideshare.net/${match}</a>`
|
return `<a href="https://www.slideshare.net/${match}">https://www.slideshare.net/${match}</a>`
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,7 +9,7 @@ import { isTag } from 'domhandler'
|
||||||
import type MarkdownIt from 'markdown-it'
|
import type MarkdownIt from 'markdown-it'
|
||||||
import mathJax from 'markdown-it-mathjax'
|
import mathJax from 'markdown-it-mathjax'
|
||||||
import React from 'react'
|
import React from 'react'
|
||||||
import { ComponentReplacer } from '../component-replacer'
|
import { ComponentReplacer, DO_NOT_REPLACE } from '../component-replacer'
|
||||||
import './katex.scss'
|
import './katex.scss'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -18,23 +18,24 @@ import './katex.scss'
|
||||||
* @param node the node to check
|
* @param node the node to check
|
||||||
* @return The given node if it is a KaTeX block element, undefined otherwise.
|
* @return The given node if it is a KaTeX block element, undefined otherwise.
|
||||||
*/
|
*/
|
||||||
const getNodeIfKatexBlock = (node: Element): Element | undefined => {
|
const containsKatexBlock = (node: Element): Element | undefined => {
|
||||||
if (node.name !== 'p' || !node.children || node.children.length === 0) {
|
if (node.name !== 'p' || !node.children || node.children.length === 0) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
return node.children.filter(isTag).find((subnode) => {
|
return node.children.filter(isTag).find((subnode) => {
|
||||||
return subnode.name === 'app-katex' && subnode.attribs?.inline === undefined
|
return isKatexTag(subnode, false) ? subnode : undefined
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Checks if the given node is a KaTeX inline element.
|
* Checks if the given node is a KaTeX element.
|
||||||
*
|
*
|
||||||
* @param node the node to check
|
* @param node the node to check
|
||||||
* @return The given node if it is a KaTeX inline element, undefined otherwise.
|
* @param expectedInline defines if the found katex element is expected to be an inline or block element.
|
||||||
|
* @return {@code true} if the given node is a katex element.
|
||||||
*/
|
*/
|
||||||
const getNodeIfInlineKatex = (node: Element): Element | undefined => {
|
const isKatexTag = (node: Element, expectedInline: boolean) => {
|
||||||
return node.name === 'app-katex' && node.attribs?.inline !== undefined ? node : undefined
|
return node.name === 'app-katex' && (node.attribs?.['data-inline'] !== undefined) === expectedInline
|
||||||
}
|
}
|
||||||
|
|
||||||
const KaTeX = React.lazy(() => import(/* webpackChunkName: "katex" */ '@matejmazur/react-katex'))
|
const KaTeX = React.lazy(() => import(/* webpackChunkName: "katex" */ '@matejmazur/react-katex'))
|
||||||
|
@ -46,18 +47,18 @@ export class KatexReplacer extends ComponentReplacer {
|
||||||
public static readonly markdownItPlugin: MarkdownIt.PluginSimple = mathJax({
|
public static readonly markdownItPlugin: MarkdownIt.PluginSimple = mathJax({
|
||||||
beforeMath: '<app-katex>',
|
beforeMath: '<app-katex>',
|
||||||
afterMath: '</app-katex>',
|
afterMath: '</app-katex>',
|
||||||
beforeInlineMath: '<app-katex inline>',
|
beforeInlineMath: '<app-katex data-inline="true">',
|
||||||
afterInlineMath: '</app-katex>',
|
afterInlineMath: '</app-katex>',
|
||||||
beforeDisplayMath: '<app-katex>',
|
beforeDisplayMath: '<app-katex>',
|
||||||
afterDisplayMath: '</app-katex>'
|
afterDisplayMath: '</app-katex>'
|
||||||
})
|
})
|
||||||
|
|
||||||
public replace(node: Element): React.ReactElement | undefined {
|
public replace(node: Element): React.ReactElement | undefined {
|
||||||
const katex = getNodeIfKatexBlock(node) || getNodeIfInlineKatex(node)
|
if (!(isKatexTag(node, true) || containsKatexBlock(node)) || node.children?.[0] === undefined) {
|
||||||
if (katex?.children && katex.children[0]) {
|
return DO_NOT_REPLACE
|
||||||
const mathJaxContent = ComponentReplacer.extractTextChildContent(katex)
|
|
||||||
const isInline = katex.attribs?.inline !== undefined
|
|
||||||
return <KaTeX block={!isInline} math={mathJaxContent} errorColor={'#cc0000'} />
|
|
||||||
}
|
}
|
||||||
|
const latexContent = ComponentReplacer.extractTextChildContent(node)
|
||||||
|
const isInline = !!node.attribs?.['data-inline']
|
||||||
|
return <KaTeX block={!isInline} math={latexContent} errorColor={'#cc0000'} />
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -35,14 +35,7 @@ export class LinkReplacer extends ComponentReplacer {
|
||||||
}
|
}
|
||||||
|
|
||||||
const url = node.attribs.href.trim()
|
const url = node.attribs.href.trim()
|
||||||
|
|
||||||
// eslint-disable-next-line no-script-url
|
|
||||||
if (url.startsWith('data:') || url.startsWith('javascript:') || url.startsWith('vbscript:')) {
|
|
||||||
return <span>{node.attribs.href}</span>
|
|
||||||
}
|
|
||||||
|
|
||||||
const isJumpMark = url.substr(0, 1) === '#'
|
const isJumpMark = url.substr(0, 1) === '#'
|
||||||
|
|
||||||
const id = url.substr(1)
|
const id = url.substr(1)
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|
12
yarn.lock
12
yarn.lock
|
@ -2275,6 +2275,13 @@
|
||||||
resolved "https://registry.yarnpkg.com/@types/diff/-/diff-5.0.1.tgz#9c9b9a331d4e41ccccff553f5d7ef964c6cf4042"
|
resolved "https://registry.yarnpkg.com/@types/diff/-/diff-5.0.1.tgz#9c9b9a331d4e41ccccff553f5d7ef964c6cf4042"
|
||||||
integrity sha512-XIpxU6Qdvp1ZE6Kr3yrkv1qgUab0fyf4mHYvW8N3Bx3PCsbN6or1q9/q72cv5jIFWolaGH08U9XyYoLLIykyKQ==
|
integrity sha512-XIpxU6Qdvp1ZE6Kr3yrkv1qgUab0fyf4mHYvW8N3Bx3PCsbN6or1q9/q72cv5jIFWolaGH08U9XyYoLLIykyKQ==
|
||||||
|
|
||||||
|
"@types/dompurify@2.3.1":
|
||||||
|
version "2.3.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/@types/dompurify/-/dompurify-2.3.1.tgz#2934adcd31c4e6b02676f9c22f9756e5091c04dd"
|
||||||
|
integrity sha512-YJth9qa0V/E6/XPH1Jq4BC8uCMmO8V1fKWn8PCvuZcAhMn7q0ez9LW6naQT04UZzjFfAPhyRMZmI2a2rbMlEFA==
|
||||||
|
dependencies:
|
||||||
|
"@types/trusted-types" "*"
|
||||||
|
|
||||||
"@types/eslint@^7.2.6":
|
"@types/eslint@^7.2.6":
|
||||||
version "7.28.2"
|
version "7.28.2"
|
||||||
resolved "https://registry.yarnpkg.com/@types/eslint/-/eslint-7.28.2.tgz#0ff2947cdd305897c52d5372294e8c76f351db68"
|
resolved "https://registry.yarnpkg.com/@types/eslint/-/eslint-7.28.2.tgz#0ff2947cdd305897c52d5372294e8c76f351db68"
|
||||||
|
@ -2596,6 +2603,11 @@
|
||||||
dependencies:
|
dependencies:
|
||||||
"@types/jest" "*"
|
"@types/jest" "*"
|
||||||
|
|
||||||
|
"@types/trusted-types@*":
|
||||||
|
version "2.0.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/@types/trusted-types/-/trusted-types-2.0.2.tgz#fc25ad9943bcac11cceb8168db4f275e0e72e756"
|
||||||
|
integrity sha512-F5DIZ36YVLE+PN+Zwws4kJogq47hNgX3Nx6WyDJ3kcplxyke3XIzB8uK5n/Lpm1HBsbGzd6nmGehL8cPekP+Tg==
|
||||||
|
|
||||||
"@types/uglify-js@*":
|
"@types/uglify-js@*":
|
||||||
version "3.13.1"
|
version "3.13.1"
|
||||||
resolved "https://registry.yarnpkg.com/@types/uglify-js/-/uglify-js-3.13.1.tgz#5e889e9e81e94245c75b6450600e1c5ea2878aea"
|
resolved "https://registry.yarnpkg.com/@types/uglify-js/-/uglify-js-3.13.1.tgz#5e889e9e81e94245c75b6450600e1c5ea2878aea"
|
||||||
|
|
Loading…
Reference in a new issue