{if $recaptchaLegacyMode|empty}
{include file='captcha'}
{else}
- {* No explicit keys were set, use legacy V1 API and WoltLab's OEM keys *}
- {if RECAPTCHA_PUBLICKEY === '' || RECAPTCHA_PRIVATEKEY === ''}
- <section class="section">
- <header class="sectionHeader">
- <h2 class="sectionTitle">{lang}wcf.recaptcha.title{/lang}</h2>
- <p class="sectionDescription">{lang}wcf.recaptcha.description{/lang}</p>
- </header>
-
- <dl class="wide reCaptcha{if $errorField|isset && $errorField == 'recaptchaString'} formError{/if}">
- {if !$ajaxCaptcha|isset || !$ajaxCaptcha}
- <script data-relocate="true">
- var RecaptchaOptions = {
- lang: '{@$recaptchaLanguageCode}',
- theme : 'custom'
- }
- </script>
- {/if}
- <dt class="jsOnly">
- <label for="recaptcha_response_field">reCAPTCHA</label>
- </dt>
- <dd class="jsOnly">
- <div id="recaptcha_image"></div>
- <input type="text" id="recaptcha_response_field" name="recaptcha_response_field" class="medium">
- {if (($errorType|isset && $errorType|is_array && $errorType[recaptchaString]|isset) || ($errorField|isset && $errorField == 'recaptchaString'))}
- {if $errorType|is_array && $errorType[recaptchaString]|isset}
- {assign var='__errorType' value=$errorType[recaptchaString]}
- {else}
- {assign var='__errorType' value=$errorType}
- {/if}
- <small class="innerError">
- {if $__errorType == 'empty'}
- {lang}wcf.global.form.error.empty{/lang}
- {else}
- {lang}wcf.recaptcha.error.recaptchaString.{$__errorType}{/lang}
- {/if}
- </small>
- {/if}
- </dd>
-
- {event name='fields'}
-
- <dd class="jsOnly">
- <ul class="buttonList smallButtons">
- <li><a href="javascript:Recaptcha.reload()" class="button small"><span class="icon icon16 fa-repeat"></span> <span>{lang}wcf.recaptcha.reload{/lang}</span></a></li>
- <li class="recaptcha_only_if_image"><a href="javascript:Recaptcha.switch_type('audio')" class="button small"><span class="icon icon16 fa-volume-up"></span> <span>{lang}wcf.recaptcha.audio{/lang}</span></a></li>
- <li class="recaptcha_only_if_audio"><a href="javascript:Recaptcha.switch_type('image')" class="button small"><span class="icon icon16 fa-eye"></span> <span>{lang}wcf.recaptcha.image{/lang}</span></a></li>
- <li><a href="javascript:Recaptcha.showhelp()" class="button small"><span class="icon icon16 fa-question"></span> <span>{lang}wcf.recaptcha.help{/lang}</span></a></li>
- {event name='buttons'}
- </ul>
- </dd>
-
- {if !$ajaxCaptcha|isset || !$ajaxCaptcha}
- <script data-relocate="true" src="//www.google.com/recaptcha/api/challenge?k={$recaptchaPublicKey}"></script>
- <noscript>
- <dd>
- <iframe src="//www.google.com/recaptcha/api/noscript?k={$recaptchaPublicKey}" height="300" width="500" seamless="seamless"></iframe><br>
- <textarea name="recaptcha_challenge_field" rows="3" cols="40"></textarea>
- <input type="hidden" name="recaptcha_response_field" value="manual_challenge">
- </dd>
- {if (($errorType|isset && $errorType|is_array && $errorType[recaptchaString]|isset) || ($errorField|isset && $errorField == 'recaptchaString'))}
- {if $errorType|is_array && $errorType[recaptchaString]|isset}
- {assign var='__errorType' value=$errorType[recaptchaString]}
- {else}
- {assign var='__errorType' value=$errorType}
- {/if}
- <small class="innerError">
- {if $errorType == 'empty'}
- {lang}wcf.global.form.error.empty{/lang}
- {else}
- {lang}wcf.recaptcha.error.recaptchaString.{$__errorType}{/lang}
- {/if}
- </small>
- {/if}
- </noscript>
- {else}
- <script data-relocate="true">
- $.getScript('//www.google.com/recaptcha/api/js/recaptcha_ajax.js', function() {
- Recaptcha.create("{$recaptchaPublicKey}", "recaptcha_image", {
- lang: '{@$recaptchaLanguageCode}',
- theme : 'custom'
- });
-
- WCF.System.Captcha.addCallback('{$captchaID}', function() {
- return {
- recaptcha_challenge_field: Recaptcha.get_challenge(),
- recaptcha_response_field: Recaptcha.get_response()
- };
- });
- });
- </script>
- {/if}
- </dl>
- </section>
- {else}
+ {if RECAPTCHA_PUBLICKEY !== '' && RECAPTCHA_PRIVATEKEY !== ''}
{if $supportsAsyncCaptcha|isset && $supportsAsyncCaptcha && RECAPTCHA_PUBLICKEY_INVISIBLE && RECAPTCHA_PRIVATEKEY_INVISIBLE}
<section class="section">
<h2 class="sectionTitle">{lang}wcf.recaptcha.title{/lang}</h2>
{if $recaptchaLegacyMode|empty}
{include file='captcha'}
{else}
- {* No explicit keys were set, use legacy V1 API and WoltLab's OEM keys *}
- {if RECAPTCHA_PUBLICKEY === '' || RECAPTCHA_PRIVATEKEY === ''}
- <section class="section">
- <header class="sectionHeader">
- <h2 class="sectionTitle">{lang}wcf.recaptcha.title{/lang}</h2>
- <p class="sectionDescription">{lang}wcf.recaptcha.description{/lang}</p>
- </header>
-
- <dl class="wide reCaptcha{if $errorField|isset && $errorField == 'recaptchaString'} formError{/if}">
- {if !$ajaxCaptcha|isset || !$ajaxCaptcha}
- <script data-relocate="true">
- var RecaptchaOptions = {
- lang: '{@$recaptchaLanguageCode}',
- theme : 'custom'
- }
- </script>
- {/if}
- <dt class="jsOnly">
- <label for="recaptcha_response_field">reCAPTCHA</label>
- </dt>
- <dd class="jsOnly">
- <div id="recaptcha_image"></div>
- <input type="text" id="recaptcha_response_field" name="recaptcha_response_field" class="medium">
- {if (($errorType|isset && $errorType|is_array && $errorType[recaptchaString]|isset) || ($errorField|isset && $errorField == 'recaptchaString'))}
- {if $errorType|is_array && $errorType[recaptchaString]|isset}
- {assign var='__errorType' value=$errorType[recaptchaString]}
- {else}
- {assign var='__errorType' value=$errorType}
- {/if}
- <small class="innerError">
- {if $__errorType == 'empty'}
- {lang}wcf.global.form.error.empty{/lang}
- {else}
- {lang}wcf.recaptcha.error.recaptchaString.{$__errorType}{/lang}
- {/if}
- </small>
- {/if}
- </dd>
-
- {event name='fields'}
-
- <dd class="jsOnly">
- <ul class="buttonList smallButtons">
- <li><a href="javascript:Recaptcha.reload()" class="button small"><span class="icon icon16 fa-repeat"></span> <span>{lang}wcf.recaptcha.reload{/lang}</span></a></li>
- <li class="recaptcha_only_if_image"><a href="javascript:Recaptcha.switch_type('audio')" class="button small"><span class="icon icon16 fa-volume-up"></span> <span>{lang}wcf.recaptcha.audio{/lang}</span></a></li>
- <li class="recaptcha_only_if_audio"><a href="javascript:Recaptcha.switch_type('image')" class="button small"><span class="icon icon16 fa-eye"></span> <span>{lang}wcf.recaptcha.image{/lang}</span></a></li>
- <li><a href="javascript:Recaptcha.showhelp()" class="button small"><span class="icon icon16 fa-question"></span> <span>{lang}wcf.recaptcha.help{/lang}</span></a></li>
- {event name='buttons'}
- </ul>
- </dd>
-
- {if !$ajaxCaptcha|isset || !$ajaxCaptcha}
- <script data-relocate="true" src="//www.google.com/recaptcha/api/challenge?k={$recaptchaPublicKey}"></script>
- <noscript>
- <dd>
- <iframe src="//www.google.com/recaptcha/api/noscript?k={$recaptchaPublicKey}" height="300" width="500" seamless="seamless"></iframe><br>
- <textarea name="recaptcha_challenge_field" rows="3" cols="40"></textarea>
- <input type="hidden" name="recaptcha_response_field" value="manual_challenge">
- </dd>
- {if (($errorType|isset && $errorType|is_array && $errorType[recaptchaString]|isset) || ($errorField|isset && $errorField == 'recaptchaString'))}
- {if $errorType|is_array && $errorType[recaptchaString]|isset}
- {assign var='__errorType' value=$errorType[recaptchaString]}
- {else}
- {assign var='__errorType' value=$errorType}
- {/if}
- <small class="innerError">
- {if $errorType == 'empty'}
- {lang}wcf.global.form.error.empty{/lang}
- {else}
- {lang}wcf.recaptcha.error.recaptchaString.{$__errorType}{/lang}
- {/if}
- </small>
- {/if}
- </noscript>
- {else}
- <script data-relocate="true">
- $.getScript('//www.google.com/recaptcha/api/js/recaptcha_ajax.js', function() {
- Recaptcha.create("{$recaptchaPublicKey}", "recaptcha_image", {
- lang: '{@$recaptchaLanguageCode}',
- theme : 'custom'
- });
-
- WCF.System.Captcha.addCallback('{$captchaID}', function() {
- return {
- recaptcha_challenge_field: Recaptcha.get_challenge(),
- recaptcha_response_field: Recaptcha.get_response()
- };
- });
- });
- </script>
- {/if}
- </dl>
- </section>
- {else}
+ {if RECAPTCHA_PUBLICKEY !== '' && RECAPTCHA_PRIVATEKEY !== ''}
{if $supportsAsyncCaptcha|isset && $supportsAsyncCaptcha && RECAPTCHA_PUBLICKEY_INVISIBLE && RECAPTCHA_PRIVATEKEY_INVISIBLE}
<section class="section">
<h2 class="sectionTitle">{lang}wcf.recaptcha.title{/lang}</h2>
<?php
namespace wcf\form;
-use wcf\system\recaptcha\RecaptchaHandler;
use wcf\system\recaptcha\RecaptchaHandlerV2;
use wcf\system\WCF;
-use wcf\util\StringUtil;
/**
* RecaptchaForm is an abstract form implementation for the use of reCAPTCHA.
public function readFormParameters() {
parent::readFormParameters();
- if (!RECAPTCHA_PUBLICKEY || !RECAPTCHA_PRIVATEKEY) {
- // V1
- if (isset($_POST['recaptcha_challenge_field'])) $this->challenge = StringUtil::trim($_POST['recaptcha_challenge_field']);
- if (isset($_POST['recaptcha_response_field'])) $this->response = StringUtil::trim($_POST['recaptcha_response_field']);
- }
- else {
- // V2
- if (isset($_POST['g-recaptcha-response'])) $this->response = $_POST['g-recaptcha-response'];
- }
+ if (isset($_POST['g-recaptcha-response'])) $this->response = $_POST['g-recaptcha-response'];
}
/**
*/
protected function validateCaptcha() {
if ($this->useCaptcha) {
- if (!RECAPTCHA_PUBLICKEY || !RECAPTCHA_PRIVATEKEY) {
- // V1
- RecaptchaHandler::getInstance()->validate($this->challenge, $this->response);
- }
- else {
- // V2
- RecaptchaHandlerV2::getInstance()->validate($this->response);
- }
+ RecaptchaHandlerV2::getInstance()->validate($this->response);
$this->useCaptcha = false;
}
public function assignVariables() {
parent::assignVariables();
- if (!RECAPTCHA_PUBLICKEY || !RECAPTCHA_PRIVATEKEY) {
- // V1
- RecaptchaHandler::getInstance()->assignVariables();
- }
- else {
- // V2
- WCF::getTPL()->assign([
- 'recaptchaLegacyMode' => true
- ]);
- }
+ WCF::getTPL()->assign([
+ 'recaptchaLegacyMode' => true
+ ]);
WCF::getTPL()->assign([
'useCaptcha' => $this->useCaptcha
namespace wcf\system\captcha;
use wcf\system\recaptcha\RecaptchaHandlerV2;
use wcf\system\WCF;
-use wcf\util\StringUtil;
/**
* Captcha handler for reCAPTCHA.
public function getFormElement() {
if (WCF::getSession()->getVar('recaptchaDone')) return '';
- if (!RECAPTCHA_PUBLICKEY || !RECAPTCHA_PRIVATEKEY) {
- // V1
- \wcf\system\recaptcha\RecaptchaHandler::getInstance()->assignVariables();
- }
- else {
- // V2
- WCF::getTPL()->assign([
- 'recaptchaLegacyMode' => true
- ]);
- }
+ WCF::getTPL()->assign([
+ 'recaptchaLegacyMode' => true
+ ]);
return WCF::getTPL()->fetch('recaptcha');
}
* @inheritDoc
*/
public function readFormParameters() {
- if (!RECAPTCHA_PUBLICKEY || !RECAPTCHA_PRIVATEKEY) {
- // V1
- if (isset($_POST['recaptcha_challenge_field'])) $this->challenge = StringUtil::trim($_POST['recaptcha_challenge_field']);
- if (isset($_POST['recaptcha_response_field'])) $this->response = StringUtil::trim($_POST['recaptcha_response_field']);
- }
- else {
- // V2
- if (isset($_POST['recaptcha-type'])) $this->challenge = $_POST['recaptcha-type'];
- if (isset($_POST['g-recaptcha-response'])) $this->response = $_POST['g-recaptcha-response'];
- }
+ if (isset($_POST['recaptcha-type'])) $this->challenge = $_POST['recaptcha-type'];
+ if (isset($_POST['g-recaptcha-response'])) $this->response = $_POST['g-recaptcha-response'];
}
/**
public function validate() {
if (WCF::getSession()->getVar('recaptchaDone')) return;
- if (!RECAPTCHA_PUBLICKEY || !RECAPTCHA_PRIVATEKEY) {
- // V1
- \wcf\system\recaptcha\RecaptchaHandler::getInstance()->validate($this->challenge, $this->response);
- }
- else {
- // V2
- RecaptchaHandlerV2::getInstance()->validate($this->response, $this->challenge ?: 'v2');
- }
+ RecaptchaHandlerV2::getInstance()->validate($this->response, $this->challenge ?: 'v2');
}
}
+++ /dev/null
-<?php
-namespace wcf\system\recaptcha;
-use wcf\system\exception\SystemException;
-use wcf\system\exception\UserInputException;
-use wcf\system\request\RouteHandler;
-use wcf\system\SingletonFactory;
-use wcf\system\WCF;
-use wcf\util\HTTPRequest;
-use wcf\util\StringUtil;
-use wcf\util\UserUtil;
-
-/**
- * Handles reCAPTCHA support.
- *
- * Based upon reCAPTCHA-plugin originally created in 2010 by Markus Bartz <roul@codingcorner.info>
- * and released under the conditions of the GNU Lesser General Public License.
- *
- * @author Alexander Ebert
- * @copyright 2001-2019 WoltLab GmbH
- * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
- * @package WoltLabSuite\Core\System\Recaptcha
- */
-class RecaptchaHandler extends SingletonFactory {
- /**
- * list of supported languages
- * @var string[]
- * @see http://code.google.com/intl/de-DE/apis/recaptcha/docs/customization.html#i18n
- */
- protected $supportedLanguages = ['de', 'en', 'es', 'fr', 'nl', 'pt', 'ru', 'tr'];
-
- /**
- * language code
- * @var string
- */
- protected $languageCode = '';
-
- /**
- * public key
- * @var string
- */
- protected $publicKey = '';
-
- /**
- * private key
- * @var string
- */
- protected $privateKey = '';
-
- // reply codes (see <http://code.google.com/intl/de-DE/apis/recaptcha/docs/verify.html>)
- const VALID_ANSWER = 'valid';
- const ERROR_UNKNOWN = 'unknown';
- const ERROR_INVALID_PUBLICKEY = 'invalid-site-public-key';
- const ERROR_INVALID_PRIVATEKEY = 'invalid-site-private-key';
- const ERROR_INVALID_COOKIE = 'invalid-request-cookie';
- const ERROR_INCORRECT_SOLUTION = 'incorrect-captcha-sol';
- const ERROR_INCORRECT_PARAMS = 'verify-params-incorrect';
- const ERROR_INVALID_REFFERER = 'invalid-referrer';
- const ERROR_NOT_REACHABLE = 'recaptcha-not-reachable';
- const ERROR_TIMEOUT_OR_DUPLICATE = 'timeout-or-duplicate';
-
- /**
- * @inheritDoc
- */
- protected function init() {
- // set appropriate language code, fallback to EN if language code is not known to reCAPTCHA-API
- $this->languageCode = WCF::getLanguage()->getFixedLanguageCode();
- if (!in_array($this->languageCode, $this->supportedLanguages)) {
- $this->languageCode = 'en';
- }
-
- // WoltLab's V1 OEM keys
- $this->publicKey = '6LfOlMYSAAAAADvo3s4puBAYDqI-6YK2ybe7BJE5';
- $this->privateKey = '6LfOlMYSAAAAAKR3m_EFxmDv1xS8PCfeaSZ2LdG9';
- }
-
- /**
- * Validates response against given challenge.
- *
- * @param string $challenge
- * @param string $response
- * @throws SystemException
- * @throws UserInputException
- */
- public function validate($challenge, $response) {
- // fail if challenge or response are empty to avoid sending api requests
- if (empty($challenge) || empty($response)) {
- throw new UserInputException('recaptchaString', 'false');
- }
-
- $response = $this->verify($challenge, $response);
- switch ($response) {
- case self::VALID_ANSWER:
- break;
-
- case self::ERROR_INCORRECT_SOLUTION:
- throw new UserInputException('recaptchaString', 'false');
- break;
-
- case self::ERROR_NOT_REACHABLE:
- // if reCaptcha server is unreachable mark captcha as done
- // this should be better than block users until server is back.
- // - RouL
- break;
-
- case self::ERROR_INVALID_COOKIE:
- // do not throw a system exception, if validation fails
- // while javascript is disabled. Otherwise, bots may produce
- // a lot of log entries.
- throw new UserInputException('recaptchaString', 'false');
- break;
-
- case self::ERROR_TIMEOUT_OR_DUPLICATE:
- // User was to slow to fill the captcha.
- throw new UserInputException('recaptchaString', 'false');
- break;
-
- default:
- throw new SystemException('reCAPTCHA returned the following error: '.$response);
- }
-
- WCF::getSession()->register('recaptchaDone', true);
- }
-
- /**
- * Queries server to verify successful response.
- *
- * @param string $challenge
- * @param string $response
- * @return string
- */
- protected function verify($challenge, $response) {
- $request = new HTTPRequest('http://www.google.com/recaptcha/api/verify', ['timeout' => 10], [
- 'privatekey' => $this->privateKey,
- 'remoteip' => UserUtil::getIpAddress(),
- 'challenge' => $challenge,
- 'response' => $response
- ]);
-
- try {
- $request->execute();
- $reply = $request->getReply();
- $reCaptchaResponse = explode("\n", $reply['body']);
-
- if (StringUtil::trim($reCaptchaResponse[0]) === "true") {
- return self::VALID_ANSWER;
- }
- else {
- return StringUtil::trim($reCaptchaResponse[1]);
- }
- }
- catch (SystemException $e) {
- return self::ERROR_NOT_REACHABLE;
- }
- }
-
- /**
- * Assigns template variables for reCAPTCHA.
- */
- public function assignVariables() {
- WCF::getTPL()->assign([
- 'recaptchaLanguageCode' => $this->languageCode,
- 'recaptchaPublicKey' => $this->publicKey,
- 'recaptchaUseSSL' => RouteHandler::secureConnection(), // @deprecated 2.1
- 'recaptchaLegacyMode' => true
- ]);
- }
-}