feat: html sanitization on all filter:parse.* hooks, closes #7872

v1.18.x
Julian Lam 5 years ago
parent e291a60964
commit 2580306db9

@ -9,6 +9,7 @@ const nconf = require('nconf');
const util = require('util');
const user = require('../user');
const posts = require('../posts');
const readdirAsync = util.promisify(fs.readdir);
@ -124,6 +125,33 @@ Plugins.reload = async function () {
console.log('');
}
Plugins.registerHook('core', {
hook: 'filter:parse.post',
method: async (data) => {
data.postData.content = posts.sanitize(data.postData.content);
return data;
},
});
Plugins.registerHook('core', {
hook: 'filter:parse.raw',
method: async content => posts.sanitize(content),
});
Plugins.registerHook('core', {
hook: 'filter:parse.aboutme',
method: async content => posts.sanitize(content),
});
Plugins.registerHook('core', {
hook: 'filter:parse.signature',
method: async (data) => {
data.userData.signature = posts.sanitize(data.userData.signature);
return data;
},
});
// Lower priority runs earlier
Object.keys(Plugins.loadedHooks).forEach(function (hook) {
Plugins.loadedHooks[hook].sort((a, b) => a.priority - b.priority);
});

@ -3,12 +3,48 @@
var nconf = require('nconf');
var url = require('url');
var winston = require('winston');
const sanitize = require('sanitize-html');
const _ = require('lodash');
var meta = require('../meta');
var plugins = require('../plugins');
var translator = require('../translator');
var utils = require('../utils');
let sanitizeConfig = {
allowedTags: sanitize.defaults.allowedTags.concat([
// Some safe-to-use tags to add
'span', 'a', 'pre', 'small',
'sup', 'sub', 'u', 'del',
'video', 'audio', 'iframe', 'embed',
'img', 'tfoot', 'h1', 'h2',
's', 'button', 'i',
]),
allowedAttributes: {
...sanitize.defaults.allowedAttributes,
a: ['href', 'hreflang', 'media', 'rel', 'target', 'type'],
img: ['alt', 'height', 'ismap', 'src', 'usemap', 'width', 'srcset'],
iframe: ['height', 'name', 'src', 'width'],
video: ['autoplay', 'controls', 'height', 'loop', 'muted', 'poster', 'preload', 'src', 'width'],
audio: ['autoplay', 'controls', 'loop', 'muted', 'preload', 'src'],
embed: ['height', 'src', 'type', 'width'],
},
globalAttributes: ['accesskey', 'class', 'contenteditable', 'dir',
'draggable', 'dropzone', 'hidden', 'id', 'lang', 'spellcheck', 'style',
'tabindex', 'title', 'translate', 'aria-expanded', 'data-*',
],
};
process.nextTick(async () => {
// Each allowed tags should have some common global attributes...
sanitizeConfig.allowedTags.forEach((tag) => {
sanitizeConfig.allowedAttributes[tag] = _.union(sanitizeConfig.allowedAttributes[tag], sanitizeConfig.globalAttributes);
});
// Some plugins might need to adjust or whitelist their own tags...
sanitizeConfig = await plugins.fireHook('filter:sanitize.config', sanitizeConfig);
});
module.exports = function (Posts) {
Posts.urlRegex = {
regex: /href="([^"]+)"/g,
@ -77,6 +113,12 @@ module.exports = function (Posts) {
return content;
};
Posts.sanitize = function (content) {
return sanitize(content, {
allowedTags: sanitizeConfig.allowedTags, allowedAttributes: sanitizeConfig.allowedAttributes,
});
};
function sanitizeSignature(signature) {
signature = translator.escape(signature);
var tagsToStrip = [];

Loading…
Cancel
Save