captcha added to page when missing (enabled after page load) and cleaned captcha handling closes #189

merge-requests/208/head
Thomas Lynch 4 years ago
parent 9f47b05f0d
commit 21191a3811
  1. 91
      gulp/res/js/captcha.js
  2. 7
      gulp/res/js/captchaformsection.js
  3. 11
      gulp/res/js/forms.js
  4. 3
      gulpfile.js
  5. 2
      views/includes/captchaformsection.pug
  6. 7
      views/mixins/captchaformsection.pug
  7. 2
      views/pages/bypass.pug

@ -1,60 +1,83 @@
window.addEventListener('DOMContentLoaded', (event) => {
class CaptchaController {
const captchaFields = document.getElementsByClassName('captchafield');
let refreshing = false;
constructor() {
this.captchaFields = [];
this.refreshing = false;
}
const updateCaptchaImages = (url) => {
for (let i = 0; i < captchaFields.length; i++) {
if (captchaFields[i].previousSibling.children.length > 0) {
captchaFields[i].previousSibling.children[0].src = url;
}
init() {
this.captchaFields = document.getElementsByClassName('captchafield');
this.refreshing = false;
for (let captcha of this.captchaFields) {
this.setupCaptchaField(captcha);
}
}
setupCaptchaField(captcha) {
if (captcha.form.dataset.captchaPreload == 'true') {
this.loadCaptcha(captcha);
} else {
captcha.placeholder = 'focus to load captcha';
captcha.addEventListener('focus', () => this.loadCaptcha(captcha), { once: true });
}
};
}
const refreshCaptchas = function(e) {
if (refreshing) {
return;
refreshCaptchas() {
if (this.refreshing) {
return null;
}
refreshing = true;
this.refreshing = true;
document.cookie = 'captchaid=; Path=/; Expires=Thu, 01 Jan 1970 00:00:01 GMT;';
const captchaImg = this;
const xhr = new XMLHttpRequest();
xhr.onload = () => {
refreshing = false;
updateCaptchaImages(xhr.responseURL);
for (let captcha of this.captchaFields) {
const existingImage = captcha.previousSibling.children[0];
if (existingImage) {
captcha.previousSibling.children[0].src = xhr.responseURL;
}
}
this.refreshing = false;
}
xhr.onerror = () => {
refreshing = false;
this.refreshing = false;
}
xhr.open('GET', '/captcha', true);
xhr.send(null);
};
}
const loadCaptcha = function(e) {
const field = e.target;
addMissingCaptcha() {
const postSubmitButton = document.getElementById('submitpost');
const captchaFormSectionHtml = captchaformsection();
postSubmitButton.insertAdjacentHTML('beforebegin', captchaFormSectionHtml);
const captchaFormSection = postSubmitButton.previousSibling;
const captchaField = captchaFormSection.querySelector('.captchafield');
this.loadCaptcha(captchaField);
}
loadCaptcha(field) {
console.log(field)
const captchaDiv = field.previousSibling;
const captchaImg = document.createElement('img');
const refreshDiv = document.createElement('div');
refreshDiv.classList.add('captcharefresh', 'noselect');
refreshDiv.addEventListener('click', refreshCaptchas, true);
refreshDiv.addEventListener('click', () => this.refreshCaptchas(), true);
refreshDiv.textContent = '↻';
field.placeholder = 'loading';
captchaImg.src = '/captcha';
captchaImg.onload = function() {
field.placeholder = '';
captchaDiv.appendChild(captchaImg);
captchaDiv.appendChild(refreshDiv);
captchaDiv.style.display = '';
}
};
for (let i = 0; i < captchaFields.length; i++) {
const field = captchaFields[i];
if (field.form.action.endsWith('/forms/blockbypass')) {
return loadCaptcha({target: field })
field.placeholder = '';
captchaDiv.appendChild(captchaImg);
captchaDiv.appendChild(refreshDiv);
captchaDiv.style.display = '';
}
field.placeholder = 'focus to load captcha';
field.addEventListener('focus', loadCaptcha, { once: true });
}
}
const captchaController = new CaptchaController();
window.addEventListener('DOMContentLoaded', () => {
captchaController.init();
});

@ -0,0 +1,7 @@
function pug_attr(t,e,n,r){if(!1===e||null==e||!e&&("class"===t||"style"===t))return"";if(!0===e)return" "+(r?t:t+'="'+t+'"');var f=typeof e;return"object"!==f&&"function"!==f||"function"!=typeof e.toJSON||(e=e.toJSON()),"string"==typeof e||(e=JSON.stringify(e),n||-1===e.indexOf('"'))?(n&&(e=pug_escape(e))," "+t+'="'+e+'"'):" "+t+"='"+e.replace(/'/g,"&#39;")+"'"}
function pug_escape(e){var a=""+e,t=pug_match_html.exec(a);if(!t)return e;var r,c,n,s="";for(r=t.index,c=0;r<a.length;r++){switch(a.charCodeAt(r)){case 34:n="&quot;";break;case 38:n="&amp;";break;case 60:n="&lt;";break;case 62:n="&gt;";break;default:continue}c!==r&&(s+=a.substring(c,r)),c=r+1,s+=n}return c!==r?s+a.substring(c,r):s}
var pug_match_html=/["&<>]/;function captchaformsection(locals) {var pug_html = "", pug_mixins = {}, pug_interp;pug_mixins["captchaformsection"] = pug_interp = function(){
var block = (this && this.block), attributes = (this && this.attributes) || {};
pug_html = pug_html + "\u003Csection class=\"row\"\u003E\u003Cdiv class=\"label\"\u003E\u003Cspan\u003ECaptcha\u003Cspan class=\"required\"\u003E*\u003C\u002Fspan\u003E\u003C\u002Fspan\u003E\u003C\u002Fdiv\u003E\u003Cdiv class=\"col\"\u003E\u003Cnoscript class=\"no-m-p\"\u003E\u003Ciframe" + (" class=\"captcha\""+" src=\"\u002Fcaptcha.html\""+pug_attr("width=210", true, true, false)+" height=\"80\" scrolling=\"no\" loading=\"lazy\"") + "\u003E\u003C\u002Fiframe\u003E\u003C\u002Fnoscript\u003E\u003Cdiv class=\"jsonly captcha\" style=\"display:none;\"\u003E\u003C\u002Fdiv\u003E\u003Cinput" + (" class=\"captchafield\""+" type=\"text\" name=\"captcha\" autocomplete=\"off\" placeholder=\"Captcha text\" pattern=\".{6}\""+pug_attr("required", true, true, false)+" title=\"6 characters\"") + "\u002F\u003E\u003C\u002Fdiv\u003E\u003C\u002Fsection\u003E";
};
pug_mixins["captchaformsection"]();;return pug_html;}

@ -68,7 +68,8 @@ class formHandler {
constructor(form) {
this.form = form;
this.enctype = this.form.getAttribute('enctype');
this.messageBox = form.querySelector('#message')
this.messageBox = form.querySelector('#message');
this.captchaField = form.querySelector('.captchafield');
this.submit = form.querySelector('input[type="submit"]');
if (this.submit) {
this.originalSubmitText = this.submit.value;
@ -184,9 +185,6 @@ class formHandler {
}
if (json.message || json.messages || json.error || json.errors) {
doModal(json);
if (json.message === 'Incorrect captcha answer') {
//todo: create captcha form, add method to captcha frontend code
}
} else if (socket && socket.connected) {
window.location.hash = json.postId
} else {
@ -205,6 +203,11 @@ class formHandler {
this.clearFiles();
}
if (json) {
if (!this.captchaField && json.message === 'Incorrect captcha answer') {
//todo: create captcha form, add method to captcha frontend code
captchaController.addMissingCaptcha();
this.captchaField = true;
}
doModal(json, () => {
this.formSubmit(e);
});

@ -199,6 +199,7 @@ function scripts() {
fs.writeFileSync('gulp/res/js/post.js', pug.compileFileClient(`${paths.pug.src}/includes/post.pug`, { compileDebug: false, debug: false, name: 'post' }));
fs.writeFileSync('gulp/res/js/modal.js', pug.compileFileClient(`${paths.pug.src}/includes/modal.pug`, { compileDebug: false, debug: false, name: 'modal' }));
fs.writeFileSync('gulp/res/js/uploaditem.js', pug.compileFileClient(`${paths.pug.src}/includes/uploaditem.pug`, { compileDebug: false, debug: false, name: 'uploaditem' }));
fs.writeFileSync('gulp/res/js/captchaformsection.js', pug.compileFileClient(`${paths.pug.src}/includes/captchaformsection.pug`, { compileDebug: false, debug: false, name: 'captchaformsection' }));
fs.symlinkSync(__dirname+'/node_modules/socket.io-client/dist/socket.io.slim.js', __dirname+'/gulp/res/js/socket.io.js', 'file');
} catch (e) {
if (e.code !== 'EEXIST') {
@ -224,7 +225,7 @@ function scripts() {
`!${paths.scripts.src}/time.js`,
])
.pipe(concat('all.js'))
.pipe(uglify({compress:false}))
// .pipe(uglify({compress:false}))
.pipe(gulp.dest(paths.scripts.dest));
return gulp.src([
`${paths.scripts.src}/dragable.js`,

@ -0,0 +1,2 @@
include ../mixins/captchaformsection.pug
+captchaformsection()

@ -0,0 +1,7 @@
mixin captchaformsection()
section.row
.label
span Captcha
span.required *
.col
include ../includes/captcha.pug

@ -8,7 +8,7 @@ block content
.form-wrapper.flex-center.mv-10
if message
p.title #{message}
form.form-post(action='/forms/blockbypass' method='POST')
form.form-post(action='/forms/blockbypass' method='POST' data-captcha-preload='true')
.row
.label Captcha
span.col

Loading…
Cancel
Save