From 3be6111fa485ff1369be01fdd7089988300867ba Mon Sep 17 00:00:00 2001 From: Zankaria Date: Fri, 24 Jan 2025 23:25:38 +0100 Subject: [PATCH 1/6] main.js: require captcha before sending a post --- templates/main.js | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/templates/main.js b/templates/main.js index c48a6ed3..8684e166 100755 --- a/templates/main.js +++ b/templates/main.js @@ -246,6 +246,8 @@ function getCookie(cookie_name) { {% if config.hcaptcha or config.turnstile %} // If any captcha // Global captcha object. Assigned by `onCaptchaLoad()`. var captcha_renderer = null; +// Captcha widget id of the post form. +var postCaptchaId = null; {% if config.hcaptcha %} // If hcaptcha function onCaptchaLoadHcaptcha() { @@ -256,7 +258,9 @@ function onCaptchaLoadHcaptcha() { callback: params['on-success'], }), remove: (widgetId) => { /* Not supported */ }, - reset: (widgetId) => hcaptcha.reset(widgetId) + reset: (widgetId) => hcaptcha.reset(widgetId), + hasResponse: (widgetId) => !!hcaptcha.getResponse(widgetId), + execute: (widgetId) => hcaptcha.execute(widgetId) }; onCaptchaLoad(renderer); @@ -291,7 +295,9 @@ function onCaptchaLoadTurnstile(action) { return widgetId; }, remove: (widgetId) => turnstile.remove(widgetId), - reset: (widgetId) => turnstile.reset(widgetId) + reset: (widgetId) => turnstile.reset(widgetId), + hasResponse: (widgetId) => !!turnstile.getResponse(widgetId), + execute: (widgetId) => turnstile.execute(widgetId) }; onCaptchaLoad(renderer); @@ -313,6 +319,7 @@ function onCaptchaLoad(renderer) { if (widgetId === null) { console.error('Could not render captcha!'); } + postCaptchaId = widgetId; document.addEventListener('afterdopost', function(e) { // User posted! Reset the captcha. renderer.reset(widgetId); @@ -390,6 +397,11 @@ function doPost(form) { saved[document.location] = form.elements['body'].value; sessionStorage.body = JSON.stringify(saved); + if (captcha_renderer && postCaptchaId && !captcha_renderer.hasResponse(postCaptchaId)) { + captcha_renderer.execute(postCaptchaId); + return false; + } + // Needs to be delayed by at least 1 frame, otherwise it may reset the form (read captcha) fields before they're sent. setTimeout(() => document.dispatchEvent(new Event('afterdopost'))); return form.elements['body'].value != "" || (form.elements['file'] && form.elements['file'].value != "") || (form.elements.file_url && form.elements['file_url'].value != ""); From 01fbbfc61a5dfd485554f253f4e0b01d219ffe85 Mon Sep 17 00:00:00 2001 From: Zankaria Date: Fri, 24 Jan 2025 23:29:34 +0100 Subject: [PATCH 2/6] main.js: add minimal jsdoc to captcha wrappers --- templates/main.js | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/templates/main.js b/templates/main.js index 8684e166..d7ae7fae 100755 --- a/templates/main.js +++ b/templates/main.js @@ -253,13 +253,28 @@ var postCaptchaId = null; function onCaptchaLoadHcaptcha() { if (captcha_renderer === null && (active_page === 'index' || active_page === 'catalog' || active_page === 'thread')) { let renderer = { + /** + * @returns {object} Opaque widget id. + */ applyOn: (container, params) => hcaptcha.render(container, { sitekey: "{{ config.hcaptcha_public }}", callback: params['on-success'], }), + /** + * @returns {void} + */ remove: (widgetId) => { /* Not supported */ }, + /** + * @returns {void} + */ reset: (widgetId) => hcaptcha.reset(widgetId), + /** + * @returns {bool} + */ hasResponse: (widgetId) => !!hcaptcha.getResponse(widgetId), + /** + * @returns {void} + */ execute: (widgetId) => hcaptcha.execute(widgetId) }; @@ -283,6 +298,9 @@ window.onCaptchaLoadTurnstile_post_thread = function() { function onCaptchaLoadTurnstile(action) { if (captcha_renderer === null && (active_page === 'index' || active_page === 'catalog' || active_page === 'thread')) { let renderer = { + /** + * @returns {object} Opaque widget id. + */ applyOn: function(container, params) { let widgetId = turnstile.render('#' + container, { sitekey: "{{ config.turnstile_public }}", @@ -294,9 +312,21 @@ function onCaptchaLoadTurnstile(action) { } return widgetId; }, + /** + * @returns {void} + */ remove: (widgetId) => turnstile.remove(widgetId), + /** + * @returns {void} + */ reset: (widgetId) => turnstile.reset(widgetId), + /** + * @returns {bool} + */ hasResponse: (widgetId) => !!turnstile.getResponse(widgetId), + /** + * @returns {void} + */ execute: (widgetId) => turnstile.execute(widgetId) }; From a45b40f59c5e4a759829f5aac612525c5416ca01 Mon Sep 17 00:00:00 2001 From: Zankaria Date: Sat, 8 Feb 2025 18:14:06 +0100 Subject: [PATCH 3/6] header.html: use new config style --- templates/header.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/templates/header.html b/templates/header.html index 7e3f9c54..27b1a31f 100644 --- a/templates/header.html +++ b/templates/header.html @@ -28,6 +28,6 @@ {% endif %} {% endif %} - {% if config.recaptcha %} + {% if config.captcha.mode == 'recaptcha' %} {% endif %} From d34b1e105e8d799e3e885140757cc8b66b0a5a2c Mon Sep 17 00:00:00 2001 From: Zankaria Date: Sat, 8 Feb 2025 18:14:32 +0100 Subject: [PATCH 4/6] captcha_script.html: use new config style --- templates/captcha_script.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/templates/captcha_script.html b/templates/captcha_script.html index 79b0b230..c2f5d87f 100644 --- a/templates/captcha_script.html +++ b/templates/captcha_script.html @@ -1,6 +1,6 @@ -{% if config.hcaptcha %} +{% if config.captcha.mode == 'hcaptcha' %} {% endif %} -{% if config.turnstile %} +{% if config.captcha.mode == 'turnstile' %} {% endif %} From 4eb12479ec2d76f7369f9927097634dbe0c14c15 Mon Sep 17 00:00:00 2001 From: Zankaria Date: Sat, 8 Feb 2025 18:14:52 +0100 Subject: [PATCH 5/6] post_form.html: use new config style --- templates/post_form.html | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/templates/post_form.html b/templates/post_form.html index adca9ef6..6cb0ea7a 100644 --- a/templates/post_form.html +++ b/templates/post_form.html @@ -90,8 +90,8 @@ {% endif %} {% endif %} - {% if config.recaptcha %} - {% if config.dynamic_captcha %} + {% if config.captcha.mode == 'recaptcha' %} + {% if config.captcha.dynamic %} {% else %} @@ -101,13 +101,13 @@ {{ antibot.html() }} -
+
{{ antibot.html() }} {% endif %} - {% if config.hcaptcha or config.turnstile %} - {% if config.dynamic_captcha %} + {% if config.captcha.mode == 'hcaptcha' or config.captcha.mode == 'turnstile' %} + {% if config.captcha.dynamic %} {% else %} From a70b6e6ec98e277c238725ba4a70614118304ee3 Mon Sep 17 00:00:00 2001 From: Zankaria Date: Sat, 8 Feb 2025 18:15:07 +0100 Subject: [PATCH 6/6] main.js: use new config style --- templates/main.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/templates/main.js b/templates/main.js index d7ae7fae..574a3611 100755 --- a/templates/main.js +++ b/templates/main.js @@ -243,13 +243,13 @@ function getCookie(cookie_name) { {% endraw %} /* BEGIN CAPTCHA REGION */ -{% if config.hcaptcha or config.turnstile %} // If any captcha +{% if config.captcha.mode == 'hcaptcha' or config.captcha.mode == 'turnstile' %} // If any captcha // Global captcha object. Assigned by `onCaptchaLoad()`. var captcha_renderer = null; // Captcha widget id of the post form. var postCaptchaId = null; -{% if config.hcaptcha %} // If hcaptcha +{% if config.captcha.mode == 'hcaptcha' %} // If hcaptcha function onCaptchaLoadHcaptcha() { if (captcha_renderer === null && (active_page === 'index' || active_page === 'catalog' || active_page === 'thread')) { let renderer = { @@ -257,7 +257,7 @@ function onCaptchaLoadHcaptcha() { * @returns {object} Opaque widget id. */ applyOn: (container, params) => hcaptcha.render(container, { - sitekey: "{{ config.hcaptcha_public }}", + sitekey: "{{ config.captcha.hcaptcha.public }}", callback: params['on-success'], }), /** @@ -282,7 +282,7 @@ function onCaptchaLoadHcaptcha() { } } {% endif %} // End if hcaptcha -{% if config.turnstile %} // If turnstile +{% if config.captcha.mode == 'turnstile' %} // If turnstile // Wrapper function to be called from thread.html window.onCaptchaLoadTurnstile_post_reply = function() { @@ -303,7 +303,7 @@ function onCaptchaLoadTurnstile(action) { */ applyOn: function(container, params) { let widgetId = turnstile.render('#' + container, { - sitekey: "{{ config.turnstile_public }}", + sitekey: "{{ config.captcha.turnstile.public }}", action: action, callback: params['on-success'], });