Файловый менеджер - Редактировать - /var/www/html/Auth.zip
Ðазад
PK ! K�(��! �! $ CaptchaPreAuthenticationProvider.phpnu �Iw�� <?php namespace MediaWiki\Extension\ConfirmEdit\Auth; use MediaWiki\Auth\AbstractPreAuthenticationProvider; use MediaWiki\Auth\AuthenticationRequest; use MediaWiki\Auth\AuthenticationResponse; use MediaWiki\Auth\AuthManager; use MediaWiki\Extension\ConfirmEdit\CaptchaTriggers; use MediaWiki\Extension\ConfirmEdit\Hooks; use MediaWiki\Extension\ConfirmEdit\SimpleCaptcha\SimpleCaptcha; use MediaWiki\Logger\LoggerFactory; use MediaWiki\Status\Status; use MediaWiki\User\User; class CaptchaPreAuthenticationProvider extends AbstractPreAuthenticationProvider { /** * @inheritDoc */ public function getAuthenticationRequests( $action, array $options ) { $captcha = Hooks::getInstance(); $user = User::newFromName( $options['username'] ); $needed = false; switch ( $action ) { case AuthManager::ACTION_CREATE: $u = $user ?: new User(); $needed = $captcha->needCreateAccountCaptcha( $u ); if ( $needed ) { $captcha->setAction( 'accountcreate' ); // This is debug level simply because generally // captchas are either always or never triggered on // view of create account, so it gets pretty noisy LoggerFactory::getInstance( 'captcha' ) ->debug( 'Captcha shown on account creation for {user}', [ 'event' => 'captcha.display', 'eventType' => 'accountcreation', 'user' => $u->getName() ] ); } break; case AuthManager::ACTION_LOGIN: // Captcha is shown on login when there were too many failed attempts from the current IP // or using a given username, or if a hook handler says that a CAPTCHA should be shown. // The varying on username is a bit awkward because we don't know the // username yet. The username from the last successful login is stored in a cookie, // but we still must make sure to not lock out other usernames, so after the first // failed login attempt using a username that needs a captcha, set a session flag // to display a captcha on login from that point on. This will result in confusing // error messages if the browser cannot persist the session (because we'll never show // a required captcha field), but then login would be impossible anyway so no big deal. // If the username ends to be one that does not trigger the captcha, that will // result in weird behavior (if the user leaves the captcha field empty, they get // a required field error; if they fill it with an invalid answer, it will pass) // - again, not a huge deal. $session = $this->manager->getRequest()->getSession(); $suggestedUsername = $session->suggestLoginUsername(); if ( $captcha->triggersCaptcha( CaptchaTriggers::LOGIN_ATTEMPT ) ) { $captcha->setAction( 'loginattempt' ); LoggerFactory::getInstance( 'captcha' ) ->info( 'Captcha shown on login attempt by {clientip} for {suggestedUser}', [ 'event' => 'captcha.display', 'eventType' => 'loginattempt', 'suggestedUser' => $suggestedUsername, 'clientip' => $this->manager->getRequest()->getIP(), 'ua' => $this->manager->getRequest()->getHeader( 'User-Agent' ) ] ); $needed = true; break; } $loginCounter = $this->getLoginAttemptCounter( $captcha ); $userProbablyNeedsCaptcha = $session->get( 'ConfirmEdit:loginCaptchaPerUserTriggered' ); if ( $loginCounter->isBadLoginTriggered() || $userProbablyNeedsCaptcha || ( $suggestedUsername && $loginCounter->isBadLoginPerUserTriggered( $suggestedUsername ) ) ) { $needed = true; $captcha->setAction( 'badlogin' ); LoggerFactory::getInstance( 'captcha' ) ->info( 'Captcha shown on login by {clientip} for {suggestedUser}', [ 'event' => 'captcha.display', 'eventType' => 'badlogin', 'suggestedUser' => $suggestedUsername, 'clientip' => $this->manager->getRequest()->getIP(), 'ua' => $this->manager->getRequest()->getHeader( 'User-Agent' ) ] ); break; } break; } if ( $needed ) { return [ $captcha->createAuthenticationRequest() ]; } else { return []; } } /** * @inheritDoc */ public function testForAuthentication( array $reqs ) { $captcha = Hooks::getInstance(); $username = AuthenticationRequest::getUsernameFromRequests( $reqs ); $loginCounter = $this->getLoginAttemptCounter( $captcha ); $success = true; $isBadLoginPerUserTriggered = $username ? $loginCounter->isBadLoginPerUserTriggered( $username ) : false; $loginTriggersCaptcha = $captcha->triggersCaptcha( CaptchaTriggers::LOGIN_ATTEMPT ); if ( $isBadLoginPerUserTriggered || $loginCounter->isBadLoginTriggered() || $loginTriggersCaptcha ) { if ( $loginTriggersCaptcha ) { $captcha->setAction( 'loginattempt' ); $captcha->setTrigger( "loginattempt login '$username'" ); } else { $captcha->setAction( 'badlogin' ); $captcha->setTrigger( "post-badlogin login '$username'" ); } $success = $this->verifyCaptcha( $captcha, $reqs, new User() ); $ip = $this->manager->getRequest()->getIP(); $action = $loginTriggersCaptcha ? 'login page' : 'bad login'; LoggerFactory::getInstance( 'captcha' )->info( "Captcha shown on $action for {user}", [ 'event' => 'captcha.submit', 'eventType' => $loginTriggersCaptcha ? 'loginattempt' : 'badlogin', 'successful' => $success, 'user' => $username ?? 'unknown', 'clientip' => $ip, 'ua' => $this->manager->getRequest()->getHeader( 'User-Agent' ) ] ); } if ( $isBadLoginPerUserTriggered ) { $session = $this->manager->getRequest()->getSession(); // A captcha is needed to log in with this username, so display it on the next attempt. $session->set( 'ConfirmEdit:loginCaptchaPerUserTriggered', true ); } // Make brute force attacks harder by not telling whether the password or the // captcha failed. return $success ? Status::newGood() : $this->makeError( 'wrongpassword', $captcha ); } /** * @inheritDoc */ public function testForAccountCreation( $user, $creator, array $reqs ) { $captcha = Hooks::getInstance(); if ( $captcha->needCreateAccountCaptcha( $creator ) ) { $username = $user->getName(); $captcha->setAction( 'accountcreate' ); $captcha->setTrigger( "new account '$username'" ); $success = $this->verifyCaptcha( $captcha, $reqs, $user ); $ip = $this->manager->getRequest()->getIP(); LoggerFactory::getInstance( 'captcha' )->info( 'Captcha submitted on account creation for {user}', [ 'event' => 'captcha.submit', 'eventType' => 'accountcreation', 'successful' => $success, 'user' => $username, 'clientip' => $ip, 'ua' => $this->manager->getRequest()->getHeader( 'User-Agent' ) ] ); if ( !$success ) { return $this->makeError( 'captcha-createaccount-fail', $captcha ); } } return Status::newGood(); } /** * @inheritDoc */ public function postAuthentication( $user, AuthenticationResponse $response ) { $captcha = Hooks::getInstance(); $loginCounter = $this->getLoginAttemptCounter( $captcha ); switch ( $response->status ) { case AuthenticationResponse::PASS: case AuthenticationResponse::RESTART: $session = $this->manager->getRequest()->getSession(); $session->remove( 'ConfirmEdit:loginCaptchaPerUserTriggered' ); $loginCounter->resetBadLoginCounter( $user ? $user->getName() : null ); break; case AuthenticationResponse::FAIL: $loginCounter->increaseBadLoginCounter( $user ? $user->getName() : null ); break; } } /** * Verify submitted captcha. * Assumes that the user has to pass the capctha (permission checks are caller's responsibility). * @param SimpleCaptcha $captcha * @param AuthenticationRequest[] $reqs * @param User $user * @return bool */ protected function verifyCaptcha( SimpleCaptcha $captcha, array $reqs, User $user ) { /** @var CaptchaAuthenticationRequest $req */ $req = AuthenticationRequest::getRequestByClass( $reqs, CaptchaAuthenticationRequest::class, true ); if ( !$req ) { return false; } return $captcha->passCaptchaLimited( $req->captchaId, $req->captchaWord, $user ); } /** * @param string $message Message key * @param SimpleCaptcha $captcha * @return Status */ protected function makeError( $message, SimpleCaptcha $captcha ) { $error = $captcha->getError(); if ( $error ) { return Status::newFatal( wfMessage( 'captcha-error', $error ) ); } return Status::newFatal( $message ); } protected function getLoginAttemptCounter( SimpleCaptcha $captcha ): LoginAttemptCounter { // Overridable for testing return new LoginAttemptCounter( $captcha ); } } PK ! =2%�� � CaptchaAuthenticationRequest.phpnu �Iw�� <?php namespace MediaWiki\Extension\ConfirmEdit\Auth; use MediaWiki\Auth\AuthenticationRequest; use MediaWiki\Auth\AuthManager; use MediaWiki\Extension\ConfirmEdit\Hooks; /** * Generic captcha authentication request class. A captcha consist some data stored in the session * (e.g. a question and its answer), an ID that references the data, and a solution. */ class CaptchaAuthenticationRequest extends AuthenticationRequest { /** @var string Identifier of the captcha. Used internally to remember which captcha was used. */ public $captchaId; /** @var array Information about the captcha (e.g. question text; solution). Exact semantics * differ between types. */ public $captchaData; /** @var string Captcha solution submitted by the user. */ public $captchaWord; /** * @param string $id * @param array $data */ public function __construct( $id, $data ) { $this->captchaId = $id; $this->captchaData = $data; } /** @inheritDoc */ public function getUniqueId() { return 'CaptchaAuthenticationRequest'; } /** * @inheritDoc */ public function loadFromSubmission( array $data ) { $success = parent::loadFromSubmission( $data ); if ( $success ) { // captchaId and captchaWord was set from the submission but captchaData was not. $captcha = Hooks::getInstance(); $this->captchaData = $captcha->retrieveCaptcha( $this->captchaId ); if ( !$this->captchaData ) { return false; } } return $success; } /** * @inheritDoc */ public function getFieldInfo() { $captcha = Hooks::getInstance(); // doesn't actually exist but *Captcha::getMessage will handle that $action = 'generic'; switch ( $this->action ) { case AuthManager::ACTION_LOGIN: $action = 'badlogin'; break; case AuthManager::ACTION_CREATE: $action = 'createaccount'; break; } $fields = [ 'captchaId' => [ 'type' => 'hidden', 'value' => $this->captchaId, 'label' => wfMessage( 'captcha-id-label' ), 'help' => wfMessage( 'captcha-id-help' ), ], 'captchaInfo' => [ 'type' => 'null', 'label' => $captcha->getMessage( $action ), 'value' => $captcha->getCaptchaInfo( $this->captchaData, $this->captchaId ), 'help' => wfMessage( 'captcha-info-help' ), ], 'captchaWord' => [ 'type' => 'string', 'label' => wfMessage( 'captcha-label' ), 'help' => wfMessage( 'captcha-help' ), ], ]; return $fields; } /** * @inheritDoc */ public function getMetadata() { return ( Hooks::getInstance() )->describeCaptchaType(); } /** * @param array $data * @return CaptchaAuthenticationRequest */ public static function __set_state( $data ) { $ret = new static( '', [] ); foreach ( $data as $k => $v ) { $ret->$k = $v; } return $ret; } } PK ! ���[ [ LoginAttemptCounter.phpnu �Iw�� <?php namespace MediaWiki\Extension\ConfirmEdit\Auth; use MediaWiki\Extension\ConfirmEdit\CaptchaTriggers; use MediaWiki\Extension\ConfirmEdit\SimpleCaptcha\SimpleCaptcha; use MediaWiki\MediaWikiServices; use MediaWiki\User\User; use MediaWiki\User\UserNameUtils; use Wikimedia\ObjectCache\BagOStuff; /** * Helper to count login attempts per IP and per username. * * @internal */ class LoginAttemptCounter { private SimpleCaptcha $captcha; public function __construct( SimpleCaptcha $captcha ) { $this->captcha = $captcha; } /** * Increase bad login counter after a failed login. * The user might be required to solve a captcha if the count is high. * @param string $username * TODO use Throttler */ public function increaseBadLoginCounter( $username ) { global $wgCaptchaBadLoginExpiration, $wgCaptchaBadLoginPerUserExpiration; $cache = MediaWikiServices::getInstance()->getObjectCacheFactory()->getLocalClusterInstance(); if ( $this->captcha->triggersCaptcha( CaptchaTriggers::BAD_LOGIN ) ) { $key = $this->badLoginKey( $cache ); $cache->incrWithInit( $key, $wgCaptchaBadLoginExpiration ); // Longer period of time $key = $this->badLoginKey( $cache, true ); $cache->incrWithInit( $key, $wgCaptchaBadLoginExpiration * 300 ); } if ( $this->captcha->triggersCaptcha( CaptchaTriggers::BAD_LOGIN_PER_USER ) && $username ) { $key = $this->badLoginPerUserKey( $username, $cache ); $cache->incrWithInit( $key, $wgCaptchaBadLoginPerUserExpiration ); $key = $this->badLoginPerUserKey( $username, $cache, true ); $cache->incrWithInit( $key, $wgCaptchaBadLoginPerUserExpiration * 300 ); } } /** * Reset bad login counter after a successful login. * @param string $username */ public function resetBadLoginCounter( $username ) { if ( $this->captcha->triggersCaptcha( CaptchaTriggers::BAD_LOGIN_PER_USER ) && $username ) { $cache = MediaWikiServices::getInstance()->getObjectCacheFactory()->getLocalClusterInstance(); $cache->delete( $this->badLoginPerUserKey( $username, $cache ) ); $cache->delete( $this->badLoginPerUserKey( $username, $cache, true ) ); } } /** * Check if a bad login has already been registered for this * IP address. If so, require a captcha. * @return bool */ public function isBadLoginTriggered() { global $wgCaptchaBadLoginAttempts; $cache = MediaWikiServices::getInstance()->getObjectCacheFactory()->getLocalClusterInstance(); return $this->captcha->triggersCaptcha( CaptchaTriggers::BAD_LOGIN ) && ( (int)$cache->get( $this->badLoginKey( $cache ) ) >= $wgCaptchaBadLoginAttempts || (int)$cache->get( $this->badLoginKey( $cache, true ) ) >= ( $wgCaptchaBadLoginAttempts * 30 ) ); } /** * Is the per-user captcha triggered? * * @param User|string $u User object, or name * @return bool */ public function isBadLoginPerUserTriggered( $u ) { global $wgCaptchaBadLoginPerUserAttempts; $cache = MediaWikiServices::getInstance()->getObjectCacheFactory()->getLocalClusterInstance(); if ( is_object( $u ) ) { $u = $u->getName(); } return $this->captcha->triggersCaptcha( CaptchaTriggers::BAD_LOGIN_PER_USER ) && ( (int)$cache->get( $this->badLoginPerUserKey( $u, $cache ) ) >= $wgCaptchaBadLoginPerUserAttempts || (int)$cache->get( $this->badLoginPerUserKey( $u, $cache, true ) ) >= ( $wgCaptchaBadLoginPerUserAttempts * 30 ) ); } /** * Internal cache key for badlogin checks. * @param BagOStuff $cache * @param bool $long * @return string */ private function badLoginKey( BagOStuff $cache, $long = false ) { global $wgRequest; $ip = $wgRequest->getIP(); if ( !$long ) { return $cache->makeGlobalKey( 'captcha', 'badlogin', 'ip', $ip ); } return $cache->makeGlobalKey( 'captcha', 'badlogin', 'ip', 'long', $ip ); } /** * Cache key for badloginPerUser checks. * @param string $username * @param BagOStuff $cache * @param bool $long * @return string */ private function badLoginPerUserKey( $username, BagOStuff $cache, $long = false ) { $userNameUtils = MediaWikiServices::getInstance()->getUserNameUtils(); $username = $userNameUtils->getCanonical( $username, UserNameUtils::RIGOR_USABLE ) ?: $username; if ( !$long ) { return $cache->makeGlobalKey( 'captcha', 'badlogin', 'user', md5( $username ) ); } return $cache->makeGlobalKey( 'captcha', 'badlogin', 'user', 'long', md5( $username ) ); } } PK ! K�(��! �! $ CaptchaPreAuthenticationProvider.phpnu �Iw�� PK ! =2%�� � "