X-Git-Url: https://git.toastfreeware.priv.at/toast/cookiecaptcha.git/blobdiff_plain/152f5e39e0ad8115470ee380e567a3ea31db6f1b..283ec4908cd436c4fcd023dee108d064afad1170:/ConfirmEdit_body.php diff --git a/ConfirmEdit_body.php b/ConfirmEdit_body.php index 8e67910..991bd63 100644 --- a/ConfirmEdit_body.php +++ b/ConfirmEdit_body.php @@ -15,13 +15,17 @@ class ConfirmEditHooks { return $wgCaptcha; } - static function confirmEdit( &$editPage, $newtext, $section ) { + static function confirmEdit( $editPage, $newtext, $section ) { return self::getInstance()->confirmEdit( $editPage, $newtext, $section ); } - static function confirmEditMerged( &$editPage, $newtext ) { + static function confirmEditMerged( $editPage, $newtext ) { return self::getInstance()->confirmEditMerged( $editPage, $newtext ); } + + static function confirmEditAPI( &$editPage, $newtext, &$resultArr ) { + return self::getInstance()->confirmEditAPI( $editPage, $newtext, $resultArr ); + } static function injectUserCreate( &$template ) { return self::getInstance()->injectUserCreate( $template ); @@ -44,13 +48,14 @@ class ConfirmEditHooks { } } -class CaptchaSpecialPage extends SpecialPage { +class CaptchaSpecialPage extends UnlistedSpecialPage { function execute( $par ) { $this->setHeaders(); $instance = ConfirmEditHooks::getInstance(); switch( $par ) { case "image": - return $instance->showImage(); + if( method_exists($instance,'showImage') ) + return $instance->showImage(); case "help": default: return $instance->showHelp(); @@ -65,6 +70,25 @@ class SimpleCaptcha { $this->storage = new $wgCaptchaStorageClass; } + function getCaptcha() { + $a = mt_rand(0, 100); + $b = mt_rand(0, 10); + $op = mt_rand(0, 1) ? '+' : '-'; + + $test = "$a $op $b"; + $answer = ($op == '+') ? ($a + $b) : ($a - $b); + return array('question' => $test, 'answer' => $answer); + } + + function addCaptchaAPI(&$resultArr) { + $captcha = $this->getCaptcha(); + $index = $this->storeCaptcha( $captcha ); + $resultArr['captcha']['type'] = 'simple'; + $resultArr['captcha']['mime'] = 'text/plain'; + $resultArr['captcha']['id'] = $index; + $resultArr['captcha']['question'] = $captcha['question']; + } + /** * Insert a captcha prompt into the edit form. * This sample implementation generates a simple arithmetic operation; @@ -75,22 +99,16 @@ class SimpleCaptcha { * @return string HTML */ function getForm() { - $a = mt_rand(0, 100); - $b = mt_rand(0, 10); - $op = mt_rand(0, 1) ? '+' : '-'; - - $test = "$a $op $b"; - $answer = ($op == '+') ? ($a + $b) : ($a - $b); + $captcha = $this->getCaptcha(); + $index = $this->storeCaptcha( $captcha ); - $index = $this->storeCaptcha( array( 'answer' => $answer ) ); - - return "

= " . - wfElement( 'input', array( + return "

= " . + Xml::element( 'input', array( 'name' => 'wpCaptchaWord', 'id' => 'wpCaptchaWord', 'tabindex' => 1 ) ) . // tab in before the edit textarea "

\n" . - wfElement( 'input', array( + Xml::element( 'input', array( 'type' => 'hidden', 'name' => 'wpCaptchaId', 'id' => 'wpCaptchaId', @@ -128,8 +146,12 @@ class SimpleCaptcha { * @return bool true to keep running callbacks */ function injectUserCreate( &$template ) { - global $wgCaptchaTriggers, $wgOut; + global $wgCaptchaTriggers, $wgOut, $wgUser; if( $wgCaptchaTriggers['createaccount'] ) { + if( $wgUser->isAllowed( 'skipcaptcha' ) ) { + wfDebug( "ConfirmEdit: user group allows skipping captcha on account creation\n" ); + return true; + } $template->set( 'header', "
" . $wgOut->parse( $this->getMessage( 'createaccount' ) ) . @@ -187,8 +209,24 @@ class SimpleCaptcha { * @access private */ function isBadLoginTriggered() { - global $wgMemc; - return intval( $wgMemc->get( $this->badLoginKey() ) ) > 0; + global $wgMemc, $wgCaptchaBadLoginAttempts; + return intval( $wgMemc->get( $this->badLoginKey() ) ) >= $wgCaptchaBadLoginAttempts; + } + + /** + * Check if the IP is allowed to skip captchas + */ + function isIPWhitelisted() { + global $wgCaptchaWhitelistIP; + if( $wgCaptchaWhitelistIP ) { + $ip = wfGetIp(); + foreach ( $wgCaptchaWhitelistIP as $range ) { + if ( IP::isInRange( $ip, $range ) ) { + return true; + } + } + } + return false; } /** @@ -206,12 +244,12 @@ class SimpleCaptcha { * * Override this! * - * @param WebRequest $request + * @param string $answer * @param array $info * @return bool */ - function keyMatch( $request, $info ) { - return $request->getVal( 'wpCaptchaWord' ) == $info['answer']; + function keyMatch( $answer, $info ) { + return $answer == $info['answer']; } // ---------------------------------- @@ -246,15 +284,8 @@ class SimpleCaptcha { wfDebug( "ConfirmEdit: user group allows skipping captcha\n" ); return false; } - global $wgCaptchaWhitelistIP; - if( !empty( $wgCaptchaWhitelistIP ) ) { - $ip = wfGetIp(); - foreach ( $wgCaptchaWhitelistIP as $range ) { - if ( IP::isInRange( $ip, $range ) ) { - return false; - } - } - } + if( $this->isIPWhitelisted() ) + return false; global $wgEmailAuthentication, $ceAllowConfirmedEmail; @@ -297,8 +328,8 @@ class SimpleCaptcha { } else { // Get link changes in the slowest way known to man $oldtext = $this->loadText( $editPage, $section ); - $oldLinks = $this->findLinks( $oldtext ); - $newLinks = $this->findLinks( $newtext ); + $oldLinks = $this->findLinks( $editPage, $oldtext ); + $newLinks = $this->findLinks( $editPage, $newtext ); } $unknownLinks = array_filter( $newLinks, array( &$this, 'filterLink' ) ); @@ -318,7 +349,7 @@ class SimpleCaptcha { } global $wgCaptchaRegexes; - if( !empty( $wgCaptchaRegexes ) ) { + if( $wgCaptchaRegexes ) { // Custom regex checks $oldtext = $this->loadText( $editPage, $section ); @@ -391,7 +422,7 @@ class SimpleCaptcha { //$regex = 'http://+[a-z0-9_\-.]*(' . implode( '|', $lines ) . ')'; //return '/' . str_replace( '/', '\/', preg_replace('|\\\*/|', '/', $regex) ) . '/Si'; $regexes = ''; - $regexStart = '/http:\/\/+[a-z0-9_\-.]*('; + $regexStart = '/^https?:\/\/+[a-z0-9_\-.]*('; $regexEnd = ')/Si'; $regexMax = 4096; $build = false; @@ -430,21 +461,17 @@ class SimpleCaptcha { $links[] = $row->el_to; } return $links; - } - + } + /** - * The main callback run on edit attempts. - * @param EditPage $editPage - * @param string $newtext - * @param string $section - * @param bool true to continue saving, false to abort and show a captcha form + * Backend function for confirmEdit() and confirmEditAPI() + * @return bool false if the CAPTCHA is rejected, true otherwise */ - function confirmEdit( &$editPage, $newtext, $section, $merged = false ) { + private function doConfirmEdit( $editPage, $newtext, $section, $merged = false ) { if( $this->shouldCheck( $editPage, $newtext, $section, $merged ) ) { if( $this->passCaptcha() ) { return true; } else { - $editPage->showEditForm( array( &$this, 'editCallback' ) ); return false; } } else { @@ -453,14 +480,44 @@ class SimpleCaptcha { } } + /** + * The main callback run on edit attempts. + * @param EditPage $editPage + * @param string $newtext + * @param string $section + * @param bool $merged + * @return bool true to continue saving, false to abort and show a captcha form + */ + function confirmEdit( $editPage, $newtext, $section, $merged = false ) { + if( defined('MW_API') ) { + # API mode + # The CAPTCHA was already checked and approved + return true; + } + if( !$this->doConfirmEdit( $editPage, $newtext, $section, $merged ) ) { + $editPage->showEditForm( array( &$this, 'editCallback' ) ); + return false; + } + return true; + } + /** * A more efficient edit filter callback based on the text after section merging * @param EditPage $editPage * @param string $newtext */ - function confirmEditMerged( &$editPage, $newtext ) { + function confirmEditMerged( $editPage, $newtext ) { return $this->confirmEdit( $editPage, $newtext, false, true ); } + + + function confirmEditAPI( &$editPage, $newtext, &$resultArr) { + if( !$this->doConfirmEdit( $editPage, $newtext, false, false ) ) { + $this->addCaptchaAPI($resultArr); + return false; + } + return true; + } /** * Hook for user creation form submissions. @@ -469,8 +526,15 @@ class SimpleCaptcha { * @return bool true to continue, false to abort user creation */ function confirmUserCreate( $u, &$message ) { - global $wgCaptchaTriggers; + global $wgCaptchaTriggers, $wgUser; if( $wgCaptchaTriggers['createaccount'] ) { + if( $wgUser->isAllowed( 'skipcaptcha' ) ) { + wfDebug( "ConfirmEdit: user group allows skipping captcha on account creation\n" ); + return true; + } + if( $this->isIPWhitelisted() ) + return true; + $this->trigger = "new account '" . $u->getName() . "'"; if( !$this->passCaptcha() ) { $message = wfMsg( 'captcha-createaccount-fail' ); @@ -488,6 +552,9 @@ class SimpleCaptcha { */ function confirmUserLogin( $u, $pass, &$retval ) { if( $this->isBadLoginTriggered() ) { + if( $this->isIPWhitelisted() ) + return true; + $this->trigger = "post-badlogin login '" . $u->getName() . "'"; if( !$this->passCaptcha() ) { $message = wfMsg( 'captcha-badlogin-fail' ); @@ -508,7 +575,7 @@ class SimpleCaptcha { $info = $this->retrieveCaptcha(); if( $info ) { global $wgRequest; - if( $this->keyMatch( $wgRequest, $info ) ) { + if( $this->keyMatch( $wgRequest->getVal('wpCaptchaWord'), $info ) ) { $this->log( "passed" ); $this->clearCaptcha( $info ); return true; @@ -595,12 +662,12 @@ class SimpleCaptcha { * @param string $text * @return array of strings */ - function findLinks( $text ) { - global $wgParser, $wgTitle, $wgUser; + function findLinks( &$editpage, $text ) { + global $wgParser, $wgUser; $options = new ParserOptions(); - $text = $wgParser->preSaveTransform( $text, $wgTitle, $wgUser, $options ); - $out = $wgParser->parse( $text, $wgTitle, $options ); + $text = $wgParser->preSaveTransform( $text, $editpage->mTitle, $wgUser, $options ); + $out = $wgParser->parse( $text, $editpage->mTitle, $options ); return array_keys( $out->getExternalLinks() ); }