diff --git a/libs/highlight.js b/libs/highlight.js index 43a8760..0239a35 100644 --- a/libs/highlight.js +++ b/libs/highlight.js @@ -1,44 +1,5 @@ -/* - * This file is part of moemark-renderer. - * - * Copyright (c) 2016 Menci - * - * moemark-renderer is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * moemark-renderer is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with moemark-renderer. If not, see . - */ - -const pygmentize = require('pygmentize-bundled-cached'); - -function escapeHTML(s) { - // Code from http://stackoverflow.com/questions/5251520/how-do-i-escape-some-html-in-javascript/5251551 - return s.replace(/[^0-9A-Za-z ]/g, (c) => { - return "&#" + c.charCodeAt(0) + ";"; - }); -} +const { highlight } = require('syzoj-renderer'); module.exports = (code, lang, cb) => { - pygmentize({ - lang: lang, - format: 'html', - options: { - nowrap: true, - classprefix: 'pl-' - } - }, code, (err, res) => { - if (err || res.toString() === 'undefined') { - cb(escapeHTML(code)); - } else { - cb(res); - } - }); + highlight(code, lang).then(cb); } diff --git a/libs/markdown.js b/libs/markdown.js index 9527145..3618d76 100644 --- a/libs/markdown.js +++ b/libs/markdown.js @@ -1,27 +1,26 @@ -/* - * This file is part of moemark-renderer. - * - * Copyright (c) 2016 Menci - * - * moemark-renderer is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * moemark-renderer is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with moemark-renderer. If not, see . - */ - -const MoeMark = require('moemark'); -const katex = require('katex'); -const mj = require('mathjax-node'); +const { markdown } = require('syzoj-renderer'); +const XSS = require('xss'); +const CSSFilter = require('cssfilter'); +const xssWhiteList = Object.assign({}, require('xss/lib/default').whiteList); + +delete xssWhiteList.audio; +delete xssWhiteList.video; + +for (const tag in xssWhiteList) { + xssWhiteList[tag] = xssWhiteList[tag].concat(['style', 'class']); +} + +const xss = new XSS.FilterXSS({ + whiteList: xssWhiteList, + stripIgnoreTag: true, + onTagAttr: (tag, name, value, isWhiteAttr) => { + if (tag.toLowerCase() === 'img' && name.toLowerCase() === 'src' && value.startsWith('data:image/')) { + return name + '="' + XSS.escapeAttrValue(value) + '"'; + } + } +}); -let defaultCache = { +const defaultCache = { data: {}, get(key) { return this.data[key]; @@ -31,124 +30,14 @@ let defaultCache = { } }; -let config = { - highlight: require('./highlight') -}; - -let uuid = require('uuid'); - -function render(s, cb) { - if (!s.trim()) return cb(''); - - let mathCnt = 0, mathPending = 0, maths = new Array(), mathID = new Array(), hlCnt = 0, hlPending = 0, hls = new Array(), hlID = new Array(), res, callback, ss, cache = render.cache, cacheOption = render.cacheOption, finished = false; - if (cacheOption.result) { - let x = cache.get('RES_' + s); - if (x !== undefined) return cb(x); - } - - MoeMark.setOptions({ - lineNumber: false, - math: true, - highlight: function(code, lang) { - if (cacheOption.highlight) { - let x = cache.get('H_' + lang + '_' + code); - if (x !== undefined) return x; - } - let id = hlCnt; - hlCnt++, hlPending++; - config.highlight(code, lang, res => { - hls[id] = res; - if (cacheOption.highlight) cache.set('H_' + lang + '_' + code, res); - if (!--hlPending) finish(); - }); - return hlID[id] = uuid(); - }, - mathRenderer: function(str, display) { - let mathFinish = (error, result) => { - if (error) maths[id] = '

' + error.toString() + '

'; - else if (display) maths[id] = '

' + result + '

'; - else maths[id] = result; - if (cacheOption.math) cache.set('M_' + display + '_' + str, maths[id]); - if (!--mathPending) finish(); - } - - const id = mathCnt; - mathCnt++, mathPending++; - - try { - let x = cache.get('M_' + display + '_' + str); - if (x !== undefined) process.nextTick(() => mathFinish(null, x)); - else { - let res = katex.renderToString(str, { displayMode: display }); - process.nextTick(() => mathFinish(null, '' + res + '')); - } - } catch (e) { - mj.typeset({ - math: str, - format: display ? 'TeX' : 'inline-TeX', - svg: true, - width: 0 - }, data => { - mathFinish(data.errors, data.svg); - }); - } - return mathID[id] = uuid(); - } - }); - - function finish() { - if (finished || !res || mathPending || hlPending) return; - finished = true; - if (maths.length || hls.length) { - for (let i = 0; i < maths.length; i++) { - res = res.replace(mathID[i], maths[i]); - } - for (let i = 0; i < hls.length; i++) { - res = res.replace(hlID[i], hls[i]); - } - } - if (cacheOption.result) cache.set('RES_' + s, res); - cb(res); - } - - try { - let XSS = require('xss'); - let CSSFilter = require('cssfilter'); - let whiteList = Object.assign({}, require('xss/lib/default').whiteList); - delete whiteList.audio; - delete whiteList.video; - for (let tag in whiteList) whiteList[tag] = whiteList[tag].concat(['style', 'class']); - let xss = new XSS.FilterXSS({ - whiteList: whiteList, - stripIgnoreTag: true, - onTagAttr: (tag, name, value, isWhiteAttr) => { - if (tag.toLowerCase() === 'img' && name.toLowerCase() === 'src' && value.startsWith('data:image/')) return name + '="' + XSS.escapeAttrValue(value) + '"'; - } - }); - let replaceXSS = s => { - s = xss.process(s); - if (s) { - s = `
${s}
`; - } - return s; - }; - - res = replaceXSS(MoeMark(s)); - if (mathPending == 0 && hlPending == 0) { - finish(); - } - } catch(e) { - cb(e); - } +function filter(html) { + html = xss.process(html); + if (html) { + html = `
${html}
`; + } + return html; }; -render.moemark = MoeMark; -render.cache = defaultCache; -render.cacheOption = { - highlight: true, - math: true, - result: false +module.exports = (markdownCode, callback) => { + markdown(markdownCode, defaultCache, filter).then(callback); }; -render.config = config; - -module.exports = render; diff --git a/package.json b/package.json index b8ed0a3..b9fce8f 100644 --- a/package.json +++ b/package.json @@ -42,17 +42,13 @@ "js-yaml": "^3.9.0", "jsondiffpatch": "0.2.5", "jsonwebtoken": "^8.4.0", - "katex": "^0.10.1", "mariadb": "^2.0.2-rc", - "mathjax-node": "^2.1.1", - "moemark": "^0.3.10", "moment": "^2.24.0", "msgpack-lite": "^0.1.26", "multer": "^1.2.0", "node-7z": "^0.4.0", "nodemailer": "^4.7.0", "object-assign-deep": "^0.4.0", - "pygmentize-bundled-cached": "^1.1.0", "randomstring": "^1.1.5", "request": "^2.74.0", "request-promise": "^4.1.1", @@ -63,6 +59,7 @@ "socket.io": "^2.2.0", "stream-to-string": "^1.1.0", "syzoj-divine": "^1.0.2", + "syzoj-renderer": "syzoj/syzoj-renderer", "tempfile": "^2.0.0", "tmp-promise": "^1.0.3", "waliyun": "^3.1.1",