feat(recaptcha): support reCAPTCHA v3 in adaptive forms (+ XFA no-iframe embed fixes) - #1977
feat(recaptcha): support reCAPTCHA v3 in adaptive forms (+ XFA no-iframe embed fixes)#1977kartikey19427 wants to merge 5 commits into
Conversation
Adds handling for the v3 site-key type across the recaptcha component:
- Client-side widget rendering and edit-dialog logic treat v3 the same
as an invisible/score-based key, since v3 has no visible challenge.
- customFunctions.js fetches the v3 token locally (classic, non-enterprise
grecaptcha namespace) since af-core's upstream fetchCaptchaToken only
handles turnstile and Enterprise score-based keys.
- submitForm() is overridden to auto-fetch the captcha token before
submit for v3 as well, matching the existing turnstile/Enterprise
behavior.
- For XFA-rendered forms, the token is applied via
globals.functions.dispatchEvent(field, 'custom:setProperty', {value})
instead of a direct field.value assignment: @aemforms/af-core-xfa's
rule-node proxy only implements a get trap (unlike af-core's, which
also implements set), so a direct assignment invokes the real value
setter with `this` bound to the proxy and crashes on internal
`this.parent` access. Dispatching the update looks the field up by id
on the raw form and applies it directly, avoiding the proxy entirely.
…load Auto-fetch captcha (invisible reCAPTCHA v2, enterprise-score, and v3) failed on XFA-backed adaptive forms embedded without an iframe: clicking Submit logged "fetchCaptchaToken is not defined" and no token was fetched. The frontend ships two runtime bundles - non-XFA (@aemforms/af-core) and XFA (@aemforms/af-core-xfa) - each with its own FunctionRuntime. customFunctions were only registered via setupFormContainer against the non-XFA runtime (window.FormView), while the XFA form's rule engine runs in af-core-xfa and never received fetchCaptchaToken (af-core-xfa ships no default for it), so its built-in submitForm errored. Register customFunctions at bundle load in the shared entry so each bundle populates its own FunctionRuntime - in main-xfa.js this happens before the XFA form instance (and its function-table snapshot) is created. registerFunctions is idempotent, so the later setupFormContainer registration is unaffected. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ts under XFA The container view's submitSuccess/submitError/saveSuccess/saveError handlers read action.target.getState().events, but the XFA runtime's getState() omits `events`, so the handlers threw "Cannot read properties of undefined" on submit/save. This was previously masked by an earlier captcha error and surfaced once captcha submit succeeds on no-iframe XFA embeds. Guard the access with optional chaining; a missing events object means no rule is configured, so the default handler runs (thank-you / error UX). No-op for the non-XFA runtime where events is always present. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Accessibility Violations Found
|
1 similar comment
Accessibility Violations Found
|
| * the framework always appends last. | ||
| * @returns {object} - Empty object, matching the original's return value. | ||
| */ | ||
| function submitForm() { |
There was a problem hiding this comment.
submitForm should not be overridden, we should use a pre-submit hook if required ? Also, can you check old captcha implementation
There was a problem hiding this comment.
Updated — removed the submitForm override. RecaptchaImpl.getCaptchaDisplayMode() now returns invisible for v3, so af-core's built-in submitForm auto-fetches the token natively (works on both the af-core and af-core-xfa runtimes). Also checked the old captcha implementation — the built-in already handles invisible/enterprise-score on the raw form, which is why the override's proxy workaround is no longer needed.
| return a.valueOf(); | ||
| } | ||
|
|
||
| function toStringOrEmpty(a) { |
There was a problem hiding this comment.
These functions are not required, make them inline or private
There was a problem hiding this comment.
Updated — deleted these; they only existed to support the submitForm override, which has been removed.
| * @param {object} globals - An object containing read-only form instance, read-only target field instance and methods for form modifications. | ||
| * @returns {string} - The captcha token. | ||
| */ | ||
| function fetchCaptchaToken(globals) { |
There was a problem hiding this comment.
We should put this af-core, so that even headless/EDS works
There was a problem hiding this comment.
Good call. The canonical fetchCaptchaToken actually lives in @aemforms/af-custom-functions (af-core just looks it up by name), so I've opened a PR there to add v3 natively — this covers headless/EDS too: https://git.corp.adobe.com/livecycle/af-custom-functions/pull/15. Keeping the local wrapper in this PR until that ships and we bump the dependency here, so v3 doesn't regress in the meantime.
|
Please add cypress test cases for runtime and authoring both |
…ode + tests Address review feedback on reCAPTCHA v3 support: - RecaptchaImpl.getCaptchaDisplayMode() returns "invisible" for v3 so af-core's built-in submitForm auto-fetches the token natively (both af-core and af-core-xfa runtimes), removing the need to override submitForm. - Remove the customFunctions.js submitForm override and its helpers (isArrayValue/valueOf/toStringOrEmpty), which only existed to support it. - Add Cypress authoring + runtime specs for v3 and the v3 IT fixtures (cloud config + sample page). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
@navneet-ag Updated — added authoring and runtime Cypress specs for v3: |
…unctions Collapse the local fetchCaptchaToken wrapper to a plain re-export of cf.fetchCaptchaToken now that v3 support lives upstream in @aemforms/af-custom-functions, removing the duplicated v3 grecaptcha.execute logic. Requires an @aemforms/af-custom-functions release that includes v3 support plus a matching dependency bump; until that lands, v3 relies on a local symlink to the updated package. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Accessibility Violations Found
|
Accessibility Violations Found
|
Accessibility Violations Found
|
Accessibility Violations Found
|
Summary
Adds reCAPTCHA v3 support to the adaptive forms recaptcha component, plus two fixes that make auto-fetch captchas work on XFA-backed forms embedded without an iframe.
reCAPTCHA v3 (feature)
customFunctions.jsfetches the v3 token locally (classic, non-enterprisegrecaptchanamespace), since upstreamfetchCaptchaTokenonly handles turnstile and Enterprise score-based keys.submitForm()is overridden to auto-fetch the captcha token before submit for v3 as well, matching the existing turnstile / Enterprise behavior.dispatchEvent(field, 'custom:setProperty', {value})instead of a directfield.value =assignment, to work with af-core-xfa's get-only rule-node proxy.XFA no-iframe embed fixes
While validating v3 on an embedded form, two pre-existing bugs surfaced that broke auto-fetch captcha (invisible v2, enterprise-score, turnstile, and v3) on XFA-backed forms embedded without an iframe:
ui.frontend/src/index.js) — the runtime ships two bundles (non-XFA@aemforms/af-coreand XFA@aemforms/af-core-xfa), each with its ownFunctionRuntime. Custom functions were registered only into the non-XFA runtime viasetupFormContainer(through the singlewindow.FormView), so the XFA form's rule engine never receivedfetchCaptchaTokenand its built-insubmitFormfailed withfetchCaptchaToken is not defined. Registering at bundle load populates each bundle's own runtime before the form model is built.registerFunctionsis idempotent, so the existing registration is unaffected.state.events(formcontainerview.js) — the XFA runtime'sgetState()omitsevents, which crashed the submit/save success/error handlers (Cannot read properties of undefined) once submit progressed. Guarded with optional chaining; a missing events object means no rule is configured, so the default handler runs. No-op for the non-XFA runtime.Testing
Verified end-to-end on a local AEM instance with an enterprise-score reCAPTCHA on an XFA form embedded no-iframe: the XFA rule engine exposes
fetchCaptchaToken, the token is fetched and set on submit,POST /adobe/forms/af/submit/... -> 200 OK, and the thank-you / success handling runs. NofetchCaptchaToken is not definedand nosubmitSuccesshandler crash. Frontend unit tests pass.🤖 Generated with Claude Code