Refactor captcha generators and captcha model

Generators changes:
- take captchaoptions as argument, so no longer require config.get or captchas db imports
- return the captcha object (gm instance) and solution (whatever).
The model itself inserts the solution to db, gets captchaid for filename and cookie, and writes the image to disk.
Slightly cleaner imo, and makes the captcha generators more testable without requiring any mocking for DB/config.
indiachan-spamvector
Thomas Lynch 2 years ago
parent f0ae0691a4
commit 06828da6c0
  1. 20
      lib/captcha/generators/grid.js
  2. 20
      lib/captcha/generators/grid2.js
  3. 20
      lib/captcha/generators/text.js
  4. 13
      models/pages/captcha.js

@ -3,16 +3,11 @@
const gm = require('@fatchan/gm').subClass({ imageMagick: true })
, { promisify } = require('util')
, randomBytes = promisify(require('crypto').randomBytes)
, { Captchas } = require(__dirname+'/../../../db/')
, config = require(__dirname+'/../../misc/config.js')
, uploadDirectory = require(__dirname+'/../../file/uploaddirectory.js')
, getDistorts = require(__dirname+'/../getdistorts.js')
, randomRange = promisify(require('crypto').randomInt)
, padding = 30; //pad edge of image to account for character size + distortion
module.exports = async () => {
const { captchaOptions } = config.get;
module.exports = async (captchaOptions) => {
const { size, trues, falses, imageSize, noise, edge } = captchaOptions.grid;
const width = imageSize+padding; //TODO: these will never be different, right?
@ -29,9 +24,6 @@ module.exports = async () => {
boolArray[(await randomRange(0, numInputs))] = true;
}
//insert the captcha to db and get id
const captchaId = await Captchas.insertOne(boolArray).then(r => r.insertedId);
const captcha = gm(width, height, '#ffffff')
.fill('#000000')
.font(__dirname+'/../font.ttf');
@ -79,14 +71,6 @@ module.exports = async () => {
captcha.noise(noise);
}
return new Promise((resolve, reject) => {
captcha
.write(`${uploadDirectory}/captcha/${captchaId}.jpg`, (err) => {
if (err) {
return reject(err);
}
return resolve({ captchaId });
});
});
return { captcha, solution: boolArray };
};

@ -2,9 +2,6 @@
const gm = require('@fatchan/gm').subClass({ imageMagick: true })
, { promisify } = require('util')
, { Captchas } = require(__dirname+'/../../../db/')
, config = require(__dirname+'/../../misc/config.js')
, uploadDirectory = require(__dirname+'/../../file/uploaddirectory.js')
, getDistorts = require(__dirname+'/../getdistorts.js')
, randomRange = promisify(require('crypto').randomInt)
, randomBytes = promisify(require('crypto').randomBytes)
@ -18,9 +15,7 @@ const gm = require('@fatchan/gm').subClass({ imageMagick: true })
, randomOf = async (arr) => { return arr[(await randomRange(0, arr.length))]; };
//TODO: last two could belong in lib/misc/(random?)
module.exports = async () => {
const { captchaOptions } = config.get;
module.exports = async (captchaOptions) => {
const { size, trues, falses, imageSize, noise, edge } = captchaOptions.grid;
const width = imageSize+padding; //TODO: these will never be different, right?
@ -110,9 +105,6 @@ module.exports = async () => {
}
}
//insert the captcha to db and get id
const captchaId = await Captchas.insertOne(answerMatrix.flat()).then(r => r.insertedId);
//create an array of distortions and apply to the image, if distortion is enabled
const { distortion, numDistorts } = captchaOptions;
if (distortion > 0) {
@ -130,14 +122,6 @@ module.exports = async () => {
captcha.noise(noise);
}
return new Promise((resolve, reject) => {
captcha
.write(`${uploadDirectory}/captcha/${captchaId}.jpg`, (err) => {
if (err) {
return reject(err);
}
return resolve({ captchaId });
});
});
return { captcha, solution: answerMatrix.flat() };
};

@ -1,9 +1,6 @@
'use strict';
const gm = require('@fatchan/gm').subClass({ imageMagick: true })
, { Captchas } = require(__dirname+'/../../../db/')
, config = require(__dirname+'/../../misc/config.js')
, uploadDirectory = require(__dirname+'/../../file/uploaddirectory.js')
, characterWidth = (char) => {
switch (char) {
case 'w':
@ -33,18 +30,13 @@ const gm = require('@fatchan/gm').subClass({ imageMagick: true })
, randomRange = promisify(require('crypto').randomInt)
, getDistorts = require(__dirname+'/../getdistorts.js');
module.exports = async () => {
const { captchaOptions } = config.get;
module.exports = async (captchaOptions) => {
/* generate random between 1000000 and 1zzzzzz and not 0 and zzzzzz, so output will have
enough characters for 000000-zzzzzz */
const textInt = await randomRange(minVal, maxVal+1);
const text = textInt.toString(36).substr(-6, 6);
//insert the captcha to db and get id
const captchaId = await Captchas.insertOne(text).then(r => r.insertedId);
const captcha = gm(width,height,'#ffffff')
.fill('#000000')
.fontSize(65);
@ -90,15 +82,7 @@ module.exports = async () => {
captcha.distort(distorts, 'Shepards');
}
return new Promise((resolve, reject) => {
captcha
.write(`${uploadDirectory}/captcha/${captchaId}.jpg`, (err) => {
if (err) {
return reject(err);
}
return resolve({ captchaId });
});
});
return { captcha, solution: text };
};

@ -2,6 +2,7 @@
const { Captchas, Ratelimits } = require(__dirname+'/../../db/')
, config = require(__dirname+'/../../lib/misc/config.js')
, uploadDirectory = require(__dirname+'/../../lib/file/uploaddirectory.js')
, production = process.env.NODE_ENV === 'production';
module.exports = async (req, res, next) => {
@ -33,7 +34,17 @@ module.exports = async (req, res, next) => {
captchaId = 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 {
({ captchaId } = await generateCaptcha());
const { captcha, solution } = await generateCaptcha(captchaOptions);
captchaId = await Captchas.insertOne(solution).then(r => r.insertedId);
//captcha.write doesn't like to be util.promisify'd
await (new Promise((resolve, reject) => {
captcha.write(`${uploadDirectory}/captcha/${captchaId}.jpg`, (err) => {
if (err) {
return reject(err);
}
resolve();
});
}));
}
} catch (err) {
return next(err);

Loading…
Cancel
Save