r48010 MediaWiki - Code Review archive

Repository:MediaWiki
Revision:r48009‎ | r48010 | r48011 >
Date:05:01, 4 March 2009
Author:werdna
Status:ok
Tags:
Comment:
svn add
Modified paths:
  • /trunk/extensions/GlobalBlocking/GlobalBlocking.class.php (added) (history)

Diff [purge]

Index: trunk/extensions/GlobalBlocking/GlobalBlocking.class.php
@@ -0,0 +1,265 @@
 2+<?php
 3+
 4+class GlobalBlocking {
 5+ static function getUserPermissionsErrors( &$title, &$user, $action, &$result ) {
 6+ global $wgApplyGlobalBlocks;
 7+ if ($action == 'read' || !$wgApplyGlobalBlocks) {
 8+ return true;
 9+ }
 10+ $ip = wfGetIp();
 11+ $blockError = self::getUserBlockErrors( $user, $ip );
 12+ if( !empty($blockError) ) {
 13+ $result[] = $blockError;
 14+ return false;
 15+ }
 16+ return true;
 17+ }
 18+
 19+ static function isBlockedGlobally( &$user, $ip, &$blocked ) {
 20+ $blockError = self::getUserBlockErrors( $user, $ip );
 21+ if( $blockError ) {
 22+ $blocked = true;
 23+ return false;
 24+ }
 25+ return true;
 26+ }
 27+
 28+ static function getUserBlockErrors( $user, $ip ) {
 29+ $dbr = GlobalBlocking::getGlobalBlockingSlave();
 30+
 31+ $hex_ip = IP::toHex( $ip );
 32+ $ip_pattern = substr( $hex_ip, 0, 4 ) . '%'; // Don't bother checking blocks out of this /16.
 33+
 34+ $conds = array(
 35+ 'gb_range_end>='.$dbr->addQuotes($hex_ip), // This block in the given range.
 36+ 'gb_range_start<='.$dbr->addQuotes($hex_ip),
 37+ 'gb_range_start like ' . $dbr->addQuotes( $ip_pattern ),
 38+ 'gb_expiry>'.$dbr->addQuotes($dbr->timestamp(wfTimestampNow()))
 39+ );
 40+
 41+ if ( !$user->isAnon() )
 42+ $conds['gb_anon_only'] = 0;
 43+
 44+ // Get the block
 45+ if ($block = $dbr->selectRow( 'globalblocks', '*', $conds, __METHOD__ )) {
 46+
 47+ // Check for local whitelisting
 48+ if (GlobalBlocking::getWhitelistInfo( $block->gb_id ) ) {
 49+ // Block has been whitelisted.
 50+ return array();
 51+ }
 52+
 53+ if ( $user->isAllowed( 'ipblock-exempt' ) ) {
 54+ // User is exempt from IP blocks.
 55+ return array();
 56+ }
 57+
 58+ $expiry = Block::formatExpiry( $block->gb_expiry );
 59+
 60+ wfLoadExtensionMessages( 'GlobalBlocking' );
 61+
 62+ $display_wiki = self::getWikiName( $block->gb_by_wiki );
 63+ $user_display = self::maybeLinkUserpage( $block->gb_by_wiki, $block->gb_by );
 64+
 65+ return array('globalblocking-blocked', $user_display, $display_wiki, $block->gb_reason, $expiry);
 66+ }
 67+ return array();
 68+ }
 69+
 70+ static function getGlobalBlockingMaster() {
 71+ global $wgGlobalBlockingDatabase;
 72+ return wfGetDB( DB_MASTER, 'globalblocking', $wgGlobalBlockingDatabase );
 73+ }
 74+
 75+ static function getGlobalBlockingSlave() {
 76+ global $wgGlobalBlockingDatabase;
 77+ return wfGetDB( DB_SLAVE, 'globalblocking', $wgGlobalBlockingDatabase );
 78+ }
 79+
 80+ static function getGlobalBlockId( $ip ) {
 81+ $dbr = GlobalBlocking::getGlobalBlockingSlave();
 82+
 83+ if (!($row = $dbr->selectRow( 'globalblocks', 'gb_id', array( 'gb_address' => $ip ), __METHOD__ )))
 84+ return 0;
 85+
 86+ return $row->gb_id;
 87+ }
 88+
 89+ static function purgeExpired() {
 90+ // This is expensive. It involves opening a connection to a new master,
 91+ // and doing a write query. We should only do it when a connection to the master
 92+ // is already open (currently, when a global block is made).
 93+ $dbw = GlobalBlocking::getGlobalBlockingMaster();
 94+
 95+ // Stand-alone transaction.
 96+ $dbw->begin();
 97+ $dbw->delete( 'globalblocks', array('gb_expiry<'.$dbw->addQuotes($dbw->timestamp())), __METHOD__ );
 98+ $dbw->commit();
 99+
 100+ // Purge the global_block_whitelist table.
 101+ // We can't be perfect about this without an expensive check on the master
 102+ // for every single global block. However, we can be clever about it and store
 103+ // the expiry of global blocks in the global_block_whitelist table.
 104+ // That way, most blocks will fall out of the table naturally when they expire.
 105+ $dbw = wfGetDB( DB_MASTER );
 106+ $dbw->begin();
 107+ $dbw->delete( 'global_block_whitelist', array( 'gbw_expiry<'.$dbw->addQuotes($dbw->timestamp())), __METHOD__ );
 108+ $dbw->commit();
 109+ }
 110+
 111+ static function getWhitelistInfo( $id = null, $address = null ) {
 112+ $conds = array();
 113+ if ($id != null) {
 114+ $conds = array( 'gbw_id' => $id );
 115+ } elseif ($address != null) {
 116+ $conds = array( 'gbw_address' => $address );
 117+ } else {
 118+ //WTF?
 119+ throw new MWException( "Neither Block IP nor Block ID given for retrieving whitelist status" );
 120+ }
 121+
 122+ $dbr = wfGetDB( DB_SLAVE );
 123+ $row = $dbr->selectRow( 'global_block_whitelist', array( 'gbw_by', 'gbw_reason' ), $conds, __METHOD__ );
 124+
 125+ if ($row == false) {
 126+ // Not whitelisted.
 127+ return false;
 128+ } else {
 129+ // Block has been whitelisted
 130+ return array( 'user' => $row->gbw_by, 'reason' => $row->gbw_reason );
 131+ }
 132+ }
 133+
 134+ static function getWhitelistInfoByIP( $block_ip ) {
 135+ return self::getWhitelistInfo( null, $block_ip );
 136+ }
 137+
 138+ static function getWikiName( $wiki_id ) {
 139+ if (class_exists('WikiMap')) {
 140+ // We can give more info than just the wiki id!
 141+ $wiki = WikiMap::getWiki( $wiki_id );
 142+
 143+ if ($wiki) {
 144+ return $wiki->getDisplayName();
 145+ }
 146+ }
 147+
 148+ return $wiki_id;
 149+ }
 150+
 151+ static function maybeLinkUserpage( $wiki_id, $user ) {
 152+ if (class_exists( 'WikiMap')) {
 153+ $wiki = WikiMap::getWiki( $wiki_id );
 154+
 155+ if ($wiki) {
 156+ return "[".$wiki->getUrl( "User:$user" )." $user]";
 157+ }
 158+ }
 159+ return $user;
 160+ }
 161+
 162+ static function insertBlock( $address, $reason, $expiry, $options = array() ) {
 163+ global $wgUser;
 164+ $errors = array();
 165+
 166+ ## Purge expired blocks.
 167+ GlobalBlocking::purgeExpired();
 168+
 169+ ## Validate input
 170+ $ip = IP::sanitizeIP( $address );
 171+
 172+ $anonOnly = in_array( 'anon-only', $options );
 173+ $modify = in_array( 'modify', $options );
 174+
 175+ if (!IP::isIPAddress($ip)) {
 176+ // Invalid IP address.
 177+ $errors[] = array( 'globalblocking-block-ipinvalid', $ip );
 178+ }
 179+
 180+ if ( false === $expiry ) {
 181+ $errors[] = array( 'globalblocking-block-expiryinvalid', $expiry );
 182+ }
 183+
 184+ $existingBlock = GlobalBlocking::getGlobalBlockId($ip);
 185+ if ( !$modify && $existingBlock ) {
 186+ $errors[] = array( 'globalblocking-block-alreadyblocked', $ip );
 187+ }
 188+
 189+ // Check for too-big ranges.
 190+ list( $range_start, $range_end ) = IP::parseRange( $ip );
 191+
 192+ if (substr( $range_start, 0, 4 ) != substr( $range_end, 0, 4 )) {
 193+ // Range crosses a /16 boundary.
 194+ $errors[] = array( 'globalblocking-block-bigrange', $ip );
 195+ }
 196+
 197+ // Normalise the range
 198+ if ($range_start != $range_end) {
 199+ $ip = Block::normaliseRange( $ip );
 200+ }
 201+
 202+ if (count($errors)>0)
 203+ return $errors;
 204+
 205+ // We're a-ok.
 206+ $dbw = GlobalBlocking::getGlobalBlockingMaster();
 207+
 208+ // Delete the old block, if applicable
 209+
 210+ if ($modify) {
 211+ $dbw->delete( 'globalblocks', array( 'gb_id' => $existingBlock ), __METHOD__ );
 212+ }
 213+
 214+ $row = array();
 215+ $row['gb_address'] = $ip;
 216+ $row['gb_by'] = $wgUser->getName();
 217+ $row['gb_by_wiki'] = wfWikiId();
 218+ $row['gb_reason'] = $reason;
 219+ $row['gb_timestamp'] = $dbw->timestamp(wfTimestampNow());
 220+ $row['gb_anon_only'] = $anonOnly;
 221+ $row['gb_expiry'] = Block::encodeExpiry($expiry, $dbw);
 222+ list( $row['gb_range_start'], $row['gb_range_end'] ) = array( $range_start, $range_end );
 223+
 224+ $dbw->insert( 'globalblocks', $row, __METHOD__ );
 225+
 226+ return array();
 227+ }
 228+
 229+ static function block( $address, $reason, $expiry, $options = array() ) {
 230+ global $wgContLang;
 231+
 232+ $expiry = Block::parseExpiryInput( $expiry );
 233+ $errors = self::insertBlock( $address, $reason, $expiry, $options );
 234+
 235+ if ( count($errors) > 0 )
 236+ return $errors;
 237+
 238+ $anonOnly = in_array( 'anon-only', $options );
 239+ $modify = in_array( 'modify', $options );
 240+
 241+ // Log it.
 242+ $logAction = $modify ? 'modify' : 'gblock2';
 243+ $flags = array();
 244+
 245+ if ($anonOnly)
 246+ $flags[] = wfMsgForContent( 'globalblocking-list-anononly' );
 247+
 248+ if ( $expiry != 'infinity' ) {
 249+ $displayExpiry = $wgContLang->timeanddate( $expiry );
 250+ $flags[] = wfMsgForContent( 'globalblocking-logentry-expiry', $displayExpiry );
 251+ } else {
 252+ $flags[] = wfMsgForContent( 'globalblocking-logentry-noexpiry' );
 253+ }
 254+
 255+ $info = implode( ', ', $flags );
 256+
 257+ $page = new LogPage( 'gblblock' );
 258+ $page->addEntry( $logAction,
 259+ Title::makeTitleSafe( NS_USER, $address ),
 260+ $reason,
 261+ array($info, $address)
 262+ );
 263+
 264+ return array();
 265+ }
 266+}
\ No newline at end of file

Status & tagging log