From: Happy-melon Date: Sat, 19 Mar 2011 23:47:08 +0000 (+0000) Subject: * Implement an extensible Block::prevents( ) function to replace the plethor... X-Git-Tag: 1.31.0-rc.0~31308 X-Git-Url: https://git.cyclocoop.org/%7B%24www_url%7Dadmin/compta/banques/?a=commitdiff_plain;h=7eac649e6d3891bc360dcd0c012d121ce147121d;p=lhc%2Fweb%2Fwiklou.git * Implement an extensible Block::prevents( ) function to replace the plethora of direct member variable accesses This pushes the historic *disable*-createaccount-vs-*allow* usertalk-edit wierdness down to the database layer * Implement accessors for isHardblock() and getRangeStart()/getRangeEnd() in the same fashion. * Make the corresponding variables private, removing external accessors. This required updating AbuseFilter with non-B/C code, so I also implemented the rest of the changes I've made to the blocking backend in that extension. * Move the "get an IP range which encompasses the given IP/range" logic to Block.php; will be needed later... :D --- diff --git a/includes/Block.php b/includes/Block.php index 06a0f44781..5ca581b38b 100644 --- a/includes/Block.php +++ b/includes/Block.php @@ -16,10 +16,18 @@ */ class Block { /* public*/ var $mAddress, $mUser, $mBy, $mReason, $mTimestamp, $mAuto, $mId, $mExpiry, - $mRangeStart, $mRangeEnd, $mAnonOnly, $mEnableAutoblock, $mHideName, - $mBlockEmail, $mByName, $mAngryAutoblock, $mAllowUsertalk; - private $mFromMaster; - + $mEnableAutoblock, $mHideName, + $mByName, $mAngryAutoblock; + private + $mFromMaster, + $mRangeStart, + $mRangeEnd, + $mAnonOnly, + $mBlockEmail, + $mAllowUsertalk, + $mCreateAccount; + + /// TYPE constants const TYPE_USER = 1; const TYPE_IP = 2; const TYPE_RANGE = 3; @@ -226,6 +234,54 @@ class Block { return false; } + /** + * Get a set of SQL conditions which will select rangeblocks encompasing a given range + * @param $start String Hexadecimal IP representation + * @param $end String Hexadecimal IP represenation, or null to use $start = $end + * @return String + */ + public static function getRangeCond( $start, $end = null ){ + if( $end === null ){ + $end = $start; + } + # Per bug 14634, we want to include relevant active rangeblocks; for + # rangeblocks, we want to include larger ranges which enclose the given + # range. We know that all blocks must be smaller than $wgBlockCIDRLimit, + # so we can improve performance by filtering on a LIKE clause + $chunk = self::getIpFragment( $start ); + $dbr = wfGetDB( DB_SLAVE ); + $like = $dbr->buildLike( $chunk, $dbr->anyString() ); + + # Fairly hard to make a malicious SQL statement out of hex characters, + # but stranger things have happened... + $safeStart = $dbr->addQuotes( $start ); + $safeEnd = $dbr->addQuotes( $end ); + + return $dbr->makeList( + array( + "ipb_range_start $like", + "ipb_range_start <= $safeStart", + "ipb_range_end >= $safeEnd", + ), + LIST_AND + ); + } + + /** + * Get the component of an IP address which is certain to be the same between an IP + * address and a rangeblock containing that IP address. + * @param $hex String Hexadecimal IP representation + * @return String + */ + protected static function getIpFragment( $hex ){ + global $wgBlockCIDRLimit; + if( substr( $hex, 0, 3 ) == 'v6-' ){ + return 'v6-' . substr( substr( $hex, 3 ), 0, floor( $wgBlockCIDRLimit['IPv6'] / 4 ) ); + } else { + return substr( $hex, 0, floor( $wgBlockCIDRLimit['IPv4'] / 4 ) ); + } + } + /** * Fill in member variables from a result wrapper * @@ -706,6 +762,38 @@ class Block { } } + /** + * Get the IP address at the start of the range in Hex form + * @return String IP in Hex form + */ + public function getRangeStart(){ + switch( $this->type ){ + case self::TYPE_USER: + return null; + case self::TYPE_IP: + return IP::toHex( $this->target ); + case self::TYPE_RANGE: + return $this->mRangeStart; + default: throw new MWException( "Block with invalid type" ); + } + } + + /** + * Get the IP address at the start of the range in Hex form + * @return String IP in Hex form + */ + public function getRangeEnd(){ + switch( $this->type ){ + case self::TYPE_USER: + return null; + case self::TYPE_IP: + return IP::toHex( $this->target ); + case self::TYPE_RANGE: + return $this->mRangeEnd; + default: throw new MWException( "Block with invalid type" ); + } + } + /** * Get the user id of the blocking sysop * @@ -739,6 +827,49 @@ class Block { return wfSetVar( $this->mFromMaster, $x ); } + /** + * Get/set whether the Block is a hardblock (affects logged-in users on a given IP/range + * @param $x Bool + * @return Bool + */ + public function isHardblock( $x = null ){ + $y = $this->mAnonOnly; + if( $x !== null){ + $this->mAnonOnly = !$x; + } + return !$y; + } + + /** + * Get/set whether the Block prevents a given action + * @param $action String + * @param $x Bool + * @return Bool + */ + public function prevents( $action, $x = null ){ + switch( $action ){ + case 'edit': + # TODO Not actually quite this simple (bug 13611 etc) + return true; + + case 'createaccount': + return wfSetVar( $this->mCreateAccount, $x ); + + case 'sendemail': + return wfSetVar( $this->mBlockEmail, $x ); + + case 'editusertalk': + $y = $this->mAllowUsertalk; + if( $x !== null){ + $this->mAllowUsertalk = !$x; + } + return !$y; + + default: + return null; + } + } + /** * Get the block name, but with autoblocked IPs hidden as per standard privacy policy * @return String, text is escaped diff --git a/includes/User.php b/includes/User.php index 218355d4ab..5e21c178d0 100644 --- a/includes/User.php +++ b/includes/User.php @@ -1157,7 +1157,7 @@ class User { $this->mBlockedby = $this->mBlock->mByName; $this->mBlockreason = $this->mBlock->mReason; $this->mHideName = $this->mBlock->mHideName; - $this->mAllowUsertalk = $this->mBlock->mAllowUsertalk; + $this->mAllowUsertalk = !$this->mBlock->prevents( 'editusertalk' ); if ( $this->isLoggedIn() && $wgUser->getID() == $this->getID() ) { $this->spreadBlock(); } @@ -2801,7 +2801,7 @@ class User { */ function isBlockedFromCreateAccount() { $this->getBlockedStatus(); - return $this->mBlock && $this->mBlock->mCreateAccount; + return $this->mBlock && $this->mBlock->prevents( 'createaccount' ); } /** @@ -2810,7 +2810,7 @@ class User { */ function isBlockedFromEmailuser() { $this->getBlockedStatus(); - return $this->mBlock && $this->mBlock->mBlockEmail; + return $this->mBlock && $this->mBlock->prevents( 'sendemail' ); } /** diff --git a/includes/specials/SpecialBlock.php b/includes/specials/SpecialBlock.php index 9f47b440dd..189f64196c 100644 --- a/includes/specials/SpecialBlock.php +++ b/includes/specials/SpecialBlock.php @@ -208,17 +208,17 @@ class SpecialBlock extends SpecialPage { || $block->mAddress == $this->target ) # or if it is, the range is what we're about to block ) { - $fields['HardBlock']['default'] = !$block->mAnonOnly; - $fields['CreateAccount']['default'] = $block->mCreateAccount; + $fields['HardBlock']['default'] = $block->isHardblock(); + $fields['CreateAccount']['default'] = $block->prevents( 'createaccount' ); $fields['AutoBlock']['default'] = $block->mEnableAutoblock; if( isset( $fields['DisableEmail'] ) ){ - $fields['DisableEmail']['default'] = $block->mBlockEmail; + $fields['DisableEmail']['default'] = $block->prevents( 'sendemail' ); } if( isset( $fields['HideUser'] ) ){ $fields['HideUser']['default'] = $block->mHideName; } if( isset( $fields['DisableUTEdit'] ) ){ - $fields['DisableUTEdit']['default'] = !$block->mAllowUsertalk; + $fields['DisableUTEdit']['default'] = $block->prevents( 'editusertalk' ); } $fields['Reason']['default'] = $block->mReason; $fields['AlreadyBlocked']['default'] = true; @@ -502,10 +502,6 @@ class SpecialBlock extends SpecialPage { return array( 'ipb_expiry_invalid' ); } - if( !$wgBlockAllowsUTEdit ){ - $data['DisableUTEdit'] = true; - } - # If the user has done the form 'properly', they won't even have been given the # option to suppress-block unless they have the 'hideuser' permission if( !isset( $data['HideUser'] ) ){ @@ -548,10 +544,11 @@ class SpecialBlock extends SpecialPage { !$data['HardBlock'], # Block anon only $data['CreateAccount'], $data['AutoBlock'], - $data['HideUser'], - $data['DisableEmail'], - !$data['DisableUTEdit'] # *Allow* UTEdit + $data['HideUser'] ); + + $block->prevents( 'editusertalk', ( !$wgBlockAllowsUTEdit || $data['DisableUTEdit'] ) ); + $block->prevents( 'sendemail', $data['DisableEmail'] ); if( !wfRunHooks( 'BlockIp', array( &$block, &$wgUser ) ) ) { return array( 'hookaborted' ); @@ -569,7 +566,7 @@ class SpecialBlock extends SpecialPage { # This returns direct blocks before autoblocks/rangeblocks, since we should # be sure the user is blocked by now it should work for our purposes - $currentBlock = Block::newFromDB( $target, $userId ); + $currentBlock = Block::newFromTargetAndType( $target, $type ); if( $block->equals( $currentBlock ) ) { return array( 'ipb_already_blocked' ); @@ -613,7 +610,7 @@ class SpecialBlock extends SpecialPage { } # Block constructor sanitizes certain block options on insert - $data['BlockEmail'] = $block->mBlockEmail; + $data['BlockEmail'] = $block->prevents( 'sendemail' ); $data['AutoBlock'] = $block->mEnableAutoblock; # Prepare log parameters diff --git a/includes/specials/SpecialBlockList.php b/includes/specials/SpecialBlockList.php index 281d7e1f5c..8b856638ce 100644 --- a/includes/specials/SpecialBlockList.php +++ b/includes/specials/SpecialBlockList.php @@ -90,26 +90,6 @@ class SpecialBlockList extends SpecialPage { $this->showList(); } - /** - * Get the component of an IP address which is certain to be the same between an IP - * address and a rangeblock containing that IP address. - * @todo: should be in IP.php?? - * @param $ip String - * @return String - */ - protected static function getIpFragment( $ip ){ - global $wgBlockCIDRLimit; - if( IP::isIPv4( $ip ) ){ - $hexAddress = IP::toHex( $ip ); - return substr( $hexAddress, 0, wfBaseconvert( $wgBlockCIDRLimit['IPv4'], 10, 16 ) ); - } elseif( IP::isIPv6( $ip ) ) { - $hexAddress = substr( IP::toHex( $ip ), 2 ); - return 'v6-' . substr( $hexAddress, 0, wfBaseconvert( $wgBlockCIDRLimit['IPv6'], 10, 16 ) ); - } else { - return null; - } - } - function showList() { global $wgOut, $wgUser; @@ -133,25 +113,16 @@ class SpecialBlockList extends SpecialPage { break; case Block::TYPE_IP: - case BLock::TYPE_RANGE: + case Block::TYPE_RANGE: list( $start, $end ) = IP::parseRange( $target ); - # Per bug 14634, we want to include relevant active rangeblocks; for - # rangeblocks, we want to include larger ranges which enclose the given - # range. We know that all blocks must be smaller than $wgBlockCIDRLimit, - # so we can improve performance by filtering on a LIKE clause - $chunk = self::getIpFragment( $start ); $dbr = wfGetDB( DB_SLAVE ); - $like = $dbr->buildLike( $chunk, $dbr->anyString() ); - - # Fairly hard to make a malicious SQL statement out of hex characters, - # but stranger things have happened... - $safeStart = $dbr->addQuotes( IP::toHex( $start ) ); - $safeEnd = $dbr->addQuotes( IP::toHex( $end ) ); - $safeTarget = $dbr->addQuotes( IP::toHex( $target ) ); - - # TODO: abstract this away - $conds[] = "(ipb_address = $safeTarget) OR - (ipb_range_start $like AND ipb_range_start <= $safeStart AND ipb_range_end >= $safeEnd)"; + $conds[] = $dbr->makeList( + array( + 'ipb_address' => $target, + Block::getRangeCond( $start, $end ) + ), + LIST_OR + ); $conds['ipb_auto'] = 0; break;