Remove reCAPTCHA v1 implementation
authorTim Düsterhus <duesterhus@woltlab.com>
Thu, 3 Dec 2020 10:06:40 +0000 (11:06 +0100)
committerTim Düsterhus <duesterhus@woltlab.com>
Thu, 3 Dec 2020 10:15:23 +0000 (11:15 +0100)
API keys can no longer be created and Google removed the necessary endpoints
for it to work. Thus the code is dead code by now.

com.woltlab.wcf/templates/recaptcha.tpl
wcfsetup/install/files/acp/templates/recaptcha.tpl
wcfsetup/install/files/lib/form/RecaptchaForm.class.php
wcfsetup/install/files/lib/system/captcha/RecaptchaHandler.class.php
wcfsetup/install/files/lib/system/recaptcha/RecaptchaHandler.class.php [deleted file]

index ce0a66293ee892b5920090407d8bfdd65f2afb49..42f74ff0432adb72f831596301f6f32035391576 100644 (file)
@@ -1,100 +1,7 @@
 {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>
index ce0a66293ee892b5920090407d8bfdd65f2afb49..42f74ff0432adb72f831596301f6f32035391576 100644 (file)
@@ -1,100 +1,7 @@
 {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>
index d05d7ffbe20ae5a622b00783187309c5ace5e6f3..ccd4162853286a24ff6b54a71da201d906e43a4f 100644 (file)
@@ -1,9 +1,7 @@
 <?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.
@@ -50,15 +48,7 @@ abstract class RecaptchaForm extends AbstractForm {
        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'];
        }
        
        /**
@@ -75,14 +65,7 @@ abstract class RecaptchaForm extends AbstractForm {
         */
        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;
                }
@@ -103,16 +86,9 @@ abstract class RecaptchaForm extends AbstractForm {
        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
index f0374e2215327b1234adac9a1e1e7ea9ad378b18..cb15d569de9772862ba17fdd51886da6fb93a616 100644 (file)
@@ -2,7 +2,6 @@
 namespace wcf\system\captcha;
 use wcf\system\recaptcha\RecaptchaHandlerV2;
 use wcf\system\WCF;
-use wcf\util\StringUtil;
 
 /**
  * Captcha handler for reCAPTCHA.
@@ -37,16 +36,9 @@ class RecaptchaHandler implements ICaptchaHandler {
        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');
        }
@@ -72,16 +64,8 @@ class RecaptchaHandler implements ICaptchaHandler {
         * @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'];
        }
        
        /**
@@ -97,13 +81,6 @@ class RecaptchaHandler implements ICaptchaHandler {
        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');
        }
 }
diff --git a/wcfsetup/install/files/lib/system/recaptcha/RecaptchaHandler.class.php b/wcfsetup/install/files/lib/system/recaptcha/RecaptchaHandler.class.php
deleted file mode 100644 (file)
index 2480c72..0000000
+++ /dev/null
@@ -1,167 +0,0 @@
-<?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
-               ]);
-       }
-}