Beta testing .onion support

***DO NOT USE***

This still has some issues and needs testing.
- needs updated nginx configs added, expects "TOR" in the x-country-code header under a separate vhost
- need to make sure bans work properly still
- need to implement system to prevent captcha ddos, since i cant just to IP ratelimit now
- im 99% sure post history of tor users is broken if viewed by non-global staff
- manual input ban form will also be broken for non-global staff
- could still use some improvement on the middleware having a little more complicated flor for tor users

But for the most part it works. Basically it will use the bypass id of a tor user as their "ip".
merge-requests/208/head
Thomas Lynch 4 years ago
parent ad2c1e030e
commit b0797f0418
  1. 2
      configs/main.js.example
  2. 81
      controllers/forms.js
  3. 4
      controllers/forms/boardsettings.js
  4. 4
      controllers/forms/editpost.js
  5. 8
      db/ratelimits.js
  6. 774
      gulp/res/css/style.css
  7. BIN
      gulp/res/img/flags.png
  8. 7
      helpers/captcha/captchaverify.js
  9. 9
      helpers/checks/blockbypass.js
  10. 1
      helpers/checks/dnsbl.js
  11. 82
      helpers/checks/torprebypass.js
  12. 4
      helpers/countries.js
  13. 65
      helpers/filemiddlewares.js
  14. 14
      helpers/geoip.js
  15. 17
      helpers/processip.js
  16. 4
      helpers/usesession.js
  17. 23
      models/forms/blockbypass.js
  18. 23
      models/forms/makepost.js
  19. 8
      models/pages/captcha.js
  20. 5
      server.js

@ -14,7 +14,7 @@ module.exports = {
port: 7000,
//secrets/salts for various things
sessionSecret: 'long random string',
cookieSecret: 'long random string',
tripcodeSecret: 'long random string',
ipHashSecret: 'long random string',
postPasswordSecret: 'long random string',

@ -3,8 +3,9 @@
const express = require('express')
, router = express.Router()
, Boards = require(__dirname+'/../db/boards.js')
, { globalLimits, debugLogs, filterFileNames, spaceFileNameReplacement } = require(__dirname+'/../configs/main.js')
//middlewares
, torPreBypassCheck = require(__dirname+'/../helpers/checks/torprebypass.js')
, geoAndTor = require(__dirname+'/../helpers/geoip.js')
, processIp = require(__dirname+'/../helpers/processip.js')
, calcPerms = require(__dirname+'/../helpers/checks/calcpermsmiddleware.js')
, hasPerms = require(__dirname+'/../helpers/checks/haspermsmiddleware.js')
@ -18,45 +19,7 @@ const express = require('express')
, sessionRefresh = require(__dirname+'/../helpers/sessionrefresh.js')
, dnsblCheck = require(__dirname+'/../helpers/checks/dnsbl.js')
, blockBypassCheck = require(__dirname+'/../helpers/checks/blockbypass.js')
, dynamicResponse = require(__dirname+'/../helpers/dynamic.js')
, uploadLimitFunction = (req, res, next) => {
return dynamicResponse(req, res, 413, 'message', {
'title': 'Payload Too Large',
'message': 'Your upload was too large',
'redirect': req.headers.referer
});
}
, upload = require('express-fileupload')
, postFiles = upload({
debug: debugLogs,
createParentPath: true,
safeFileNames: filterFileNames,
spaceFileNameReplacement,
preserveExtension: 4,
limits: {
totalSize: globalLimits.postFilesSize.max,
fileSize: globalLimits.postFilesSize.max,
//files: globalLimits.postFiles.max
},
limitHandler: uploadLimitFunction,
useTempFiles: true,
tempFileDir: __dirname+'/../tmp/'
})
, bannerFiles = upload({
debug: debugLogs,
createParentPath: true,
safeFileNames: filterFileNames,
spaceFileNameReplacement,
preserveExtension: 4,
limits: {
totalSize: globalLimits.bannerFilesSize.max,
fileSize: globalLimits.bannerFilesSize.max,
files: globalLimits.bannerFiles.max
},
limitHandler: uploadLimitFunction,
useTempFiles: true,
tempFileDir: __dirname+'/../tmp/'
})
, { handleBannerFiles, handlePostFilesEarlyTor, handlePostFiles } = require(__dirname+'/../helpers/filemiddlewares.js')
//controllers
, deleteBoardController = require(__dirname+'/forms/deleteboard.js')
, editBansController = require(__dirname+'/forms/editbans.js')
@ -83,32 +46,32 @@ const express = require('express')
, logout = require(__dirname+'/../models/forms/logout.js');
//make new post
router.post('/board/:board/post', processIp, useSession, sessionRefresh, Boards.exists, calcPerms, banCheck, postFiles,
router.post('/board/:board/post', geoAndTor, handlePostFilesEarlyTor, torPreBypassCheck, processIp, useSession, sessionRefresh, Boards.exists, calcPerms, banCheck, handlePostFiles,
paramConverter, verifyCaptcha, numFiles, blockBypassCheck, dnsblCheck, makePostController);
router.post('/board/:board/modpost', processIp, useSession, sessionRefresh, Boards.exists, calcPerms, banCheck, isLoggedIn, hasPerms(3), postFiles,
router.post('/board/:board/modpost', geoAndTor, handlePostFilesEarlyTor, torPreBypassCheck, processIp, useSession, sessionRefresh, Boards.exists, calcPerms, banCheck, isLoggedIn, hasPerms(3), handlePostFiles,
paramConverter, csrf, numFiles, blockBypassCheck, dnsblCheck, makePostController); //mod post has token instead of captcha
//post actions
router.post('/board/:board/actions', processIp, useSession, sessionRefresh, Boards.exists, calcPerms, banCheck, paramConverter, verifyCaptcha, actionController); //public, with captcha
router.post('/board/:board/modactions', processIp, useSession, sessionRefresh, csrf, Boards.exists, calcPerms, banCheck, isLoggedIn, hasPerms(3), paramConverter, actionController); //board manage page
router.post('/global/actions', processIp, useSession, sessionRefresh, csrf, calcPerms, isLoggedIn, hasPerms(1), paramConverter, globalActionController); //global manage page
router.post('/board/:board/actions', geoAndTor, torPreBypassCheck, processIp, useSession, sessionRefresh, Boards.exists, calcPerms, banCheck, paramConverter, verifyCaptcha, actionController); //public, with captcha
router.post('/board/:board/modactions', geoAndTor, torPreBypassCheck, processIp, useSession, sessionRefresh, csrf, Boards.exists, calcPerms, banCheck, isLoggedIn, hasPerms(3), paramConverter, actionController); //board manage page
router.post('/global/actions', geoAndTor, torPreBypassCheck, processIp, useSession, sessionRefresh, csrf, calcPerms, isLoggedIn, hasPerms(1), paramConverter, globalActionController); //global manage page
//appeal ban
router.post('/appeal', processIp, useSession, sessionRefresh, paramConverter, verifyCaptcha, appealController);
router.post('/appeal', geoAndTor, torPreBypassCheck, processIp, useSession, sessionRefresh, paramConverter, verifyCaptcha, appealController);
//edit post
router.post('/editpost', processIp, useSession, sessionRefresh, csrf, paramConverter, Boards.bodyExists, calcPerms, hasPerms(3), editPostController);
router.post('/editpost', geoAndTor, torPreBypassCheck, processIp, useSession, sessionRefresh, csrf, paramConverter, Boards.bodyExists, calcPerms, hasPerms(3), editPostController);
//board management forms
router.post('/board/:board/transfer', processIp, useSession, sessionRefresh, csrf, Boards.exists, calcPerms, banCheck, isLoggedIn, hasPerms(2), paramConverter, transferController);
router.post('/board/:board/settings', processIp, useSession, sessionRefresh, csrf, Boards.exists, calcPerms, banCheck, isLoggedIn, hasPerms(2), paramConverter, boardSettingsController);
router.post('/board/:board/addbanners', processIp, useSession, sessionRefresh, bannerFiles, csrf, Boards.exists, calcPerms, banCheck, isLoggedIn, hasPerms(2), paramConverter, numFiles, uploadBannersController); //add banners
router.post('/board/:board/deletebanners', processIp, useSession, sessionRefresh, csrf, Boards.exists, calcPerms, banCheck, isLoggedIn, hasPerms(2), paramConverter, deleteBannersController); //delete banners
router.post('/board/:board/addban', processIp, useSession, sessionRefresh, csrf, Boards.exists, calcPerms, banCheck, isLoggedIn, hasPerms(3), paramConverter, addBanController); //add ban manually without post
router.post('/board/:board/editbans', processIp, useSession, sessionRefresh, csrf, Boards.exists, calcPerms, banCheck, isLoggedIn, hasPerms(3), paramConverter, editBansController); //edit bans
router.post('/board/:board/deleteboard', processIp, useSession, sessionRefresh, csrf, Boards.exists, calcPerms, banCheck, isLoggedIn, hasPerms(2), deleteBoardController); //delete board
router.post('/board/:board/transfer', /*geoAndTor, torPreBypassCheck, processIp,*/ useSession, sessionRefresh, csrf, Boards.exists, calcPerms, isLoggedIn, hasPerms(2), paramConverter, transferController);
router.post('/board/:board/settings', /*geoAndTor, torPreBypassCheck, processIp,*/ useSession, sessionRefresh, csrf, Boards.exists, calcPerms, isLoggedIn, hasPerms(2), paramConverter, boardSettingsController);
router.post('/board/:board/addbanners', /*geoAndTor, torPreBypassCheck, processIp,*/ useSession, sessionRefresh, handleBannerFiles, csrf, Boards.exists, calcPerms, isLoggedIn, hasPerms(2), paramConverter, numFiles, uploadBannersController); //add banners
router.post('/board/:board/deletebanners', /*geoAndTor, torPreBypassCheck, processIp,*/ useSession, sessionRefresh, csrf, Boards.exists, calcPerms, isLoggedIn, hasPerms(2), paramConverter, deleteBannersController); //delete banners
router.post('/board/:board/addban', geoAndTor, torPreBypassCheck, processIp, useSession, sessionRefresh, csrf, Boards.exists, calcPerms, isLoggedIn, hasPerms(3), paramConverter, addBanController); //add ban manually without post
router.post('/board/:board/editbans', /*geoAndTor, torPreBypassCheck, processIp,*/ useSession, sessionRefresh, csrf, Boards.exists, calcPerms, isLoggedIn, hasPerms(3), paramConverter, editBansController); //edit bans
router.post('/board/:board/deleteboard', /*geoAndTor, torPreBypassCheck, processIp,*/ useSession, sessionRefresh, csrf, Boards.exists, calcPerms, isLoggedIn, hasPerms(2), deleteBoardController); //delete board
//global management forms
router.post('/global/editbans', useSession, sessionRefresh, csrf, calcPerms, isLoggedIn, hasPerms(1), paramConverter, editBansController); //remove bans
router.post('/global/addban', processIp, useSession, sessionRefresh, csrf, calcPerms, isLoggedIn, hasPerms(1), paramConverter, addBanController); //add ban manually without post
router.post('/global/addban', geoAndTor, torPreBypassCheck, processIp, useSession, sessionRefresh, csrf, calcPerms, isLoggedIn, hasPerms(1), paramConverter, addBanController); //add ban manually without post
router.post('/global/deleteboard', useSession, sessionRefresh, csrf, paramConverter, calcPerms, isLoggedIn, hasPerms(1), deleteBoardController); //delete board
router.post('/global/addnews', useSession, sessionRefresh, csrf, calcPerms, isLoggedIn, hasPerms(0), addNewsController); //add new newspost
router.post('/global/deletenews', useSession, sessionRefresh, csrf, calcPerms, isLoggedIn, hasPerms(0), paramConverter, deleteNewsController); //delete news
@ -116,17 +79,17 @@ router.post('/global/editaccounts', useSession, sessionRefresh, csrf, calcPerms,
router.post('/global/settings', useSession, sessionRefresh, csrf, calcPerms, isLoggedIn, hasPerms(0), paramConverter, globalSettingsController); //global settings
//create board
router.post('/create', processIp, useSession, sessionRefresh, isLoggedIn, verifyCaptcha, calcPerms, hasPerms(4), createBoardController);
router.post('/create', /*geoAndTor, torPreBypassCheck, processIp,*/ useSession, sessionRefresh, isLoggedIn, verifyCaptcha, calcPerms, hasPerms(4), createBoardController);
//accounts
router.post('/login', useSession, loginController);
router.post('/logout', useSession, logout);
router.post('/register', processIp, useSession, sessionRefresh, verifyCaptcha, calcPerms, registerController);
router.post('/changepassword', processIp, useSession, sessionRefresh, verifyCaptcha, changePasswordController);
router.post('/register', /*geoAndTor, torPreBypassCheck, processIp,*/ useSession, sessionRefresh, verifyCaptcha, calcPerms, registerController);
router.post('/changepassword', /*geoAndTor, torPreBypassCheck, processIp,*/ useSession, sessionRefresh, verifyCaptcha, changePasswordController);
//removes captcha cookie, for refreshing for noscript users
router.post('/newcaptcha', newCaptcha);
//solve captcha for block bypass
router.post('/blockbypass', processIp, verifyCaptcha, blockBypass);
router.post('/blockbypass', geoAndTor, /*torPreBypassCheck, processIp, */ verifyCaptcha, blockBypass);
module.exports = router;

@ -136,8 +136,8 @@ module.exports = async (req, res, next) => {
if (res.locals.permLevel > 1) { //if not global staff or above
const ratelimitBoard = await Ratelimits.incrmentQuota(req.params.board, 'settings', rateLimitCost.boardSettings); //2 changes a minute
const ratelimitIp = await Ratelimits.incrmentQuota(res.locals.ip.single, 'settings', rateLimitCost.boardSettings);
if (ratelimitBoard > 100 || ratelimitIp > 100) {
// const ratelimitIp = await Ratelimits.incrmentQuota(res.locals.ip.single, 'settings', rateLimitCost.boardSettings);
if (ratelimitBoard > 100 /* || ratelimitIp > 100 */) {
return dynamicResponse(req, res, 429, 'message', {
'title': 'Ratelimited',
'error': 'You are changing settings too quickly, please wait a minute and try again',

@ -49,8 +49,8 @@ module.exports = async (req, res, next) => {
if (res.locals.permLevel > 1) { //if not global staff or above
const ratelimitUser = await Ratelimits.incrmentQuota(req.session.user, 'edit', rateLimitCost.editPost);
const ratelimitIp = await Ratelimits.incrmentQuota(res.locals.ip.single, 'edit', rateLimitCost.editPost);
if (ratelimitUser > 100 || ratelimitIp > 100) {
// const ratelimitIp = await Ratelimits.incrmentQuota(res.locals.ip.single, 'edit', rateLimitCost.editPost);
if (ratelimitUser > 100 /* || ratelimitIp > 100 */) {
return dynamicResponse(req, res, 429, 'message', {
'title': 'Ratelimited',
'error': 'You are editing posts too quickly, please wait a minute and try again',

@ -7,14 +7,14 @@ module.exports = {
db,
resetQuota: (id, suffix) => {
return db.deleteOne({ '_id': `${id}-${suffix}` });
resetQuota: (identifier, action) => {
return db.deleteOne({ '_id': `${identifier}-${action}` });
},
incrmentQuota: (ip, suffix, amount) => {
incrmentQuota: (identifier, action, amount) => {
return db.findOneAndUpdate(
{
'_id': `${ip}-${suffix}`
'_id': `${identifier}-${action}`
},
{
'$inc': {

File diff suppressed because one or more lines are too long

Binary file not shown.

Before

Width:  |  Height:  |  Size: 79 KiB

After

Width:  |  Height:  |  Size: 102 KiB

@ -11,6 +11,11 @@ module.exports = async (req, res, next) => {
const isBypass = req.path === '/blockbypass';
//already solved in pre stage for getting bypassID for "ip"
if (res.locals.tor && res.locals.solvedCaptcha) {
return next();
}
//skip captcha if disabled on board for posts only
if (res.locals.board
&& req.path === `/board/${res.locals.board._id}/post`) {
@ -83,7 +88,7 @@ module.exports = async (req, res, next) => {
res.locals.solvedCaptcha = true;
res.clearCookie('captchaid');
await Promise.all([
Ratelimits.resetQuota(res.locals.ip.single, 'captcha'),
!res.locals.tor && Ratelimits.resetQuota(res.locals.ip.single, 'captcha'),
remove(`${uploadDirectory}/captcha/${captchaId}.jpg`)
]);

@ -9,17 +9,17 @@ const { Bypass } = require(__dirname+'/../../db/')
module.exports = async (req, res, next) => {
if (!blockBypass.enabled) {
if (!blockBypass.enabled && !res.locals.tor) { //for now, tor MUST solve a bypass
return next();
}
//check if blockbypass exists and right length
const bypassId = req.cookies.bypassid;
const bypassId = req.signedCookies.bypassid;
if (!res.locals.solvedCaptcha && (!bypassId || bypassId.length !== 24)) {
deleteTempFiles(req).catch(e => console.error);
return dynamicResponse(req, res, 403, 'message', {
'title': 'Forbidden',
'message': 'Please complete a block bypass to post',
'message': 'Please complete a block bypass to continue',
'frame': '/bypass_minimal.html',
'link': {
'href': '/bypass.html',
@ -52,7 +52,8 @@ module.exports = async (req, res, next) => {
res.cookie('bypassid', newBypassId.toString(), {
'maxAge': blockBypass.expireAfterTime,
'secure': production && secureCookies,
'sameSite': 'strict'
'sameSite': 'strict',
'signed': true
});
return next();
}

@ -9,6 +9,7 @@ const cache = require(__dirname+'/../../redis.js')
module.exports = async (req, res, next) => {
if (dnsbl.enabled && dnsbl.blacklists.length > 0 //if dnsbl enabled and has more than 0 blacklists
&& !res.locals.tor //tor cant be dnsbl'd
&& (!res.locals.blockBypass || !blockBypass.bypassDnsbl)) { //and there is no valid block bypass, or they do not bypass dnsbl
const ip = req.headers[ipHeader] || req.connection.remoteAddress;
let isBlacklisted = await cache.get(`blacklisted:${ip}`);

@ -0,0 +1,82 @@
'use strict';
const { Bypass, Captchas } = require(__dirname+'/../../db/')
, { ObjectId } = require(__dirname+'/../../db/db.js')
, { secureCookies, blockBypass } = require(__dirname+'/../../configs/main.js')
, remove = require('fs-extra').remove
, uploadDirectory = require(__dirname+'/../files/uploadDirectory.js')
, dynamicResponse = require(__dirname+'/../dynamic.js')
, production = process.env.NODE_ENV === 'production';
module.exports = async (req, res, next) => {
console.log('TOR PRE BYPASS')
//early byapss is only needed for tor users
if (!res.locals.tor) {
return next();
}
//for captcha in existing form (NOTE: wont work for multipart forms yet)
const input = req.body.captcha;
if (input && input.length !== 6) {
return dynamicResponse(req, res, 403, 'message', {
'title': 'Forbidden',
'message': 'Incorrect captcha answer',
'redirect': req.headers.referer,
});
}
const captchaId = req.cookies.captchaid;
if (input) {
// try to get the captcha from the DB
let captcha;
try {
const captchaMongoId = ObjectId(captchaId);
captcha = await Captchas.findOneAndDelete(captchaMongoId, input);
} catch (err) {
return next(err);
}
if (captcha && captcha.value && captcha.value.text === input) {
res.locals.solvedCaptcha = true;
res.clearCookie('captchaid');
remove(`${uploadDirectory}/captcha/${captchaId}.jpg`).catch(e => { console.error(e) });
} else {
return dynamicResponse(req, res, 403, 'message', {
'title': 'Forbidden',
'message': 'Incorrect captcha answer',
'redirect': req.headers.referer,
});
}
}
if (res.locals.solvedCaptcha) {
//they dont have a valid bypass, but just solved a captcha, so give them a new one
const newBypass = await Bypass.getBypass();
const newBypassId = newBypass.insertedId;
res.locals.blockBypass = newBypass.ops[0];
res.cookie('bypassid', newBypassId.toString(), {
'maxAge': blockBypass.expireAfterTime,
'secure': production && secureCookies,
'sameSite': 'strict',
'signed': true
});
return next();
}
//check if blockbypass exists and right length
const bypassId = req.signedCookies.bypassid;
if (!bypassId || bypassId.length !== 24) {
return dynamicResponse(req, res, 403, 'message', {
'title': 'Forbidden',
'message': 'Please complete a block bypass to continue',
'frame': '/bypass_minimal.html',
'link': {
'href': '/bypass.html',
'text': 'Get block bypass',
},
});
}
console.log('in tor pre bypass', bypassId)
return next();
}

@ -2,10 +2,12 @@
const countries = require('i18n-iso-countries')
, countryNamesMap = countries.getNames('en')
, countryCodes = Object.keys(countryNamesMap);
, countryCodes = ['XX', 'T1', 'TOR']
.concat(Object.keys(countryNamesMap));
countryNamesMap['XX'] = 'Unknown';
countryNamesMap['T1'] = 'Tor Exit Node';
countryNamesMap['TOR'] = 'Tor Onion';
module.exports = {
countryNamesMap,

@ -0,0 +1,65 @@
'use strict';
const { globalLimits, debugLogs, filterFileNames, spaceFileNameReplacement } = require(__dirname+'/../configs/main.js')
, dynamicResponse = require(__dirname+'/dynamic.js')
, uploadLimitFunction = (req, res, next) => {
return dynamicResponse(req, res, 413, 'message', {
'title': 'Payload Too Large',
'message': 'Your upload was too large',
'redirect': req.headers.referer
});
}
, upload = require('express-fileupload')
, postFiles = upload({
debug: debugLogs,
createParentPath: true,
safeFileNames: filterFileNames,
spaceFileNameReplacement,
preserveExtension: 4,
limits: {
totalSize: globalLimits.postFilesSize.max,
fileSize: globalLimits.postFilesSize.max,
//files: globalLimits.postFiles.max
},
limitHandler: uploadLimitFunction,
useTempFiles: true,
tempFileDir: __dirname+'/../tmp/'
});
module.exports = {
handleBannerFiles: upload({
debug: debugLogs,
createParentPath: true,
safeFileNames: filterFileNames,
spaceFileNameReplacement,
preserveExtension: 4,
limits: {
totalSize: globalLimits.bannerFilesSize.max,
fileSize: globalLimits.bannerFilesSize.max,
files: globalLimits.bannerFiles.max
},
limitHandler: uploadLimitFunction,
useTempFiles: true,
tempFileDir: __dirname+'/../tmp/'
}),
handlePostFilesEarlyTor: (req, res, next) => {
console.log('handlePostFilesEarlyTor')
console.log(res.locals.tor, postFiles)
if (res.locals.tor) {
return postFiles(req, res, next);
}
return next();
},
handlePostFiles: (req, res, next) => {
console.log('handlePostFiles')
if (res.locals.tor) {
return next();
}
return postFiles(req, res, next);
},
}

@ -0,0 +1,14 @@
'use strict'
const { countryNamesMap } = require(__dirname+'/countries.js')
, { countryCodeHeader } = require(__dirname+'/../configs/main.js');
module.exports = (req, res, next) => {
const code = req.headers[countryCodeHeader] || 'XX';
res.locals.tor = code === 'TOR';
res.locals.country = {
code,
name: countryNamesMap[code],
}
return next();
}

@ -2,9 +2,25 @@
const { ipHeader, ipHashPermLevel } = require(__dirname+'/../configs/main.js')
, { parse } = require('ip6addr')
, deleteTempFiles = require(__dirname+'/files/deletetempfiles.js')
, dynamicResponse = require(__dirname+'/dynamic.js')
, hashIp = require(__dirname+'/haship.js');
module.exports = (req, res, next) => {
//tor user ip uses bypassid, if they dont have one send to blockbypass
if (res.locals.tor) {
const bypassId = req.signedCookies.bypassid;
res.locals.ip = {
raw: bypassId,
single: bypassId,
qrange: bypassId,
hrange: bypassId,
};
return next();
}
//ip for normal user
const ip = req.headers[ipHeader] || req.connection.remoteAddress;
try {
const ipParsed = parse(ip);
@ -31,4 +47,5 @@ module.exports = (req, res, next) => {
'message': 'Malformed IP' //should never get here
});
}
}

@ -2,13 +2,13 @@
const session = require('express-session')
, redisStore = require('connect-redis')(session)
, { sessionSecret, secureCookies } = require(__dirname+'/../configs/main.js')
, { cookieSecret, secureCookies } = require(__dirname+'/../configs/main.js')
, { redisClient } = require(__dirname+'/../redis.js')
, production = process.env.NODE_ENV === 'production'
, { DAY } = require(__dirname+'/timeutils.js');
module.exports = session({
secret: sessionSecret,
secret: cookieSecret,
store: new redisStore({
client: redisClient,
}),

@ -11,16 +11,17 @@ module.exports = async (req, res, next) => {
const bypassId = bypass.insertedId;
res.locals.blockBypass = bypass.ops[0];
return res
.cookie('bypassid', bypassId.toString(), {
'maxAge': blockBypass.expireAfterTime,
'secure': production && secureCookies,
'sameSite': 'strict'
})
.render('message', {
'minimal': req.body.minimal, //todo: make use x- header for ajax once implm.
'title': 'Success',
'message': 'Completed block bypass, you may go back and make your post.',
});
res.cookie('bypassid', bypassId.toString(), {
'maxAge': blockBypass.expireAfterTime,
'secure': production && secureCookies,
'sameSite': 'strict',
'signed': true,
})
return dynamicResponse(req, res, 200, 'message', {
'minimal': req.body.minimal, //todo: make use x- header for ajax once implm.
'title': 'Success',
'message': 'Completed block bypass, you may go back and make your post.',
});
}

@ -1,7 +1,6 @@
'use strict';
const path = require('path')
, { countryNamesMap } = require('../../helpers/countries.js')
, { createHash, randomBytes } = require('crypto')
, randomBytesAsync = require('util').promisify(randomBytes)
, { remove, pathExists } = require('fs-extra')
@ -24,7 +23,7 @@ const path = require('path')
, timeUtils = require(__dirname+'/../../helpers/timeutils.js')
, deletePosts = require(__dirname+'/deletepost.js')
, spamCheck = require(__dirname+'/../../helpers/checks/spamcheck.js')
, { countryCodeHeader, thumbSize, thumbExtension, postPasswordSecret, strictFiltering } = require(__dirname+'/../../configs/main.js')
, { thumbSize, thumbExtension, postPasswordSecret, strictFiltering } = require(__dirname+'/../../configs/main.js')
, buildQueue = require(__dirname+'/../../queue.js')
, dynamicResponse = require(__dirname+'/../../helpers/dynamic.js')
, { buildThread } = require(__dirname+'/../../helpers/tasks.js');
@ -52,11 +51,11 @@ module.exports = async (req, res, next) => {
captchaMode, lockMode, allowedFileTypes, flags } = res.locals.board.settings;
if (flags === true
&& res.locals.permLevel >= 4
&& req.headers[countryCodeHeader]
&& blockedCountries.includes(req.headers[countryCodeHeader])) {
&& res.locals.country
&& blockedCountries.includes(res.locals.country.code)) {
return dynamicResponse(req, res, 403, 'message', {
'title': 'Forbidden',
'message': `Your country code ${req.headers[countryCodeHeader]} is not allowed to post on this board`,
'message': `Your country "${res.locals.country.name}" is not allowed to post on this board`,
'redirect': redirect
});
}
@ -309,16 +308,16 @@ module.exports = async (req, res, next) => {
salt = (await randomBytesAsync(128)).toString('base64');
}
if (ids === true) {
const fullUserIdHash = createHash('sha256').update(salt + res.locals.ip.raw).digest('hex');
userId = fullUserIdHash.substring(fullUserIdHash.length-6);
// if (res.locals.country.code === 'TOR') {
// userId = '000000';
// } else {
const fullUserIdHash = createHash('sha256').update(salt + res.locals.ip.raw).digest('hex');
userId = fullUserIdHash.substring(fullUserIdHash.length-6);
// }
}
let country = null;
if (flags === true) {
const code = req.headers[countryCodeHeader];
country = {
code,
'name': countryNamesMap[code]
}
country = res.locals.country;
}
let password = null;
if (req.body.postpassword) {

@ -13,9 +13,11 @@ module.exports = async (req, res, next) => {
let captchaId;
try {
const ratelimit = await Ratelimits.incrmentQuota(res.locals.ip.single, 'captcha', rateLimitCost.captcha);
if (ratelimit > 100) {
return res.status(429).redirect('/file/ratelimit.png');
if (!res.locals.tor) {
const ratelimit = await Ratelimits.incrmentQuota(res.locals.ip.single, 'captcha', rateLimitCost.captcha);
if (ratelimit > 100) {
return res.status(429).redirect('/file/ratelimit.png');
}
}
const { id, text } = await generateCaptcha();
captchaId = id;

@ -9,7 +9,7 @@ const express = require('express')
, app = express()
, server = require('http').createServer(app)
, cookieParser = require('cookie-parser')
, { cacheTemplates, boardDefaults, globalLimits,
, { cacheTemplates, boardDefaults, globalLimits, cookieSecret,
enableUserBoardCreation, enableUserAccountCreation,
debugLogs, ipHashPermLevel, meta, port, enableWebring } = require(__dirname+'/configs/main.js')
, referrerCheck = require(__dirname+'/helpers/referrercheck.js')
@ -40,7 +40,7 @@ const express = require('express')
// parse forms
app.use(express.urlencoded({extended: false}));
// parse cookies
app.use(cookieParser());
app.use(cookieParser(cookieSecret));
// session store
const sessionMiddleware = require(__dirname+'/helpers/usesession.js');
@ -81,6 +81,7 @@ const express = require('express')
app.use(express.static(__dirname+'/static/html', { redirect: false }));
app.use(express.static(__dirname+'/static/json', { redirect: false }));
}
app.use('/forms', require(__dirname+'/controllers/forms.js'));
app.use('/', require(__dirname+'/controllers/pages.js'));

Loading…
Cancel
Save