From e561f250adb9fd0ee02f64abd018ea3077b9dc68 Mon Sep 17 00:00:00 2001 From: fatchan Date: Sat, 1 Feb 2020 15:02:49 +1100 Subject: [PATCH] custom css per board, with option to apply filter or disable completely --- configs/main.js.example | 15 ++++++++++++--- controllers/forms/boardsettings.js | 8 ++++++++ helpers/paramconverter.js | 2 +- models/forms/changeboardsettings.js | 6 ++++-- views/includes/head.pug | 2 ++ views/pages/managesettings.pug | 4 ++++ 6 files changed, 31 insertions(+), 6 deletions(-) diff --git a/configs/main.js.example b/configs/main.js.example index 3b18c6e6..1ebfb64b 100644 --- a/configs/main.js.example +++ b/configs/main.js.example @@ -151,11 +151,20 @@ module.exports = { max: 10485760 }, messageLength: { //max length of a post mesage field + /* NOTE: postFilesSize and bannerFilesSize counts in bytes the amount of total data in form submission including + other fields like message, name, etc. Therefore a very long message would reduce the space left for files very slightly. + To counteract this, consider increasing postFilesSize and bannerFilesSize beyond your desired max filesize by a small margin */ max: 4000 + }, + customCss: { + enabled: true, //allow custom css by board owners + max: 10000, //max number of characters to allow + strict: true, //enables filters to block certain strings in custom css + filters: [ + '@', + 'url(', + ] } - /* NOTE: postFilesSize and bannerFilesSize counts in bytes the amount of total data in form submission including - other fields like message, name, etc. Therefore a very long message would reduce the space left for files very slightly. - To counteract this, consider increasing postFilesSize and bannerFilesSize beyond your desired max filesize by a small margin */ }, //default board settings when a board is created diff --git a/controllers/forms/boardsettings.js b/controllers/forms/boardsettings.js index c770509f..ca9e461a 100644 --- a/controllers/forms/boardsettings.js +++ b/controllers/forms/boardsettings.js @@ -22,6 +22,14 @@ module.exports = async (req, res, next) => { if (req.body.filters && req.body.filters.length > 2000) { errors.push('Filters length must be 2000 characters or less'); } + if (req.body.custom_css && globalLimits.customCss.enabled) { + if (globalLimits.customCss.strict && globalLimits.customCss.filters.some(filter => req.body.custom_css.includes(filter))) { + errors.push(`Custom CSS strict mode is enabled and does not allow the following: "${globalLimits.customCss.filters.join('", "')}"`); + } + if (req.body.custom_css.length > globalLimits.customCss.max) { + errors.push(`Custom CSS must be ${globalLimits.customCss.max} characters or less`); + } + } if (req.body.moderators && req.body.moderators.length > 500) { errors.push('Moderators length must be 500 characters orless'); } diff --git a/helpers/paramconverter.js b/helpers/paramconverter.js index 8fe09b5f..a19e0d14 100644 --- a/helpers/paramconverter.js +++ b/helpers/paramconverter.js @@ -4,7 +4,7 @@ const { ObjectId } = require(__dirname+'/../db/db.js') , allowedArrays = new Set(['checkednews', 'checkedposts', 'globalcheckedposts', 'checkedreports', 'checkedbans', 'checkedbanners', 'checkedaccounts']) //only these should be arrays, since express bodyparser can output arrays , trimFields = ['tags', 'uri', 'moderators', 'filters', 'announcement', 'description', 'message', - 'name', 'subject', 'email', 'password', 'default_name', 'report_reason', 'ban_reason', 'log_message'] //trim if we dont want filed with whitespace + 'name', 'subject', 'email', 'password', 'default_name', 'report_reason', 'ban_reason', 'log_message', 'custom_css'] //trim if we dont want filed with whitespace , numberFields = ['filter_mode', 'captcha_mode', 'tph_trigger', 'pph_trigger', 'trigger_action', 'reply_limit', 'move_to_thread', 'max_files', 'thread_limit', 'thread', 'max_thread_message_length', 'max_reply_message_length', 'min_thread_message_length', 'min_reply_message_length', 'auth_level'] //convert these to numbers before they hit our routes , banDurationRegex = /^(?[\d]+y)?(?[\d]+m)?(?[\d]+w)?(?[\d]+d)?(?[\d]+h)?$/ diff --git a/models/forms/changeboardsettings.js b/models/forms/changeboardsettings.js index 90b12109..d9ea0a05 100644 --- a/models/forms/changeboardsettings.js +++ b/models/forms/changeboardsettings.js @@ -1,6 +1,7 @@ 'use strict'; const { Boards, Posts, Accounts } = require(__dirname+'/../../db/') + , { globalLimits } = require(__dirname+'/../../configs/main.js') , uploadDirectory = require(__dirname+'/../../helpers/files/uploadDirectory.js') , buildQueue = require(__dirname+'/../../queue.js') , cache = require(__dirname+'/../../redis.js') @@ -31,7 +32,7 @@ module.exports = async (req, res, next) => { //array of promises we might need const promises = []; - let markdownAnnouncement; + let markdownAnnouncement = oldSettings.announcement.markdown; if (req.body.announcement !== oldSettings.announcement.raw) { //remarkup the announcement if it changes const styled = markdown(req.body.announcement); @@ -71,7 +72,7 @@ module.exports = async (req, res, next) => { 'description': trimSetting(req.body.description, oldSettings.description), 'defaultName': trimSetting(req.body.default_name, oldSettings.defaultName), 'theme': req.body.theme || oldSettings.theme, - 'codeTheme': req.body.code_theme || oldSettings.codeTheme, + 'codeTheme': req.body.code_theme || oldSettings.codeTheme, 'sfw': booleanSetting(req.body.sfw), 'unlisted': booleanSetting(req.body.unlisted), 'webring': booleanSetting(req.body.webring), @@ -104,6 +105,7 @@ module.exports = async (req, res, next) => { 'filterBanDuration': numberSetting(req.body.ban_duration, oldSettings.filterBanDuration), 'tags': arraySetting(req.body.tags, oldSettings.tags, 10), 'filters': arraySetting(req.body.filters, oldSettings.filters, 50), + 'customCss': globalLimits.customCss.enabled ? (req.body.custom_css !== null ? req.body.custom_css : oldSettings.customCss) : null, 'announcement': { 'raw': req.body.announcement !== null ? req.body.announcement : oldSettings.announcement.raw, 'markdown': req.body.announcement !== null ? markdownAnnouncement : oldSettings.announcement.markdown, diff --git a/views/includes/head.pug b/views/includes/head.pug index ceea71ee..7b4a4edc 100644 --- a/views/includes/head.pug +++ b/views/includes/head.pug @@ -12,5 +12,7 @@ link(rel='stylesheet' href='/css/style.css') - const theme = isBoard ? board.settings.theme : defaultTheme; - const codeTheme = isBoard ? board.settings.codeTheme : defaultCodeTheme; link#theme(rel='stylesheet' data-theme=theme href=`/css/themes/${theme}.css`) +if isBoard && board.settings.customCss + style #{board.settings.customCss} link#codetheme(rel='stylesheet' data-theme=codeTheme href=`/css/codethemes/${codeTheme}.css`) link(rel='shortcut icon' href='/favicon.ico' type='image/x-icon') diff --git a/views/pages/managesettings.pug b/views/pages/managesettings.pug index 5a2642a5..c9d61659 100644 --- a/views/pages/managesettings.pug +++ b/views/pages/managesettings.pug @@ -176,6 +176,10 @@ block content select(name='code_theme') each theme in codeThemes option(value=theme selected=board.settings.codeTheme === theme) #{theme} + if globalLimits.customCss.enabled + .row + .label Custom CSS + textarea(name='custom_css' placeholder='test first in top-right settings if you have javascript enabled' maxlength=globalLimits.customCss.max) #{board.settings.customCss} .row .label Captcha Mode select(name='captcha_mode')