Migration, and a change that will make it not get completely destroyed by ddos over TOR

merge-requests/208/head
Thomas Lynch 4 years ago
parent 60d36bbb6a
commit 14dc090e08
  1. 3
      configs/main.js.example
  2. 2
      controllers/forms.js
  3. 2
      controllers/pages.js
  4. 8
      db/captchas.js
  5. 2
      helpers/captcha/generators/grid.js
  6. 2
      helpers/captcha/generators/text.js
  7. 0
      helpers/captcha/verify.js
  8. 1
      migrations/index.js
  9. 6
      migrations/migration-0.0.11.js
  10. 17
      models/pages/captcha.js
  11. 2
      package.json

@ -42,7 +42,8 @@ nano module.exports = {
//settings for captchas
captchaOptions: {
type: 'grid', //"text", "grid" or "google"
google: {
generateLimit: 1000, //max number of captchas to have generated at any time, prevent mass unsolved captcha spam, especially on TOR.
google: { //options for google captcha, when captcha type is google
siteKey: 'zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz',
secretKey: 'zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz'
},

@ -13,7 +13,7 @@ const express = require('express')
, numFiles = require(__dirname+'/../helpers/numfiles.js')
, banCheck = require(__dirname+'/../helpers/checks/bancheck.js')
, isLoggedIn = require(__dirname+'/../helpers/checks/isloggedin.js')
, verifyCaptcha = require(__dirname+'/../helpers/captcha/captchaverify.js')
, verifyCaptcha = require(__dirname+'/../helpers/captcha/verify.js')
, csrf = require(__dirname+'/../helpers/checks/csrfmiddleware.js')
, useSession = require(__dirname+'/../helpers/usesession.js')
, sessionRefresh = require(__dirname+'/../helpers/sessionrefresh.js')

@ -68,7 +68,7 @@ router.get('/globalmanage/settings.html', useSession, sessionRefresh, isLoggedIn
//captcha
if (captchaOptions.type !== 'google') {
router.get('/captcha', processIp, captcha); //get captcha image and cookie
router.get('/captcha', geoAndTor, processIp, captcha); //get captcha image and cookie
}
router.get('/captcha.html', captchaPage); //iframed for noscript users
router.get('/bypass.html', blockBypass); //block bypass page

@ -25,6 +25,14 @@ module.exports = {
});
},
randomSample: () => {
return db.aggregate([
{
$sample: { size: 1 }
}
]).toArray().then(res => res[0]);
},
deleteAll: () => {
return db.deleteMany({});
},

@ -75,7 +75,7 @@ module.exports = async () => {
if (err) {
return reject(err);
}
return resolve({ id: captchaId, boolArray });
return resolve({ id: captchaId });
});
});

@ -86,7 +86,7 @@ module.exports = async () => {
if (err) {
return reject(err);
}
return resolve({ id: captchaId, text });
return resolve({ id: captchaId });
});
});

@ -11,4 +11,5 @@ module.exports = {
'0.0.8': require(__dirname+'/migration-0.0.8.js'), //option to auto reset triggers after hour is over
'0.0.9': require(__dirname+'/migration-0.0.9.js'), //ip changes
'0.0.10': require(__dirname+'/migration-0.0.10.js'), //add links to modlog for new logs
'0.0.11': require(__dirname+'/migration-0.0.11.js'), //rename captcha "text" field to "answer" since we support multiple captcha types now
}

@ -0,0 +1,6 @@
'use strict';
module.exports = async(db, redis) => {
console.log('Expiring existing captchas, so new ones get new answer format');
await db.collection('captcha').deleteMany({});
};

@ -1,6 +1,6 @@
'use strict';
const { Ratelimits } = require(__dirname+'/../../db/')
const { Captchas, Ratelimits } = require(__dirname+'/../../db/')
, { secureCookies, rateLimitCost, captchaOptions } = require(__dirname+'/../../configs/main.js')
, generateCaptcha = require(__dirname+`/../../helpers/captcha/generators/${captchaOptions.type}.js`)
, production = process.env.NODE_ENV === 'production';
@ -12,6 +12,7 @@ module.exports = async (req, res, next) => {
}
let captchaId;
let maxAge = 5*60*1000;
try {
if (!res.locals.tor) {
const ratelimit = await Ratelimits.incrmentQuota(res.locals.ip.single, 'captcha', rateLimitCost.captcha);
@ -19,7 +20,15 @@ module.exports = async (req, res, next) => {
return res.status(429).redirect('/file/ratelimit.png');
}
}
const { id } = await generateCaptcha();
let id;
if ((await Captchas.db.estimatedDocumentCount()) >= captchaOptions.generateLimit) {
//TODOs: round robin sample? store in redis? only sample random with longer than x expiry?
const randomCaptcha = await Captchas.randomSample();
id = randomCaptcha._id;
maxAge = Math.abs((randomCaptcha.expireAt.getTime()+maxAge) - Date.now()); //abs in case mongo hasn't pruned, and will not be too big since it can't be too far away from pruning anyway
} else {
({ id } = await generateCaptcha());
}
captchaId = id;
} catch (err) {
return next(err);
@ -27,9 +36,9 @@ module.exports = async (req, res, next) => {
return res
.cookie('captchaid', captchaId.toString(), {
'maxAge': 5*60*1000, //5 minute cookie
'secure': production && secureCookies,
'sameSite': 'strict'
'sameSite': 'strict',
maxAge,
})
.redirect(`/captcha/${captchaId}.jpg`);

@ -1,7 +1,7 @@
{
"name": "jschan",
"version": "0.0.1",
"migrateVersion": "0.0.10",
"migrateVersion": "0.0.11",
"description": "",
"main": "server.js",
"dependencies": {

Loading…
Cancel
Save