From 74fbe776356ac7384f620633c5b749871b7b0855 Mon Sep 17 00:00:00 2001 From: Sebastian Fischer Date: Tue, 24 Sep 2024 21:42:42 +0200 Subject: [PATCH 01/10] [TASK] Add category and labels to settings definitions --- Configuration/Sets/Recaptcha/labels.xlf | 64 +++++++++++++++++++ .../Sets/Recaptcha/settings.definitions.yaml | 39 ++++++----- 2 files changed, 82 insertions(+), 21 deletions(-) create mode 100644 Configuration/Sets/Recaptcha/labels.xlf diff --git a/Configuration/Sets/Recaptcha/labels.xlf b/Configuration/Sets/Recaptcha/labels.xlf new file mode 100644 index 0000000..c175b27 --- /dev/null +++ b/Configuration/Sets/Recaptcha/labels.xlf @@ -0,0 +1,64 @@ + + + +
+ + + reCAPTCHA + + + + reCAPTCHA + + + + API-server address + + + api url + + + VERIFY-server address + + + verify url + + + public key + + + Public key of your reCAPTCHA-account + + + private key + + + Private key of your reCAPTCHA-account + + + language + + + Language of frontend (autodetected if empty) + + + enforcing captcha even in development mode + + + theme + + + Theme of frontend (light or dark) + + + robotMode + + + If you use a frontend testing tool, which cannot solve the recaptcha + + + Frontend user registration what captcha to use + + + + diff --git a/Configuration/Sets/Recaptcha/settings.definitions.yaml b/Configuration/Sets/Recaptcha/settings.definitions.yaml index dab0a7c..d36c773 100644 --- a/Configuration/Sets/Recaptcha/settings.definitions.yaml +++ b/Configuration/Sets/Recaptcha/settings.definitions.yaml @@ -1,45 +1,42 @@ +categories: + recaptcha: ~ + sf-register: + label: 'Frontend user registration' + settings: evoweb.recaptcha.apiServer: default: 'https://www.google.com/recaptcha/api.js' - label: 'reCAPTCHA API-server address' type: string - description: 'api url' + category: recaptcha evoweb.recaptcha.verifyServer: default: 'https://www.google.com/recaptcha/api/siteverify' - label: 'reCAPTCHA VERIFY-server address' type: string - description: 'verify url' + category: recaptcha evoweb.recaptcha.publicKey: default: '6LeIxAcTAAAAAJcZVRqyHh71UMIEGNQ_MXjiZKhI' - label: 'reCAPTCHA public key: Public key of your reCAPTCHA-account' type: string + category: recaptcha evoweb.recaptcha.privateKey: default: '6LeIxAcTAAAAAGG-vFI1TnRWxMZNFuojJ4WifJWe' - label: 'reCAPTCHA private key: Private key of your reCAPTCHA-account' type: string - description: '' + category: recaptcha evoweb.recaptcha.lang: default: '?hl=' - label: 'reCAPTCHA language: Language of reCAPTCHA frontend (autodetected if empty)' type: string - description: '' - evoweb.recaptcha.enforceCaptcha: - default: 0 - label: 'enforcing captcha even in development mode' - type: bool - description: '' + category: recaptcha evoweb.recaptcha.theme: default: 'light' - label: 'reCAPTCHA theme: Theme of reCAPTCHA frontend (light or dark)' type: string - description: '' + category: recaptcha evoweb.recaptcha.robotMode: default: 0 - label: 'reCAPTCHA robotMode: If you use a frontend testing tool, which cannot solve the recaptcha' type: bool - description: '' - evoweb.sf_register.captchaId: + category: recaptcha + evoweb.recaptcha.enforceCaptcha: + default: 0 + type: bool + category: recaptcha + evoweb.sf-register.captchaId: default: 'recaptcha' - label: 'Frontend user registration what captcha to use' type: string - description: '' + category: sf-register From 3986eb47756fde0812302d207f03ba53c29560f4 Mon Sep 17 00:00:00 2001 From: Sebastian Fischer Date: Tue, 24 Sep 2024 21:53:26 +0200 Subject: [PATCH 02/10] [TASK] Improve labels of settings --- Configuration/Sets/Recaptcha/labels.xlf | 4 ++-- .../Sets/Recaptcha/settings.definitions.yaml | 17 ++++++++++------- Configuration/TypoScript/constants.typoscript | 2 +- Configuration/TypoScript/setup.typoscript | 2 +- 4 files changed, 14 insertions(+), 11 deletions(-) diff --git a/Configuration/Sets/Recaptcha/labels.xlf b/Configuration/Sets/Recaptcha/labels.xlf index c175b27..4f59d8c 100644 --- a/Configuration/Sets/Recaptcha/labels.xlf +++ b/Configuration/Sets/Recaptcha/labels.xlf @@ -39,7 +39,7 @@ language - Language of frontend (autodetected if empty) + Language of frontend (autodetected if empty). Valid language codes can be found at https://developers.google.com/recaptcha/docs/language?hl=de enforcing captcha even in development mode @@ -48,7 +48,7 @@ theme - Theme of frontend (light or dark) + Theme of frontend can be light or dark robotMode diff --git a/Configuration/Sets/Recaptcha/settings.definitions.yaml b/Configuration/Sets/Recaptcha/settings.definitions.yaml index d36c773..887f1b2 100644 --- a/Configuration/Sets/Recaptcha/settings.definitions.yaml +++ b/Configuration/Sets/Recaptcha/settings.definitions.yaml @@ -5,28 +5,31 @@ categories: settings: evoweb.recaptcha.apiServer: - default: 'https://www.google.com/recaptcha/api.js' + default: '' type: string category: recaptcha evoweb.recaptcha.verifyServer: - default: 'https://www.google.com/recaptcha/api/siteverify' + default: '' type: string category: recaptcha evoweb.recaptcha.publicKey: - default: '6LeIxAcTAAAAAJcZVRqyHh71UMIEGNQ_MXjiZKhI' + default: '' type: string category: recaptcha evoweb.recaptcha.privateKey: - default: '6LeIxAcTAAAAAGG-vFI1TnRWxMZNFuojJ4WifJWe' + default: '' type: string category: recaptcha evoweb.recaptcha.lang: - default: '?hl=' + default: '' type: string category: recaptcha evoweb.recaptcha.theme: - default: 'light' + default: '' type: string + enum: + light: 'light' + dark: 'dark' category: recaptcha evoweb.recaptcha.robotMode: default: 0 @@ -37,6 +40,6 @@ settings: type: bool category: recaptcha evoweb.sf-register.captchaId: - default: 'recaptcha' + default: '' type: string category: sf-register diff --git a/Configuration/TypoScript/constants.typoscript b/Configuration/TypoScript/constants.typoscript index 9b0b27e..eec7168 100644 --- a/Configuration/TypoScript/constants.typoscript +++ b/Configuration/TypoScript/constants.typoscript @@ -14,7 +14,7 @@ plugin.tx_recaptcha { private_key = 6LeIxAcTAAAAAGG-vFI1TnRWxMZNFuojJ4WifJWe # cat=plugin.recaptcha//06; type=string; label= reCAPTCHA language: Language of reCAPTCHA frontend (autodetected if empty) - lang = ?hl= + lang = # cat=plugin.recaptcha//07; type=boolean; label= enforcing captcha even in development mode enforceCaptcha = 0 diff --git a/Configuration/TypoScript/setup.typoscript b/Configuration/TypoScript/setup.typoscript index a56ab2b..c4efbea 100644 --- a/Configuration/TypoScript/setup.typoscript +++ b/Configuration/TypoScript/setup.typoscript @@ -25,7 +25,7 @@ plugin.tx_recaptcha { plugin.tx_sfregister.settings { recaptcha.public_key = {$plugin.tx_recaptcha.public_key ?? $evoweb.recaptcha.publicKey} - recaptcha.lang = {$plugin.tx_recaptcha.lang ?? $evoweb.recaptcha.lang} + recaptcha.lang = ?hl={$plugin.tx_recaptcha.lang ?? $evoweb.recaptcha.lang} # register recaptcha as captcha possibility captcha.recaptcha = Evoweb\Recaptcha\Adapter\SfRegisterAdapter From 4991209ecd7c6bc35232dfd544b6fcb6b79d90e3 Mon Sep 17 00:00:00 2001 From: Sebastian Fischer Date: Wed, 25 Sep 2024 20:01:48 +0200 Subject: [PATCH 03/10] [TASK] Change labels --- Configuration/Sets/Recaptcha/labels.xlf | 16 ++++++++-------- .../Sets/Recaptcha/settings.definitions.yaml | 8 ++++---- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/Configuration/Sets/Recaptcha/labels.xlf b/Configuration/Sets/Recaptcha/labels.xlf index 4f59d8c..0cad300 100644 --- a/Configuration/Sets/Recaptcha/labels.xlf +++ b/Configuration/Sets/Recaptcha/labels.xlf @@ -15,43 +15,43 @@ API-server address - api url + API Url VERIFY-server address - verify url + Verify Url - public key + Public Key Public key of your reCAPTCHA-account - private key + Private Key Private key of your reCAPTCHA-account - language + Language Language of frontend (autodetected if empty). Valid language codes can be found at https://developers.google.com/recaptcha/docs/language?hl=de - enforcing captcha even in development mode + Enforcing captcha even in development mode - theme + Theme Theme of frontend can be light or dark - robotMode + Robot Mode If you use a frontend testing tool, which cannot solve the recaptcha diff --git a/Configuration/Sets/Recaptcha/settings.definitions.yaml b/Configuration/Sets/Recaptcha/settings.definitions.yaml index 887f1b2..11c9d31 100644 --- a/Configuration/Sets/Recaptcha/settings.definitions.yaml +++ b/Configuration/Sets/Recaptcha/settings.definitions.yaml @@ -4,19 +4,19 @@ categories: label: 'Frontend user registration' settings: - evoweb.recaptcha.apiServer: + evoweb.recaptcha.publicKey: default: '' type: string category: recaptcha - evoweb.recaptcha.verifyServer: + evoweb.recaptcha.privateKey: default: '' type: string category: recaptcha - evoweb.recaptcha.publicKey: + evoweb.recaptcha.apiServer: default: '' type: string category: recaptcha - evoweb.recaptcha.privateKey: + evoweb.recaptcha.verifyServer: default: '' type: string category: recaptcha From c833d098f9c411fb4f86cff6c36030afa140e094 Mon Sep 17 00:00:00 2001 From: Sebastian Fischer Date: Wed, 25 Sep 2024 20:14:48 +0200 Subject: [PATCH 04/10] [TASK] Restore defaults --- .../Sets/Recaptcha/settings.definitions.yaml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/Configuration/Sets/Recaptcha/settings.definitions.yaml b/Configuration/Sets/Recaptcha/settings.definitions.yaml index 11c9d31..b6dbc85 100644 --- a/Configuration/Sets/Recaptcha/settings.definitions.yaml +++ b/Configuration/Sets/Recaptcha/settings.definitions.yaml @@ -5,19 +5,19 @@ categories: settings: evoweb.recaptcha.publicKey: - default: '' + default: '6LeIxAcTAAAAAJcZVRqyHh71UMIEGNQ_MXjiZKhI' type: string category: recaptcha evoweb.recaptcha.privateKey: - default: '' + default: '6LeIxAcTAAAAAGG-vFI1TnRWxMZNFuojJ4WifJWe' type: string category: recaptcha evoweb.recaptcha.apiServer: - default: '' + default: 'https://www.google.com/recaptcha/api.js' type: string category: recaptcha evoweb.recaptcha.verifyServer: - default: '' + default: 'https://www.google.com/recaptcha/api/siteverify' type: string category: recaptcha evoweb.recaptcha.lang: @@ -25,7 +25,7 @@ settings: type: string category: recaptcha evoweb.recaptcha.theme: - default: '' + default: 'light' type: string enum: light: 'light' @@ -40,6 +40,6 @@ settings: type: bool category: recaptcha evoweb.sf-register.captchaId: - default: '' + default: 'recaptcha' type: string category: sf-register From 3d2ff96ea52908dddef9f6759fc382c2e6282d73 Mon Sep 17 00:00:00 2001 From: Sebastian Fischer Date: Sat, 5 Oct 2024 11:13:43 +0200 Subject: [PATCH 05/10] [BUGFIX] Fix usage of sf_register session --- Classes/Adapter/SfRegisterAdapter.php | 1 + 1 file changed, 1 insertion(+) diff --git a/Classes/Adapter/SfRegisterAdapter.php b/Classes/Adapter/SfRegisterAdapter.php index 343b866..4c1b86c 100644 --- a/Classes/Adapter/SfRegisterAdapter.php +++ b/Classes/Adapter/SfRegisterAdapter.php @@ -29,6 +29,7 @@ public function __construct(protected CaptchaService $captchaService, protected */ public function render(): array|string { + $this->session->initializeUserSessionManager(); $this->session->remove('captchaWasValid'); return $this->captchaService->getReCaptcha(); } From f9576f1ef6c9c077b6c85f06892dcb0588dd9800 Mon Sep 17 00:00:00 2001 From: Sebastian Fischer Date: Fri, 11 Oct 2024 20:56:36 +0200 Subject: [PATCH 06/10] [TASK] Add link to label --- Configuration/Sets/Recaptcha/labels.xlf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Configuration/Sets/Recaptcha/labels.xlf b/Configuration/Sets/Recaptcha/labels.xlf index 0cad300..eec1b93 100644 --- a/Configuration/Sets/Recaptcha/labels.xlf +++ b/Configuration/Sets/Recaptcha/labels.xlf @@ -27,7 +27,7 @@ Public Key - Public key of your reCAPTCHA-account + Public key of your reCAPTCHA-account. Get your keys at https://www.google.com/recaptcha/admin Private Key From ce122d0ed9fba51c940f7f2111c1dbd39fea2bd4 Mon Sep 17 00:00:00 2001 From: Sebastian Fischer Date: Fri, 11 Oct 2024 20:58:15 +0200 Subject: [PATCH 07/10] [TASK] Replace checkValidity with reportValidity --- Resources/Public/JavaScript/Frontend/form.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Resources/Public/JavaScript/Frontend/form.js b/Resources/Public/JavaScript/Frontend/form.js index 937ce47..1962b2b 100644 --- a/Resources/Public/JavaScript/Frontend/form.js +++ b/Resources/Public/JavaScript/Frontend/form.js @@ -46,7 +46,7 @@ class Recaptcha { * @param {PointerEvent} event */ visibleRecaptchaButtonClicked(event) { - if (!this.form.checkValidity() || !this.recaptchaFieldValid()) { + if (!this.form.reportValidity() || !this.recaptchaFieldValid()) { event.preventDefault(); } } @@ -72,7 +72,7 @@ class Recaptcha { */ submitForm(response) { this.response = response; - if (this.form.checkValidity()) { + if (this.form.reportValidity()) { this.field.value = response; this.form.submit(); } From 09bf84dc0c80de0dea964e6c9d8dd8fa6982d674 Mon Sep 17 00:00:00 2001 From: Sebastian Fischer Date: Sat, 12 Oct 2024 17:02:15 +0200 Subject: [PATCH 08/10] [TASK] Introduce possibility to configure keys for visible and invisible recaptcha With this its possible to define site config or TypoScript constants for both visible and invisible recaptcha. This allows to use both types in one pagetree. --- Classes/Services/CaptchaService.php | 7 +++- Configuration/Sets/Recaptcha/labels.xlf | 6 +++ .../Sets/Recaptcha/settings.definitions.yaml | 8 ++++ Configuration/TypoScript/constants.typoscript | 10 ++++- Configuration/TypoScript/setup.typoscript | 15 ++------ Resources/Private/Partials/Form/Captcha.html | 37 +++++++++++-------- .../Private/Partials/Form/Navigation.html | 9 ++++- Resources/Private/Partials/Recaptcha.html | 6 ++- ext_conf_template.txt | 6 +++ 9 files changed, 70 insertions(+), 34 deletions(-) diff --git a/Classes/Services/CaptchaService.php b/Classes/Services/CaptchaService.php index 46f86f1..1e92854 100644 --- a/Classes/Services/CaptchaService.php +++ b/Classes/Services/CaptchaService.php @@ -156,8 +156,13 @@ public function validateReCaptcha(string $value = ''): array ]; } + $privateKey = $this->getRequest()->getParsedBody()['recaptcha-invisible'] ?? false + ? $this->configuration['invisible_private_key'] + : $this->configuration['private_key']; + $privateKey = $privateKey ?: $this->configuration['private_key']; + $request = [ - 'secret' => $this->configuration['private_key'] ?? '', + 'secret' => $privateKey, 'response' => trim( !empty($value) ? $value : (string)($this->getRequest()->getParsedBody()['g-recaptcha-response'] ?? '') ), diff --git a/Configuration/Sets/Recaptcha/labels.xlf b/Configuration/Sets/Recaptcha/labels.xlf index eec1b93..a2346ff 100644 --- a/Configuration/Sets/Recaptcha/labels.xlf +++ b/Configuration/Sets/Recaptcha/labels.xlf @@ -35,6 +35,12 @@ Private key of your reCAPTCHA-account + + Public key for invisible recaptcha + + + Private key for invisible recaptcha + Language diff --git a/Configuration/Sets/Recaptcha/settings.definitions.yaml b/Configuration/Sets/Recaptcha/settings.definitions.yaml index b6dbc85..80de13b 100644 --- a/Configuration/Sets/Recaptcha/settings.definitions.yaml +++ b/Configuration/Sets/Recaptcha/settings.definitions.yaml @@ -12,6 +12,14 @@ settings: default: '6LeIxAcTAAAAAGG-vFI1TnRWxMZNFuojJ4WifJWe' type: string category: recaptcha + evoweb.recaptcha.invisiblePublicKey: + default: '' + type: string + category: recaptcha + evoweb.recaptcha.invisiblePrivateKey: + default: '' + type: string + category: recaptcha evoweb.recaptcha.apiServer: default: 'https://www.google.com/recaptcha/api.js' type: string diff --git a/Configuration/TypoScript/constants.typoscript b/Configuration/TypoScript/constants.typoscript index eec7168..f307dab 100644 --- a/Configuration/TypoScript/constants.typoscript +++ b/Configuration/TypoScript/constants.typoscript @@ -13,10 +13,16 @@ plugin.tx_recaptcha { # cat=plugin.recaptcha//04; type=string; label= reCAPTCHA private key: Private key of your reCAPTCHA-account private_key = 6LeIxAcTAAAAAGG-vFI1TnRWxMZNFuojJ4WifJWe - # cat=plugin.recaptcha//06; type=string; label= reCAPTCHA language: Language of reCAPTCHA frontend (autodetected if empty) + # cat=plugin.recaptcha//05; type=string; label= reCAPTCHA public key: Public key of your reCAPTCHA-account + invisible_public_key = + + # cat=plugin.recaptcha//06; type=string; label= reCAPTCHA public key: Public key of your reCAPTCHA-account + invisible_private_key = + + # cat=plugin.recaptcha//07; type=string; label= reCAPTCHA language: Language of reCAPTCHA frontend (autodetected if empty) lang = - # cat=plugin.recaptcha//07; type=boolean; label= enforcing captcha even in development mode + # cat=plugin.recaptcha//08; type=boolean; label= enforcing captcha even in development mode enforceCaptcha = 0 # cat=plugin.recaptcha//10; type=string; label= reCAPTCHA theme: Theme of reCAPTCHA frontend (light or dark) diff --git a/Configuration/TypoScript/setup.typoscript b/Configuration/TypoScript/setup.typoscript index c4efbea..c27e619 100644 --- a/Configuration/TypoScript/setup.typoscript +++ b/Configuration/TypoScript/setup.typoscript @@ -10,6 +10,9 @@ plugin.tx_recaptcha { # look at https://www.google.com/recaptcha/admin to register a key for your server private_key = {$plugin.tx_recaptcha.private_key ?? $evoweb.recaptcha.privateKey} + invisible_public_key = {$plugin.tx_recaptcha.invisible_public_key ?? $evoweb.recaptcha.invisiblePublicKey} + invisible_private_key = {$plugin.tx_recaptcha.invisible_private_key ?? $evoweb.recaptcha.invisiblePrivateKey} + api_server = {$plugin.tx_recaptcha.api_server ?? $evoweb.recaptcha.apiServer} verify_server = {$plugin.tx_recaptcha.verify_server ?? $evoweb.recaptcha.verifyServer} @@ -23,10 +26,6 @@ plugin.tx_recaptcha { # register recaptcha as captcha for sf_register plugin.tx_sfregister.settings { - recaptcha.public_key = {$plugin.tx_recaptcha.public_key ?? $evoweb.recaptcha.publicKey} - - recaptcha.lang = ?hl={$plugin.tx_recaptcha.lang ?? $evoweb.recaptcha.lang} - # register recaptcha as captcha possibility captcha.recaptcha = Evoweb\Recaptcha\Adapter\SfRegisterAdapter @@ -52,11 +51,3 @@ plugin.tx_sfregister.view.partialRootPaths.1974 = EXT:recaptcha/Resources/Privat # add settings for EXT:form plugin.tx_form.settings.yamlConfigurations.1974 = EXT:recaptcha/Configuration/Yaml/FormSetup.yaml plugin.tx_form.view.partialRootPaths.1974 = EXT:recaptcha/Resources/Private/Partials/ - - -page.includeJSFooterlibs.recaptcha = {$plugin.tx_recaptcha.api_server ?? $evoweb.recaptcha.apiServer}{$plugin.tx_recaptcha.lang ?? $evoweb.recaptcha.lang} -page.includeJSFooterlibs.recaptcha { - external = 1 - disableCompression = 1 - excludeFromConcatenation = 1 -} diff --git a/Resources/Private/Partials/Form/Captcha.html b/Resources/Private/Partials/Form/Captcha.html index aed2bb1..5fe977e 100644 --- a/Resources/Private/Partials/Form/Captcha.html +++ b/Resources/Private/Partials/Form/Captcha.html @@ -1,19 +1,24 @@ - -{validationResults.flattenedErrors -> f:count()} - -
- -
-
-
+ + + + + {validationResults.flattenedErrors -> f:count()} + +
+ +
+
+
+
diff --git a/Resources/Private/Partials/Form/Navigation.html b/Resources/Private/Partials/Form/Navigation.html index 7dd308a..d0c9fb8 100644 --- a/Resources/Private/Partials/Form/Navigation.html +++ b/Resources/Private/Partials/Form/Navigation.html @@ -23,7 +23,6 @@ - @@ -31,12 +30,18 @@ + + {configuration.invisible_public_key} + {configuration.public_key} + + diff --git a/Resources/Private/Partials/Recaptcha.html b/Resources/Private/Partials/Recaptcha.html index 2fd2a12..9df5e6b 100644 --- a/Resources/Private/Partials/Recaptcha.html +++ b/Resources/Private/Partials/Recaptcha.html @@ -2,12 +2,14 @@ xmlns:formvh="http://typo3.org/ns/TYPO3/CMS/Form/ViewHelpers" xmlns:r="http://typo3.org/ns/Evoweb/Recaptcha/ViewHelpers" data-namespace-typo3-fluid="true"> + - + + + + Date: Sat, 12 Oct 2024 17:15:29 +0200 Subject: [PATCH 09/10] [TASK] Refactor javascript to handle multiple form on a page With this change, it's now possible to have more than one form on a page, that uses recaptcha. --- Resources/Public/JavaScript/Frontend/form.js | 145 +++++++++++++------ 1 file changed, 103 insertions(+), 42 deletions(-) diff --git a/Resources/Public/JavaScript/Frontend/form.js b/Resources/Public/JavaScript/Frontend/form.js index 1962b2b..7ccb982 100644 --- a/Resources/Public/JavaScript/Frontend/form.js +++ b/Resources/Public/JavaScript/Frontend/form.js @@ -1,52 +1,61 @@ -class Recaptcha { +class RecaptchaForm { /** * @type {string} */ - fieldSelector = '[data-recaptcha-form-field]'; + #fieldSelector = '[data-recaptcha-form-field]'; + + #submitSelector = '[data-recaptcha-form-submit]'; + + #invisibleSubmitSelector = '[data-invisible-recaptcha-form-submit]'; /** - * @type {HTMLFormElement} + * @type {Recaptcha} */ - form = null; + #recaptcha = null; /** - * @type {HTMLInputElement} + * @type {HTMLFormElement} */ - field = null; + #form = null; /** - * @type {string} + * @type {HTMLInputElement} */ - response = ''; + #field = null; /** + * @param {Recaptcha} recaptcha * @param {HTMLFormElement} form */ - constructor(form) { + constructor(recaptcha, form) { + this.#recaptcha = recaptcha; + this.#form = form; + this.initializeElements(form); this.initializeEvents(); - this.registerCallback(); } /** * @param {HTMLFormElement} form */ initializeElements(form) { - this.form = form; - this.field = this.form.querySelector(this.fieldSelector); + this.#field = form.querySelector(this.#fieldSelector); } initializeEvents() { // used with visible recaptcha - [...this.form.querySelectorAll('[data-recaptcha-form-submit]')] + [...this.#form.querySelectorAll(this.#submitSelector)] .map(button => button.addEventListener('click', event => this.visibleRecaptchaButtonClicked(event))); + // used with invisible recaptcha + [...this.#form.querySelectorAll(this.#invisibleSubmitSelector)] + .map(button => button.addEventListener('click', () => this.#recaptcha.setLastForm(this))); } /** * @param {PointerEvent} event */ visibleRecaptchaButtonClicked(event) { - if (!this.form.reportValidity() || !this.recaptchaFieldValid()) { + if (!this.#form.reportValidity() || !this.fieldValid()) { event.preventDefault(); } } @@ -54,54 +63,106 @@ class Recaptcha { /** * @return {boolean} */ - recaptchaFieldValid() { - return this.field.value !== '' && this.field.value === this.response; + fieldValid() { + return this.#field.value !== '' && this.#field.value === this.#recaptcha.getResponse(); + } + + setFieldValue(value) { + this.#field.value = value; + } + + /** + * @return {boolean} + */ + reportValidity() { + return this.#form.reportValidity(); + } + + submit() { + this.#form.submit(); + } +} + +class Recaptcha { + /** + * @type {RecaptchaForm[]} + */ + #forms = []; + + /** + * @type {RecaptchaForm} + */ + #lastForm = null; + + /** + * @type {string} + */ + #response = ''; + + constructor() { + this.initializeForms(); + this.registerCallback(); + } + + initializeForms() { + [...document.querySelectorAll('form .g-recaptcha')] + .map(element => { + const form = element.closest('form'); + if (form) { + this.#forms.push(new RecaptchaForm(this, form)); + } + }) } registerCallback() { // for box recaptcha - window.onRecaptchaCallback = (response) => this.callback(response); + window.onRecaptchaCallback = (response) => this.recaptchaCallback(response); window.onRecaptchaExpired = () => this.recaptchaExpired(); window.onRecaptchaError = () => this.recaptchaError(); // for invisible recaptcha - window.onRecaptchaSubmit = (response) => this.submitForm(response); + window.onRecaptchaSubmit = (response) => this.recaptchaSubmit(response); } /** * @param {string} response */ - submitForm(response) { - this.response = response; - if (this.form.reportValidity()) { - this.field.value = response; - this.form.submit(); - } + recaptchaCallback(response) { + this.#response = response; + this.#forms.forEach(form => form.setFieldValue(response)); + } + + recaptchaExpired() { + this.#lastForm = null; + this.#response = ''; + this.#forms.forEach(form => form.setFieldValue('')); + } + + recaptchaError() { + this.#lastForm = null; + this.#response = ''; + this.#forms.forEach(form => form.setFieldValue('')); } /** * @param {string} response */ - callback(response) { - this.response = response; - this.field.value = response; - } - - recaptchaExpired() { - this.response = ''; - this.field.value = ''; + recaptchaSubmit(response) { + this.#response = response; + if (this.#lastForm && this.#lastForm.reportValidity()) { + this.#lastForm.setFieldValue(response); + this.#lastForm.submit(); + } } - recaptchaError() { - this.response = ''; - this.field.value = ''; + /** + * @returns {string} + */ + getResponse() { + return this.#response; } - static initializeForms() { - [...document.querySelectorAll('form .g-recaptcha')] - .map(element => { - const form = element.closest('form'); - new Recaptcha(form); - }) + setLastForm(lastForm) { + this.#lastForm = lastForm; } } -Recaptcha.initializeForms(); +new Recaptcha(); From 78eb13af33bd6115d0b050f95d9c6da543910c65 Mon Sep 17 00:00:00 2001 From: Sebastian Fischer Date: Sat, 12 Oct 2024 17:53:25 +0200 Subject: [PATCH 10/10] [TASK] Add documentation about breaking change --- Documentation/BreakingChanges/Index.rst | 17 +++++++++++++++++ Documentation/guides.xml | 4 ++-- ext_emconf.php | 2 +- 3 files changed, 20 insertions(+), 3 deletions(-) diff --git a/Documentation/BreakingChanges/Index.rst b/Documentation/BreakingChanges/Index.rst index 59f4687..945e7c3 100644 --- a/Documentation/BreakingChanges/Index.rst +++ b/Documentation/BreakingChanges/Index.rst @@ -6,6 +6,23 @@ Breaking Changes ================ +12. October 2024 +================ + +The possibility for configuring extra keys for invisible recaptcha was added. For +this to work, the partials needed to be modified. If you override the partials, +please check that they contain the changes. + +In addition it was made possible to have more than one form with recaptcha on +a page. These needed a complete refactoring of form.js for the frontend. Check +that the inclusion via f:asset.script is the same in your site. + +Lastly the inclusion of the recaptcha.js was change from TypoScript includeFooterJs +to f:asset.script. By this only on page with a form that is protected with +recaptcha, the js file gets loaded. For this to work, you need to synchronize +the partials if you override them. + + 13. August 2023 =============== diff --git a/Documentation/guides.xml b/Documentation/guides.xml index 6f245d7..0084956 100644 --- a/Documentation/guides.xml +++ b/Documentation/guides.xml @@ -16,8 +16,8 @@ interlink-shortcode="evoweb/recaptcha" /> diff --git a/ext_emconf.php b/ext_emconf.php index 8a7cb16..53e0b2c 100644 --- a/ext_emconf.php +++ b/ext_emconf.php @@ -9,7 +9,7 @@ 'author_email' => 'typo3@evoweb.de', 'author_company' => 'evoWeb', 'state' => 'stable', - 'version' => '13.0.2', + 'version' => '14.0.0', 'constraints' => [ 'depends' => [ 'typo3' => '13.0.0-13.4.99',