181 lines
		
	
	
		
			5.3 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
			
		
		
	
	
			181 lines
		
	
	
		
			5.3 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
| <?php
 | |
| /**
 | |
|  * @package     Joomla.Plugin
 | |
|  * @subpackage  Captcha
 | |
|  *
 | |
|  * @author      Peter Martin
 | |
|  * @copyright   Copyright 2016-2024 Peter Martin. All rights reserved.
 | |
|  * @license     GNU General Public License version 2 or later
 | |
|  * @link        https://data2site.com
 | |
|  */
 | |
| 
 | |
| defined('_JEXEC') or die;
 | |
| 
 | |
| use Joomla\CMS\Application\CMSApplication;
 | |
| use Joomla\CMS\Factory;
 | |
| use Joomla\CMS\Http\HttpFactory;
 | |
| use Joomla\CMS\Language\Text;
 | |
| use Joomla\CMS\Plugin\CMSPlugin;
 | |
| use Joomla\Utilities\IpHelper;
 | |
| 
 | |
| /**
 | |
|  * hCaptcha Plugin
 | |
|  * Using the https://www.hcaptcha.com/ CAPTCHA service
 | |
|  *
 | |
|  * @since  1.0.0
 | |
|  */
 | |
| class PlgCaptchaHcaptcha extends CMSPlugin
 | |
| {
 | |
|     /**
 | |
|      * Load the language file on instantiation.
 | |
|      *
 | |
|      * @var    boolean
 | |
|      * @since  1.0.0
 | |
|      */
 | |
|     protected $autoloadLanguage = true;
 | |
| 
 | |
|     /**
 | |
|      * Application object.
 | |
|      *
 | |
|      * @var    CMSApplication
 | |
|      * @since  4.0.0
 | |
|      */
 | |
|     protected $app;
 | |
| 
 | |
|     /**
 | |
|      * Reports the privacy related capabilities for this plugin to site administrators.
 | |
|      *
 | |
|      * @return  array
 | |
|      *
 | |
|      * @since   1.0.0
 | |
|      */
 | |
|     public function onPrivacyCollectAdminCapabilities()
 | |
|     {
 | |
|         $this->loadLanguage();
 | |
| 
 | |
|         return [
 | |
|             Text::_('PLG_CAPTCHA_HCAPTCHA') => [
 | |
|                 Text::_('PLG_CAPTCHA_HCAPTCHA_PRIVACY_CAPABILITY_IP_ADDRESS'),
 | |
|             ]
 | |
|         ];
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * Initialise the captcha
 | |
|      *
 | |
|      * @return  boolean    True on success, false otherwise
 | |
|      *
 | |
|      * @throws  Exception
 | |
|      * @since   1.0.0
 | |
|      */
 | |
|     public function onInit()
 | |
|     {
 | |
|         // If there is no Public Key set, then this plugin is no use, so exit
 | |
|         if ($this->params->get('publicKey', '') === '') {
 | |
|             throw new \RuntimeException(Text::_('PLG_CAPTCHA_HCAPTCHA_ERROR_NO_PUBLIC_KEY'));
 | |
|         }
 | |
| 
 | |
|         // Load the JavaScript from hCaptcha
 | |
|         $this->app->getDocument()->getWebAssetManager()
 | |
|             ->registerAndUseScript('plg_captcha_hcaptcha.api', 'https://hcaptcha.com/1/api.js', [], ['defer' => true]);
 | |
| 
 | |
|         return true;
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * Gets the challenge HTML
 | |
|      *
 | |
|      * @param string $name The name of the field. Not Used.
 | |
|      * @param string $id The id of the field.
 | |
|      * @param string $class The class of the field.
 | |
|      *
 | |
|      * @return  string  The HTML to be embedded in the form.
 | |
|      * @throws  Exception
 | |
|      * @since   1.0.0
 | |
|      */
 | |
|     public function onDisplay($name = null, $id = 'hcaptcha', $class = '')
 | |
|     {
 | |
|         $dom = new \DOMDocument('1.0', 'UTF-8');
 | |
|         $ele = $dom->createElement('div');
 | |
|         $ele->setAttribute('id', $id);
 | |
|         $ele->setAttribute('class', 'h-captcha required');
 | |
|         $ele->setAttribute('data-sitekey', $this->params->get('publicKey', ''));
 | |
|         $ele->setAttribute('data-theme', $this->params->get('theme', 'light'));
 | |
|         $ele->setAttribute('data-size', $this->params->get('size', 'normal'));
 | |
| 
 | |
|         $dom->appendChild($ele);
 | |
| 
 | |
|         return $dom->saveHTML($ele);
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * Calls an HTTP POST function to verify if the user's guess was correct
 | |
|      *
 | |
|      * @param string $code Answer provided by user. Not needed for the Hcaptcha implementation
 | |
|      *
 | |
|      * @return  boolean
 | |
|      * @throws  Exception
 | |
|      * @since   1.0.0
 | |
|      */
 | |
|     public function onCheckAnswer($code = null)
 | |
|     {
 | |
|         $input = Factory::getApplication()->input;
 | |
|         $privateKey = $this->params->get('privateKey');
 | |
|         $remoteIp = IpHelper::getIp();
 | |
|         $hCaptchaResponse = $code ?? $input->get('h-captcha-response', '', 'cmd');
 | |
| 
 | |
|         // Check for Private Key
 | |
|         if (empty($privateKey)) {
 | |
|             throw new \RuntimeException(Text::_('PLG_CAPTCHA_HCAPTCHA_ERROR_NO_PRIVATE_KEY'));
 | |
|         }
 | |
| 
 | |
|         // Check for IP
 | |
|         if (empty($remoteIp)) {
 | |
|             throw new \RuntimeException(Text::_('PLG_CAPTCHA_HCAPTCHA_ERROR_NO_IP'));
 | |
|         }
 | |
| 
 | |
|         if (empty($hCaptchaResponse)) {
 | |
|             throw new \RuntimeException(Text::_('PLG_CAPTCHA_HCAPTCHA_ERROR_EMPTY_SOLUTION'));
 | |
|         }
 | |
| 
 | |
|         return $this->getResponse($privateKey, $remoteIp, $hCaptchaResponse);
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * Get the hCaptcha response.
 | |
|      *
 | |
|      * @param string $privateKey The private key for authentication.
 | |
|      * @param string $remoteIp The remote IP of the visitor.
 | |
|      * @param string $hCaptchaResponse The response received from Google.
 | |
|      *
 | |
|      * @return  bool True if response is good | False if response is bad.
 | |
|      *
 | |
|      * @throws  \RuntimeException
 | |
|      * @since   1.4.0
 | |
|      */
 | |
|     private function getResponse(string $privateKey, string $remoteIp, string $hCaptchaResponse)
 | |
|     {
 | |
|         try {
 | |
|             $verifyResponse = HttpFactory::getHttp()->get(
 | |
|                 'https://hcaptcha.com/siteverify?secret=' . $privateKey .
 | |
|                 '&response=' . $hCaptchaResponse .
 | |
|                 '&remoteip=' . $remoteIp
 | |
|             );
 | |
|         } catch (RuntimeException $e) {
 | |
|             throw new \RuntimeException(Text::_('PLG_CAPTCHA_HCAPTCHA_ERROR_CANT_CONNECT_TO_HCAPTCHA_SERVERS'));
 | |
|         }
 | |
| 
 | |
|         if ($verifyResponse->code !== 200 || $verifyResponse->body === '') {
 | |
|             throw new \RuntimeException(Text::_('PLG_CAPTCHA_HCAPTCHA_ERROR_INVALID_RESPONSE'));
 | |
|         }
 | |
| 
 | |
|         $responseData = json_decode($verifyResponse->body);
 | |
| 
 | |
|         if ($responseData->success) {
 | |
|             return true;
 | |
|         }
 | |
| 
 | |
|         throw new \RuntimeException(Text::_('PLG_CAPTCHA_HCAPTCHA_ERROR_INCORRECT_CAPTCHA'));
 | |
|     }
 | |
| }
 |