-
Notifications
You must be signed in to change notification settings - Fork 28
/
library.js
132 lines (107 loc) · 4.44 KB
/
library.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
"use strict";
var controllers = require('./lib/controllers'),
SocketPlugins = require.main.require('./src/socket.io/plugins'),
defaultComposer = module.parent.require('nodebb-plugin-composer-default'),
plugins = module.parent.exports,
meta = require.main.require('./src/meta'),
helpers = require.main.require('./src/controllers/helpers'),
utils = require.main.require('./public/src/utils'),
async = require('async'),
winston = module.parent.require('winston'),
nconf = module.parent.require('nconf'),
sanitize = require('sanitize-html'),
plugin = {};
var allowedTags = ['span', 'a', 'pre', 'blockquote', 'small', 'em', 'strong',
'code', 'kbd', 'mark', 'address', 'cite', 'var', 'samp', 'dfn',
'sup', 'sub', 'b', 'i', 'u', 'del', 'ol', 'ul', 'li', 'dl',
'dt', 'dd', 'p', 'br', 'video', 'audio', 'source', 'iframe', 'embed',
'param', 'img', 'table', 'tbody', 'tfoot', 'thead', 'tr', 'td', 'th',
'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'hr'];
var allowedAttributes = {
'a': ['href', 'hreflang', 'media', 'rel', 'target', 'type'],
'img': ['alt', 'height', 'ismap', 'src', 'usemap', 'width'],
'iframe': ['height', 'name', 'src', 'width'],
'span': [],
'video': ['autoplay', 'controls', 'height', 'loop', 'muted', 'poster', 'preload', 'src', 'width'],
'audio': ['autoplay', 'controls', 'loop', 'muted', 'preload', 'src'],
'embed': ['height', 'src', 'type', 'width'],
'param': ['name', 'value'],
'source': ['media', 'src', 'type']};
var globalAttributes = ['accesskey', 'class', 'contenteditable', 'dir',
'draggable', 'dropzone', 'hidden', 'id', 'lang', 'spellcheck', 'style',
'tabindex', 'title', 'translate'];
for (var i = 0; i < allowedTags.length; i++) {
if (!allowedAttributes[allowedTags[i]]) allowedAttributes[allowedTags[i]] = [];
for (var j = 0; j < globalAttributes.length; j++) allowedAttributes[allowedTags[i]].push(globalAttributes[j]);
}
plugin.init = function(data, callback) {
var router = data.router,
hostMiddleware = data.middleware,
hostControllers = data.controllers;
router.get('/admin/plugins/composer-redactor', hostMiddleware.admin.buildHeader, controllers.renderAdminPage);
router.get('/api/admin/plugins/composer-redactor', controllers.renderAdminPage);
// Expose the default composer's socket method calls for this composer as well
plugin.checkCompatibility(function(err, checks) {
if (checks.composer) {
SocketPlugins.composer = defaultComposer.socketMethods;
} else {
winston.warn('[plugin/composer-redactor] Another composer plugin is active! Please disable all other composers.');
}
});
callback();
};
plugin.checkCompatibility = function(callback) {
async.parallel({
active: async.apply(plugins.getActive),
markdown: async.apply(meta.settings.get, 'markdown')
}, function(err, data) {
callback(null, {
markdown: data.active.indexOf('nodebb-plugin-markdown') === -1 || data.markdown.html === 'on',
// ^ plugin disabled ^ HTML sanitization disabled
composer: data.active.filter(function(plugin) {
return plugin.startsWith('nodebb-plugin-composer-') && plugin !== 'nodebb-plugin-composer-redactor';
}).length === 0
})
});
};
plugin.addAdminNavigation = function(header, callback) {
header.plugins.push({
route: '/plugins/composer-redactor',
icon: 'fa-edit',
name: 'Redactor (Composer)'
});
callback(null, header);
};
plugin.sanitize = function(data, callback) {
function noop(u) { return u }
if (data && data.content) {
data.content = sanitize(data.content, {allowedTags: allowedTags, allowedAttributes: allowedAttributes});
}else if (data && data.post && data.post.content) {
data.post.content = sanitize(data.post.content, {allowedTags: allowedTags, allowedAttributes: allowedAttributes});
}
callback(null, data);
};
plugin.build = function(data, callback) {
// No plans for a standalone composer route, so handle redirection on f5
var req = data.req;
var res = data.res;
if (req.query.p) {
if (!res.locals.isAPI) {
if (req.query.p.startsWith(nconf.get('relative_path'))) {
req.query.p = req.query.p.replace(nconf.get('relative_path'), '');
}
return helpers.redirect(res, req.query.p);
} else {
return res.render('', {});
}
} else if (!req.query.pid && !req.query.tid && !req.query.cid) {
return helpers.redirect(res, '/');
}
callback(null, data);
}
plugin.checkContent = function (data, callback) {
data.content = utils.stripHTMLTags(data.content);
data.length = String(data.content).trim();
process.nextTick(callback, null, data);
};
module.exports = plugin;