diff --git a/controllers/forms.js b/controllers/forms.js index be1bbc06..e1e5e312 100644 --- a/controllers/forms.js +++ b/controllers/forms.js @@ -6,8 +6,6 @@ const express = require('express') , Boards = require(__dirname+'/../db/boards.js') , Posts = require(__dirname+'/../db/posts.js') , upload = require('express-fileupload') - , path = require('path') - , alphaNumericRegex = /^[a-zA-Z0-9]+$/ , postFiles = upload({ createParentPath: true, safeFileNames: /[^\w-]+/g, @@ -18,684 +16,77 @@ const express = require('express') }, abortOnLimit: true, useTempFiles: true, - tempFileDir: path.join(__dirname+'/../tmp/') + tempFileDir: __dirname+'/../tmp/' }) , bannerFiles = upload({ createParentPath: true, safeFileNames: /[^\w-]+/g, - preserveExtension: 4, + preserveExtension: 3, limits: { fileSize: 10 * 1024 * 1024, files: 10 }, abortOnLimit: true, useTempFiles: true, - tempFileDir: path.join(__dirname+'/../tmp/') + tempFileDir: __dirname+'/../tmp/' }) - , removeBans = require(__dirname+'/../models/forms/removebans.js') - , makePost = require(__dirname+'/../models/forms/makepost.js') - , deleteTempFiles = require(__dirname+'/../helpers/files/deletetempfiles.js') - , uploadBanners = require(__dirname+'/../models/forms/uploadbanners.js') - , deleteBanners = require(__dirname+'/../models/forms/deletebanners.js') - , deleteBoard = require(__dirname+'/../models/forms/deleteboard.js') - , loginAccount = require(__dirname+'/../models/forms/login.js') - , changePassword = require(__dirname+'/../models/forms/changepassword.js') - , changeBoardSettings = require(__dirname+'/../models/forms/changeboardsettings.js') - , registerAccount = require(__dirname+'/../models/forms/register.js') - , createBoard = require(__dirname+'/../models/forms/create.js') + //controllers + , deleteBoardController = require(__dirname+'/forms/deleteboard.js') + , removeBansController = require(__dirname+'/forms/removebans.js') + , globalActionController = require(__dirname+'/forms/globalactions.js') + , actionController = require(__dirname+'/forms/actions.js') + , uploadBannersController = require(__dirname+'/forms/uploadbanners.js') + , deleteBannersController = require(__dirname+'/forms/deletebanners.js') + , boardSettingsController = require(__dirname+'/forms/boardsettings.js') + , loginController = require(__dirname+'/forms/login.js') + , registerController = require(__dirname+'/forms/register.js') + , changePasswordController = require(__dirname+'/forms/changepassword.js') + , createBoardController = require(__dirname+'/forms/create.js') + , makePostController = require(__dirname+'/forms/makepost.js') + //middlewarechecks , calcPerms = require(__dirname+'/../helpers/checks/calcpermsmiddleware.js') , hasPerms = require(__dirname+'/../helpers/checks/haspermsmiddleware.js') - , spamCheck = require(__dirname+'/../helpers/checks/spamcheck.js') , paramConverter = require(__dirname+'/../helpers/paramconverter.js') , banCheck = require(__dirname+'/../helpers/checks/bancheck.js') , isLoggedIn = require(__dirname+'/../helpers/checks/isloggedin.js') , verifyCaptcha = require(__dirname+'/../helpers/captcha/captchaverify.js') - , actionHandler = require(__dirname+'/../models/forms/actionhandler.js') , csrf = require(__dirname+'/../helpers/checks/csrfmiddleware.js') - , uploadDirectory = require(__dirname+'/../helpers/files/uploadDirectory.js') - , actionChecker = require(__dirname+'/../helpers/checks/actionchecker.js'); - - -// login to account -router.post('/login', async (req, res, next) => { - - const errors = []; - - //check exist - if (!req.body.username || req.body.username.length <= 0) { - errors.push('Missing username'); - } - if (!req.body.password || req.body.password.length <= 0) { - errors.push('Missing password'); - } - - //check too long - if (req.body.username && req.body.username.length > 50) { - errors.push('Username must be 50 characters or less'); - } - if (req.body.password && req.body.password.length > 100) { - errors.push('Password must be 100 characters or less'); - } - - if (errors.length > 0) { - return res.status(400).render('message', { - 'title': 'Bad request', - 'errors': errors, - 'redirect': '/login.html' - }) - } - - try { - await loginAccount(req, res, next); - } catch (err) { - return next(err); - } - -}); - -//change password -router.post('/changepassword', verifyCaptcha, async (req, res, next) => { - - const errors = []; - - //check exist - if (!req.body.username || req.body.username.length <= 0) { - errors.push('Missing username'); - } - if (!req.body.password || req.body.password.length <= 0) { - errors.push('Missing password'); - } - if (!req.body.newpassword || req.body.newpassword.length <= 0) { - errors.push('Missing new password'); - } - if (!req.body.newpasswordconfirm || req.body.newpasswordconfirm.length <= 0) { - errors.push('Missing new password confirmation'); - } - - //check too long - if (req.body.username && req.body.username.length > 50) { - errors.push('Username must be 50 characters or less'); - } - if (req.body.password && req.body.password.length > 100) { - errors.push('Password must be 100 characters or less'); - } - if (req.body.newpassword && req.body.newpassword.length > 100) { - errors.push('Password must be 100 characters or less'); - } - if (req.body.newpasswordconfirm && req.body.newpasswordconfirm.length > 100) { - errors.push('Password confirmation must be 100 characters or less'); - } - if (req.body.newpassword != req.body.newpasswordconfirm) { - errors.push('New password and password confirmation must match'); - } - - if (errors.length > 0) { - return res.status(400).render('message', { - 'title': 'Bad request', - 'errors': errors, - 'redirect': '/changepassword.html' - }) - } - - try { - await changePassword(req, res, next); - } catch (err) { - return next(err); - } - -}); - -//create board -router.post('/create', csrf, isLoggedIn, verifyCaptcha, calcPerms, hasPerms(4), (req, res, next) => { - - if (enableUserBoards === false && res.locals.permLevel !== 0) { - //only board admin can create boards when user board creation disabled - return res.status(400).render('message', { - 'title': 'Bad request', - 'error': 'Board creation is only available to site administration', - 'redirect': '/' - }) - } - - const errors = []; - - //check exist - if (!req.body.uri || req.body.uri.length <= 0) { - errors.push('Missing URI'); - } - if (!req.body.name || req.body.name.length <= 0) { - errors.push('Missing name'); - } - if (!req.body.description || req.body.description.length <= 0) { - errors.push('Missing description'); - } - - //other validation - if (req.body.uri) { - if (req.body.uri.length > 50) { - errors.push('URI must be 50 characters or less'); - } - if (alphaNumericRegex.test(req.body.uri) !== true) { - errors.push('URI must contain a-z 0-9 only'); - } - } - if (req.body.name && req.body.name.length > 50) { - errors.push('Name must be 50 characters or less'); - } - if (req.body.description && req.body.description.length > 50) { - errors.push('Description must be 50 characters or less'); - } - - if (errors.length > 0) { - return res.status(400).render('message', { - 'title': 'Bad request', - 'errors': errors, - 'redirect': '/create.html' - }); - } - - createBoard(req, res, next); -}); - -//register account -router.post('/register', verifyCaptcha, (req, res, next) => { - - const errors = []; - - //check exist - if (!req.body.username || req.body.username.length <= 0) { - errors.push('Missing username'); - } - if (!req.body.password || req.body.password.length <= 0) { - errors.push('Missing password'); - } - if (!req.body.passwordconfirm || req.body.passwordconfirm.length <= 0) { - errors.push('Missing password confirmation'); - } - - //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'); - } - if (req.body.passwordconfirm && req.body.passwordconfirm.length > 100) { - errors.push('Password confirmation must be 100 characters or less'); - } - if (req.body.password != req.body.passwordconfirm) { - errors.push('Password and password confirmation must match'); - } - - if (errors.length > 0) { - return res.status(400).render('message', { - 'title': 'Bad request', - 'errors': errors, - 'redirect': '/register.html' - }) - } - - registerAccount(req, res, next); - -}); +//accounts +router.post('/login', loginController); +router.post('/register', verifyCaptcha, registerController); +router.post('/changepassword', verifyCaptcha, changePasswordController); +// create board +router.post('/create', csrf, isLoggedIn, verifyCaptcha, calcPerms, hasPerms(4), createBoardController); // make new post -router.post('/board/:board/post', Boards.exists, calcPerms, banCheck, postFiles, paramConverter, verifyCaptcha, async (req, res, next) => { - - if (req.files && req.files.file) { - if (Array.isArray(req.files.file)) { - res.locals.numFiles = req.files.file.filter(file => file.size > 0).length; - } else { - res.locals.numFiles = req.files.file.size > 0 ? 1 : 0; - req.files.file = [req.files.file]; - } - res.locals.numFiles = Math.min(res.locals.numFiles, res.locals.board.settings.maxFiles) - } - - const errors = []; - - // even if force file and message are off, the post must contain one of either. - if (!req.body.message && res.locals.numFiles === 0) { - errors.push('Posts must include a message or file'); - } - - // check file, subject and message enforcement according to board settings - if (!req.body.subject || req.body.subject.length === 0) { - if (!req.body.thread && res.locals.board.settings.forceThreadSubject) { - errors.push('Threads must include a subject'); - } //no option to force op subject, seems useless - } - if (res.locals.board.settings.maxFiles !== 0 && res.locals.numFiles === 0) { - if (!req.body.thread && res.locals.board.settings.forceThreadFile) { - errors.push('Threads must include a file'); - } else if (res.locals.board.settings.forceReplyFile) { - errors.push('Posts must include a file'); - } - } - if (!req.body.message || req.body.message.length === 0) { - if (!req.body.thread && res.locals.board.settings.forceThreadMessage) { - errors.push('Threads must include a message'); - } else if (res.locals.board.settings.forceReplyMessage) { - errors.push('Posts must include a message'); - } - } - if (req.body.message) { - if (req.body.message.length > 4000) { - errors.push('Message must be 4000 characters or less'); - } else if (!req.body.thread && req.body.message.length < res.locals.board.settings.minThreadMessageLength) { - errors.push(`Thread messages must be at least ${res.locals.board.settings.minMessageLength} characters long`); - } else if (req.body.thread && req.body.message.length < res.locals.board.settings.minReplyMessageLength) { - errors.push(`Reply messages must be at least ${res.locals.board.settings.minMessageLength} characters long`); - } - } - - // subject, email, name, password limited length - if (req.body.name && req.body.name.length > 50) { - errors.push('Name must be 50 characters or less'); - } - if (req.body.subject && req.body.subject.length > 50) { - errors.push('Subject must be 50 characters or less'); - } - if (req.body.email && req.body.email.length > 50) { - errors.push('Email must be 50 characters or less'); - } - if (req.body.password && req.body.password.length > 50) { - errors.push('Password must be 50 characters or less'); - } - - if (errors.length > 0) { - await deleteTempFiles(req).catch(e => console.error); - return res.status(400).render('message', { - 'title': 'Bad request', - 'errors': errors, - 'redirect': `/${req.params.board}${req.body.thread ? '/thread/' + req.body.thread + '.html' : ''}` - }); - } - - const flood = await spamCheck(req, res); - if (flood) { - deleteTempFiles(req).catch(e => console.error); - return res.status(429).render('message', { - 'title': 'Flood detected', - 'message': 'Please wait before making another post, or a post similar to another user', - 'redirect': `/${req.params.board}${req.body.thread ? '/thread/' + req.body.thread + '.html' : ''}` - }); - } - - try { - await makePost(req, res, next); - } catch (err) { - await deleteTempFiles(req).catch(e => console.error); - return next(err); - } - -}); - -//board settings -router.post('/board/:board/settings', csrf, Boards.exists, calcPerms, banCheck, isLoggedIn, hasPerms(2), paramConverter, async (req, res, next) => { - - const errors = []; - - if (req.body.description && (req.body.description.length < 1 || req.body.description.length > 50)) { - errors.push('Board description must be 1-50 characters'); - } - if (req.body.announcements && (req.body.announcements.length < 1 || req.body.announcements.length > 2000)) { - errors.push('Board announcements must be 1-2000 characters'); - } - if (req.body.name && (req.body.name.length < 1 || req.body.name.length > 50)) { - errors.push('Board name must be 1-50 characters'); - } - if (req.body.default_name && (req.body.default_name.length < 1 || req.body.default_name.length > 50)) { - errors.push('Anon name must be 1-50 characters'); - } - if (typeof req.body.reply_limit === 'number' && (req.body.reply_limit < 1 || req.body.reply_limit > 1000)) { - errors.push('Reply Limit must be from 1-1000'); - } - if (typeof req.body.thread_limit === 'number' && (req.body.thread_limit < 10 || req.body.thread_limit > 250)) { - errors.push('Threads Limit must be 10-250'); - } - if (typeof req.body.max_files === 'number' && (req.body.max_files < 0 || req.body.max_files > 3)) { - errors.push('Max files must be 0-3'); - } - if (typeof req.body.min_thread_message_length === 'number' && (req.body.min_thread_message_length < 0 || req.body.min_thread_message_length > 4000)) { - errors.push('Min thread message length must be 0-4000. 0 is disabled.'); - } - if (typeof req.body.min_reply_message_length === 'number' && (req.body.min_reply_message_length < 0 || req.body.min_reply_message_length > 4000)) { - errors.push('Min reply message length must be 0-4000. 0 is disabled.'); - } - if (typeof req.body.captcha_mode === 'number' && (req.body.captcha_mode < 0 || req.body.captcha_mode > 2)) { - errors.push('Invalid captcha mode.'); - } - if (typeof req.body.tph_trigger === 'number' && (req.body.tph_trigger < 0 || req.body.tph_trigger > 10000)) { - errors.push('Invalid tph trigger threshold.'); - } - if (typeof req.body.tph_trigger_action === 'number' && (req.body.tph_trigger_action < 0 || req.body.tph_trigger_action > 3)) { - errors.push('Invalid tph trigger action.') - } - 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', { - 'title': 'Bad request', - 'errors': errors, - 'redirect': `/${req.params.board}/manage.html` - }) - } - - try { - await changeBoardSettings(req, res, next); - } catch (err) { - return next(err); - } - -}); - -//upload banners -router.post('/board/:board/addbanners', bannerFiles, csrf, Boards.exists, calcPerms, banCheck, isLoggedIn, hasPerms(2), paramConverter, async (req, res, next) => { - - if (req.files && req.files.file) { - if (Array.isArray(req.files.file)) { - res.locals.numFiles = req.files.file.filter(file => file.size > 0).length; - } else { - res.locals.numFiles = req.files.file.size > 0 ? 1 : 0; - req.files.file = [req.files.file]; - } - } - - const errors = []; - - if (res.locals.numFiles === 0) { - errors.push('Must provide a file'); - } - if (res.locals.board.banners.length+res.locals.numFiles > 100) { - errors.push('Number of uploads would exceed 100 banner limit'); - } - - if (errors.length > 0) { - await deleteTempFiles(req).catch(e => console.error); - return res.status(400).render('message', { - 'title': 'Bad request', - 'errors': errors, - 'redirect': `/${req.params.board}/manage.html` - }) - } - - try { - await uploadBanners(req, res, next); - } catch (err) { - await deleteTempFiles(req).catch(e => console.error); - return next(err); - } - -}); - -//delete banners -router.post('/board/:board/deletebanners', csrf, Boards.exists, calcPerms, banCheck, isLoggedIn, hasPerms(2), paramConverter, async (req, res, next) => { - - const errors = []; - - if (!req.body.checkedbanners || req.body.checkedbanners.length === 0 || req.body.checkedbanners.length > 10) { - errors.push('Must select 1-10 banners to delete'); - } - - if (errors.length > 0) { - return res.status(400).render('message', { - 'title': 'Bad request', - 'errors': errors, - 'redirect': `/${req.params.board}/manage.html` - }) - } - - for (let i = 0; i < req.body.checkedbanners.length; i++) { - if (!res.locals.board.banners.includes(req.body.checkedbanners[i])) { - return res.status(400).render('message', { - 'title': 'Bad request', - 'message': 'Invalid banners selected', - 'redirect': `/${req.params.board}/manage.html` - }) - } - } - - try { - await deleteBanners(req, res, next); - } catch (err) { - console.error(err); - return next(err); - } - -}); - -//actions for a specific board -router.post('/board/:board/actions', Boards.exists, calcPerms, banCheck, paramConverter, verifyCaptcha, boardActionController); //Captcha on regular actions -router.post('/board/:board/modactions', csrf, Boards.exists, calcPerms, banCheck, isLoggedIn, hasPerms(3), paramConverter, boardActionController); //CSRF for mod actions -async function boardActionController(req, res, next) { - - const errors = []; - - //make sure they checked 1-10 posts - if (!req.body.checkedposts || req.body.checkedposts.length === 0 || req.body.checkedposts.length > 10) { - errors.push('Must select 1-10 posts'); - } - - res.locals.actions = actionChecker(req); - - //make sure they selected at least 1 action - if (!res.locals.actions.anyValid) { - errors.push('No actions selected'); - } - - //check if they have permission to perform the actions - if (res.locals.permLevel > res.locals.actions.authRequired) { - errors.push('No permission'); - } - if (res.locals.permLevel >= 4) { - if (req.body.delete && !res.locals.board.settings.userPostDelete) { - errors.push('Post deletion is disabled on this board'); - } - if (req.body.spoiler && !res.locals.board.settings.userPostSpoiler) { - errors.push('File spoilers are disabled on this board'); - } - if (req.body.unlink_file && !res.locals.board.settings.userPostUnlink) { - errors.push('File unlinking is disabled on this board'); - } - } - - //check that actions are valid - if (req.body.password && req.body.password.length > 50) { - errors.push('Password must be 50 characters or less'); - } - if (req.body.report_reason && req.body.report_reason.length > 50) { - errors.push('Report must be 50 characters or less'); - } - if (req.body.ban_reason && req.body.ban_reason.length > 50) { - errors.push('Ban reason must be 50 characters or less'); - } - if ((req.body.report || req.body.global_report) && (!req.body.report_reason || req.body.report_reason.length === 0)) { - errors.push('Reports must have a reason'); - } - - if (errors.length > 0) { - return res.status(400).render('message', { - 'title': 'Bad request', - 'errors': errors, - 'redirect': `/${req.params.board}/` - }) - } +router.post('/board/:board/post', Boards.exists, calcPerms, banCheck, postFiles, paramConverter, verifyCaptcha, makePostController); - res.locals.posts = await Posts.getPosts(req.params.board, req.body.checkedposts, true); - if (!res.locals.posts || res.locals.posts.length === 0) { - return res.status(404).render('message', { - 'title': 'Not found', - 'error': 'Selected posts not found', - 'redirect': `/${req.params.board}/` - }) - } +// post actions for a specific board e.g. reports +router.post('/board/:board/actions', Boards.exists, calcPerms, banCheck, paramConverter, verifyCaptcha, actionController); //Captcha on regular actions +router.post('/board/:board/modactions', csrf, Boards.exists, calcPerms, banCheck, isLoggedIn, hasPerms(3), paramConverter, actionController); //CSRF for mod actions +router.post('/global/actions', csrf, calcPerms, isLoggedIn, hasPerms(1), paramConverter, globalActionController); //global manage page version (muilti-board, uses mongoids - try { - await actionHandler(req, res, next); - } catch (err) { - console.error(err); - return next(err); - } +// board settings +router.post('/board/:board/settings', csrf, Boards.exists, calcPerms, banCheck, isLoggedIn, hasPerms(2), paramConverter, boardSettingsController); -} +//add/remove banners +router.post('/board/:board/addbanners', bannerFiles, csrf, Boards.exists, calcPerms, banCheck, isLoggedIn, hasPerms(2), paramConverter, uploadBannersController); +router.post('/board/:board/deletebanners', csrf, Boards.exists, calcPerms, banCheck, isLoggedIn, hasPerms(2), paramConverter, deleteBannersController); -//global actions (global manage page) -router.post('/global/actions', csrf, calcPerms, isLoggedIn, hasPerms(1), paramConverter, globalActionController); -async function globalActionController(req, res, next) { - - const errors = []; - - //make sure they checked 1-10 posts - if (!req.body.globalcheckedposts || req.body.globalcheckedposts.length === 0 || req.body.globalcheckedposts.length > 10) { - errors.push('Must select 1-10 posts') - } - - res.locals.actions = actionChecker(req); - - //make sure they have any global actions, and that they only selected global actions - if (!res.locals.actions.anyGlobal || res.locals.actions.anyValid > res.locals.actions.anyGlobal) { - errors.push('Invalid actions selected'); - } - - //check that actions are valid - if (req.body.password && req.body.password.length > 50) { - errors.push('Password must be 50 characters or less'); - } - if (req.body.ban_reason && req.body.ban_reason.length > 50) { - errors.push('Ban reason must be 50 characters or less'); - } - - //return the errors - if (errors.length > 0) { - return res.status(400).render('message', { - 'title': 'Bad request', - 'errors': errors, - 'redirect': '/globalmanage.html' - }) - } - - //get posts with global ids only - res.locals.posts = await Posts.globalGetPosts(req.body.globalcheckedposts, true); - if (!res.locals.posts || res.locals.posts.length === 0) { - return res.status(404).render('message', { - 'title': 'Not found', - 'errors': 'Selected posts not found', - 'redirect': '/globalmanage.html' - }) - } - - try { - await actionHandler(req, res, next); - } catch (err) { - console.error(err); - return next(err); - } - -} - -//unban +//unbans router.post('/global/unban', csrf, calcPerms, isLoggedIn, hasPerms(1), paramConverter, removeBansController); router.post('/board/:board/unban', csrf, Boards.exists, calcPerms, banCheck, isLoggedIn, hasPerms(3), paramConverter, removeBansController); -async function removeBansController(req, res, next) { - - //keep this for later in case i add other options to unbans - const errors = []; - - if (!req.body.checkedbans || req.body.checkedbans.length === 0 || req.body.checkedbans.length > 10) { - errors.push('Must select 1-10 bans') - } - - const redirect = req.params.board ? `/${req.params.board}/manage.html` : '/globalmanage.html'; - - if (errors.length > 0) { - return res.status(400).render('message', { - 'title': 'Bad request', - 'errors': errors, - redirect - }); - } - - let amount = 0; - try { - amount = await removeBans(req, res, next); - } catch (err) { - return next(err); - } - - return res.render('message', { - 'title': 'Success', - 'message': `Removed ${amount} bans`, - redirect - }); - -} //delete board router.post('/board/:board/deleteboard', csrf, Boards.exists, calcPerms, banCheck, isLoggedIn, hasPerms(2), deleteBoardController); router.post('/global/deleteboard', csrf, calcPerms, isLoggedIn, hasPerms(1), deleteBoardController); -async function deleteBoardController(req, res, next) { - - const errors = []; - - if (!req.body.confirm) { - errors.push('Missing confirmation'); - } - if (!req.body.uri) { - errors.push('Missing URI'); - } - if (alphaNumericRegex.test(req.body.uri) !== true) { - errors.push('URI must contain a-z 0-9 only'); - } else { - //no need to check these if the board name is completely invalid - if (req.params.board != null && req.params.board !== req.body.uri) { - //board manage page to not be able to delete other boards; - errors.push('URI does not match current board'); - } else if (!(await Boards.findOne(req.body.uri))) { - //global must chech exist because it skips Boards.exists middleware - errors.push(`Board /${req.body.uri}/ does not exist`); - } - } - - if (errors.length > 0) { - return res.status(400).render('message', { - 'title': 'Bad request', - 'errors': errors, - 'redirect': req.params.board ? `/${req.params.board}/manage.html` : '/globalmanage.html' - }); - } - - try { - await deleteBoard(req.body.uri); - } catch (err) { - return next(err); - } - - return res.render('message', { - 'title': 'Success', - 'message': 'Board deleted', - 'redirect': req.params.board ? '/' : '/globalmanage.html' - }); - -} router.post('/newcaptcha', async(req, res, next) => { - + //does this really need a separate file? probs not res.clearCookie('captchaid'); return res.redirect('/captcha.html'); - }); module.exports = router; diff --git a/controllers/forms/actions.js b/controllers/forms/actions.js new file mode 100644 index 00000000..8093dd6b --- /dev/null +++ b/controllers/forms/actions.js @@ -0,0 +1,81 @@ +'use strict'; + +const Posts = require(__dirname+'/../../db/posts.js') + , actionHandler = require(__dirname+'/../../models/forms/actionhandler.js') + , actionChecker = require(__dirname+'/../../helpers/checks/actionchecker.js'); + +module.exports = async (req, res, next) => { + + const errors = []; + + //make sure they checked 1-10 posts + if (!req.body.checkedposts || req.body.checkedposts.length === 0 || req.body.checkedposts.length > 10) { + errors.push('Must select 1-10 posts'); + } + + res.locals.actions = actionChecker(req); + + //make sure they selected at least 1 action + if (!res.locals.actions.anyValid) { + errors.push('No actions selected'); + } + + //check if they have permission to perform the actions + if (res.locals.permLevel > res.locals.actions.authRequired) { + errors.push('No permission'); + } + if (res.locals.permLevel >= 4) { + if (req.body.delete && !res.locals.board.settings.userPostDelete) { + errors.push('Post deletion is disabled on this board'); + } + if (req.body.spoiler && !res.locals.board.settings.userPostSpoiler) { + errors.push('File spoilers are disabled on this board'); + } + if (req.body.unlink_file && !res.locals.board.settings.userPostUnlink) { + errors.push('File unlinking is disabled on this board'); + } + } + + //check that actions are valid + if (req.body.password && req.body.password.length > 50) { + errors.push('Password must be 50 characters or less'); + } + if (req.body.report_reason && req.body.report_reason.length > 50) { + errors.push('Report must be 50 characters or less'); + } + if (req.body.ban_reason && req.body.ban_reason.length > 50) { + errors.push('Ban reason must be 50 characters or less'); + } + if ((req.body.report || req.body.global_report) && (!req.body.report_reason || req.body.report_reason.length === 0)) { + errors.push('Reports must have a reason'); + } + + if (errors.length > 0) { + return res.status(400).render('message', { + 'title': 'Bad request', + 'errors': errors, + 'redirect': `/${req.params.board}/` + }) + } + + try { + res.locals.posts = await Posts.getPosts(req.params.board, req.body.checkedposts, true); + } catch (err) { + return next(err); + } + if (!res.locals.posts || res.locals.posts.length === 0) { + return res.status(404).render('message', { + 'title': 'Not found', + 'error': 'Selected posts not found', + 'redirect': `/${req.params.board}/` + }) + } + + try { + await actionHandler(req, res, next); + } catch (err) { + return next(err); + } + +} + diff --git a/controllers/forms/boardsettings.js b/controllers/forms/boardsettings.js new file mode 100644 index 00000000..983c590e --- /dev/null +++ b/controllers/forms/boardsettings.js @@ -0,0 +1,66 @@ +'use strict'; + +const changeBoardSettings = require(__dirname+'/../../models/forms/changeboardsettings.js'); + +module.exports = async (req, res, next) => { + + const errors = []; + + if (req.body.description && (req.body.description.length < 1 || req.body.description.length > 50)) { + errors.push('Board description must be 1-50 characters'); + } + if (req.body.announcements && (req.body.announcements.length < 1 || req.body.announcements.length > 2000)) { + errors.push('Board announcements must be 1-2000 characters'); + } + if (req.body.name && (req.body.name.length < 1 || req.body.name.length > 50)) { + errors.push('Board name must be 1-50 characters'); + } + if (req.body.default_name && (req.body.default_name.length < 1 || req.body.default_name.length > 50)) { + errors.push('Anon name must be 1-50 characters'); + } + if (typeof req.body.reply_limit === 'number' && (req.body.reply_limit < 1 || req.body.reply_limit > 1000)) { + errors.push('Reply Limit must be from 1-1000'); + } + if (typeof req.body.thread_limit === 'number' && (req.body.thread_limit < 10 || req.body.thread_limit > 250)) { + errors.push('Threads Limit must be 10-250'); + } + if (typeof req.body.max_files === 'number' && (req.body.max_files < 0 || req.body.max_files > 3)) { + errors.push('Max files must be 0-3'); + } + if (typeof req.body.min_thread_message_length === 'number' && (req.body.min_thread_message_length < 0 || req.body.min_thread_message_length > 4000)) { + errors.push('Min thread message length must be 0-4000. 0 is disabled.'); + } + if (typeof req.body.min_reply_message_length === 'number' && (req.body.min_reply_message_length < 0 || req.body.min_reply_message_length > 4000)) { + errors.push('Min reply message length must be 0-4000. 0 is disabled.'); + } + if (typeof req.body.captcha_mode === 'number' && (req.body.captcha_mode < 0 || req.body.captcha_mode > 2)) { + errors.push('Invalid captcha mode.'); + } + if (typeof req.body.tph_trigger === 'number' && (req.body.tph_trigger < 0 || req.body.tph_trigger > 10000)) { + errors.push('Invalid tph trigger threshold.'); + } + if (typeof req.body.tph_trigger_action === 'number' && (req.body.tph_trigger_action < 0 || req.body.tph_trigger_action > 3)) { + errors.push('Invalid tph trigger action.') + } + 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', { + 'title': 'Bad request', + 'errors': errors, + 'redirect': `/${req.params.board}/manage.html` + }) + } + + try { + await changeBoardSettings(req, res, next); + } catch (err) { + return next(err); + } + +} diff --git a/controllers/forms/changepassword.js b/controllers/forms/changepassword.js new file mode 100644 index 00000000..a43a58bf --- /dev/null +++ b/controllers/forms/changepassword.js @@ -0,0 +1,52 @@ +'use strict'; + +module.exports = async (req, res, next) => { + + const errors = []; + + //check exist + if (!req.body.username || req.body.username.length <= 0) { + errors.push('Missing username'); + } + if (!req.body.password || req.body.password.length <= 0) { + errors.push('Missing password'); + } + if (!req.body.newpassword || req.body.newpassword.length <= 0) { + errors.push('Missing new password'); + } + if (!req.body.newpasswordconfirm || req.body.newpasswordconfirm.length <= 0) { + errors.push('Missing new password confirmation'); + } + + //check too long + if (req.body.username && req.body.username.length > 50) { + errors.push('Username must be 50 characters or less'); + } + if (req.body.password && req.body.password.length > 100) { + errors.push('Password must be 100 characters or less'); + } + if (req.body.newpassword && req.body.newpassword.length > 100) { + errors.push('Password must be 100 characters or less'); + } + if (req.body.newpasswordconfirm && req.body.newpasswordconfirm.length > 100) { + errors.push('Password confirmation must be 100 characters or less'); + } + if (req.body.newpassword != req.body.newpasswordconfirm) { + errors.push('New password and password confirmation must match'); + } + + if (errors.length > 0) { + return res.status(400).render('message', { + 'title': 'Bad request', + 'errors': errors, + 'redirect': '/changepassword.html' + }) + } + + try { + await changePassword(req, res, next); + } catch (err) { + return next(err); + } + +} diff --git a/controllers/forms/create.js b/controllers/forms/create.js new file mode 100644 index 00000000..7dc65c81 --- /dev/null +++ b/controllers/forms/create.js @@ -0,0 +1,59 @@ +'use strict'; + +const createBoard = require(__dirname+'/../../models/forms/create.js'); + +module.exports = async (req, res, next) => { + + if (enableUserBoards === false && res.locals.permLevel !== 0) { + //only board admin can create boards when user board creation disabled + return res.status(400).render('message', { + 'title': 'Bad request', + 'error': 'Board creation is only available to site administration', + 'redirect': '/' + }) + } + + const errors = []; + + //check exist + if (!req.body.uri || req.body.uri.length <= 0) { + errors.push('Missing URI'); + } + if (!req.body.name || req.body.name.length <= 0) { + errors.push('Missing name'); + } + if (!req.body.description || req.body.description.length <= 0) { + errors.push('Missing description'); + } + + //other validation + if (req.body.uri) { + if (req.body.uri.length > 50) { + errors.push('URI must be 50 characters or less'); + } + if (alphaNumericRegex.test(req.body.uri) !== true) { + errors.push('URI must contain a-z 0-9 only'); + } + } + if (req.body.name && req.body.name.length > 50) { + errors.push('Name must be 50 characters or less'); + } + if (req.body.description && req.body.description.length > 50) { + errors.push('Description must be 50 characters or less'); + } + + if (errors.length > 0) { + return res.status(400).render('message', { + 'title': 'Bad request', + 'errors': errors, + 'redirect': '/create.html' + }); + } + + try { + await createBoard(req, res, next); + } catch (err) { + return next(err); + } + +} diff --git a/controllers/forms/deletebanners.js b/controllers/forms/deletebanners.js new file mode 100644 index 00000000..3b24042c --- /dev/null +++ b/controllers/forms/deletebanners.js @@ -0,0 +1,38 @@ +'use strict'; + +const deleteBanners = require(__dirname+'/../../models/forms/deletebanners.js'); + +module.exports = async (req, res, next) => { + + const errors = []; + + if (!req.body.checkedbanners || req.body.checkedbanners.length === 0 || req.body.checkedbanners.length > 10) { + errors.push('Must select 1-10 banners to delete'); + } + + if (errors.length > 0) { + return res.status(400).render('message', { + 'title': 'Bad request', + 'errors': errors, + 'redirect': `/${req.params.board}/manage.html` + }) + } + + for (let i = 0; i < req.body.checkedbanners.length; i++) { + if (!res.locals.board.banners.includes(req.body.checkedbanners[i])) { + return res.status(400).render('message', { + 'title': 'Bad request', + 'message': 'Invalid banners selected', + 'redirect': `/${req.params.board}/manage.html` + }) + } + } + + try { + await deleteBanners(req, res, next); + } catch (err) { + console.error(err); + return next(err); + } + +} diff --git a/controllers/forms/deleteboard.js b/controllers/forms/deleteboard.js new file mode 100644 index 00000000..90c9c187 --- /dev/null +++ b/controllers/forms/deleteboard.js @@ -0,0 +1,57 @@ +'use strict'; + +const Boards = require(__dirname+'/../../db/boards.js') + , deleteBoard = require(__dirname+'/../../models/forms/deleteboard.js') + , boardUriRegex = require(__dirname+'/../../helpers/checks/boarduriregex.js') + +module.exports = async (req, res, next) => { + + const errors = []; + + if (!req.body.confirm) { + errors.push('Missing confirmation'); + } + if (!req.body.uri) { + errors.push('Missing URI'); + } + if (boardUriRegex.test(req.body.uri) !== true) { + errors.push('URI must contain a-z 0-9 only'); + } else { + //no need to check these if the board name is completely invalid + if (req.params.board != null && req.params.board !== req.body.uri) { + //board manage page to not be able to delete other boards; + errors.push('URI does not match current board'); + } + let board; + try { + board = await Boards.findOne(req.body.uri) + } catch (err) { + return next(err); + } + if (board != null) { + //global must check exists because the route skips Boards.exists middleware + errors.push(`Board /${req.body.uri}/ does not exist`); + } + } + + if (errors.length > 0) { + return res.status(400).render('message', { + 'title': 'Bad request', + 'errors': errors, + 'redirect': req.params.board ? `/${req.params.board}/manage.html` : '/globalmanage.html' + }); + } + + try { + await deleteBoard(req.body.uri); + } catch (err) { + return next(err); + } + + return res.render('message', { + 'title': 'Success', + 'message': 'Board deleted', + 'redirect': req.params.board ? '/' : '/globalmanage.html' + }); + +} diff --git a/controllers/forms/globalactions.js b/controllers/forms/globalactions.js new file mode 100644 index 00000000..8b659bb0 --- /dev/null +++ b/controllers/forms/globalactions.js @@ -0,0 +1,62 @@ +'use strict'; + +const Posts = require(__dirname+'/../../db/posts.js') + , actionHandler = require(__dirname+'/../../models/forms/actionhandler.js') + , actionChecker = require(__dirname+'/../../helpers/checks/actionchecker.js'); + +module.exports = async (req, res, next) => { + + const errors = []; + + //make sure they checked 1-10 posts + if (!req.body.globalcheckedposts || req.body.globalcheckedposts.length === 0 || req.body.globalcheckedposts.length > 10) { + errors.push('Must select 1-10 posts') + } + + res.locals.actions = actionChecker(req); + + //make sure they have any global actions, and that they only selected global actions + if (!res.locals.actions.anyGlobal || res.locals.actions.anyValid > res.locals.actions.anyGlobal) { + errors.push('Invalid actions selected'); + } + + //check that actions are valid + if (req.body.password && req.body.password.length > 50) { + errors.push('Password must be 50 characters or less'); + } + if (req.body.ban_reason && req.body.ban_reason.length > 50) { + errors.push('Ban reason must be 50 characters or less'); + } + + //return the errors + if (errors.length > 0) { + return res.status(400).render('message', { + 'title': 'Bad request', + 'errors': errors, + 'redirect': '/globalmanage.html' + }) + } + + //get posts with global ids only + try { + res.locals.posts = await Posts.globalGetPosts(req.body.globalcheckedposts, true); + } catch (err) { + return next(err); + } + if (!res.locals.posts || res.locals.posts.length === 0) { + return res.status(404).render('message', { + 'title': 'Not found', + 'errors': 'Selected posts not found', + 'redirect': '/globalmanage.html' + }) + } + + try { + await actionHandler(req, res, next); + } catch (err) { + console.error(err); + return next(err); + } + +} + diff --git a/controllers/forms/login.js b/controllers/forms/login.js new file mode 100644 index 00000000..6f9d267e --- /dev/null +++ b/controllers/forms/login.js @@ -0,0 +1,39 @@ +'use strict'; + +const loginAccount = require(__dirname+'/../../models/forms/login.js'); + +module.exports = async (req, res, next) => { + + const errors = []; + + //check exist + if (!req.body.username || req.body.username.length <= 0) { + errors.push('Missing username'); + } + if (!req.body.password || req.body.password.length <= 0) { + errors.push('Missing password'); + } + + //check too long + if (req.body.username && req.body.username.length > 50) { + errors.push('Username must be 50 characters or less'); + } + if (req.body.password && req.body.password.length > 100) { + errors.push('Password must be 100 characters or less'); + } + + if (errors.length > 0) { + return res.status(400).render('message', { + 'title': 'Bad request', + 'errors': errors, + 'redirect': '/login.html' + }) + } + + try { + await loginAccount(req, res, next); + } catch (err) { + return next(err); + } + +} diff --git a/controllers/forms/makepost.js b/controllers/forms/makepost.js new file mode 100644 index 00000000..b9164668 --- /dev/null +++ b/controllers/forms/makepost.js @@ -0,0 +1,85 @@ +'use strict'; + +const makePost = require(__dirname+'/../../models/forms/makepost.js') + , deleteTempFiles = require(__dirname+'/../../helpers/files/deletetempfiles.js'); + +module.exports = async (req, res, next) => { + + if (req.files && req.files.file) { + if (Array.isArray(req.files.file)) { + res.locals.numFiles = req.files.file.filter(file => file.size > 0).length; + } else { + res.locals.numFiles = req.files.file.size > 0 ? 1 : 0; + req.files.file = [req.files.file]; + } + res.locals.numFiles = Math.min(res.locals.numFiles, res.locals.board.settings.maxFiles) + } + + const errors = []; + + // even if force file and message are off, the post must contain one of either. + if (!req.body.message && res.locals.numFiles === 0) { + errors.push('Posts must include a message or file'); + } + + // check file, subject and message enforcement according to board settings + if (!req.body.subject || req.body.subject.length === 0) { + if (!req.body.thread && res.locals.board.settings.forceThreadSubject) { + errors.push('Threads must include a subject'); + } //no option to force op subject, seems useless + } + if (res.locals.board.settings.maxFiles !== 0 && res.locals.numFiles === 0) { + if (!req.body.thread && res.locals.board.settings.forceThreadFile) { + errors.push('Threads must include a file'); + } else if (res.locals.board.settings.forceReplyFile) { + errors.push('Posts must include a file'); + } + } + if (!req.body.message || req.body.message.length === 0) { + if (!req.body.thread && res.locals.board.settings.forceThreadMessage) { + errors.push('Threads must include a message'); + } else if (res.locals.board.settings.forceReplyMessage) { + errors.push('Posts must include a message'); + } + } + if (req.body.message) { + if (req.body.message.length > 4000) { + errors.push('Message must be 4000 characters or less'); + } else if (!req.body.thread && req.body.message.length < res.locals.board.settings.minThreadMessageLength) { + errors.push(`Thread messages must be at least ${res.locals.board.settings.minMessageLength} characters long`); + } else if (req.body.thread && req.body.message.length < res.locals.board.settings.minReplyMessageLength) { + errors.push(`Reply messages must be at least ${res.locals.board.settings.minMessageLength} characters long`); + } + } + + // subject, email, name, password limited length + if (req.body.name && req.body.name.length > 50) { + errors.push('Name must be 50 characters or less'); + } + if (req.body.subject && req.body.subject.length > 50) { + errors.push('Subject must be 50 characters or less'); + } + if (req.body.email && req.body.email.length > 50) { + errors.push('Email must be 50 characters or less'); + } + if (req.body.password && req.body.password.length > 50) { + errors.push('Password must be 50 characters or less'); + } + + if (errors.length > 0) { + await deleteTempFiles(req).catch(e => console.error); + return res.status(400).render('message', { + 'title': 'Bad request', + 'errors': errors, + 'redirect': `/${req.params.board}${req.body.thread ? '/thread/' + req.body.thread + '.html' : ''}` + }); + } + + try { + await makePost(req, res, next); + } catch (err) { + await deleteTempFiles(req).catch(e => console.error); + return next(err); + } + +} diff --git a/controllers/forms/register.js b/controllers/forms/register.js new file mode 100644 index 00000000..2879ff2f --- /dev/null +++ b/controllers/forms/register.js @@ -0,0 +1,51 @@ +'use strict'; + +module.exports = async (req, res, next) => { + + const errors = []; + + //check exist + if (!req.body.username || req.body.username.length <= 0) { + errors.push('Missing username'); + } + if (!req.body.password || req.body.password.length <= 0) { + errors.push('Missing password'); + } + if (!req.body.passwordconfirm || req.body.passwordconfirm.length <= 0) { + errors.push('Missing password confirmation'); + } + + //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'); + } + if (req.body.passwordconfirm && req.body.passwordconfirm.length > 100) { + errors.push('Password confirmation must be 100 characters or less'); + } + if (req.body.password != req.body.passwordconfirm) { + errors.push('Password and password confirmation must match'); + } + + if (errors.length > 0) { + return res.status(400).render('message', { + 'title': 'Bad request', + 'errors': errors, + 'redirect': '/register.html' + }) + } + + try { + await registerAccount(req, res, next); + } catch (err) { + return next(err); + } + +} diff --git a/controllers/forms/removebans.js b/controllers/forms/removebans.js new file mode 100644 index 00000000..590c6268 --- /dev/null +++ b/controllers/forms/removebans.js @@ -0,0 +1,37 @@ +'use strict'; + +const removeBans = require(__dirname+'/../../models/forms/removebans.js'); + +module.exports = async (req, res, next) => { + + //keep this for later in case i add other options to unbans + const errors = []; + + if (!req.body.checkedbans || req.body.checkedbans.length === 0 || req.body.checkedbans.length > 10) { + errors.push('Must select 1-10 bans') + } + + const redirect = req.params.board ? `/${req.params.board}/manage.html` : '/globalmanage.html'; + + if (errors.length > 0) { + return res.status(400).render('message', { + 'title': 'Bad request', + 'errors': errors, + redirect + }); + } + + let amount = 0; + try { + amount = await removeBans(req, res, next); + } catch (err) { + return next(err); + } + + return res.render('message', { + 'title': 'Success', + 'message': `Removed ${amount} bans`, + redirect + }); + +} diff --git a/controllers/forms/uploadbanners.js b/controllers/forms/uploadbanners.js new file mode 100644 index 00000000..1b88dbaa --- /dev/null +++ b/controllers/forms/uploadbanners.js @@ -0,0 +1,42 @@ +'use strict'; + +const uploadBanners = require(__dirname+'/../../models/forms/uploadbanners.js') + , deleteTempFiles = require(__dirname+'/../../helpers/files/deletetempfiles.js'); + +module.exports = async (req, res, next) => { + + if (req.files && req.files.file) { + if (Array.isArray(req.files.file)) { + res.locals.numFiles = req.files.file.filter(file => file.size > 0).length; + } else { + res.locals.numFiles = req.files.file.size > 0 ? 1 : 0; + req.files.file = [req.files.file]; + } + } + + const errors = []; + + if (res.locals.numFiles === 0) { + errors.push('Must provide a file'); + } + if (res.locals.board.banners.length+res.locals.numFiles > 100) { + errors.push('Number of uploads would exceed 100 banner limit'); + } + + if (errors.length > 0) { + await deleteTempFiles(req).catch(e => console.error); + return res.status(400).render('message', { + 'title': 'Bad request', + 'errors': errors, + 'redirect': `/${req.params.board}/manage.html` + }) + } + + try { + await uploadBanners(req, res, next); + } catch (err) { + await deleteTempFiles(req).catch(e => console.error); + return next(err); + } + +} diff --git a/helpers/checks/boarduriregex.js b/helpers/checks/boarduriregex.js new file mode 100644 index 00000000..dd375743 --- /dev/null +++ b/helpers/checks/boarduriregex.js @@ -0,0 +1,4 @@ +'use strict'; + +//literally just alphanumeric ¯\_(ツ)_/¯ +module.exports = /^[a-zA-Z0-9]+$/ diff --git a/models/forms/create.js b/models/forms/create.js index 9f304cc2..1cbb0a33 100644 --- a/models/forms/create.js +++ b/models/forms/create.js @@ -7,12 +7,7 @@ module.exports = async (req, res, next) => { const { name, description } = req.body , uri = req.body.uri.toLowerCase(); - let board; - try { - board = await Boards.findOne(uri); - } catch (err) { - return next(err); - } + const board = await Boards.findOne(uri); // if board exists reject if (board != null) { @@ -62,11 +57,7 @@ module.exports = async (req, res, next) => { } } - try { - await Boards.insertOne(newBoard); - } catch (err) { - return next(err); - } + await Boards.insertOne(newBoard); return res.redirect(`/${uri}/index.html`); diff --git a/models/forms/login.js b/models/forms/login.js index a574d568..94f6d04e 100644 --- a/models/forms/login.js +++ b/models/forms/login.js @@ -11,12 +11,7 @@ module.exports = async (req, res, next) => { const failRedirect = `/login.html${goto ? '?goto='+goto : ''}` //fetch an account - let account; - try { - account = await Accounts.findOne(username); - } catch (err) { - return next(err); - } + const account = await Accounts.findOne(username); //if the account doesnt exist, reject if (!account) { @@ -28,12 +23,7 @@ module.exports = async (req, res, next) => { } // bcrypt compare input to saved hash - let passwordMatch; - try { - passwordMatch = await bcrypt.compare(password, account.passwordHash); - } catch (err) { - return next(err); - } + const passwordMatch = await bcrypt.compare(password, account.passwordHash); //if hashes matched if (passwordMatch === true) { diff --git a/models/forms/makepost.js b/models/forms/makepost.js index 3ebe3a13..e5e2224a 100644 --- a/models/forms/makepost.js +++ b/models/forms/makepost.js @@ -27,11 +27,23 @@ const path = require('path') , deleteTempFiles = require(__dirname+'/../../helpers/files/deletetempfiles.js') , msTime = require(__dirname+'/../../helpers/mstime.js') , deletePosts = require(__dirname+'/deletepost.js') + , spamCheck = require(__dirname+'/../../helpers/checks/spamcheck.js') , { postPasswordSecret } = require(__dirname+'/../../configs/main.json') , { buildCatalog, buildThread, buildBoard, buildBoardMultiple } = require(__dirname+'/../../helpers/build.js'); module.exports = async (req, res, next) => { + //spam/flood check + const flood = await spamCheck(req, res); + if (flood) { + deleteTempFiles(req).catch(e => console.error); + return res.status(429).render('message', { + 'title': 'Flood detected', + 'message': 'Please wait before making another post, or a post similar to another user', + 'redirect': `/${req.params.board}${req.body.thread ? '/thread/' + req.body.thread + '.html' : ''}` + }); + } + // check if this is responding to an existing thread let redirect = `/${req.params.board}/` let salt = null; diff --git a/models/forms/register.js b/models/forms/register.js index 17e4c12f..00f9e3ae 100644 --- a/models/forms/register.js +++ b/models/forms/register.js @@ -8,12 +8,7 @@ module.exports = async (req, res, next) => { const username = req.body.username.toLowerCase(); const password = req.body.password; - let account; - try { - account = await Accounts.findOne(username); - } catch (err) { - return next(err); - } + const account = await Accounts.findOne(username); // if the account exists reject if (account != null) { @@ -25,12 +20,8 @@ module.exports = async (req, res, next) => { } // add account to db. password is hashed in db model func for easier tests - try { - await Accounts.insertOne(username, password, 4); - } catch (err) { - return next(err); - } + await Accounts.insertOne(username, password, 4); - return res.redirect('/login.html') + return res.redirect('/login.html'); }