diff --git a/controllers/forms.js b/controllers/forms.js index 3d9184c0..1498a9e0 100644 --- a/controllers/forms.js +++ b/controllers/forms.js @@ -33,6 +33,7 @@ const express = require('express') , deleteBannersController = require(__dirname+'/forms/deletebanners.js') , boardSettingsController = require(__dirname+'/forms/boardsettings.js') , transferController = require(__dirname+'/forms/transfer.js') + , resignController = require(__dirname+'/forms/resign.js') , loginController = require(__dirname+'/forms/login.js') , registerController = require(__dirname+'/forms/register.js') , changePasswordController = require(__dirname+'/forms/changepassword.js') @@ -86,6 +87,7 @@ router.post('/login', useSession, loginController); router.post('/logout', useSession, logout); router.post('/register', geoAndTor, torPreBypassCheck, processIp, useSession, sessionRefresh, verifyCaptcha, calcPerms, registerController); router.post('/changepassword', geoAndTor, torPreBypassCheck, processIp, useSession, sessionRefresh, verifyCaptcha, changePasswordController); +router.post('/resign', useSession, sessionRefresh, csrf, calcPerms, isLoggedIn, hasPerms(3), paramConverter, resignController); //removes captcha cookie, for refreshing for noscript users router.post('/newcaptcha', newCaptcha); diff --git a/controllers/forms/resign.js b/controllers/forms/resign.js new file mode 100644 index 00000000..6b92d26e --- /dev/null +++ b/controllers/forms/resign.js @@ -0,0 +1,44 @@ +'use strict'; + +const { Boards } = require(__dirname+'/../../db/') + , resignFromBoard = require(__dirname+'/../../models/forms/resign.js') + , dynamicResponse = require(__dirname+'/../../helpers/dynamic.js') + , alphaNumericRegex = require(__dirname+'/../../helpers/checks/alphanumregex.js'); + +module.exports = async (req, res, next) => { + + const errors = []; + + if (!req.body.confirm) { + errors.push('Missing confirmation'); + } + if (!req.body.board || req.body.board.length === 0) { + errors.push('You did not select a board'); + } else if (alphaNumericRegex.test(req.body.board) !== true) { + errors.push('URI must contain a-z 0-9 only'); + } else { + try { + res.locals.board = await Boards.findOne(req.body.board); + } catch (err) { + return next(err); + } + if (!res.locals.board) { + errors.push(`Board /${req.body.board}/ does not exist`); + } + } + + if (errors.length > 0) { + return dynamicResponse(req, res, 400, 'message', { + 'title': 'Bad request', + 'errors': errors, + 'redirect': `/account.html` + }) + } + + try { + await resignFromBoard(req, res, next); + } catch (err) { + return next(err); + } + +} diff --git a/controllers/forms/transfer.js b/controllers/forms/transfer.js index 01f5937c..979f29ab 100644 --- a/controllers/forms/transfer.js +++ b/controllers/forms/transfer.js @@ -18,7 +18,7 @@ module.exports = async (req, res, next) => { errors.push('New owner username must not be same as old owner'); } if (alphaNumericRegex.test(req.body.username) !== true) { - errors.push('URI must contain a-z 0-9 only'); + errors.push('Username must contain a-z 0-9 only'); } if (errors.length > 0) { @@ -26,7 +26,7 @@ module.exports = async (req, res, next) => { 'title': 'Bad request', 'errors': errors, 'redirect': `/${req.params.board}/manage/settings.html` - }) + }); } try { diff --git a/controllers/pages.js b/controllers/pages.js index ae7e2db7..dda6aba0 100644 --- a/controllers/pages.js +++ b/controllers/pages.js @@ -75,7 +75,7 @@ router.get('/bypass.html', blockBypass); //block bypass page router.get('/bypass_minimal.html', setMinimal, blockBypass); //block bypass page //accounts -router.get('/account.html', useSession, sessionRefresh, isLoggedIn, account); //page showing boards you are mod/owner of, links to password rese, logout, etc +router.get('/account.html', useSession, sessionRefresh, isLoggedIn, csrf, account); //page showing boards you are mod/owner of, links to password rese, logout, etc router.get('/login.html', login); router.get('/register.html', register); router.get('/changepassword.html', changePassword); diff --git a/models/forms/resign.js b/models/forms/resign.js new file mode 100644 index 00000000..a3ea9333 --- /dev/null +++ b/models/forms/resign.js @@ -0,0 +1,36 @@ +'use strict'; + +const { Boards, Accounts } = require(__dirname+'/../../db/') + , dynamicResponse = require(__dirname+'/../../helpers/dynamic.js'); + +module.exports = async (req, res, next) => { + + const moderatesBoard = res.locals.user.modBoards.includes(req.body.board); + const ownsBoard = res.locals.user.ownedBoards.includes(req.body.board); + if (!ownsBoard && !moderatesBoard) { + return dynamicResponse(req, res, 400, 'message', { + 'title': 'Bad request', + 'message': 'You do not own or moderate that board', + 'redirect': `/account.html` + }); + } + + if (ownsBoard) { + await Promise.all([ + Accounts.removeOwnedBoard(res.locals.user.username, req.body.board), + Boards.setOwner(req.body.board, null), + ]); + } else if (moderatesBoard) { + await Promise.all([ + Boards.removeModerator(req.body.board, res.locals.user.username), + Accounts.removeModBoard([res.locals.user.username], req.body.board), + ]); + } + + return dynamicResponse(req, res, 200, 'message', { + 'title': 'Success', + 'message': `Resigned from ${ownsBoard ? 'owner' : 'moderator'} position on /${req.body.board}/`, + 'redirect': `/account.html` + }); + +} diff --git a/models/pages/account.js b/models/pages/account.js index 4d9506c9..51a7c3c3 100644 --- a/models/pages/account.js +++ b/models/pages/account.js @@ -5,6 +5,7 @@ module.exports = async (req, res, next) => { res .set('Cache-Control', 'private, max-age=5') .render('account', { + csrf: req.csrfToken(), user: res.locals.user, }); diff --git a/views/pages/account.pug b/views/pages/account.pug index f8be50ac..b797b589 100644 --- a/views/pages/account.pug +++ b/views/pages/account.pug @@ -66,3 +66,23 @@ block content a(href=`/${b}/manage/logs.html`) Logs else p None + hr(size=1) + h4.no-m-p Resign from a staff position: + .form-wrapper.flexleft.mt-10 + form.form-post(action=`/forms/resign`, enctype='application/x-www-form-urlencoded', method='POST') + input(type='hidden' name='_csrf' value=csrf) + .row + .label Boards + select(name='board' size='5') + optgroup(label='You own') + each board in user.ownedBoards + option(value=board) #{board} + optgroup(label='You moderate') + each board in user.modBoards + option(value=board) #{board} + .row + .label I'm sure + label.postform-style.ph-5 + input(type='checkbox', name='confirm', value='true' required) + input(type='submit', value='submit') +