From 5101afb5335406efc8958eb6a6733df46305f0eb Mon Sep 17 00:00:00 2001 From: Alex Skrypnyk Date: Thu, 19 Feb 2026 14:28:46 +1100 Subject: [PATCH] Fixed captcha on login screen. --- ...tcha_v3.recaptcha_v3_action.recaptcha3.yml | 2 +- .../custom/do_base/do_base.libraries.yml | 7 ++ .../do_base/js/do_base.recaptcha_v3_guard.js | 68 +++++++++++++++++++ .../custom/do_base/src/Hook/FormAlterHook.php | 32 +++++++++ web/themes/custom/drevops/drevops.theme | 10 +++ 5 files changed, 118 insertions(+), 1 deletion(-) create mode 100644 web/modules/custom/do_base/js/do_base.recaptcha_v3_guard.js create mode 100644 web/modules/custom/do_base/src/Hook/FormAlterHook.php diff --git a/config/default/recaptcha_v3.recaptcha_v3_action.recaptcha3.yml b/config/default/recaptcha_v3.recaptcha_v3_action.recaptcha3.yml index 25e9986..cd1826d 100644 --- a/config/default/recaptcha_v3.recaptcha_v3_action.recaptcha3.yml +++ b/config/default/recaptcha_v3.recaptcha_v3_action.recaptcha3.yml @@ -4,5 +4,5 @@ status: true dependencies: { } id: recaptcha3 label: reCaptcha3 -threshold: 0.7 +threshold: 0.5 challenge: image_captcha/Image diff --git a/web/modules/custom/do_base/do_base.libraries.yml b/web/modules/custom/do_base/do_base.libraries.yml index 8fb82d5..4e5355b 100644 --- a/web/modules/custom/do_base/do_base.libraries.yml +++ b/web/modules/custom/do_base/do_base.libraries.yml @@ -1,3 +1,10 @@ +recaptcha_v3_guard: + js: + js/do_base.recaptcha_v3_guard.js: {} + dependencies: + - core/drupal + - core/once + highlight_js.gherkin: js: https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/languages/gherkin.min.js: { type: external, minified: true } diff --git a/web/modules/custom/do_base/js/do_base.recaptcha_v3_guard.js b/web/modules/custom/do_base/js/do_base.recaptcha_v3_guard.js new file mode 100644 index 0000000..3a8e7e0 --- /dev/null +++ b/web/modules/custom/do_base/js/do_base.recaptcha_v3_guard.js @@ -0,0 +1,68 @@ +/** + * @file + * Prevents form submission until the reCAPTCHA v3 token is populated. + * @param {Object} Drupal - The Drupal object. + * @param {Function} once - The once function. + */ + +(function doBaseRecaptchaV3Guard(Drupal, once) { + /** + * Enables all submit buttons in a form. + * + * @param {NodeList} submits - The submit buttons to enable. + */ + function enableSubmits(submits) { + submits.forEach(function enableBtn(btn) { + btn.disabled = false; + }); + } + + /** + * Watches a token input and enables submit buttons when the token is set. + * + * @param {HTMLElement} tokenInput - The reCAPTCHA token hidden input. + * @param {NodeList} submits - The submit buttons to control. + */ + function watchToken(tokenInput, submits) { + // Poll for the token value since hidden input value changes do not + // reliably fire DOM events. + const poll = setInterval(function checkToken() { + if (tokenInput.value) { + clearInterval(poll); + enableSubmits(submits); + } + }, 200); + + // Safety timeout: re-enable buttons after 5 seconds regardless so the + // form is never permanently locked. + setTimeout(function safetyTimeout() { + clearInterval(poll); + enableSubmits(submits); + }, 5000); + } + + Drupal.behaviors.doBaseRecaptchaV3Guard = { + attach: function attachGuard(context) { + once('recaptcha-v3-guard', '.recaptcha-v3-token', context).forEach( + function processToken(tokenInput) { + const form = tokenInput.closest('form'); + if (!form) { + return; + } + + const submits = form.querySelectorAll('[type="submit"]'); + if (!submits.length) { + return; + } + + // Disable submit buttons until the token is ready. + submits.forEach(function disableBtn(btn) { + btn.disabled = true; + }); + + watchToken(tokenInput, submits); + }, + ); + }, + }; +})(Drupal, once); diff --git a/web/modules/custom/do_base/src/Hook/FormAlterHook.php b/web/modules/custom/do_base/src/Hook/FormAlterHook.php new file mode 100644 index 0000000..a02aafe --- /dev/null +++ b/web/modules/custom/do_base/src/Hook/FormAlterHook.php @@ -0,0 +1,32 @@ +