diff --git a/administrator/components/com_admin/sql/updates/mysql/4.0.0-2020-09-21.sql b/administrator/components/com_admin/sql/updates/mysql/4.0.0-2020-09-21.sql new file mode 100644 index 0000000000000..4fd21a6975a28 --- /dev/null +++ b/administrator/components/com_admin/sql/updates/mysql/4.0.0-2020-09-21.sql @@ -0,0 +1,2 @@ +INSERT INTO `#__extensions` (`package_id`, `name`, `type`, `element`, `folder`, `client_id`, `enabled`, `access`, `protected`, `locked`, `manifest_cache`, `params`, `custom_data`, `checked_out`, `checked_out_time`, `ordering`, `state`) VALUES +(0, 'plg_captcha_hcaptcha', 'plugin', 'hcaptcha', 'captcha', 0, 0, 1, 0, 1, '', '{"publicKey":"","privateKey":"","theme":"light","size":"normal"}', '', 0, NULL, 0, 0); diff --git a/administrator/components/com_admin/sql/updates/postgresql/4.0.0-2020-09-21.sql b/administrator/components/com_admin/sql/updates/postgresql/4.0.0-2020-09-21.sql new file mode 100644 index 0000000000000..f8a56fb4cdd2b --- /dev/null +++ b/administrator/components/com_admin/sql/updates/postgresql/4.0.0-2020-09-21.sql @@ -0,0 +1,2 @@ +INSERT INTO "#__extensions" ("package_id", "name", "type", "element", "folder", "client_id", "enabled", "access", "protected", "locked", "manifest_cache", "params", "custom_data", "checked_out", "checked_out_time", "ordering", "state") VALUES +(0, 'plg_captcha_hcaptcha', 'plugin', 'hcaptcha', 'captcha', 0, 0, 1, 0, 1, '', '{"publicKey":"","privateKey":"","theme":"light","size":"normal"}', '', 0, NULL, 0, 0); diff --git a/administrator/language/en-GB/plg_captcha_hcaptcha.ini b/administrator/language/en-GB/plg_captcha_hcaptcha.ini new file mode 100644 index 0000000000000..0025f18c1e387 --- /dev/null +++ b/administrator/language/en-GB/plg_captcha_hcaptcha.ini @@ -0,0 +1,33 @@ +; Joomla! Project +; Copyright (C) 2005 - 2020 Open Source Matters. All rights reserved. +; License GNU General Public License version 2 or later; see LICENSE.txt +; Note : All ini files need to be saved as UTF-8 + +PLG_CAPTCHA_HCAPTCHA="CAPTCHA - hCaptcha" +PLG_CAPTCHA_HCAPTCHA_XML_DESCRIPTION="This CAPTCHA plugin uses the hCAPTCHA service to prevent spammers. To get a site and secret key for your domain, go to https://www.hcaptcha.com. To use this for new account registration, go to Options in the User Manager and select CAPTCHA - hCAPTCHA as the CAPTCHA." + +; Params +PLG_CAPTCHA_HCAPTCHA_PUBLIC_KEY="Site Key" +PLG_CAPTCHA_HCAPTCHA_PUBLIC_KEY_DESC="Site Keys are used to uniquely identify your site." +PLG_CAPTCHA_HCAPTCHA_PRIVATE_KEY="Secret Key" +PLG_CAPTCHA_HCAPTCHA_PRIVATE_KEY_DESC="A secret Key is used to verify your hCaptcha account." + +PLG_CAPTCHA_HCAPTCHA_THEME="Theme" +PLG_CAPTCHA_HCAPTCHA_THEME_LIGHT="Light" +PLG_CAPTCHA_HCAPTCHA_THEME_DARK="Dark" + +PLG_CAPTCHA_HCAPTCHA_SIZE="Size" +PLG_CAPTCHA_HCAPTCHA_SIZE_NORMAL="Normal" +PLG_CAPTCHA_HCAPTCHA_SIZE_COMPACT="Compact" + +; Privacy +PLG_CAPTCHA_HCAPTCHA_PRIVACY_CAPABILITY_IP_ADDRESS="The hCaptcha plugin integrates with hcaptcha's CAPTCHA system as a spam protection service. As part of this service, the IP address of the user answering the captcha challenge is transmitted to hcaptcha.com." + +; Error messages +PLG_CAPTCHA_HCAPTCHA_ERROR_CANT_CONNECT_TO_HCAPTCHA_SERVERS="Unable to connect to the hcaptcha.com servers" +PLG_CAPTCHA_HCAPTCHA_ERROR_NO_PUBLIC_KEY="Public Key (Site Key) is missing" +PLG_CAPTCHA_HCAPTCHA_ERROR_NO_PRIVATE_KEY="Private Key (Secret Key) is missing" +PLG_CAPTCHA_HCAPTCHA_ERROR_NO_IP="Error: No IP address" +PLG_CAPTCHA_HCAPTCHA_ERROR_EMPTY_SOLUTION="Please complete the CAPTCHA" +PLG_CAPTCHA_HCAPTCHA_ERROR_INCORRECT_CAPTCHA="The CAPTCHA was incorrect" +PLG_CAPTCHA_HCAPTCHA_ERROR_INVALID_RESPONSE="Invalid response from hcaptcha.com" diff --git a/administrator/language/en-GB/plg_captcha_hcaptcha.sys.ini b/administrator/language/en-GB/plg_captcha_hcaptcha.sys.ini new file mode 100644 index 0000000000000..f464b03294455 --- /dev/null +++ b/administrator/language/en-GB/plg_captcha_hcaptcha.sys.ini @@ -0,0 +1,7 @@ +; Joomla! Project +; Copyright (C) 2005 - 2020 Open Source Matters. All rights reserved. +; License GNU General Public License version 2 or later; see LICENSE.txt +; Note : All ini files need to be saved as UTF-8 + +PLG_CAPTCHA_HCAPTCHA="CAPTCHA - hCaptcha" +PLG_CAPTCHA_HCAPTCHA_XML_DESCRIPTION="This CAPTCHA plugin uses the hCAPTCHA service to prevent spammers. To get a site and secret key for your domain, go to https://www.hcaptcha.com. To use this for new account registration, go to Options in the User Manager and select CAPTCHA - hCAPTCHA as the CAPTCHA." diff --git a/installation/sql/mysql/base.sql b/installation/sql/mysql/base.sql index 677625d971ce3..925f508ec3f68 100644 --- a/installation/sql/mysql/base.sql +++ b/installation/sql/mysql/base.sql @@ -270,6 +270,7 @@ INSERT INTO `#__extensions` (`package_id`, `name`, `type`, `element`, `folder`, (0, 'plg_quickicon_joomlaupdate', 'plugin', 'joomlaupdate', 'quickicon', 0, 1, 1, 0, 1, '', '', '', 0, 0), (0, 'plg_quickicon_downloadkey', 'plugin', 'downloadkey', 'quickicon', 0, 1, 1, 0, 1, '', '', '', 0, 0), (0, 'plg_quickicon_extensionupdate', 'plugin', 'extensionupdate', 'quickicon', 0, 1, 1, 0, 1, '', '', '', 0, 0), +(0, 'plg_captcha_hcaptcha', 'plugin', 'hcaptcha', 'captcha', 0, 0, 1, 0, 1, '', '{"publicKey":"","privateKey":"","theme":"light","size":"normal"}', '', 0, 0), (0, 'plg_captcha_recaptcha', 'plugin', 'recaptcha', 'captcha', 0, 0, 1, 0, 1, '', '{"public_key":"","private_key":"","theme":"clean"}', '', 0, 0), (0, 'plg_system_highlight', 'plugin', 'highlight', 'system', 0, 1, 1, 0, 1, '', '', '', 7, 0), (0, 'plg_content_finder', 'plugin', 'finder', 'content', 0, 1, 1, 0, 1, '', '', '', 0, 0), diff --git a/installation/sql/postgresql/base.sql b/installation/sql/postgresql/base.sql index 259b9df2f5f93..d354cebbc9298 100644 --- a/installation/sql/postgresql/base.sql +++ b/installation/sql/postgresql/base.sql @@ -276,6 +276,7 @@ INSERT INTO "#__extensions" ("package_id", "name", "type", "element", "folder", (0, 'plg_quickicon_joomlaupdate', 'plugin', 'joomlaupdate', 'quickicon', 0, 1, 1, 0, 1, '', '', '', 0, 0), (0, 'plg_quickicon_downloadkey', 'plugin', 'downloadkey', 'quickicon', 0, 1, 1, 0, 1, '', '', '', 0, 0), (0, 'plg_quickicon_extensionupdate', 'plugin', 'extensionupdate', 'quickicon', 0, 1, 1, 0, 1, '', '', '', 0, 0), +(0, 'plg_captcha_hcaptcha', 'plugin', 'hcaptcha', 'captcha', 0, 0, 1, 0, 1, '', '{"publicKey":"","privateKey":"","theme":"light","size":"normal"}', '', 0, 0), (0, 'plg_captcha_recaptcha', 'plugin', 'recaptcha', 'captcha', 0, 0, 1, 0, 1, '', '{"public_key":"","private_key":"","theme":"clean"}', '', 0, 0), (0, 'plg_system_highlight', 'plugin', 'highlight', 'system', 0, 1, 1, 0, 1, '', '', '', 7, 0), (0, 'plg_content_finder', 'plugin', 'finder', 'content', 0, 1, 1, 0, 1, '', '', '', 0, 0), diff --git a/plugins/captcha/hcaptcha/hcaptcha.php b/plugins/captcha/hcaptcha/hcaptcha.php new file mode 100644 index 0000000000000..2c688d343ccc4 --- /dev/null +++ b/plugins/captcha/hcaptcha/hcaptcha.php @@ -0,0 +1,160 @@ + array( + Text::_('PLG_CAPTCHA_HCAPTCHA_PRIVACY_CAPABILITY_IP_ADDRESS'), + ) + ); + } + + /** + * Initialise the captcha + * + * @return boolean True on success, false otherwise + * + * @since 4.0.0 + * @throws Exception + */ + 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 + Factory::getApplication()->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. + * + * @since 4.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'); + $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 + * @since 4.0.0 + * @throws Exception + */ + 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')); + } + + 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')); + } +} diff --git a/plugins/captcha/hcaptcha/hcaptcha.xml b/plugins/captcha/hcaptcha/hcaptcha.xml new file mode 100644 index 0000000000000..746ccb4920320 --- /dev/null +++ b/plugins/captcha/hcaptcha/hcaptcha.xml @@ -0,0 +1,67 @@ + + + plg_captcha_hcaptcha + 1.0.0 + April 2020 + Joomla! Project + admin@joomla.org + www.joomla.org + Copyright (C) 2005 - 2019 Open Source Matters. All rights reserved. + GNU General Public License version 2 or later; see LICENSE.txt + PLG_CAPTCHA_HCAPTCHA_XML_DESCRIPTION + + hcaptcha.php + language + + + plg_captcha_hcaptcha.ini + plg_captcha_hcaptcha.sys.ini + + + +
+ + + + + + + + + + + + + +
+
+
+