diff --git a/framework/elements/formbuilder/ajax.php b/framework/elements/formbuilder/ajax.php index 9fca36ab..38231421 100644 --- a/framework/elements/formbuilder/ajax.php +++ b/framework/elements/formbuilder/ajax.php @@ -46,17 +46,17 @@ $message = $params->get('email_body', ''); $email_headers = $params->get('email_headers', ''); $gcaptcha = $mainframe->input->post->get('g-recaptcha-response'); - $pluginParams = Helper::getPluginParams(); + $pluginParams = Helper::getPluginParams('captcha', 'astroidcaptcha'); foreach ($asformbuilder as $field => $value) { $message = str_replace('{{'.$field.'}}', $value, $message); $email_headers = str_replace('{{'.$field.'}}', $value, $email_headers); } $replyToMail = $replyToName = ''; + if (intval($params->get('enable_captcha', 0))) { $captcha_type = $pluginParams->get('captcha_type', 'default'); $invalidCaptchaMessage = Text::_('ASTROID_AJAX_ERROR_INVALID_CAPTCHA'); - if ($captcha_type == 'recaptcha' || $captcha_type == 'recaptcha_invisible') { if (empty($gcaptcha) || !Helper\Captcha::verifyGoogleCaptcha($gcaptcha)) { throw new \Exception($invalidCaptchaMessage); diff --git a/framework/elements/formbuilder/formbuilder.php b/framework/elements/formbuilder/formbuilder.php index 58fdbf29..cbd54b1a 100644 --- a/framework/elements/formbuilder/formbuilder.php +++ b/framework/elements/formbuilder/formbuilder.php @@ -56,14 +56,21 @@ $document = Framework::getDocument(); $show_label = $params->get('show_label', 1); -$pluginParams = Helper::getPluginParams(); +$pluginParams = Helper::getPluginParams('captcha', 'astroidcaptcha'); $captcha_attr = ''; if ($params->get('enable_captcha', 0) == 1) { $captcha_type = $pluginParams->get('captcha_type', 'default'); $captcha_attr = ' data-captcha="'.$captcha_type.'"'; if ($captcha_type == 'recaptcha' || $captcha_type == 'recaptcha_invisible') { - $document->loadGoogleReCaptcha(); + $captcha_attr .= ' data-sitekey="'.$pluginParams->get('g_site_key', '').'"'; + if ($captcha_type == 'recaptcha_invisible') { + $document->loadGoogleReCaptcha([], 'explicit'); + $captcha_attr .= ' data-badge="'.$pluginParams->get('badge', 'bottomright').'"'; + } else { + $document->loadGoogleReCaptcha(); + } + $captcha_attr .= ' data-tabindex="'.$pluginParams->get('tabindex', '0').'"'; } } @@ -184,7 +191,6 @@ } else { echo Helper\Captcha::loadCaptcha('as-formbuilder-captcha'); } - echo ''; echo ''; } echo ''; diff --git a/framework/library/astroid/Document.php b/framework/library/astroid/Document.php index 838dc943..25abeecf 100644 --- a/framework/library/astroid/Document.php +++ b/framework/library/astroid/Document.php @@ -1031,10 +1031,26 @@ public function loadLenis(): void } } - public function loadGoogleReCaptcha(): void + public function loadGoogleReCaptcha($onload = [], $render = ''): void { - $wa = Factory::getApplication()->getDocument()->getWebAssetManager(); - $wa->registerAndUseScript('google.recaptcha', '//www.google.com/recaptcha/api.js', ['relative' => true, 'version' => 'auto']); + $app = Factory::getApplication(); + $wa = $app->getDocument()->getWebAssetManager(); + $query = array(); + $depends = []; + if (empty($onload)) { + $onload = ['url' => '', 'function' => '']; + } + if (!empty($onload['url'])) { + $wa->registerAndUseScript('google.recaptcha.onload', $onload['url'], [], ['defer' => true]); + $query[] = 'onload=' . $onload['function']; + $depends[] = 'google.recaptcha.onload'; + } + if (!empty($render)) { + $query[] = 'render=' . $render; + } + $query[] = 'hl=' . $app->getLanguage()->getTag(); + $wa->registerAndUseScript('google.recaptcha', '//www.google.com/recaptcha/api.js?' + .implode('&',$query), [], ['defer' => true], $depends); } public function moveFile(&$array, $a, $b): void diff --git a/framework/library/astroid/Helper.php b/framework/library/astroid/Helper.php index e3aa6396..c199f831 100644 --- a/framework/library/astroid/Helper.php +++ b/framework/library/astroid/Helper.php @@ -36,9 +36,9 @@ public static function loadLanguage($extension, $client = 'site') $lang->load($extension, ($client == 'site' ? JPATH_SITE : JPATH_ADMINISTRATOR)); } - public static function getPluginParams() + public static function getPluginParams($group = 'system', $plugin = 'astroid') { - $plugin = PluginHelper::getPlugin('system', 'astroid'); + $plugin = PluginHelper::getPlugin($group, $plugin); return new Registry($plugin->params); } diff --git a/framework/library/astroid/Helper/Captcha.php b/framework/library/astroid/Helper/Captcha.php index b28869fd..7bd3d4ea 100644 --- a/framework/library/astroid/Helper/Captcha.php +++ b/framework/library/astroid/Helper/Captcha.php @@ -11,6 +11,10 @@ use Astroid\Helper; use Joomla\CMS\Factory; +use Joomla\CMS\Captcha\Google\HttpBridgePostRequestMethod; +use ReCaptcha\ReCaptcha; +use ReCaptcha\RequestMethod; +use Joomla\Utilities\IpHelper; defined('_JEXEC') or die; @@ -24,7 +28,7 @@ public static function loadCaptcha($context = '') { $value2 = rand(1,100); $app->setUserState( $context.'.value1', $value1 ); $app->setUserState( $context.'.value2', $value2 ); - return '
'.($value1 . ' + ' . $value2 .' = ?').'
'; + return '
'.($value1 . ' + ' . $value2 .' = ?').'
'; } public static function getCaptcha($context = '') { @@ -35,35 +39,31 @@ public static function getCaptcha($context = '') { return ( $value1 + $value2 == $value_result ); } - public static function verifyGoogleCaptcha($gRecaptchaResponse, $secretKey = '') { - if (empty($gRecaptchaResponse)) { - return false; - } + public static function verifyGoogleCaptcha($gRecaptchaResponse, $secretKey = '', RequestMethod $requestMethod = new HttpBridgePostRequestMethod()) { + $app = Factory::getApplication(); if (empty($secretKey)) { - $pluginParams = Helper::getPluginParams(); + $pluginParams = Helper::getPluginParams('captcha', 'astroidcaptcha'); $secretKey = $pluginParams->get('g_secret_key', ''); } if (empty($secretKey)) { + throw new \RuntimeException($app->getLanguage()->_('ASTROID_GOOGLE_RECAPTCHA_ERROR_NO_PRIVATE_KEY')); + } + $remoteip = IpHelper::getIp(); + // Check for IP + if (empty($remoteip)) { + throw new \RuntimeException($app->getLanguage()->_('ASTROID_GOOGLE_RECAPTCHA_ERROR_NO_IP')); + } + if (empty($gRecaptchaResponse)) { + throw new \RuntimeException($app->getLanguage()->_('ASTROID_GOOGLE_RECAPTCHA_ERROR_EMPTY_SOLUTION')); + } + $reCaptcha = new ReCaptcha($secretKey, $requestMethod); + $response = $reCaptcha->verify($gRecaptchaResponse, $remoteip); + if (!$response->isSuccess()) { + foreach ($response->getErrorCodes() as $error) { + throw new \RuntimeException($error); + } return false; } - $url = 'https://www.google.com/recaptcha/api/siteverify'; - $data = [ - 'secret' => $secretKey, - 'response' => $gRecaptchaResponse - ]; - - $options = [ - 'http' => [ - 'header' => "Content-type: application/x-www-form-urlencoded\r\n", - 'method' => 'POST', - 'content' => http_build_query($data), - ], - ]; - - $context = stream_context_create($options); - $result = file_get_contents($url, false, $context); - $response = json_decode($result, true); - - return isset($response['success']) && $response['success'] === true; + return true; } } \ No newline at end of file diff --git a/js/formbuilder.js b/js/formbuilder.js index 63afb44d..015c820c 100644 --- a/js/formbuilder.js +++ b/js/formbuilder.js @@ -1,37 +1,80 @@ -jQuery(function($){ - if ($('.as-form-builder').length) { - $(document).on('submit', '.as-form-builder' , function (e) { - e.preventDefault(); - var request = {}, - $this = $(this), - data = $this.serializeArray(); - let id = Date.now() * 1000 + Math.random() * 1000; - id = id.toString(16).replace(/\./g, "").padEnd(14, "0")+Math.trunc(Math.random() * 100000000); - for (let i = 0; i < data.length; i++) { - request[data[i]['name']] = data[i]['value']; - } - request[$this.find('.token').attr('name')] = 1; - $.ajax({ - type : 'POST', - url : $this.attr('action')+'&t='+id, - data : request, - beforeSend: function(){ - $this.find('.as-formbuilder-status').empty(); - $this.find('.as-form-builer-submit').attr('disabled', 'disabled'); - }, - success: function (response) { - if (response.status === 'success') { - $this.find('.as-formbuilder-status').append(''); - $this.trigger("reset"); - $this.find('.g-recaptcha').each(function(){ - grecaptcha.reset(this); - }) - } else { - $this.find('.as-formbuilder-status').append(''); - } - $this.find('.as-form-builer-submit').removeAttr('disabled'); - } - }); - }); - } +class FormBuilder { + constructor(el) { + this.el = el; + if (this.el.dataset.captcha === 'recaptcha' || this.el.dataset.captcha === 'recaptcha_invisible') { + this.initReCaptcha(); + } + this.el.querySelector('.as-form-builer-submit').addEventListener('click', this.onSubmit.bind(this)); + } + + initReCaptcha() { + let color = 'light'; + if (typeof ASTROID_COLOR_MODE !== 'undefined') { + color = ASTROID_COLOR_MODE; + } + let config = { + 'sitekey': this.el.dataset.sitekey, + 'tabindex': this.el.dataset.tabindex, + 'theme': color + } + if (this.el.dataset.captcha === 'recaptcha_invisible') { + config['badge'] = this.el.dataset.badge; + config['size'] = 'invisible'; + config['callback'] = this.onCallAjax.bind(this); + } + grecaptcha.ready(() => { + grecaptcha.render(this.el.querySelector('.google-recaptcha'), config); + }); + } + + onSubmit() { + if (!this.el.checkValidity()) { + this.el.classList.add('was-validated'); + return; + } + if (this.el.dataset.captcha === 'recaptcha_invisible') { + grecaptcha.execute(); + } else { + this.onCallAjax(); + } + } + + onCallAjax(token) { + var request = {}, + $this = jQuery(this.el), + data = $this.serializeArray(); + let id = Date.now() * 1000 + Math.random() * 1000; + id = id.toString(16).replace(/\./g, "").padEnd(14, "0")+Math.trunc(Math.random() * 100000000); + for (let i = 0; i < data.length; i++) { + request[data[i]['name']] = data[i]['value']; + } + request[$this.find('.token').attr('name')] = 1; + jQuery.ajax({ + type : 'POST', + url : $this.attr('action')+'&t='+id, + data : request, + beforeSend: function(){ + $this.find('.as-formbuilder-status').empty(); + $this.find('.as-form-builer-submit').attr('disabled', 'disabled'); + }, + success: function (response) { + if (response.status === 'success') { + $this.find('.as-formbuilder-status').append(''); + $this.trigger("reset"); + $this.find('.google-recaptcha').each(function(){ + grecaptcha.reset(this); + }) + } else { + $this.find('.as-formbuilder-status').append(''); + } + $this.find('.as-form-builer-submit').removeAttr('disabled'); + $this.removeClass('was-validated'); + } + }); + } +} +jQuery(function($) { + $('.as-form-builder').each(function() { + new FormBuilder(this); + }); }); \ No newline at end of file diff --git a/js/formbuilder.min.js b/js/formbuilder.min.js index f35366a4..2280a386 100644 --- a/js/formbuilder.min.js +++ b/js/formbuilder.min.js @@ -1 +1 @@ -jQuery((function(e){e(".as-form-builder").length&&e(document).on("submit",".as-form-builder",(function(t){t.preventDefault();var a={},r=e(this),s=r.serializeArray();let i=1e3*Date.now()+1e3*Math.random();i=i.toString(16).replace(/\./g,"").padEnd(14,"0")+Math.trunc(1e8*Math.random());for(let e=0;e'+e.message+""),r.trigger("reset"),r.find(".g-recaptcha").each((function(){grecaptcha.reset(this)}))):r.find(".as-formbuilder-status").append('"),r.find(".as-form-builer-submit").removeAttr("disabled")}})}))})); \ No newline at end of file +class FormBuilder{constructor(el){this.el=el;if(this.el.dataset.captcha==="recaptcha"||this.el.dataset.captcha==="recaptcha_invisible"){this.initReCaptcha()}this.el.querySelector(".as-form-builer-submit").addEventListener("click",this.onSubmit.bind(this))}initReCaptcha(){let color="light";if(typeof ASTROID_COLOR_MODE!=="undefined"){color=ASTROID_COLOR_MODE}let config={sitekey:this.el.dataset.sitekey,tabindex:this.el.dataset.tabindex,theme:color};if(this.el.dataset.captcha==="recaptcha_invisible"){config["badge"]=this.el.dataset.badge;config["size"]="invisible";config["callback"]=this.onCallAjax.bind(this)}grecaptcha.ready(()=>{grecaptcha.render(this.el.querySelector(".google-recaptcha"),config)})}onSubmit(){if(!this.el.checkValidity()){this.el.classList.add("was-validated");return}if(this.el.dataset.captcha==="recaptcha_invisible"){grecaptcha.execute()}else{this.onCallAjax()}}onCallAjax(token){var request={},$this=jQuery(this.el),data=$this.serializeArray();let id=Date.now()*1e3+Math.random()*1e3;id=id.toString(16).replace(/\./g,"").padEnd(14,"0")+Math.trunc(Math.random()*1e8);for(let i=0;i'+response.message+"");$this.trigger("reset");$this.find(".google-recaptcha").each(function(){grecaptcha.reset(this)})}else{$this.find(".as-formbuilder-status").append('")}$this.find(".as-form-builer-submit").removeAttr("disabled");$this.removeClass("was-validated")}})}}jQuery(function($){$(".as-form-builder").each(function(){new FormBuilder(this)})}); \ No newline at end of file diff --git a/js/recaptcha_invisible.js b/js/recaptcha_invisible.js new file mode 100644 index 00000000..5a1c7510 --- /dev/null +++ b/js/recaptcha_invisible.js @@ -0,0 +1,25 @@ +((window, document) => { + + window.AstroidinitReCaptchaInvisible = () => { + const optionKeys = ['sitekey', 'badge', 'size', 'tabindex', 'callback', 'expired-callback', 'error-callback']; + document.querySelectorAll('.g-recaptcha').forEach(element => { + let options = {}; + if (element.dataset) { + options = element.dataset; + } else { + optionKeys.forEach(key => { + const optionKeyFq = `data-${optionKeys[key]}`; + if (element.hasAttribute(optionKeyFq)) { + options[optionKeys[key]] = element.getAttribute(optionKeyFq); + } + }); + } + + // Set the widget id of the recaptcha item + element.setAttribute('data-recaptcha-widget-id', window.grecaptcha.render(element, options)); + + // Execute the invisible reCAPTCHA + window.grecaptcha.execute(element.getAttribute('data-recaptcha-widget-id')); + }); + }; +})(window, document); \ No newline at end of file diff --git a/js/recaptcha_invisible.min.js b/js/recaptcha_invisible.min.js new file mode 100644 index 00000000..e484b0b1 --- /dev/null +++ b/js/recaptcha_invisible.min.js @@ -0,0 +1 @@ +((window,document)=>{window.AstroidinitReCaptchaInvisible=()=>{const optionKeys=["sitekey","badge","size","tabindex","callback","expired-callback","error-callback"];document.querySelectorAll(".g-recaptcha").forEach(element=>{let options={};if(element.dataset){options=element.dataset}else{optionKeys.forEach(key=>{const optionKeyFq=`data-${optionKeys[key]}`;if(element.hasAttribute(optionKeyFq)){options[optionKeys[key]]=element.getAttribute(optionKeyFq)}})}element.setAttribute("data-recaptcha-widget-id",window.grecaptcha.render(element,options));window.grecaptcha.execute(element.getAttribute("data-recaptcha-widget-id"))})}})(window,document); \ No newline at end of file diff --git a/language/en-GB/en-GB.astroid.ini b/language/en-GB/en-GB.astroid.ini index 9d0ac77d..21c552d9 100644 --- a/language/en-GB/en-GB.astroid.ini +++ b/language/en-GB/en-GB.astroid.ini @@ -1188,12 +1188,31 @@ TPL_ASTROID_MINIFYJS_EXCLUDES_LABEL="Exclude JS Files" TPL_ASTROID_MINIFYJS_EXCLUDES_DESC="Add comma separated filesnames to exclude files from JS minification. You can add filename directly or use available filename patterns:
*.min.js
jquery.*
*bootstrap*" ; ReCaptcha -COM_PLUGINS_ASTROID_CAPTCHA_FIELDSET_LABEL="Captcha" ASTROID_RECAPTCHA_NOTE="Google ReCaptcha" ASTROID_GOOGLE_SITE_KEY="Site Key" ASTROID_GOOGLE_SITE_KEY_DESC="Use this site key in the HTML code your site serves to users." ASTROID_GOOGLE_SECRET_KEY="Secret Key" ASTROID_GOOGLE_SECRET_KEY_DESC="Use this secret key for communication between your site and reCAPTCHA." +ASTROID_GOOGLE_RECAPTCHA_INVISIBLE_BADGE_BOTTOMLEFT="Bottom left" +ASTROID_GOOGLE_RECAPTCHA_INVISIBLE_BADGE_BOTTOMRIGHT="Bottom right" +ASTROID_GOOGLE_RECAPTCHA_INVISIBLE_BADGE_DESC="Positioning of the reCAPTCHA badge." +ASTROID_GOOGLE_RECAPTCHA_INVISIBLE_BADGE_INLINE="Inline" +ASTROID_GOOGLE_RECAPTCHA_INVISIBLE_BADGE_LABEL="Badge" +ASTROID_GOOGLE_RECAPTCHA_INVISIBLE_CALLBACK_DESC="(Optional) JavaScript callback, executed after successful reCAPTCHA response." +ASTROID_GOOGLE_RECAPTCHA_INVISIBLE_CALLBACK_LABEL="Callback" +ASTROID_GOOGLE_RECAPTCHA_INVISIBLE_ERROR_CALLBACK_DESC="(Optional) JavaScript callback, executed when the reCAPTCHA encounters an error." +ASTROID_GOOGLE_RECAPTCHA_INVISIBLE_ERROR_CALLBACK_LABEL="Error Callback" +ASTROID_GOOGLE_RECAPTCHA_ERROR_EMPTY_SOLUTION="Empty solution not allowed." +ASTROID_GOOGLE_RECAPTCHA_ERROR_NO_IP="For security reasons, you must pass the remote IP address to reCAPTCHA." +ASTROID_GOOGLE_RECAPTCHA_ERROR_NO_PRIVATE_KEY="reCAPTCHA plugin needs a secret key to be set in its parameters. Please contact a site administrator." +ASTROID_GOOGLE_RECAPTCHA_ERROR_NO_PUBLIC_KEY="reCAPTCHA plugin needs a site key to be set in its parameters. Please contact a site administrator." +ASTROID_GOOGLE_RECAPTCHA_INVISIBLE_EXPIRED_CALLBACK_DESC="(Optional) JavaScript callback, executed when the reCAPTCHA expired." +ASTROID_GOOGLE_RECAPTCHA_INVISIBLE_EXPIRED_CALLBACK_LABEL="Expired Callback" +ASTROID_GOOGLE_RECAPTCHA_INVISIBLE_PRIVACY_CAPABILITY_IP_ADDRESS="The Invisible reCAPTCHA plugin integrates with Google's reCAPTCHA system as a spam protection service. As part of this service, the IP address of the user answering the captcha challenge is transmitted to Google." +ASTROID_GOOGLE_RECAPTCHA_INVISIBLE_PRIVATE_KEY_DESC="Used in the communication between your server and the reCAPTCHA server. Be sure to keep it a secret." +ASTROID_GOOGLE_RECAPTCHA_INVISIBLE_PUBLIC_KEY_DESC="Used in the JavaScript code that is served to your users." +ASTROID_GOOGLE_RECAPTCHA_INVISIBLE_TABINDEX_DESC="The tabindex of the challenge." +ASTROID_GOOGLE_RECAPTCHA_INVISIBLE_TABINDEX_LABEL="Tabindex" ; Widgets ASTROID_ELEMENT_CATEGORY_SYSTEM="System" diff --git a/plugins/astroidcaptcha/astroidcaptcha.xml b/plugins/astroidcaptcha/astroidcaptcha.xml new file mode 100644 index 00000000..6c56589d --- /dev/null +++ b/plugins/astroidcaptcha/astroidcaptcha.xml @@ -0,0 +1,87 @@ + + + Astroid Captcha + Astroid Framework Team + December 2024 + 1.0.0 + https://www.astroidframe.work + Copyright (C) 2024 TemPlaza, Inc. All rights reserved. + GNU General Public License version 3 or later; see LICENSE.txt + info@templaza.com + https://www.templaza.com + Astroid Framework Plugin Description Here + Joomla\Plugin\Captcha\AstroidCaptcha + + services + src + + + +
+ + + + + + + + + + + + + + + + + + + + + + +
+
+
+
\ No newline at end of file diff --git a/plugins/astroidcaptcha/services/provider.php b/plugins/astroidcaptcha/services/provider.php new file mode 100644 index 00000000..89f667d3 --- /dev/null +++ b/plugins/astroidcaptcha/services/provider.php @@ -0,0 +1,45 @@ +set( + PluginInterface::class, + function (Container $container) { + $dispatcher = $container->get(DispatcherInterface::class); + $plugin = new AstroidCaptcha( + $dispatcher, + (array) PluginHelper::getPlugin('captcha', 'astroidcaptcha'), + new HttpBridgePostRequestMethod() + ); + $plugin->setApplication(Factory::getApplication()); + + return $plugin; + } + ); + } +}; \ No newline at end of file diff --git a/plugins/astroidcaptcha/src/Extension/AstroidCaptcha.php b/plugins/astroidcaptcha/src/Extension/AstroidCaptcha.php new file mode 100644 index 00000000..ab12e461 --- /dev/null +++ b/plugins/astroidcaptcha/src/Extension/AstroidCaptcha.php @@ -0,0 +1,96 @@ +requestMethod = $requestMethod; + } + public function onInit($id = null) + { + $app = $this->getApplication(); + $captcha_type = $this->params->get('captcha_type', 'default'); + if ($captcha_type == 'recaptcha' || $captcha_type == 'recaptcha_invisible') { + if ($this->params->get('g_site_key', '') === '') { + throw new \RuntimeException($app->getLanguage()->_('ASTROID_GOOGLE_RECAPTCHA_ERROR_NO_PUBLIC_KEY')); + } + if ($captcha_type == 'recaptcha_invisible') { + $onload = ['url' => 'astroid/recaptcha_invisible.min.js', 'function' => 'AstroidinitReCaptchaInvisible']; + $render = 'explicit'; + } else { + $onload = []; + $render = ''; + } + Framework::getDocument()->loadGoogleReCaptcha($onload, $render); + } + return true; + } + public function onDisplay($name = null, $id = 'astroid-recaptcha', $class = '') + { + $captcha_type = $this->params->get('captcha_type', 'default'); + $html = '
'; + if ($captcha_type == 'recaptcha' || $captcha_type == 'recaptcha_invisible') { + $dom = new \DOMDocument('1.0', 'UTF-8'); + $ele = $dom->createElement('div'); + $ele->setAttribute('id', $id); + $ele->setAttribute('class', ((trim($class) == '') ? 'g-recaptcha' : ($class . ' g-recaptcha'))); + $ele->setAttribute('data-sitekey', $this->params->get('g_site_key', '')); + if ($captcha_type == 'recaptcha_invisible') { + $ele->setAttribute('data-badge', $this->params->get('badge', 'bottomright')); + $ele->setAttribute('data-size', 'invisible'); + } + $ele->setAttribute('data-tabindex', $this->params->get('tabindex', '0')); + $callback = $this->params->get('callback', ''); + if ($callback != '') { + $ele->setAttribute('data-callback', $callback); + } + $expired_callback = $this->params->get('expired_callback', ''); + if ($expired_callback != '') { + $ele->setAttribute('data-expired-callback', $expired_callback); + } + $error_callback = $this->params->get('error_callback', ''); + if ($error_callback != '') { + $ele->setAttribute('data-error-callback', $error_callback); + } + $dom->appendChild($ele); + $html .= $dom->saveHTML($ele); + } else { + $html .= Helper\Captcha::loadCaptcha('as-joomla-captcha'); + } + $html .= '
'; + return $html; + } + public function onCheckAnswer($code = null) + { + $captcha_type = $this->params->get('captcha_type', 'default'); + if ($captcha_type == 'recaptcha' || $captcha_type == 'recaptcha_invisible') { + $input = $this->getApplication()->getInput(); + $privatekey = $this->params->get('g_secret_key', ''); + $gcaptcha = $input->post->get('g-recaptcha-response', '', 'string'); + return Helper\Captcha::verifyGoogleCaptcha($gcaptcha, $privatekey, $this->requestMethod); + } elseif (!Helper\Captcha::getCaptcha('as-joomla-captcha')) { + throw new \RuntimeException(Text::_('ASTROID_AJAX_ERROR_INVALID_CAPTCHA')); + } else { + return true; + } + } +} \ No newline at end of file