mirror of https://gitgud.io/fatchan/jschan.git
merge-requests/208/head
parent
f751436ae4
commit
60d36bbb6a
26 changed files with 294 additions and 112 deletions
@ -0,0 +1,4 @@ |
||||
const themes = ['amoled', 'chaos', 'choc', 'clear', 'darkblue', 'gurochan', 'lain', 'miku', 'navy', 'pink', 'rei-zero', 'robot', 'tomorrow', 'tomorrow2', 'win95', 'yotsuba b', 'yotsuba']; |
||||
const codeThemes = ['a11y-dark', 'a11y-light', 'agate', 'an-old-hope', 'androidstudio', 'arduino-light', 'arta', 'ascetic', 'atelier-cave-dark', 'atelier-cave-light', 'atelier-dune-dark', 'atelier-dune-light', 'atelier-estuary-dark', 'atelier-estuary-light', 'atelier-forest-dark', 'atelier-forest-light', 'atelier-heath-dark', 'atelier-heath-light', 'atelier-lakeside-dark', 'atelier-lakeside-light', 'atelier-plateau-dark', 'atelier-plateau-light', 'atelier-savanna-dark', 'atelier-savanna-light', 'atelier-seaside-dark', 'atelier-seaside-light', 'atelier-sulphurpool-dark', 'atelier-sulphurpool-light', 'atom-one-dark-reasonable', 'atom-one-dark', 'atom-one-light', 'brown-paper', 'brown-papersq', 'codepen-embed', 'color-brewer', 'darcula', 'dark', 'default', 'docco', 'dracula', 'far', 'foundation', 'github-gist', 'github', 'gml', 'googlecode', 'gradient-dark', 'grayscale', 'gruvbox-dark', 'gruvbox-light', 'hopscotch', 'hybrid', 'idea', 'ir-black', 'isbl-editor-dark', 'isbl-editor-light', 'kimbie.dark', 'kimbie.light', 'lightfair', 'lioshi', 'magula', 'mono-blue', 'monokai-sublime', 'monokai', 'night-owl', 'nnfx-dark', 'nnfx', 'nord', 'obsidian', 'ocean', 'paraiso-dark', 'paraiso-light', 'pojoaque', 'pojoaque', 'purebasic', 'qtcreator_dark', 'qtcreator_light', 'railscasts', 'rainbow', 'routeros', 'school-book', 'school-book', 'shades-of-purple', 'solarized-dark', 'solarized-light', 'srcery', 'sunburst', 'tomorrow-night-blue', 'tomorrow-night-bright', 'tomorrow-night-eighties', 'tomorrow-night', 'tomorrow', 'vs', 'vs2015', 'xcode', 'xt256', 'zenburn']; |
||||
const captchaType = 'grid'; |
||||
const SERVER_TIMEZONE = 'UTC' |
@ -0,0 +1,94 @@ |
||||
const gm = require('gm').subClass({ imageMagick: true }) |
||||
, { Captchas } = require(__dirname+'/../../../db/') |
||||
, { captchaOptions } = require(__dirname+'/../../../configs/main.js') |
||||
, uploadDirectory = require(__dirname+'/../../files/uploadDirectory.js') |
||||
, { promisify } = require('util') |
||||
, randomBytes = promisify(require('crypto').randomBytes) |
||||
, characterWidth = (char) => { |
||||
switch (char) { |
||||
case 'w': |
||||
case 'm': |
||||
return 45; |
||||
case 'i': |
||||
case 'l': |
||||
return 12; |
||||
case 'f': |
||||
case 'j': |
||||
case 't': |
||||
return 15; |
||||
default: |
||||
return 30; |
||||
} |
||||
} |
||||
, totalWidth = (text) => { |
||||
return text.split('').reduce((acc, char) => { |
||||
return characterWidth(char) + acc + 1; |
||||
}, 0); |
||||
} |
||||
, width = 210 |
||||
, height = 80 |
||||
, distortion = captchaOptions.distortion |
||||
, minVal = parseInt('1000000', 36) |
||||
, maxVal = parseInt('1zzzzzz', 36); |
||||
|
||||
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 |
||||
do { |
||||
g = (await randomBytes(4)).readUInt32LE(); |
||||
} while (g > div * mod - 1); |
||||
return ((g / div) | 0) + min; |
||||
}; |
||||
|
||||
module.exports = async () => { |
||||
// generate between 1000000 and 1zzzzzz and not 0 and zzzzzz, so toString
|
||||
// will have enough characters
|
||||
const textInt = await randomRange(minVal, maxVal); |
||||
const text = textInt.toString(36).substr(-6, 6); |
||||
const captchaId = await Captchas.insertOne(text).then(r => r.insertedId); |
||||
const distorts = []; |
||||
const numDistorts = await randomRange( |
||||
captchaOptions.numDistorts.min,captchaOptions.numDistorts.max); |
||||
const div = width/numDistorts; |
||||
|
||||
for (let i = 0; i < numDistorts; i++) { |
||||
const divStart = (div*i) |
||||
, divEnd = (div*(i+1)); |
||||
const originx = await randomRange(divStart, divEnd) |
||||
, originy = await randomRange(0,height); |
||||
const destx = await randomRange(Math.max(distortion,originx-distortion),Math.min(width-distortion,originx+distortion)) |
||||
, desty = await randomRange(Math.max(distortion,originy-distortion*2),Math.min(height-distortion,originy+distortion*2)); |
||||
distorts.push([ |
||||
{x:originx,y:originy}, //origin
|
||||
{x:destx,y:desty} //dest
|
||||
]); |
||||
|
||||
} |
||||
|
||||
const lineY = await randomRange(35,45); |
||||
return new Promise((resolve, reject) => { |
||||
const captcha = gm(width,height,'#ffffff') |
||||
.fill('#000000') |
||||
.fontSize(65); |
||||
const startX = (width-totalWidth(text))/2; |
||||
let charX = startX; |
||||
for (let i = 0; i < 6; i++) { |
||||
captcha.drawText(charX, 60, text[i]); |
||||
charX += characterWidth(text[i]); |
||||
} |
||||
captcha |
||||
.drawRectangle(startX, lineY, charX, lineY+4) |
||||
.distort(distorts, 'Shepards') |
||||
.paint(2) |
||||
.write(`${uploadDirectory}/captcha/${captchaId}.jpg`, (err) => { |
||||
if (err) { |
||||
return reject(err); |
||||
} |
||||
return resolve({ id: captchaId, text }); |
||||
}); |
||||
}); |
||||
|
||||
} |
||||
|
@ -1,12 +1,19 @@ |
||||
if googleRecaptchaEnabled |
||||
div(class="g-recaptcha" data-sitekey=`${googleRecaptchaSiteKey}` data-theme="dark" data-size="compact" data-callback="recaptchaCallback") |
||||
else |
||||
noscript.no-m-p |
||||
iframe.captcha(src='/captcha.html' width='150' height='150' scrolling='no' loading='lazy') |
||||
.jsonly.captcha(style='display:none') |
||||
.captchafield.noselect |
||||
- for(let i = 0; i < 16; i++) { |
||||
label.captchachecklabel |
||||
input(type='checkbox' name='captcha' value=i) |
||||
span.captchacheckbox |
||||
- } |
||||
case captchaType |
||||
when 'google' |
||||
div(class="g-recaptcha" data-sitekey=`${googleRecaptchaSiteKey}` data-theme="dark" data-size="compact" data-callback="recaptchaCallback") |
||||
when 'text' |
||||
noscript.no-m-p |
||||
iframe.captcha(src='/captcha.html' 'width=210' height='80' scrolling='no' loading='lazy') |
||||
.jsonly.captcha(style='display:none;') |
||||
input.captchafield(type='text' name='captcha' autocomplete='off' placeholder='Captcha text' pattern=".{6}" required title='6 characters') |
||||
when 'grid' |
||||
.catalog |
||||
noscript.no-m-p |
||||
iframe.captcha(src='/captcha.html' width='150' height='150' scrolling='no' loading='lazy') |
||||
.jsonly.captcha(style='display:none') |
||||
.captchafield.noselect |
||||
- for(let i = 0; i < captchaGridSize**2; i++) { |
||||
label.captchachecklabel |
||||
input(type='checkbox' name='captcha' value=i) |
||||
span.captchacheckbox |
||||
- } |
||||
|
@ -1,5 +1,4 @@ |
||||
details.row.label.mr-0 |
||||
summary.pv-5 Captcha |
||||
span.required * |
||||
.catalog |
||||
include ./captcha.pug |
||||
include ./captcha.pug |
||||
|
@ -1,5 +1,4 @@ |
||||
.row.label.mr-0 |
||||
.pv-5 Captcha |
||||
span.required * |
||||
.catalog |
||||
include ./captcha.pug |
||||
include ./captcha.pug |
||||
|
@ -0,0 +1,6 @@ |
||||
section.row |
||||
.label |
||||
span Captcha |
||||
span.required * |
||||
.col |
||||
include ./captcha.pug |
Loading…
Reference in new issue