[4.8.2] shopFunctionsF::renderCaptcha() broadcasts onDisplay on Joomla 5 - edito

Started by ptrouw, Yesterday at 15:12:28 PM

Previous topic - Next topic

ptrouw

On Joomla 5, renderCaptcha() fires onDisplay on the application dispatcher instead of targeting the captcha plugin group. Every plugin listening to onDisplay responds, including the editor plugins, so the registration form renders an editor instead of a captcha.

components/com_virtuemart/helpers/shopfunctionsf.php, renderCaptcha(), line 1351 in build 11336:

    if (JVM_VERSION < 5) {
        vDispatcher::directTrigger('captcha', $reCaptchaName, 'onInit', array($id));
        $output = vDispatcher::directTrigger('captcha', $reCaptchaName, 'onDisplay', array($reCaptchaName, $id, 'g-recaptcha required'));
    } else {
        $app = JFactory::getApplication();
        $results = $app->triggerEvent('onInit', [$id]);
        $output  = $app->triggerEvent('onDisplay', [$reCaptchaName, $id, 'g-recaptcha required']);
    }

The legacy branch passes the plugin group 'captcha' and the plugin name, so only that plugin is called. The Joomla 5 branch has no group, so the event reaches every onDisplay listener. onDisplay is also the event Joomla editors use to render.

The three captcha arguments land in the editor signature onDisplay($name, $content, $width, $height, $col, $row, ...):

    arg 1  recaptcha_v3          -> $name
    arg 2  dynamic_recaptcha_1   -> $content
    arg 3  g-recaptcha required  -> $width

Actual output on the registration form:

    <textarea name="recaptcha_v3" id="recaptcha_v3" cols="20" rows="4"
              style="width: g-recaptcha required; height: 500px;"
              class="mce_editable wf-editor">dynamic_recaptcha_1</textarea>

cols="20" rows="4" are the editor defaults for the arguments VirtueMart does not pass.

Side effect: the stray editor instance requests its own language file and the editor-api ES module, which produces a 403, a MIME type error and an unresolved module specifier in the browser console. Those disappear once the event is targeted correctly.

To reproduce:
1. Install any captcha plugin and select it under Global Configuration > Site > Default Captcha (Joomla 5 ships none, we use reCAPTCHA v3 by SharkyKZ 1.3.1)
2. VirtueMart > Configuration > Shopfront, enable the captcha on registration
3. Open the user registration form as a guest

Expected: the captcha. Actual: an editor containing the literal text dynamic_recaptcha_1.

Switching the default editor between TinyMCE, JCE and None changes the markup each time, which confirms the editor group is receiving the event rather than one specific editor being at fault.

Suggested fix, using the Joomla 5 captcha API so only the selected plugin is called:

    } else {
        if ($reCaptchaName === '') {
            $output = '';
        } else {
            $captcha = \Joomla\CMS\Captcha\Captcha::getInstance($reCaptchaName);
            $captcha->initialise($id);
            $output = $captcha->display($reCaptchaName, $id, 'g-recaptcha required');
        }
    }

The surrounding try/catch and the is_string($output) branch below already handle this return value, so nothing else needs to change.

One related note: checkCaptcha() a few lines down uses vDispatcher::trigger('onCheckAnswer', ...), which is also a broadcast. Nothing outside the captcha group listens to that event, so it causes no collision, but it does mean every enabled captcha plugin validates the answer.