Bug in RNG causing blocking, and make captcha show properly in modal for mobile

merge-requests/208/head
Thomas Lynch 4 years ago
parent dcc93f75fc
commit 536aecffcc
  1. 2
      db/captchas.js
  2. 14
      gulp/res/css/style.css
  3. 67
      helpers/captcha/generators/grid.js
  4. 19
      helpers/captcha/generators/text.js
  5. 11
      models/pages/captcha.js
  6. 2
      views/mixins/modal.pug

@ -30,7 +30,7 @@ module.exports = {
{
$sample: { size: 1 }
}
]).toArray().then(res => res[0]);
]).toArray();
},
deleteAll: () => {

@ -1,3 +1,7 @@
table, img, .label, .pages, .catalog-tile, .post-container, .stickynav, .toggle-summary, .postform-style, input[type="button"], input[type="file"], input[type="number"], input[type="password"], input[type="range"], input[type="submit"], input[type="text"], select, textarea {
border-radius: 2px!important;
}
body {
font-family: arial, helvetica, sans-serif;
font-size: 10pt;
@ -488,6 +492,10 @@ td, th {
align-items: center;
}
.f1 {
flex: 1;
}
.stickynav {
bottom: 5px;
right: 5px;
@ -1069,7 +1077,7 @@ iframe.captcha, iframe.bypass {
}
iframe.bypass {
height: var(--bypass-height); /*probs needs bigger for google captcha*/
height: var(--bypass-height);
width: 450px;
}
@ -1301,6 +1309,10 @@ row.wrap.sb .col {
max-width: 150px;
}
iframe.bypass {
height: 100vh;
}
.file-thumb {
max-width: 128px;
max-height: 128px;

@ -7,12 +7,15 @@ const gm = require('gm').subClass({ imageMagick: true })
, randomRange = async (min, max) => {
if (max <= min) return min;
const mod = max - min + 1;
const div = (((0xffffffff - (mod-1)) / mod) | 0) + 1;
let g
const div = Math.ceil(Math.log2(mod));
const numberBytes = Math.ceil(div / 4);
const mask = (1 << div) - 1;
let rand;
do {
g = (await randomBytes(4)).readUInt32LE();
} while (g > div * mod - 1);
return ((g / div) | 0) + min;
rand = (await randomBytes(numberBytes)).readUIntBE(0, numberBytes);
rand = rand & mask;
} while (rand > mod);
return rand + min;
}
, padding = 30
, width = captchaOptions.grid.imageSize+padding
@ -44,8 +47,8 @@ module.exports = async () => {
, divEnd = (div*(i+1));
const originx = await randomRange(divStart, divEnd)
, originy = await randomRange(0,height);
const destx = await randomRange(Math.max(captchaOptions.distortion,originx-captchaOptions.distortion),Math.min(width-captchaOptions.distortion,originx+captchaOptions.distortion))
, desty = await randomRange(Math.max(captchaOptions.distortion,originy-captchaOptions.distortion*2),Math.min(height-captchaOptions.distortion,originy+captchaOptions.distortion*2));
const destx = await randomRange(Math.max(captchaOptions.distortion,originx-captchaOptions.distortion),Math.min(width-captchaOptions.distortion,originx+captchaOptions.distortion)).catch(e => console.error(e))
, desty = await randomRange(Math.max(captchaOptions.distortion,originy-captchaOptions.distortion*2),Math.min(height-captchaOptions.distortion,originy+captchaOptions.distortion*2)).catch(e => console.error(e));
distorts.push([
{x:originx,y:originy},
{x:destx,y:desty}
@ -53,39 +56,41 @@ module.exports = async () => {
}
}
return new Promise(async(resolve, reject) => {
const captcha = gm(width,height,'#ffffff')
.fill('#000000')
.font(__dirname+'/../font.ttf');
const captcha = gm(width,height,'#ffffff')
.fill('#000000')
.font(__dirname+'/../font.ttf');
const spaceSize = (width-padding)/gridSize;
for(let j = 0; j < gridSize; j++) {
let cxOffset = await randomRange(0, spaceSize*1.5);
for(let i = 0; i < gridSize; i++) {
const index = (j*gridSize)+i;
const cyOffset = await randomRange(0, captchaOptions.grid.iconYOffset);
const charIndex = await randomRange(0, ones.length-1);
const character = (boolArray[index] ? ones : zeros)[charIndex];
captcha.fontSize((await randomRange(20,30)))
captcha.drawText(
spaceSize*(i)+cxOffset,
spaceSize*(j+1)+cyOffset,
character
);
}
const spaceSize = (width-padding)/gridSize;
for(let j = 0; j < gridSize; j++) {
let cxOffset = await randomRange(0, spaceSize*1.5);
for(let i = 0; i < gridSize; i++) {
const index = (j*gridSize)+i;
const cyOffset = await randomRange(0, captchaOptions.grid.iconYOffset);
const charIndex = await randomRange(0, ones.length-1);
const character = (boolArray[index] ? ones : zeros)[charIndex];
captcha.fontSize((await randomRange(20,30)))
captcha.drawText(
spaceSize*(i)+cxOffset,
spaceSize*(j+1)+cyOffset,
character
);
}
}
if (captchaOptions.distortion > 0) {
captcha.distort(distorts, 'Shepards');
}
if (captchaOptions.distortion > 0) {
captcha.distort(distorts, 'Shepards');
}
captcha
.edge(25);
return new Promise((resolve, reject) => {
captcha
.edge(25)
.write(`${uploadDirectory}/captcha/${captchaId}.jpg`, (err) => {
if (err) {
return reject(err);
}
return resolve({ id: captchaId });
return resolve({ captchaId });
});
});

@ -31,16 +31,19 @@ const gm = require('gm').subClass({ imageMagick: true })
, minVal = parseInt('1000000', 36)
, maxVal = parseInt('1zzzzzz', 36);
const randomRange = async (min, max) => {
const randomRange = async (min, max) => {
if (max <= min) return min;
const mod = max - min + 1;
const div = (((0xffffffff - (mod-1)) / mod) | 0) + 1;
let g
const div = Math.ceil(Math.log2(mod));
const numberBytes = Math.ceil(div / 4);
const mask = (1 << div) - 1;
let rand;
do {
g = (await randomBytes(4)).readUInt32LE();
} while (g > div * mod - 1);
return ((g / div) | 0) + min;
};
rand = (await randomBytes(numberBytes)).readUIntBE(0, numberBytes);
rand = rand & mask;
} while (rand > mod);
return rand + min;
}
module.exports = async () => {
// generate between 1000000 and 1zzzzzz and not 0 and zzzzzz, so toString
@ -86,7 +89,7 @@ module.exports = async () => {
if (err) {
return reject(err);
}
return resolve({ id: captchaId });
return resolve({ captchaId });
});
});

@ -21,15 +21,16 @@ module.exports = async (req, res, next) => {
}
}
let id;
if ((await Captchas.db.estimatedDocumentCount()) >= captchaOptions.generateLimit) {
const captchaCount = await Captchas.db.estimatedDocumentCount();
if (captchaCount >= 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;
const captchaSample = await Captchas.randomSample();
const randomCaptcha = captchaSample[0];
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 {
({ id } = await generateCaptcha());
({ captchaId } = await generateCaptcha());
}
captchaId = id;
} catch (err) {
return next(err);
}

@ -18,7 +18,7 @@ mixin modal(data)
each error in data.errors
li #{error}
if data.frame
.row
.row.f1
iframe.bypass#modalframe(src=data.frame frameborder='0' scrolling='no')
else if data.link
.row

Loading…
Cancel
Save