diff --git a/_build/data/properties/properties.quipreply.php b/_build/data/properties/properties.quipreply.php index 3c26195..df199bd 100644 --- a/_build/data/properties/properties.quipreply.php +++ b/_build/data/properties/properties.quipreply.php @@ -153,12 +153,10 @@ 'desc' => 'quip.prop_reply_recaptchatheme_desc', 'type' => 'list', 'options' => array( - array('text' => 'quip.opt_red','value' => 'red'), - array('text' => 'quip.opt_white','value' => 'white'), - array('text' => 'quip.opt_clean','value' => 'clean'), - array('text' => 'quip.opt_blackglass','value' => 'blackglass'), + array('text' => 'quip.opt_dark','value' => 'dark'), + array('text' => 'quip.opt_light','value' => 'light'), ), - 'value' => 'clean', + 'value' => 'light', 'lexicon' => 'quip:properties', ), array( diff --git a/core/components/quip/controllers/web/ThreadReply.php b/core/components/quip/controllers/web/ThreadReply.php index d12214a..99c9d82 100644 --- a/core/components/quip/controllers/web/ThreadReply.php +++ b/core/components/quip/controllers/web/ThreadReply.php @@ -312,7 +312,7 @@ public function loadReCaptcha() { /** @var reCaptcha $recaptcha */ $recaptcha = $this->modx->getService('recaptcha','reCaptcha',$this->quip->config['modelPath'].'recaptcha/'); if ($recaptcha instanceof reCaptcha) { - $recaptchaTheme = $this->getProperty('recaptchaTheme','clean'); + $recaptchaTheme = $this->getProperty('recaptchaTheme','light'); $html = $recaptcha->getHtml($recaptchaTheme); $this->modx->setPlaceholder('quip.recaptcha_html',$html); } else { diff --git a/core/components/quip/elements/snippets/snippet.quipreply.php b/core/components/quip/elements/snippets/snippet.quipreply.php index 92a5444..2a74377 100644 --- a/core/components/quip/elements/snippets/snippet.quipreply.php +++ b/core/components/quip/elements/snippets/snippet.quipreply.php @@ -167,7 +167,7 @@ if ($useRecaptcha && !($disableRecaptchaWhenLoggedIn && $hasAuth) && !$hasPreview) { $recaptcha = $modx->getService('recaptcha','reCaptcha',$quip->config['modelPath'].'recaptcha/'); if ($recaptcha instanceof reCaptcha) { - $recaptchaTheme = $modx->getOption('recaptchaTheme',$scriptProperties,'clean'); + $recaptchaTheme = $modx->getOption('recaptchaTheme',$scriptProperties,'light'); $html = $recaptcha->getHtml($recaptchaTheme); $modx->setPlaceholder('quip.recaptcha_html',$html); } else { diff --git a/core/components/quip/lexicon/de/properties.inc.php b/core/components/quip/lexicon/de/properties.inc.php index 6d8fbae..c8b7113 100644 --- a/core/components/quip/lexicon/de/properties.inc.php +++ b/core/components/quip/lexicon/de/properties.inc.php @@ -36,10 +36,8 @@ $_lang['quip.comment'] = 'Kommentar'; $_lang['quip.descending'] = 'Absteigend'; $_lang['quip.family'] = 'Familie'; -$_lang['quip.opt_blackglass'] = 'Black Glass'; -$_lang['quip.opt_clean'] = 'Clean'; -$_lang['quip.opt_red'] = 'Red'; -$_lang['quip.opt_white'] = 'White'; +$_lang['quip.opt_light'] = 'Light'; +$_lang['quip.opt_dark'] = 'Dark'; $_lang['quip.thread'] = 'Thread'; $_lang['quip.user'] = 'Benutzer'; diff --git a/core/components/quip/lexicon/en/properties.inc.php b/core/components/quip/lexicon/en/properties.inc.php index 66f55d4..6181929 100644 --- a/core/components/quip/lexicon/en/properties.inc.php +++ b/core/components/quip/lexicon/en/properties.inc.php @@ -34,10 +34,8 @@ $_lang['quip.comment'] = 'Comment'; $_lang['quip.descending'] = 'Descending'; $_lang['quip.family'] = 'Family'; -$_lang['quip.opt_blackglass'] = 'Black Glass'; -$_lang['quip.opt_clean'] = 'Clean'; -$_lang['quip.opt_red'] = 'Red'; -$_lang['quip.opt_white'] = 'White'; +$_lang['quip.opt_light'] = 'Light'; +$_lang['quip.opt_dark'] = 'Dark'; $_lang['quip.thread'] = 'Thread'; $_lang['quip.user'] = 'User'; diff --git a/core/components/quip/lexicon/ja/properties.inc.php b/core/components/quip/lexicon/ja/properties.inc.php index 66f55d4..6181929 100644 --- a/core/components/quip/lexicon/ja/properties.inc.php +++ b/core/components/quip/lexicon/ja/properties.inc.php @@ -34,10 +34,8 @@ $_lang['quip.comment'] = 'Comment'; $_lang['quip.descending'] = 'Descending'; $_lang['quip.family'] = 'Family'; -$_lang['quip.opt_blackglass'] = 'Black Glass'; -$_lang['quip.opt_clean'] = 'Clean'; -$_lang['quip.opt_red'] = 'Red'; -$_lang['quip.opt_white'] = 'White'; +$_lang['quip.opt_light'] = 'Light'; +$_lang['quip.opt_dark'] = 'Dark'; $_lang['quip.thread'] = 'Thread'; $_lang['quip.user'] = 'User'; diff --git a/core/components/quip/model/recaptcha/recaptcha.class.php b/core/components/quip/model/recaptcha/recaptcha.class.php index 1635183..58f9a61 100644 --- a/core/components/quip/model/recaptcha/recaptcha.class.php +++ b/core/components/quip/model/recaptcha/recaptcha.class.php @@ -28,8 +28,6 @@ * @package recaptcha */ class reCaptcha { - const OPT_API_SERVER = 'api_server'; - const OPT_API_SECURE_SERVER = 'api_secure_server'; const OPT_API_VERIFY_SERVER = 'api_verify_server'; const OPT_PRIVATE_KEY = 'privateKey'; const OPT_PUBLIC_KEY = 'publicKey'; @@ -42,9 +40,7 @@ function __construct(modX &$modx,array $config = array()) { reCaptcha::OPT_PRIVATE_KEY => $this->modx->getOption('recaptcha.private_key',$config,''), reCaptcha::OPT_PUBLIC_KEY => $this->modx->getOption('recaptcha.public_key',$config,''), reCaptcha::OPT_USE_SSL => $this->modx->getOption('recaptcha.use_ssl',$config,false), - reCaptcha::OPT_API_SERVER => 'http://www.google.com/recaptcha/api/', - reCaptcha::OPT_API_SECURE_SERVER => 'https://www.google.com/recaptcha/api/', - reCaptcha::OPT_API_VERIFY_SERVER => 'api-verify.recaptcha.net', + reCaptcha::OPT_API_VERIFY_SERVER => 'https://www.google.com/recaptcha/api/siteverify?', ),$config); } @@ -65,40 +61,19 @@ protected function qsencode($data) { } /** - * Submits an HTTP POST to a reCAPTCHA server - * @param string $host - * @param string $path - * @param array $data - * @param int port - * @return array response + * Submits an HTTP GET to a reCAPTCHA server. + * + * @param string $path - url path to recaptcha server. + * @param array $data - array of parameters to be sent. + * + * @return array - response */ - protected function httpPost($host, $path, array $data = array(), $port = 80) { - $data['privatekey'] = $this->config[reCaptcha::OPT_PRIVATE_KEY]; + function httpGet($path, $data) { $req = $this->qsencode($data); - - $http_request = "POST $path HTTP/1.0\r\n"; - $http_request .= "Host: $host\r\n"; - $http_request .= "Content-Type: application/x-www-form-urlencoded;\r\n"; - $http_request .= "Content-Length: " . strlen($req) . "\r\n"; - $http_request .= "User-Agent: reCAPTCHA/PHP\r\n"; - $http_request .= "\r\n"; - $http_request .= $req; - - $response = ''; - if(false == ($fs = @fsockopen($host, $port, $errno, $errstr, 10))) { - return 'Could not open socket'; - } - - fwrite($fs, $http_request); - while (!feof($fs)) { - $response .= fgets($fs, 1160); // One TCP-IP packet - } - fclose($fs); - $response = explode("\r\n\r\n", $response, 2); - + $response = file_get_contents($path . $req); return $response; } - + /** * Gets the challenge HTML (javascript and non-javascript version). * This is called from the browser, and the resulting reCAPTCHA HTML widget @@ -109,28 +84,29 @@ protected function httpPost($host, $path, array $data = array(), $port = 80) { * @return string - The HTML to be embedded in the user's form. */ - public function getHtml($theme = 'clean',$error = null) { + public function getHtml($theme = 'light') { if (empty($this->config[reCaptcha::OPT_PUBLIC_KEY])) { return $this->error($this->modx->lexicon('recaptcha.no_api_key')); } - /* use ssl or not */ - $server = !empty($this->config[reCaptcha::OPT_USE_SSL]) ? $this->config[reCaptcha::OPT_API_SECURE_SERVER] : $this->config[reCaptcha::OPT_API_SERVER]; + $opts = array( + 'data-theme' => $theme, + 'data-sitekey' => $this->config[reCaptcha::OPT_PUBLIC_KEY], + 'hl' => $this->modx->getOption('cultureKey',null,'en'), + ); + + $optstrings = array(); - $errorpart = ''; - if ($error) { - $errorpart = "&error=" . $error; + foreach ($opts as $attr => $val) { + $optstrings[] = "{$attr}=\"{$val}\""; } - $opt = array( - 'theme' => $theme, - 'lang' => $this->modx->getOption('cultureKey',null,'en'), - ); - return ' - '; + + $attributes = implode(' ', $optstrings); + + $markup = ''; + $markup .= '
'; + + return $markup; } protected function error($message = '') { @@ -148,118 +124,36 @@ protected function error($message = '') { * @param array $extra_params an array of extra variables to post to the server * @return ReCaptchaResponse */ - public function checkAnswer ($remoteIp, $challenge, $responseField, $extraParams = array()) { - if (empty($this->config[reCaptcha::OPT_PRIVATE_KEY])) { - return $this->error($this->modx->lexicon('recaptcha.no_api_key')); - } - - if (empty($remoteIp)) { - return $this->error($this->modx->lexicon('recaptcha.no_remote_ip')); - } - - //discard spam submissions - if (empty($challenge) || empty($responseField)) { - return $this->error($this->modx->lexicon('recaptcha.empty_answer')); + public function checkAnswer($remoteIp, $response) { + // Discard empty solution submissions + if ($response == null || strlen($response) == 0) { + $reCaptchaResponse = new reCaptchaResponse(); + $reCaptchaResponse->is_valid = false; + $reCaptchaResponse->error = 'missing-input'; + return $reCaptchaResponse; } $verifyServer = $this->config[reCaptcha::OPT_API_VERIFY_SERVER]; - $response = $this->httpPost($verifyServer,"/verify",array ( - 'remoteip' => $remoteIp, - 'challenge' => $challenge, - 'response' => $responseField, - ) + $extraParams); - - $answers = explode("\n",$response[1]); - $response = new reCaptchaResponse(); - - if (trim($answers[0]) == 'true') { - $response->is_valid = true; - } else { - $response->is_valid = false; - $response->error = $answers [1]; - } - return $response; - } - - /** - * gets a URL where the user can sign up for reCAPTCHA. If your application - * has a configuration page where you enter a key, you should provide a link - * using this function. - * @param string $domain The domain where the page is hosted - * @param string $appname The name of your application - */ - public function getSignupUrl ($domain = null, $appname = null) { - return "http://recaptcha.net/api/getkey?" . $this->qsencode(array ('domain' => $domain, 'app' => $appname)); - } - - protected function aesPad($val) { - $block_size = 16; - $numpad = $block_size - (strlen ($val) % $block_size); - return str_pad($val, strlen ($val) + $numpad, chr($numpad)); - } - - /* Mailhide related code */ - protected function aesEncrypt($val,$ky) { - if (!function_exists("mcrypt_encrypt")) { - return $this->error($this->modx->lexicon('recaptcha.mailhide_no_mcrypt')); - } - $mode=MCRYPT_MODE_CBC; - $enc=MCRYPT_RIJNDAEL_128; - $val= $this->aesPad($val); - return mcrypt_encrypt($enc, $ky, $val, $mode, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"); - } - - - protected function mailhideUrlbase64 ($x) { - return strtr(base64_encode ($x), '+/', '-_'); - } - - /* gets the reCAPTCHA Mailhide url for a given email, public key and private key */ - public function mailhideUrl($email) { - if (empty($this->config[reCaptcha::OPT_PUBLIC_KEY]) || empty($this->config[reCaptcha::OPT_PRIVATE_KEY])) { - return $this->error($this->modx->lexicon('recaptcha.mailhide_no_api_key')); - } - $ky = pack('H*',$this->config[reCaptcha::OPT_PRIVATE_KEY]); - $cryptmail = $this->aesEncrypt($email, $ky); - return 'http://mailhide.recaptcha.net/d?k=' - . $this->config[reCaptcha::OPT_PUBLIC_KEY] - . '&c=' . $this->mailhideUrlbase64($cryptmail); - } + $getResponse = $this->httpGet($verifyServer,array ( + 'remoteip' => $remoteIp, + 'secret' => $this->config[reCaptcha::OPT_PRIVATE_KEY], + 'response' => $response, + )); - /** - * gets the parts of the email to expose to the user. - * eg, given johndoe@example,com return ["john", "example.com"]. - * the email is then displayed as john...@example.com - */ - public function mailhideEmailParts ($email) { - $arr = preg_split("/@/", $email); + $answers = json_decode($getResponse, true); + $reCaptchaResponse = new reCaptchaResponse(); - if (strlen($arr[0]) <= 4) { - $arr[0] = substr($arr[0], 0, 1); - } else if (strlen ($arr[0]) <= 6) { - $arr[0] = substr($arr[0], 0, 3); + if ($answers['success'] === true) { + $reCaptchaResponse->is_valid = true; } else { - $arr[0] = substr($arr[0], 0, 4); + $reCaptchaResponse->is_valid = false; + $reCaptchaResponse->error = $answers['error-codes']; } - return $arr; - } - - /** - * Gets html to display an email address given a public an private key. - * to get a key, go to: - * - * http://mailhide.recaptcha.net/apikey - */ - public function mailhideHtml($email) { - $emailparts = $this->mailhideEmailParts($email); - $url = $this->mailhideUrl($email); - return htmlentities($emailparts[0]) . "...@" . htmlentities ($emailparts [1]); + return $reCaptchaResponse; } - } /** diff --git a/core/components/quip/processors/web/comment/create.php b/core/components/quip/processors/web/comment/create.php index 138cedd..976759d 100644 --- a/core/components/quip/processors/web/comment/create.php +++ b/core/components/quip/processors/web/comment/create.php @@ -54,12 +54,10 @@ } elseif (empty($recaptcha->config[reCaptcha::OPT_PRIVATE_KEY])) { $errors['recaptcha'] = $modx->lexicon('recaptcha.no_api_key'); } else { - $response = $recaptcha->checkAnswer($_SERVER['REMOTE_ADDR'],$fields['recaptcha_challenge_field'],$fields['recaptcha_response_field']); + $response = $recaptcha->checkAnswer($_SERVER['REMOTE_ADDR'],$fields['g-recaptcha-response']); if (!$response->is_valid) { - $errors['recaptcha'] = $modx->lexicon('recaptcha.incorrect',array( - 'error' => $response->error != 'incorrect-captcha-sol' ? $response->error : '', - )); + $errors['recaptcha'] = $modx->lexicon('recaptcha.incorrect',array('error' => '')); } } } diff --git a/core/components/quip/processors/web/comment/preview.php b/core/components/quip/processors/web/comment/preview.php index c4c8688..016dcf3 100644 --- a/core/components/quip/processors/web/comment/preview.php +++ b/core/components/quip/processors/web/comment/preview.php @@ -50,12 +50,10 @@ } elseif (empty($recaptcha->config[reCaptcha::OPT_PRIVATE_KEY])) { $errors['recaptcha'] = $modx->lexicon('recaptcha.no_api_key'); } else { - $response = $recaptcha->checkAnswer($_SERVER['REMOTE_ADDR'],$fields['recaptcha_challenge_field'],$fields['recaptcha_response_field']); + $response = $recaptcha->checkAnswer($_SERVER['REMOTE_ADDR'],$fields['g-recaptcha-response']); if (!$response->is_valid) { - $errors['recaptcha'] = $modx->lexicon('recaptcha.incorrect',array( - 'error' => $response->error != 'incorrect-captcha-sol' ? $response->error : '', - )); + $errors['recaptcha'] = $modx->lexicon('recaptcha.incorrect',array('error' => '')); } } } diff --git a/core/components/quip/test/Tests/Core/QuipReplyTest.php b/core/components/quip/test/Tests/Core/QuipReplyTest.php index be2db1a..4e2cd01 100644 --- a/core/components/quip/test/Tests/Core/QuipReplyTest.php +++ b/core/components/quip/test/Tests/Core/QuipReplyTest.php @@ -153,7 +153,7 @@ public function providerIsOpen() { * @param boolean $userHasAuth * @dataProvider providerLoadReCaptcha */ - public function testLoadReCaptcha($shouldLoad = true,$recaptcha = true,$disableRecaptchaWhenLoggedIn = true,$recaptchaTheme = 'clean',$userHasAuth = false) { + public function testLoadReCaptcha($shouldLoad = true,$recaptcha = true,$disableRecaptchaWhenLoggedIn = true,$recaptchaTheme = 'light',$userHasAuth = false) { $this->controller->setProperty('disableRecaptchaWhenLoggedIn',$disableRecaptchaWhenLoggedIn); $this->controller->setProperty('recaptcha',$recaptcha); $this->controller->setProperty('recaptchaTheme',$recaptchaTheme); @@ -175,8 +175,8 @@ public function testLoadReCaptcha($shouldLoad = true,$recaptcha = true,$disableR */ public function providerLoadReCaptcha() { return array( - array(true,true,true,'clean'), - array(false,true,true,'clean',true), + array(true,true,true,'light'), + array(false,true,true,'light',true), array(false,false), ); }