Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
4b14b35
CaptchaProviderInterface, CaptchaRegistry, CaptchaEvent
Fedik Jan 16, 2023
546b500
CaptchaNotFoundException
Fedik Jan 16, 2023
2ac8fa9
CaptchaRegistry service provider
Fedik Jan 16, 2023
9a9334c
Update Captcha class
Fedik Jan 16, 2023
ffee769
InvisibleCaptchaProvider
Fedik Jan 16, 2023
234702e
Comment
Fedik Jan 17, 2023
5e24819
Folder
Fedik Jan 17, 2023
428b81f
phpcs
Fedik Jan 17, 2023
34d4f5d
Sync. Merge branch '4.3-dev' into captcha-event2
Fedik Jan 17, 2023
b9bbbfa
Only values
Fedik Jan 17, 2023
2fe6823
Retrieve name from instance
Fedik Jan 17, 2023
685e0b1
Make sure registry has been init before add
Fedik Jan 17, 2023
40dd41c
Sync: Merge branch '4.3-dev' into captcha-event2
Fedik Feb 20, 2023
7d1ca64
Update
Fedik Feb 20, 2023
6a79176
Update
Fedik Feb 20, 2023
60bb97c
Update
Fedik Feb 20, 2023
4c28239
Update
Fedik Feb 20, 2023
7610e0e
Update
Fedik Feb 20, 2023
6e7f0f7
Update
Fedik Feb 20, 2023
473829c
Update plugins/captcha/recaptcha_invisible/src/Extension/InvisibleReC…
Fedik Feb 20, 2023
87ddc21
Update
Fedik Feb 20, 2023
fe4346b
Update
Fedik Feb 20, 2023
a028742
Update
Fedik Feb 20, 2023
782e8c2
Sync. Merge branch '4.4-dev' into captcha-event2
Fedik Mar 26, 2023
c5af2bf
Merge branch '5.0-dev' into captcha-event2
Fedik Apr 7, 2023
3905f73
Event improve
Fedik Apr 7, 2023
4c50d16
Event improve
Fedik Apr 7, 2023
673f166
Fixes
Fedik Apr 7, 2023
de94e15
Better naming
Fedik Apr 10, 2023
9bff0ed
Sync. Merge branch '5.0-dev' into captcha-event2
Fedik Jul 1, 2023
cf1d340
phpcs
Fedik Jul 1, 2023
610da81
Merge branch '5.0-dev' into captcha-event2
HLeithner Aug 14, 2023
6034939
Merge branch '5.0-dev' into captcha-event2
Fedik Aug 20, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
58 changes: 53 additions & 5 deletions libraries/src/Captcha/Captcha.php
Original file line number Diff line number Diff line change
Expand Up @@ -37,9 +37,19 @@ class Captcha implements DispatcherAwareInterface
*
* @var CMSPlugin
* @since 2.5
*
* @deprecated Should use Provider instance
*/
private $captcha;

/**
* Captcha Provider instance
*
* @var CaptchaProviderInterface
* @since __DEPLOY_VERSION__
*/
private $provider;

/**
* Editor Plugin name
*
Expand Down Expand Up @@ -69,13 +79,25 @@ public function __construct($captcha, $options)
{
$this->name = $captcha;

if (!empty($options['dispatcher']) && $options['dispatcher'] instanceof DispatcherInterface) {
$this->setDispatcher($options['dispatcher']);
/** @var CaptchaRegistry $registry */
$registry = $options['registry'] ?? Factory::getContainer()->get(CaptchaRegistry::class);

if ($registry->has($captcha)) {
$this->provider = $registry->get($captcha);
} else {
$this->setDispatcher(Factory::getApplication()->getDispatcher());
@trigger_error(
'Use of legacy Captcha is deprecated. Use onCaptchaSetup event to register your Captcha provider.',
E_USER_DEPRECATED
);

if (!empty($options['dispatcher']) && $options['dispatcher'] instanceof DispatcherInterface) {
$this->setDispatcher($options['dispatcher']);
} else {
$this->setDispatcher(Factory::getApplication()->getDispatcher());
}

$this->_load($options);
}

$this->_load($options);
}

/**
Expand Down Expand Up @@ -110,9 +132,15 @@ public static function getInstance($captcha, array $options = [])
*
* @since 2.5
* @throws \RuntimeException
*
* @deprecated Without replacement
*/
public function initialise($id)
{
if ($this->provider) {
return true;
}

$arg = ['id' => $id];

$this->update('onInit', $arg);
Expand All @@ -134,6 +162,13 @@ public function initialise($id)
*/
public function display($name, $id, $class = '')
{
if ($this->provider) {
return $this->provider->display($name, [
'id' => $id ?: $name,
'class' => $class,
]);
}

// Check if captcha is already loaded.
if ($this->captcha === null) {
return '';
Expand Down Expand Up @@ -167,6 +202,10 @@ public function display($name, $id, $class = '')
*/
public function checkAnswer($code)
{
if ($this->provider) {
return $this->provider->checkAnswer($code);
}

// Check if captcha is already loaded
if ($this->captcha === null) {
return false;
Expand All @@ -190,6 +229,11 @@ public function checkAnswer($code)
*/
public function setupField(CaptchaField $field, \SimpleXMLElement $element)
{
if ($this->provider) {
$this->provider->setupField($field, $element);
return;
}

if ($this->captcha === null) {
return;
}
Expand All @@ -208,6 +252,8 @@ public function setupField(CaptchaField $field, \SimpleXMLElement $element)
* @return mixed
*
* @since 4.0.0
*
* @deprecated Without replacement
*/
private function update($name, &$args)
{
Expand All @@ -227,6 +273,8 @@ private function update($name, &$args)
*
* @since 2.5
* @throws \RuntimeException
*
* @deprecated Should use CaptchaRegistry
*/
private function _load(array $options = [])
{
Expand Down
70 changes: 70 additions & 0 deletions libraries/src/Captcha/CaptchaProviderInterface.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
<?php

/**
* Joomla! Content Management System
*
* @copyright (C) 2023 Open Source Matters, Inc. <https://www.joomla.org>
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/

namespace Joomla\CMS\Captcha;

use Joomla\CMS\Form\FormField;

/**
* Captcha Provider Interface
*
* @since __DEPLOY_VERSION__
*/
interface CaptchaProviderInterface
{
/**
* Return Captcha name, CMD string.
*
* @return string
* @since __DEPLOY_VERSION__
*/
public function getName(): string;

/**
* Gets the challenge HTML
*
* @param string $name Input name
* @param array $attributes The class of the field
*
* @return string The HTML to be embedded in the form
*
* @since __DEPLOY_VERSION__
*
* @throws \RuntimeException
*/
public function display(string $name = '', array $attributes = []): string;

/**
* Calls an HTTP POST function to verify if the user's guess was correct.
*
* @param string $code Answer provided by user
*
* @return bool If the answer is correct, false otherwise
*
* @since __DEPLOY_VERSION__
*
* @throws \RuntimeException
*/
public function checkAnswer(string $code = null): bool;

/**
* Method to react on the setup of a captcha field. Gives the possibility
* to change the field and/or the XML element for the field.
*
* @param FormField $field Captcha field instance
* @param \SimpleXMLElement $element XML form definition
*
* @return void
*
* @since __DEPLOY_VERSION__
*
* @throws \RuntimeException
*/
public function setupField(FormField $field, \SimpleXMLElement $element): void;
}
119 changes: 119 additions & 0 deletions libraries/src/Captcha/CaptchaRegistry.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
<?php

/**
* Joomla! Content Management System
*
* @copyright (C) 2023 Open Source Matters, Inc. <https://www.joomla.org>
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/

namespace Joomla\CMS\Captcha;

use Joomla\CMS\Captcha\Exception\CaptchaNotFoundException;
use Joomla\CMS\Event\Captcha\CaptchaSetupEvent;
use Joomla\Event\DispatcherAwareInterface;
use Joomla\Event\DispatcherAwareTrait;

// phpcs:disable PSR1.Files.SideEffects
\defined('JPATH_PLATFORM') or die;
// phpcs:enable PSR1.Files.SideEffects

/**
* Captcha Registry class
* @since __DEPLOY_VERSION__
*/
final class CaptchaRegistry implements DispatcherAwareInterface
{
use DispatcherAwareTrait;

/**
* List of registered elements
*
* @var CaptchaProviderInterface[]
* @since __DEPLOY_VERSION__
*/
private $registry = [];

/**
* Internal flag of initialisation
*
* @var boolean
* @since __DEPLOY_VERSION__
*/
private $initialised = false;

/**
* Return list of all registered elements
*
* @return CaptchaProviderInterface[]
* @since __DEPLOY_VERSION__
*/
public function getAll(): array
{
return array_values($this->registry);
}

/**
* Check whether the element exists in the registry.
*
* @param string $name Element name
*
* @return bool
* @since __DEPLOY_VERSION__
*/
public function has(string $name): bool
{
return !empty($this->registry[$name]);
}

/**
* Return element by name.
*
* @param string $name Element name
*
* @return CaptchaProviderInterface
* @throws CaptchaNotFoundException
* @since __DEPLOY_VERSION__
*/
public function get(string $name): CaptchaProviderInterface
{
if (empty($this->registry[$name])) {
throw new CaptchaNotFoundException(sprintf('Captcha element "%s" not found in the registry.', $name));
}

return $this->registry[$name];
}

/**
* Register element in registry, add new or override existing.
*
* @param CaptchaProviderInterface $instance
*
* @return static
* @since __DEPLOY_VERSION__
*/
public function add(CaptchaProviderInterface $instance)
{
$this->registry[$instance->getName()] = $instance;

return $this;
}

/**
* Trigger event to allow register the element through plugins.
*
* @return static
* @since __DEPLOY_VERSION__
*/
public function initRegistry()
{
if (!$this->initialised) {
$this->initialised = true;

$event = new CaptchaSetupEvent('onCaptchaSetup', ['subject' => $this]);
$this->getDispatcher()->dispatch($event->getName(), $event);
}

return $this;
}
}
23 changes: 23 additions & 0 deletions libraries/src/Captcha/Exception/CaptchaNotFoundException.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<?php

/**
* Joomla! Content Management System
*
* @copyright (C) 2023 Open Source Matters, Inc. <https://www.joomla.org>
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/

namespace Joomla\CMS\Captcha\Exception;

// phpcs:disable PSR1.Files.SideEffects
\defined('JPATH_PLATFORM') or die;
// phpcs:enable PSR1.Files.SideEffects

/**
* Exception class defining a missing element
*
* @since __DEPLOY_VERSION__
*/
class CaptchaNotFoundException extends \RuntimeException
{
}
Loading