scuffed bans. todo: custom duration, expiry in DB, show banned post

merge-requests/208/head
fatchan 5 years ago
parent cbc7135c90
commit e823cad14e
  1. 193
      controllers/forms.js
  2. 29
      db-models/bans.js
  3. 22
      helpers/bancheck.js
  4. 52
      models/forms/ban-poster.js
  5. 49
      models/forms/delete-post.js
  6. 28
      models/forms/dismiss-report.js
  7. 26
      models/forms/edit-post.js
  8. 2
      models/forms/make-post.js
  9. 15
      models/forms/report-post.js
  10. 62
      models/forms/spoiler-post.js
  11. 11
      views/pages/manage.pug
  12. 4
      views/pages/message.pug
  13. 3
      wipe.js

@ -5,92 +5,95 @@ const express = require('express')
, Boards = require(__dirname+'/../db-models/boards.js')
, Posts = require(__dirname+'/../db-models/posts.js')
, Trips = require(__dirname+'/../db-models/trips.js')
, Bans = require(__dirname+'/../db-models/bans.js')
, banPoster = require(__dirname+'/../models/forms/ban-poster.js')
, makePost = require(__dirname+'/../models/forms/make-post.js')
, deletePosts = require(__dirname+'/../models/forms/delete-post.js')
, spoilerPosts = require(__dirname+'/../models/forms/spoiler-post.js')
, reportPosts = require(__dirname+'/../models/forms/report-post.js')
, dismissReports = require(__dirname+'/../models/forms/dismiss-report.js')
, loginAccount = require(__dirname+'/../models/forms/login.js')
, registerAccount = require(__dirname+'/../models/forms/register.js')
, numberConverter = require(__dirname+'/../helpers/number-converter.js');
, registerAccount = require(__dirname+'/../models/forms/register.js')
, numberConverter = require(__dirname+'/../helpers/number-converter.js')
, banCheck = require(__dirname+'/../helpers/bancheck.js');
// login to account
router.post('/login', (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'
})
}
loginAccount(req, res);
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'
})
}
loginAccount(req, res);
});
//register account
router.post('/register', (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 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.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'
})
}
registerAccount(req, res);
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 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.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'
})
}
registerAccount(req, res);
});
// make new post
router.post('/board/:board', Boards.exists, numberConverter, (req, res, next) => {
router.post('/board/:board', Boards.exists, banCheck, numberConverter, async (req, res, next) => {
let numFiles = 0;
if (req.files && req.files.file) {
@ -139,7 +142,7 @@ router.post('/board/:board', Boards.exists, numberConverter, (req, res, next) =>
});
//report, delete, sticky, etc
router.post('/board/:board/posts', Boards.exists, numberConverter, (req, res, next) => {
router.post('/board/:board/posts', Boards.exists, banCheck, numberConverter, async (req, res, next) => {
const errors = [];
@ -152,12 +155,20 @@ router.post('/board/:board/posts', Boards.exists, numberConverter, (req, res, ne
if (req.body.reason && req.body.reason.length > 50) {
errors.push('Report must be 50 characters or less');
}
if (!(req.body.report || req.body.delete || req.body.dismiss || req.body.spoiler)) {
if (!(req.body.report
|| req.body.delete
|| req.body.dismiss
|| req.body.spoiler
|| req.body.ban
|| req.body.global_ban)) {
errors.push('Must select an action')
}
if (req.body.report && (!req.body.reason || req.body.reason.length === 0)) {
errors.push('Reports must have a reason')
}
if ((req.body.ban || req.body.global_ban) && (!req.body.reason || req.body.reason.length === 0)) {
errors.push('Bans must have a reason')
}
if (errors.length > 0) {
return res.status(400).render('message', {
@ -167,16 +178,46 @@ router.post('/board/:board/posts', Boards.exists, numberConverter, (req, res, ne
})
}
if (req.body.report) {
reportPosts(req, res);
} else if (req.body.delete) {
deletePosts(req, res);
} else if (req.body.spoiler) {
spoilerPosts(req, res);
} else if (req.body.dismiss) {
dismissReports(req, res);
const messages = [];
try {
//TODO: maybe fetch the posts first instead of checking multiple times with multiple actions
//global or board ban
if (req.body.global_ban) {
messages.push((await banPoster(req, res, null)));
} else if (req.body.ban) {
messages.push((await banPoster(req, res, req.params.board)));
}
// then if not deleting, we can spoiler and report or dismiss reports
if (req.body.delete) {
messages.push((await deletePosts(req, res)));
} else {
if (req.body.spoiler) {
messages.push((await spoilerPosts(req, res)));
}
if (req.body.report) {
messages.push((await reportPosts(req, res)));
} else if (req.body.dismiss) {
messages.push((await dismissReports(req, res)));
}
}
} catch (err) {
if (err.status) {
return res.status(err.status).render('message', err.message);
}
console.error(err);
return res.status(500).render('error');
}
return res.render('message', {
'title': 'Success',
'messages': messages,
'redirect': `/${req.params.board}`
});
});

@ -0,0 +1,29 @@
'use strict';
const Mongo = require(__dirname+'/../helpers/db.js')
, db = Mongo.client.db('jschan').collection('bans');
module.exports = {
find: (ip, board) => {
return db.find({
'ip': ip,
'board': {
'$in': [board, null]
}
}).toArray();
},
insertOne: (ban) => {
return db.insertOne(ban);
},
insertMany: (bans) => {
return db.insertMany(bans);
},
deleteAll: () => {
return db.deleteMany({});
},
}

@ -0,0 +1,22 @@
'use strict';
const Bans = require(__dirname+'/../db-models/bans.js')
, hasPerms = require(__dirname+'/has-perms.js');
module.exports = async (req, res, next) => {
if (!hasPerms(req, res)) {
const ip = req.headers['x-real-ip'] || req.connection.remoteAddress;
const bans = await Bans.find(ip, res.locals.board._id);
if (bans && bans.length > 0) {
//TODO: show posts banned for, expiry, etc
return res.status(403).render('message', {
'title': 'Forbidden',
'message': 'You are banned',
'redirect': '/'
});
}
}
next();
}

@ -0,0 +1,52 @@
'use strict';
const uploadDirectory = require(__dirname+'/../../helpers/uploadDirectory.js')
, hasPerms = require(__dirname+'/../../helpers/has-perms.js')
, Bans = require(__dirname+'/../../db-models/bans.js')
, Posts = require(__dirname+'/../../db-models/posts.js');
module.exports = async (req, res, board) => {
//if user is not logged in or if logged in but not authed, they cannot ban
if (!hasPerms(req, res)) {
throw {
'status': 403,
'message': {
'title': 'Forbidden',
'message': 'You do not have permission to issue bans',
'redirect': `/${req.params.board}`
}
};
}
//get all posts that were checked
let posts = await Posts.getPosts(req.params.board, req.body.checked, true); //admin arument true, fetches passwords and salts
if (!posts || posts.length === 0) {
throw {
'status': 400,
'message': {
'title': 'Bad requests',
'message': 'No posts found',
'redirect': `/${req.params.board}`
}
};
}
const bans = posts.map(post => {
return {
'ip': post.ip,
'board': board,
'post': post,
'issuer': req.session.user.username
}
});
let bannedIps = 0;
const result = await Bans.insertMany(bans, board);
console.log(result)
bannedIps = result.insertedCount;
return `Banned ${bannedIps} ips`;
}

@ -11,20 +11,17 @@ const path = require('path')
module.exports = async (req, res) => {
//get all posts that were checked
let posts;
try {
posts = await Posts.getPosts(req.params.board, req.body.checked, true); //admin arument true, fetches passwords and salts
} catch (err) {
console.error(err);
return res.status(500).render('error');
}
let posts = await Posts.getPosts(req.params.board, req.body.checked, true); //admin arument true, fetches passwords and salts
if (!posts || posts.length === 0) {
return res.status(400).render('message', {
'title': 'Bad requests',
'message': 'No posts found',
'redirect': `/${req.params.board}`
});
throw {
'status': 400,
'message': {
'title': 'Bad request',
'message': 'No posts found',
'redirect': `/${req.params.board}`
}
};
}
//if user is not logged in OR if lgoged in but not authed, filter the posts by passwords that are not null
@ -37,11 +34,14 @@ module.exports = async (req, res) => {
&& post.password == req.body.password
});
if (posts.length === 0) {
return res.status(403).render('message', {
'title': 'Forbidden',
'message': 'Password did not match any selected posts',
'redirect': `/${req.params.board}`
});
throw {
'status': 403,
'message': {
'title': 'Forbidden',
'message': 'Password did not match any selected posts',
'redirect': `/${req.params.board}`
}
};
}
}
@ -60,13 +60,8 @@ module.exports = async (req, res) => {
//delete posts from DB
let deletedPosts = 0;
try {
const result = await Posts.deleteMany(req.params.board, allPosts.map(x => x.postId));
deletedPosts = result.deletedCount;
} catch (err) {
console.error(err);
return res.status(500).render('error');
}
const result = await Posts.deleteMany(req.params.board, allPosts.map(x => x.postId));
deletedPosts = result.deletedCount;
//get filenames from all the posts
let fileNames = [];
@ -84,10 +79,6 @@ module.exports = async (req, res) => {
}));
//hooray!
return res.render('message', {
'title': 'Success',
'message': `Deleted ${threadIds.length} threads and ${deletedPosts} posts`,
'redirect': `/${req.params.board}`
});
return `Deleted ${threadIds.length} threads and ${deletedPosts} posts`
}

@ -6,26 +6,18 @@ const Posts = require(__dirname+'/../../db-models/posts.js')
module.exports = async (req, res) => {
if (!hasPerms(req, res)) {
return res.status(403).render('message', {
'title': 'Forbidden',
'message': `You are not authorised to dismiss reports.`,
'redirect': `/${req.params.board}`
});
throw {
'status': 403,
'message': {
'title': 'Forbidden',
'message': `You are not authorised to dismiss reports.`,
'redirect': `/${req.params.board}`
}
};
}
try {
//dismiss reports from all checked posts
await Posts.dismissReports(req.params.board, req.body.checked);
} catch (err) {
console.error(err);
return res.status(500).render('error');
}
await Posts.dismissReports(req.params.board, req.body.checked);
//hooray!
return res.render('message', {
'title': 'Success',
'message': `Dismissed report(s) successfully`,
'redirect': `/${req.params.board}/manage`
});
return `Dismissed report(s) successfully`
}

@ -7,19 +7,17 @@ const uuidv4 = require('uuid/v4')
module.exports = async (req, res, numFiles) => {
// get the post that we are trying to edit
let post;
try {
post = await Posts.getPost(req.params.board, req.body.id, true);
} catch (err) {
console.error(err);
return res.status(500).render('error');
}
let post = await Posts.getPost(req.params.board, req.body.id, true);
if (!thread || thread.thread != null) {
return res.status(400).render('message', {
'title': 'Bad request',
'message': 'Post does not exist.',
'redirect': redirect
});
throw {
'status': 400,
'message': {
'title': 'Bad request',
'message': 'Post does not exist.',
'redirect': redirect
}
};
}
// sticky, lock, sage, spoiler, etc
@ -27,8 +25,6 @@ module.exports = async (req, res, numFiles) => {
//TODO
}
const post = await Posts.updateOne(req.params.board, data)
const successRedirect = `/${req.params.board}/thread/${req.body.thread || post.insertedId}`;
return ``;
return res.redirect(successRedirect);
}

@ -178,7 +178,7 @@ module.exports = async (req, res, numFiles) => {
return res.status(500).render('error');
}
const successRedirect = `/${req.params.board}/thread/${req.body.thread || postId}`;
const successRedirect = `/${req.params.board}/thread/${req.body.thread || postId}#${postId}`;
return res.redirect(successRedirect);
}

@ -11,19 +11,10 @@ module.exports = async (req, res) => {
'ip': ip
}
try {
//push the report to all checked posts
await Posts.reportMany(req.params.board, req.body.checked, report);
} catch (err) {
console.error(err);
return res.status(500).render('error');
}
//push the report to all checked posts
await Posts.reportMany(req.params.board, req.body.checked, report);
//hooray!
return res.render('message', {
'title': 'Success',
'message': `Reported post(s) successfully`,
'redirect': `/${req.params.board}`
});
return `Reported post(s) successfully`
}

@ -11,20 +11,17 @@ const path = require('path')
module.exports = async (req, res) => {
//get all posts that were checked
let posts;
try {
posts = await Posts.getPosts(req.params.board, req.body.checked, true); //admin arument true, fetches passwords and salts
} catch (err) {
console.error(err);
return res.status(500).render('error');
}
let posts = await Posts.getPosts(req.params.board, req.body.checked, true); //admin arument true, fetches passwords and salts
if (!posts || posts.length === 0) {
return res.status(400).render('message', {
'title': 'Bad requests',
'message': 'No posts found',
'redirect': `/${req.params.board}`
});
throw {
'status': 400,
'message': {
'title': 'Bad requests',
'message': 'No posts found',
'redirect': `/${req.params.board}`
}
};
}
//if user is not logged in OR if lgoged in but not authed, filter the posts by passwords that are not null
@ -37,11 +34,14 @@ module.exports = async (req, res) => {
&& post.password == req.body.password
});
if (posts.length === 0) {
return res.status(403).render('message', {
'title': 'Forbidden',
'message': 'Password did not match any selected posts',
'redirect': `/${req.params.board}`
});
throw {
'status': 403,
'message': {
'title': 'Forbidden',
'message': 'Password did not match any selected posts',
'redirect': `/${req.params.board}`
}
};
}
}
@ -51,28 +51,22 @@ module.exports = async (req, res) => {
return !post.spoiler
});
if (posts.length === 0) {
return res.status(409).render('message', {
'title': 'Conflict',
'message': 'Selected posts are already spoilered',
'redirect': `/${req.params.board}`
});
throw {
'status': 409,
'message': {
'title': 'Conflict',
'message': 'Posts already spoilered',
'redirect': `/${req.params.board}`
}
};
}
// spoiler posts
let spoileredPosts = 0;
try {
const result = await Posts.spoilerMany(req.params.board, posts.map(x => x.postId));
spoileredPosts = result.modifiedCount;
} catch (err) {
console.error(err);
return res.status(500).render('error');
}
const result = await Posts.spoilerMany(req.params.board, posts.map(x => x.postId));
spoileredPosts = result.modifiedCount;
//hooray!
return res.render('message', {
'title': 'Success',
'message': `Spoilered ${spoileredPosts} posts`,
'redirect': `/${req.params.board}`
});
return `Spoilered ${spoileredPosts} posts`
}

@ -2,7 +2,7 @@ extends ../layout.pug
include ../mixins/post.pug
block head
title Login
title Manage
block content
include ../includes/boardheader.pug
@ -28,8 +28,13 @@ block content
| Spoiler
span
label
input.post-check(type='checkbox', name='dismiss' value=1)
| Dismiss
input.post-check(type='checkbox', name='ban' value=1)
| Ban
label
input.post-check(type='checkbox', name='global_ban' value=1)
| Global Ban
label
input#report(type='text', name='reason', placeholder='ban reason' autocomplete='off')
input(type='submit', value='submit')

@ -7,6 +7,10 @@ block content
h1 #{title}
if message
blockquote #{message}
if messages
ul
each msg in messages
li #{msg}
if errors
ul
each error in errors

@ -12,6 +12,7 @@ const Mongo = require(__dirname+'/helpers/db.js')
await Mongo.connect();
const Boards = require(__dirname+'/db-models/boards.js')
, Posts = require(__dirname+'/db-models/posts.js')
, Bans = require(__dirname+'/db-models/bans.js')
, Trips = require(__dirname+'/db-models/trips.js')
, Accounts = require(__dirname+'/db-models/accounts.js');
console.log('deleting accounts')
@ -24,6 +25,8 @@ const Mongo = require(__dirname+'/helpers/db.js')
await Boards.deleteIncrement('b');
await Boards.deleteAll();
await Trips.deleteAll();
console.log('deleting bans');
await Bans.deleteAll();
console.log('adding b and pol')
await Boards.insertOne({
_id: 'pol',

Loading…
Cancel
Save