add more options for filters, filter mode and auto ban configurable duration

merge-requests/208/head
fatchan 5 years ago
parent 5ba4b66a38
commit 22e4033b82
  1. 22
      controllers/forms.js
  2. 3
      gulp/res/css/style.css
  3. 1
      gulpfile.js
  4. 2
      helpers/paramconverter.js
  5. 4
      models/forms/changeboardsettings.js
  6. 2
      models/forms/create.js
  7. 39
      models/forms/makepost.js
  8. 9
      views/pages/manage.pug
  9. 2
      views/pages/register.pug

@ -9,6 +9,7 @@ const express = require('express')
, { remove } = require('fs-extra')
, upload = require('express-fileupload')
, path = require('path')
, alphaNumericRegex = /^[a-zA-Z0-9]+$/
, postFiles = upload({
createParentPath: true,
safeFileNames: /[^\w-]+/g,
@ -170,12 +171,12 @@ router.post('/create', csrf, isLoggedIn, verifyCaptcha, (req, res, next) => {
errors.push('Missing description');
}
//check exist
//other validation
if (req.body.uri) {
if (req.body.uri.length > 50) {
errors.push('URI must be 50 characters or less');
}
if (!req.body.uri.match(/^[a-zA-Z0-9]+$/)) {
if (alphaNumericRegex.test(req.body.uri) !== true) {
errors.push('URI must contain a-z 0-9 only');
}
}
@ -214,9 +215,14 @@ router.post('/register', verifyCaptcha, (req, res, next) => {
errors.push('Missing password confirmation');
}
//check too long
if (req.body.username && req.body.username.length > 50) {
errors.push('Username must be 50 characters or less');
//check
if (req.body.username) {
if (req.body.username.length > 50) {
errors.push('Username must be 50 characters or less');
}
if (alphaNumericRegex.test(req.body.username) !== true) {
errors.push('Username must contain a-z 0-9 only');
}
}
if (req.body.password && req.body.password.length > 100) {
errors.push('Password must be 100 characters or less');
@ -361,6 +367,12 @@ router.post('/board/:board/settings', csrf, Boards.exists, isLoggedIn, checkPerm
if (typeof req.body.captcha_trigger_mode === 'number' && (req.body.captcha_trigger_mode < 0 || req.body.captcha_trigger_mode > 2)) {
errors.push('Invalid captcha trigger mode.')
}
if (typeof req.body.filter_mode === 'number' && (req.body.filter_mode < 0 || req.body.filter_mode > 2)) {
errors.push('Invalid filter mode.');
}
if (typeof req.body.ban_duration === 'number' && req.body.ban_duration <= 0) {
errors.push('Invalid filter auto ban duration.')
}
if (errors.length > 0) {
return res.status(400).render('message', {

@ -108,6 +108,9 @@ pre {
.mv-10 {
margin: 10px 0;
}
.mv-0 {
margin: 0 auto;
}
.mb-10 {
margin-bottom: 10px;
}

@ -73,6 +73,7 @@ async function wipe() {
'markdown':null
},
'filters':[]
'filterMode': 0,
}
})
//add indexes - should profiled and changed at some point if necessary

@ -3,7 +3,7 @@
const Mongo = require(__dirname+'/../db/db.js')
, allowedArrays = new Set(['checkedposts', 'globalcheckedposts', 'checkedbans', 'checkedbanners']) //only these can be arrays, since express bodyparser will output arrays
, trimFields = ['uri', 'filters', 'announcement', 'description', 'message', 'name', 'subject', 'email', 'password', 'default_name', 'report_reason', 'ban_reason'] //trim if we dont want filed with whitespace
, numberFields = ['captcha_mode', 'captcha_trigger', 'captcha_trigger_mode', 'reply_limit', 'max_files', 'thread_limit', 'thread', 'min_message_length'] //convert these to numbers before they hit our routes
, numberFields = ['filter_mode', 'captcha_mode', 'captcha_trigger', 'captcha_trigger_mode', 'reply_limit', 'max_files', 'thread_limit', 'thread', 'min_message_length'] //convert these to numbers before they hit our routes
, banDurationRegex = /^(?<year>[\d]+y)?(?<month>[\d]+m)?(?<week>[\d]+w)?(?<day>[\d]+d)?(?<hour>[\d]+h)?$/
, msTime = require(__dirname+'/mstime.js')

@ -52,7 +52,9 @@ module.exports = async (req, res, next) => {
raw: req.body.announcement !== null ? req.body.announcement : oldSettings.announcement.raw,
markdown: markdownAnnouncement || oldSettings.announcement.markdown
},
filters: req.body.filters !== null ? req.body.filters.split('\n').filter(n => n) /*prevents empty*/ : oldSettings.filters
filters: req.body.filters !== null ? req.body.filters.split('\n').filter(n => n) /*prevents empty*/ : oldSettings.filters,
filterMode: typeof req.body.filter_mode === 'number' && req.body.filter_mode !== oldSettings.filterMode ? req.body.filter_mode : oldSettings.filterMode,
filterBanDuration: typeof req.body.ban_duration === 'number' && req.body.ban_duration !== oldSettings.filterBanDuration ? req.body.ban_duration : oldSettings.filterBanDuration
};
//settings changed in the db

@ -43,7 +43,7 @@ module.exports = async (req, res, next) => {
'userPostUnlink': true,
'threadLimit': 200,
'replyLimit': 500,
'maxFiles': 0,
'maxFiles': 3,
'forceOPSubject': false,
'forceOPMessage': true,
'forceOPFile': false,

@ -8,6 +8,7 @@ const path = require('path')
, Posts = require(__dirname+'/../../db/posts.js')
, Boards = require(__dirname+'/../../db/boards.js')
, Files = require(__dirname+'/../../db/files.js')
, Bans = require(__dirname+'/../../db/bans.js')
, getTripCode = require(__dirname+'/../../helpers/posting/tripcode.js')
, linkQuotes = require(__dirname+'/../../helpers/posting/quotes.js')
, simpleMarkdown = require(__dirname+'/../../helpers/posting/markdown.js')
@ -42,7 +43,7 @@ module.exports = async (req, res, next) => {
let salt = null;
let thread = null;
const permLevel = permsCheck(req, res);
const { filters, maxFiles, forceAnon, replyLimit, threadLimit, ids, userPostSpoiler, defaultName, captchaTrigger, captchaTriggerMode, captchaMode } = res.locals.board.settings;
const { filters, filterBanDuration, filterMode, maxFiles, forceAnon, replyLimit, threadLimit, ids, userPostSpoiler, defaultName, captchaTrigger, captchaTriggerMode, captchaMode } = res.locals.board.settings;
if (req.body.thread) {
thread = await Posts.getPost(req.params.board, req.body.thread, true);
if (!thread || thread.thread != null) {
@ -81,15 +82,35 @@ module.exports = async (req, res, next) => {
});
}
//filters
if (filters && filters.length > 0) {
const containsFilter = filters.some(filter => { return req.body.message.includes(filter) });
if (containsFilter) {
if (permLevel >= 4 && filterMode > 0 && filters && filters.length > 0) {
const allContents = req.body.name+req.body.message+req.body.subject+req.body.email;
const containsFilter = filters.some(filter => { return allContents.includes(filter) });
if (containsFilter === true) {
await deleteTempFiles(req).catch(e => console.error);
return res.status(400).render('message', { //is this a 400?
'title': 'Bad request',
'message': `Your message was blocked by a filter.`,
'redirect': redirect
});
if (filterMode === 1) {
return res.status(400).render('message', {
'title': 'Bad request',
'message': 'Your post was blocked by a word filter',
'redirect': redirect
});
} else if (filterMode === 2) {
const banDate = new Date();
const banExpiry = new Date(filterBanDuration + banDate.getTime());
const ban = {
'ip': res.locals.ip,
'reason': 'post word filter auto ban',
'board': res.locals.board._id,
'post': null,
'issuer': 'system', //what should i call this
'date': banDate,
'expireAt': banExpiry
};
await Bans.insertOne(ban);
const bans = await Bans.find(res.locals.ip, res.locals.board._id);
return res.status(403).render('ban', {
bans: bans
});
}
}
}
let files = [];

@ -86,6 +86,15 @@ block content
section.row
.label Filters
textarea(name='filters' placeholder='newline separated') #{board.settings.filters.join('\n')}
section.row
.label Filter Mode
select(name='filter_mode' checked=board.settings.filterMode)
option(value='0', selected=board.settings.filterMode === 0) Do nothing
option(value='1', selected=board.settings.filterMode === 1) Block post
option(value='2', selected=board.settings.filterMode === 2) Auto ban
section.row
.label Filter Auto Ban Duration
input(type='text' name='ban_duration' placeholder='e.g. 1w' value=board.settings.filterBanDuration)
input(type='submit', value='save settings')
hr(size=1)
h4.no-m-p Add Banners:

@ -9,7 +9,7 @@ block content
form.form-post(action='/forms/register' method='POST')
section.row
.label Username
input(type='text', name='username', maxlength='50' required)
input(type='text', name='username', maxlength='50' pattern='[a-zA-Z0-9]+' required title='alphanumeric only')
section.row
.label Password
input(type='password', name='password', maxlength='100' required)

Loading…
Cancel
Save