mirror of
https://github.com/NodeBB/NodeBB.git
synced 2025-10-26 08:36:12 +01:00
feat: html sanitization on all filter:parse.* hooks, closes #7872
This commit is contained in:
@@ -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 = [];
|
||||
|
||||
Reference in New Issue
Block a user