Add option to disable HTML rendering (#2414)

This commit is contained in:
Felix Häusler 2020-12-17 23:19:22 +01:00 committed by GitHub
parent 2634f42204
commit 19eab7d1fc
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 56 additions and 10 deletions

View File

@ -289,6 +289,11 @@
"type": "boolean", "type": "boolean",
"default": false "default": false
}, },
"isHtmlEnabled": {
"description": "Markdown-Enable HTML rendering",
"type": "boolean",
"default": true
},
"isGitlabCompatibilityEnabled": { "isGitlabCompatibilityEnabled": {
"description": "Markdown-Enable GitLab compatibility mode.", "description": "Markdown-Enable GitLab compatibility mode.",
"type": "boolean", "type": "boolean",

View File

@ -283,7 +283,10 @@ export const MUYA_DEFAULT_OPTION = Object.freeze({
// Markdown extensions // Markdown extensions
superSubScript: false, superSubScript: false,
footnote: false, footnote: false,
isGitlabCompatibilityEnabled: false isGitlabCompatibilityEnabled: false,
// Whether HTML rendering is disabled or not.
disableHtml: true
}) })
// export const DIAGRAM_TEMPLATE = Object.freeze({ // export const DIAGRAM_TEMPLATE = Object.freeze({

View File

@ -74,7 +74,8 @@ const pasteCtrl = ContentState => {
} }
// Prevent XSS and sanitize HTML. // Prevent XSS and sanitize HTML.
const sanitizedHtml = sanitize(html, PREVIEW_DOMPURIFY_CONFIG) const { disableHtml } = this.muya.options
const sanitizedHtml = sanitize(html, PREVIEW_DOMPURIFY_CONFIG, disableHtml)
const tempWrapper = document.createElement('div') const tempWrapper = document.createElement('div')
tempWrapper.innerHTML = sanitizedHtml tempWrapper.innerHTML = sanitizedHtml

View File

@ -30,5 +30,7 @@ export default {
frontMatter: true, frontMatter: true,
superSubScript: false, superSubScript: false,
footnote: false, footnote: false,
isGitlabCompatibilityEnabled: false isGitlabCompatibilityEnabled: false,
isHtmlEnabled: true
} }

View File

@ -132,7 +132,8 @@ export default function renderLeafBlock (parent, block, activeBlocks, matches, u
selector += `.${CLASS_OR_ID.AG_HTML_PREVIEW}` selector += `.${CLASS_OR_ID.AG_HTML_PREVIEW}`
Object.assign(data.attrs, { spellcheck: 'false' }) Object.assign(data.attrs, { spellcheck: 'false' })
const htmlContent = sanitize(code, PREVIEW_DOMPURIFY_CONFIG) const { disableHtml } = this.muya.options
const htmlContent = sanitize(code, PREVIEW_DOMPURIFY_CONFIG, disableHtml)
// handle empty html bock // handle empty html bock
if (/^<([a-z][a-z\d]*)[^>]*?>(\s*)<\/\1>$/.test(htmlContent.trim())) { if (/^<([a-z][a-z\d]*)[^>]*?>(\s*)<\/\1>$/.test(htmlContent.trim())) {

View File

@ -13,7 +13,7 @@ import { validEmoji } from '../ui/emojis'
export const getSanitizeHtml = (markdown, options) => { export const getSanitizeHtml = (markdown, options) => {
const html = marked(markdown, options) const html = marked(markdown, options)
return sanitize(html, EXPORT_DOMPURIFY_CONFIG) return sanitize(html, EXPORT_DOMPURIFY_CONFIG, false)
} }
const DIAGRAM_TYPE = [ const DIAGRAM_TYPE = [
@ -143,7 +143,7 @@ class ExportHtml {
mathRenderer: this.mathRenderer mathRenderer: this.mathRenderer
}) })
html = sanitize(html, EXPORT_DOMPURIFY_CONFIG) html = sanitize(html, EXPORT_DOMPURIFY_CONFIG, false)
const exportContainer = this.exportContainer = document.createElement('div') const exportContainer = this.exportContainer = document.createElement('div')
exportContainer.classList.add('ag-render-container') exportContainer.classList.add('ag-render-container')
@ -192,7 +192,7 @@ class ExportHtml {
<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1"> <meta name="viewport" content="width=device-width, initial-scale=1">
<title>${sanitize(title, EXPORT_DOMPURIFY_CONFIG)}</title> <title>${sanitize(title, EXPORT_DOMPURIFY_CONFIG, true)}</title>
<style> <style>
${githubMarkdownCss} ${githubMarkdownCss}
</style> </style>
@ -304,7 +304,7 @@ class ExportHtml {
} }
output = output + createTableBody(html) + HF_TABLE_END output = output + createTableBody(html) + HF_TABLE_END
return sanitize(output, EXPORT_DOMPURIFY_CONFIG) return sanitize(output, EXPORT_DOMPURIFY_CONFIG, false)
} }
} }

View File

@ -6,6 +6,14 @@ let id = 0
const TIMEOUT = 1500 const TIMEOUT = 1500
const HTML_TAG_REPLACEMENTS = {
'&': '&amp;',
'<': '&lt;',
'>': '&gt;',
'"': '&quot;',
"'": '&#39;'
}
export const getUniqueId = () => `${ID_PREFIX}${id++}` export const getUniqueId = () => `${ID_PREFIX}${id++}`
export const getLongUniqueId = () => `${getUniqueId()}-${(+new Date()).toString(32)}` export const getLongUniqueId = () => `${getUniqueId()}-${(+new Date()).toString(32)}`
@ -322,6 +330,10 @@ export const escapeInBlockHtml = html => {
}) })
} }
export const escapeHtmlTags = html => {
return html.replace(/[&<>"']/g, x => { return HTML_TAG_REPLACEMENTS[x] })
}
export const wordCount = markdown => { export const wordCount = markdown => {
const paragraph = markdown.split(/\n{2,}/).filter(line => line).length const paragraph = markdown.split(/\n{2,}/).filter(line => line).length
let word = 0 let word = 0
@ -363,8 +375,12 @@ export const mixins = (constructor, ...object) => {
return Object.assign(constructor.prototype, ...object) return Object.assign(constructor.prototype, ...object)
} }
export const sanitize = (html, options) => { export const sanitize = (html, purifyOptions, disableHtml) => {
return runSanitize(escapeInBlockHtml(html), options) if (disableHtml) {
return runSanitize(escapeHtmlTags(html), purifyOptions)
} else {
return runSanitize(escapeInBlockHtml(html), purifyOptions)
}
} }
export const getParagraphReference = (ele, id) => { export const getParagraphReference = (ele, id) => {

View File

@ -140,6 +140,7 @@ export default {
frontmatterType: state => state.preferences.frontmatterType, frontmatterType: state => state.preferences.frontmatterType,
superSubScript: state => state.preferences.superSubScript, superSubScript: state => state.preferences.superSubScript,
footnote: state => state.preferences.footnote, footnote: state => state.preferences.footnote,
isHtmlEnabled: state => state.preferences.isHtmlEnabled,
isGitlabCompatibilityEnabled: state => state.preferences.isGitlabCompatibilityEnabled, isGitlabCompatibilityEnabled: state => state.preferences.isGitlabCompatibilityEnabled,
lineHeight: state => state.preferences.lineHeight, lineHeight: state => state.preferences.lineHeight,
fontSize: state => state.preferences.fontSize, fontSize: state => state.preferences.fontSize,
@ -285,6 +286,13 @@ export default {
} }
}, },
isHtmlEnabled: function (value, oldValue) {
const { editor } = this
if (value !== oldValue && editor) {
editor.setOptions({ disableHtml: !value }, true)
}
},
isGitlabCompatibilityEnabled: function (value, oldValue) { isGitlabCompatibilityEnabled: function (value, oldValue) {
const { editor } = this const { editor } = this
if (value !== oldValue && editor) { if (value !== oldValue && editor) {
@ -525,6 +533,7 @@ export default {
frontmatterType, frontmatterType,
superSubScript, superSubScript,
footnote, footnote,
isHtmlEnabled,
isGitlabCompatibilityEnabled, isGitlabCompatibilityEnabled,
hideQuickInsertHint, hideQuickInsertHint,
editorLineWidth, editorLineWidth,
@ -573,6 +582,7 @@ export default {
frontmatterType, frontmatterType,
superSubScript, superSubScript,
footnote, footnote,
disableHtml: !isHtmlEnabled,
isGitlabCompatibilityEnabled, isGitlabCompatibilityEnabled,
hideQuickInsertHint, hideQuickInsertHint,
hideLinkPopup, hideLinkPopup,

View File

@ -62,6 +62,11 @@
></bool> ></bool>
<separator></separator> <separator></separator>
<h5>Compatibility</h5> <h5>Compatibility</h5>
<bool
description="Enable HTML rendering"
:bool="isHtmlEnabled"
:onChange="value => onSelectChange('isHtmlEnabled', value)"
></bool>
<bool <bool
description="Enable GitLab compatibility mode" description="Enable GitLab compatibility mode"
:bool="isGitlabCompatibilityEnabled" :bool="isGitlabCompatibilityEnabled"
@ -121,6 +126,7 @@ export default {
frontmatterType: state => state.preferences.frontmatterType, frontmatterType: state => state.preferences.frontmatterType,
superSubScript: state => state.preferences.superSubScript, superSubScript: state => state.preferences.superSubScript,
footnote: state => state.preferences.footnote, footnote: state => state.preferences.footnote,
isHtmlEnabled: state => state.preferences.isHtmlEnabled,
isGitlabCompatibilityEnabled: state => state.preferences.isGitlabCompatibilityEnabled, isGitlabCompatibilityEnabled: state => state.preferences.isGitlabCompatibilityEnabled,
sequenceTheme: state => state.preferences.sequenceTheme sequenceTheme: state => state.preferences.sequenceTheme
}) })

View File

@ -47,6 +47,7 @@ const state = {
frontmatterType: '-', frontmatterType: '-',
superSubScript: false, superSubScript: false,
footnote: false, footnote: false,
isHtmlEnabled: true,
isGitlabCompatibilityEnabled: false, isGitlabCompatibilityEnabled: false,
sequenceTheme: 'hand', sequenceTheme: 'hand',

View File

@ -43,6 +43,7 @@
"frontmatterType": "-", "frontmatterType": "-",
"superSubScript": false, "superSubScript": false,
"footnote": false, "footnote": false,
"isHtmlEnabled": true,
"isGitlabCompatibilityEnabled": false, "isGitlabCompatibilityEnabled": false,
"sequenceTheme": "hand", "sequenceTheme": "hand",