*/
function wfSpecialBlockip( $par ) {
global $wgUser, $wgOut, $wgRequest;
-
# Can't block when the database is locked
if( wfReadOnly() ) {
$wgOut->readOnlyPage();
return;
}
-
# Permission check
if( !$wgUser->isAllowed( 'block' ) ) {
$wgOut->permissionRequired( 'block' );
$ipb = new IPBlockForm( $par );
$action = $wgRequest->getVal( 'action' );
- if ( 'success' == $action ) {
+ if( 'success' == $action ) {
$ipb->showSuccess();
- } else if ( $wgRequest->wasPosted() && 'submit' == $action &&
+ } else if( $wgRequest->wasPosted() && 'submit' == $action &&
$wgUser->matchEditToken( $wgRequest->getVal( 'wpEditToken' ) ) ) {
$ipb->doSubmit();
} else {
*/
class IPBlockForm {
var $BlockAddress, $BlockExpiry, $BlockReason;
-# var $BlockEmail;
+ // The maximum number of edits a user can have and still be hidden
+ const HIDEUSER_CONTRIBLIMIT = 1000;
- function IPBlockForm( $par ) {
+ public function __construct( $par ) {
global $wgRequest, $wgUser, $wgBlockAllowsUTEdit;
$this->BlockAddress = $wgRequest->getVal( 'wpBlockAddress', $wgRequest->getVal( 'ip', $par ) );
$this->BlockAnonOnly = $wgRequest->getBool( 'wpAnonOnly', $byDefault );
$this->BlockCreateAccount = $wgRequest->getBool( 'wpCreateAccount', $byDefault );
$this->BlockEnableAutoblock = $wgRequest->getBool( 'wpEnableAutoblock', $byDefault );
- $this->BlockEmail = $wgRequest->getBool( 'wpEmailBan', false );
+ $this->BlockEmail = false;
+ if( self::canBlockEmail( $wgUser ) ) {
+ $this->BlockEmail = $wgRequest->getBool( 'wpEmailBan', false );
+ }
$this->BlockWatchUser = $wgRequest->getBool( 'wpWatchUser', false );
# Re-check user's rights to hide names, very serious, defaults to 0
$this->BlockHideName = ( $wgRequest->getBool( 'wpHideName', 0 ) && $wgUser->isAllowed( 'hideuser' ) ) ? 1 : 0;
$this->BlockReblock = $wgRequest->getBool( 'wpChangeBlock', false );
}
- function showForm( $err ) {
+ public function showForm( $err ) {
global $wgOut, $wgUser, $wgSysopUserBans;
$wgOut->setPagetitle( wfMsg( 'blockip' ) );
$user = User::newFromName( $this->BlockAddress );
$alreadyBlocked = false;
- if ( $err && $err[0] != 'ipb_already_blocked' ) {
+ if( $err && $err[0] != 'ipb_already_blocked' ) {
$key = array_shift($err);
$msg = wfMsgReal($key, $err);
$wgOut->setSubtitle( wfMsgHtml( 'formerror' ) );
$wgOut->addHTML( Xml::tags( 'p', array( 'class' => 'error' ), $msg ) );
- } elseif ( $this->BlockAddress ) {
+ } elseif( $this->BlockAddress ) {
$userId = 0;
- if ( is_object( $user ) )
+ if( is_object( $user ) )
$userId = $user->getId();
$currentBlock = Block::newFromDB( $this->BlockAddress, $userId );
- if ( !is_null($currentBlock) && !$currentBlock->mAuto && # The block exists and isn't an autoblock
+ if( !is_null($currentBlock) && !$currentBlock->mAuto && # The block exists and isn't an autoblock
( $currentBlock->mRangeStart == $currentBlock->mRangeEnd || # The block isn't a rangeblock
# or if it is, the range is what we're about to block
( $currentBlock->mAddress == $this->BlockAddress ) ) ) {
$wgOut->addWikiMsg( 'ipb-needreblock', $this->BlockAddress );
$alreadyBlocked = true;
+ # Set the block form settings to the existing block
+ $this->BlockAnonOnly = $currentBlock->mAnonOnly;
+ $this->BlockCreateAccount = $currentBlock->mCreateAccount;
+ $this->BlockEnableAutoblock = $currentBlock->mEnableAutoblock;
+ $this->BlockEmail = $currentBlock->mBlockEmail;
+ $this->BlockHideName = $currentBlock->mHideName;
+ $this->BlockAllowUsertalk = $currentBlock->mAllowUsertalk;
+ if( $currentBlock->mExpiry == 'infinity' ) {
+ $this->BlockOther = 'indefinite';
+ } else {
+ $this->BlockOther = wfTimestamp( TS_ISO_8601, $currentBlock->mExpiry );
+ }
+ $this->BlockReason = $currentBlock->mReason;
}
}
$scBlockExpiryOptions = wfMsgForContent( 'ipboptions' );
$showblockoptions = $scBlockExpiryOptions != '-';
- if (!$showblockoptions)
- $mIpbother = $mIpbexpiry;
+ if( !$showblockoptions ) $mIpbother = $mIpbexpiry;
$blockExpiryFormOptions = Xml::option( wfMsg( 'ipbotheroption' ), 'other' );
foreach (explode(',', $scBlockExpiryOptions) as $option) {
- if ( strpos($option, ":") === false ) $option = "$option:$option";
+ if( strpos($option, ":") === false ) $option = "$option:$option";
list($show, $value) = explode(":", $option);
$show = htmlspecialchars($show);
$value = htmlspecialchars($value);
</tr>
<tr>"
);
- if ( $showblockoptions ) {
+ if( $showblockoptions ) {
$wgOut->addHTML("
<td class='mw-label'>
{$mIpbexpiry}
</tr>"
);
- global $wgSysopEmailBans, $wgBlockAllowsUTEdit;
- if ( $wgSysopEmailBans && $wgUser->isAllowed( 'blockemail' ) ) {
+ if( self::canBlockEmail( $wgUser ) ) {
$wgOut->addHTML("
<tr id='wpEnableEmailBan'>
<td> </td>
}
// Allow some users to hide name from block log, blocklist and listusers
- if ( $wgUser->isAllowed( 'hideuser' ) ) {
+ if( $wgUser->isAllowed( 'hideuser' ) ) {
$wgOut->addHTML("
<tr id='wpEnableHideUser'>
<td> </td>
- <td class='mw-input'>" .
+ <td class='mw-input'><strong>" .
Xml::checkLabel( wfMsg( 'ipbhidename' ),
'wpHideName', 'wpHideName', $this->BlockHideName,
array( 'tabindex' => '10' ) ) . "
- </td>
+ </strong></td>
</tr>"
);
}
</td>
</tr>"
);
+
+ # Can we explicitly disallow the use of user_talk?
+ global $wgBlockAllowsUTEdit;
if( $wgBlockAllowsUTEdit ){
$wgOut->addHTML("
<tr id='wpAllowUsertalkRow'>
$this->showLogFragment( $wgOut, Title::makeTitle( NS_USER, $this->BlockAddress ) );
}
}
+
+ /**
+ * Can we do an email block?
+ * @param User $user The sysop wanting to make a block
+ * @return boolean
+ */
+ public static function canBlockEmail( $user ) {
+ global $wgEnableUserEmail, $wgSysopEmailBans;
+ return ($wgEnableUserEmail && $wgSysopEmailBans && $user->isAllowed( 'blockemail' ));
+ }
/**
* Backend block code.
$rxIP = "($rxIP4|$rxIP6)";
# Check for invalid specifications
- if ( !preg_match( "/^$rxIP$/", $this->BlockAddress ) ) {
+ if( !preg_match( "/^$rxIP$/", $this->BlockAddress ) ) {
$matches = array();
- if ( preg_match( "/^($rxIP4)\\/(\\d{1,2})$/", $this->BlockAddress, $matches ) ) {
+ if( preg_match( "/^($rxIP4)\\/(\\d{1,2})$/", $this->BlockAddress, $matches ) ) {
# IPv4
- if ( $wgSysopRangeBans ) {
- if ( !IP::isIPv4( $this->BlockAddress ) || $matches[2] < 16 || $matches[2] > 32 ) {
+ if( $wgSysopRangeBans ) {
+ if( !IP::isIPv4( $this->BlockAddress ) || $matches[2] < 16 || $matches[2] > 32 ) {
return array('ip_range_invalid');
}
$this->BlockAddress = Block::normaliseRange( $this->BlockAddress );
# Range block illegal
return array('range_block_disabled');
}
- } else if ( preg_match( "/^($rxIP6)\\/(\\d{1,3})$/", $this->BlockAddress, $matches ) ) {
+ } else if( preg_match( "/^($rxIP6)\\/(\\d{1,3})$/", $this->BlockAddress, $matches ) ) {
# IPv6
- if ( $wgSysopRangeBans ) {
- if ( !IP::isIPv6( $this->BlockAddress ) || $matches[2] < 64 || $matches[2] > 128 ) {
+ if( $wgSysopRangeBans ) {
+ if( !IP::isIPv6( $this->BlockAddress ) || $matches[2] < 64 || $matches[2] > 128 ) {
return array('ip_range_invalid');
}
$this->BlockAddress = Block::normaliseRange( $this->BlockAddress );
}
} else {
# Username block
- if ( $wgSysopUserBans ) {
+ if( $wgSysopUserBans ) {
$user = User::newFromName( $this->BlockAddress );
if( !is_null( $user ) && $user->getId() ) {
# Use canonical name
}
}
- if ( $wgUser->isBlocked() && ( $wgUser->getId() !== $userId ) ) {
+ if( $wgUser->isBlocked() && ( $wgUser->getId() !== $userId ) ) {
return array( 'cant-block-while-blocked' );
}
$reasonstr = $this->BlockReasonList;
- if ( $reasonstr != 'other' && $this->BlockReason != '' ) {
+ if( $reasonstr != 'other' && $this->BlockReason != '' ) {
// Entry from drop down menu + additional comment
$reasonstr .= wfMsgForContent( 'colon-separator' ) . $this->BlockReason;
- } elseif ( $reasonstr == 'other' ) {
+ } elseif( $reasonstr == 'other' ) {
$reasonstr = $this->BlockReason;
}
if( $expirestr == 'other' )
$expirestr = $this->BlockOther;
- if ( ( strlen( $expirestr ) == 0) || ( strlen( $expirestr ) > 50) ) {
+ if( ( strlen( $expirestr ) == 0) || ( strlen( $expirestr ) > 50) ) {
return array('ipb_expiry_invalid');
}
- if ( false === ($expiry = Block::parseExpiryInput( $expirestr )) ) {
+ if( false === ($expiry = Block::parseExpiryInput( $expirestr )) ) {
// Bad expiry.
return array('ipb_expiry_invalid');
}
- if( $this->BlockHideName && $expiry != 'infinity' ) {
- // Bad expiry.
- return array('ipb_expiry_temp');
+ if( $this->BlockHideName ) {
+ // Recheck params here...
+ if( !$userId || !$wgUser->isAllowed('hideuser') ) {
+ $this->BlockHideName = false; // IP users should not be hidden
+ } else if( $expiry !== 'infinity' ) {
+ // Bad expiry.
+ return array('ipb_expiry_temp');
+ } else if( User::edits($userId) > self::HIDEUSER_CONTRIBLIMIT ) {
+ // Typically, the user should have a handful of edits.
+ // Disallow hiding users with many edits for performance.
+ return array('ipb_hide_invalid');
+ }
}
- # Create block
+ # Create block object
# Note: for a user block, ipb_address is only for display purposes
$block = new Block( $this->BlockAddress, $userId, $wgUser->getId(),
$reasonstr, wfTimestampNow(), 0, $expiry, $this->BlockAnonOnly,
$this->BlockCreateAccount, $this->BlockEnableAutoblock, $this->BlockHideName,
- $this->BlockEmail, isset( $this->BlockAllowUsertalk ) ? $this->BlockAllowUsertalk : $wgBlockAllowsUTEdit );
-
- if ( wfRunHooks('BlockIp', array(&$block, &$wgUser)) ) {
+ $this->BlockEmail, isset( $this->BlockAllowUsertalk ) ? $this->BlockAllowUsertalk : $wgBlockAllowsUTEdit
+ );
- if ( !$block->insert() ) {
- if ( !$this->BlockReblock ) {
+ # Should this be privately logged?
+ $suppressLog = (bool)$this->BlockHideName;
+ if( wfRunHooks('BlockIp', array(&$block, &$wgUser)) ) {
+ # Try to insert block. Is there a conflicting block?
+ if( !$block->insert() ) {
+ # Show form unless the user is already aware of this...
+ if( !$this->BlockReblock ) {
return array( 'ipb_already_blocked' );
+ # Otherwise, try to update the block...
} else {
# This returns direct blocks before autoblocks/rangeblocks, since we should
# be sure the user is blocked by now it should work for our purposes
if( $block->equals( $currentBlock ) ) {
return array( 'ipb_already_blocked' );
}
+ # If the name was hidden and the blocking user cannot hide
+ # names, then don't allow any block changes...
+ if( $currentBlock->mHideName && !$wgUser->isAllowed('hideuser') ) {
+ return array( 'hookaborted' );
+ }
$currentBlock->delete();
$block->insert();
+ # If hiding/unhiding a name, this should go in the private logs
+ $suppressLog = $suppressLog || (bool)$currentBlock->mHideName;
$log_action = 'reblock';
+ # Unset _deleted fields if requested
+ if( $currentBlock->mHideName && !$this->BlockHideName ) {
+ self::unsuppressUserName( $this->BlockAddress, $userId );
+ }
}
} else {
$log_action = 'block';
}
wfRunHooks('BlockIpComplete', array($block, $wgUser));
- if ( $this->BlockWatchUser ) {
- $wgUser->addWatch ( Title::makeTitle( NS_USER, $this->BlockAddress ) );
+ # Set *_deleted fields if requested
+ if( $this->BlockHideName ) {
+ self::suppressUserName( $this->BlockAddress, $userId );
}
+ # Only show watch link when this is no range block
+ if( $this->BlockWatchUser && $block->mRangeStart == $block->mRangeEnd ) {
+ $wgUser->addWatch( Title::makeTitle( NS_USER, $this->BlockAddress ) );
+ }
+
+ # Block constructor sanitizes certain block options on insert
+ $this->BlockEmail = $block->mBlockEmail;
+ $this->BlockEnableAutoblock = $block->mEnableAutoblock;
+
# Prepare log parameters
$logParams = array();
$logParams[] = $expirestr;
$logParams[] = $this->blockLogFlags();
# Make log entry, if the name is hidden, put it in the oversight log
- $log_type = ($this->BlockHideName) ? 'suppress' : 'block';
+ $log_type = $suppressLog ? 'suppress' : 'block';
$log = new LogPage( $log_type );
$log->addEntry( $log_action, Title::makeTitle( NS_USER, $this->BlockAddress ),
- $reasonstr, $logParams );
+ $reasonstr, $logParams );
# Report to the user
return array();
- }
- else
+ } else {
return array('hookaborted');
+ }
+ }
+
+ public static function suppressUserName( $name, $userId ) {
+ $op = '|'; // bitwise OR
+ return self::setUsernameBitfields( $name, $userId, $op );
+ }
+
+ public static function unsuppressUserName( $name, $userId ) {
+ $op = '&'; // bitwise AND
+ return self::setUsernameBitfields( $name, $userId, $op );
+ }
+
+ private static function setUsernameBitfields( $name, $userId, $op ) {
+ if( $op !== '|' && $op !== '&' ) return false; // sanity check
+ $dbw = wfGetDB( DB_MASTER );
+ $delUser = Revision::DELETED_USER | Revision::DELETED_RESTRICTED;
+ $delAction = LogPage::DELETED_ACTION | Revision::DELETED_RESTRICTED;
+ # Normalize user name
+ $userTitle = Title::makeTitleSafe( NS_USER, $name );
+ $userDbKey = $userTitle->getDBkey();
+ # To suppress, we OR the current bitfields with Revision::DELETED_USER
+ # to put a 1 in the username *_deleted bit. To unsuppress we AND the
+ # current bitfields with the inverse of Revision::DELETED_USER. The
+ # username bit is made to 0 (x & 0 = 0), while others are unchanged (x & 1 = x).
+ # The same goes for the sysop-restricted *_deleted bit.
+ if( $op == '&' ) {
+ $delUser = "~{$delUser}";
+ $delAction = "~{$delAction}";
+ }
+ # Hide name from live edits
+ $dbw->update( 'revision', array("rev_deleted = rev_deleted $op $delUser"),
+ array('rev_user' => $userId), __METHOD__ );
+ # Hide name from deleted edits
+ $dbw->update( 'archive', array("ar_deleted = ar_deleted $op $delUser"),
+ array('ar_user_text' => $name), __METHOD__ );
+ # Hide name from logs
+ $dbw->update( 'logging', array("log_deleted = log_deleted $op $delUser"),
+ array('log_user' => $userId, "log_type != 'suppress'"), __METHOD__ );
+ $dbw->update( 'logging', array("log_deleted = log_deleted $op $delAction"),
+ array('log_namespace' => NS_USER, 'log_title' => $userDbKey,
+ "log_type != 'suppress'"), __METHOD__ );
+ # Hide name from RC
+ $dbw->update( 'recentchanges', array("rc_deleted = rc_deleted $op $delUser"),
+ array('rc_user_text' => $name), __METHOD__ );
+ $dbw->update( 'recentchanges', array("rc_deleted = rc_deleted $op $delAction"),
+ array('rc_namespace' => NS_USER, 'rc_title' => $userDbKey, 'rc_logid > 0'), __METHOD__ );
+ # Hide name from live images
+ $dbw->update( 'oldimage', array("oi_deleted = oi_deleted $op $delUser"),
+ array('oi_user_text' => $name), __METHOD__ );
+ # Hide name from deleted images
+ # WMF - schema change pending
+ # $dbw->update( 'filearchive', array("fa_deleted = fa_deleted $op $delUser"),
+ # array('fa_user_text' => $name), __METHOD__ );
+ # Done!
+ return true;
}
/**
* UI entry point for blocking
* Wraps around doBlock()
*/
- function doSubmit()
- {
+ public function doSubmit() {
global $wgOut;
$retval = $this->doBlock();
- if(empty($retval)) {
+ if( empty($retval) ) {
$titleObj = SpecialPage::getTitleFor( 'Blockip' );
$wgOut->redirect( $titleObj->getFullURL( 'action=success&ip=' .
urlencode( $this->BlockAddress ) ) );
$this->showForm( $retval );
}
- function showSuccess() {
+ public function showSuccess() {
global $wgOut;
$wgOut->setPagetitle( wfMsg( 'blockip' ) );
$wgOut->addHTML( $text );
}
- function showLogFragment( $out, $title ) {
+ private function showLogFragment( $out, $title ) {
global $wgUser;
$out->addHTML( Xml::element( 'h2', NULL, LogPage::logName( 'block' ) ) );
$count = LogEventsList::showLogExtract( $out, 'block', $title->getPrefixedText(), '', 10 );
- if($count > 10){
+ if( $count > 10 ) {
$out->addHTML( $wgUser->getSkin()->link(
SpecialPage::getTitleFor( 'Log' ),
wfMsgHtml( 'blocklog-fulllog' ),
'type' => 'block',
'page' => $title->getPrefixedText() ) ) );
}
+ // Add suppression block entries if allowed
+ if( $wgUser->isAllowed('hideuser') ) {
+ $out->addHTML( Xml::element( 'h2', NULL, LogPage::logName( 'suppress' ) ) );
+ LogEventsList::showLogExtract( $out, 'suppress', $title->getPrefixedText(), '',
+ 10, array('log_action' => array('block','reblock','unblock')) );
+ }
}
/**
global $wgBlockAllowsUTEdit;
$flags = array();
if( $this->BlockAnonOnly && IP::isIPAddress( $this->BlockAddress ) )
- // when blocking a user the option 'anononly' is not available/has no effect -> do not write this into log
+ // when blocking a user the option 'anononly' is not available/has no effect -> do not write this into log
$flags[] = 'anononly';
if( $this->BlockCreateAccount )
$flags[] = 'nocreate';
- if( !$this->BlockEnableAutoblock )
+ if( !$this->BlockEnableAutoblock && !IP::isIPAddress( $this->BlockAddress ) )
+ // Same as anononly, this is not displayed when blocking an IP address
$flags[] = 'noautoblock';
- if ( $this->BlockEmail )
+ if( $this->BlockEmail )
$flags[] = 'noemail';
- if ( !$this->BlockAllowUsertalk && $wgBlockAllowsUTEdit )
+ if( !$this->BlockAllowUsertalk && $wgBlockAllowsUTEdit )
$flags[] = 'nousertalk';
+ if( $this->BlockHideName )
+ $flags[] = 'hiddenname';
return implode( ',', $flags );
}
* @return string
*/
private function getConvenienceLinks() {
- global $wgUser;
+ global $wgUser, $wgLang;
$skin = $wgUser->getSkin();
if( $this->BlockAddress )
$links[] = $this->getContribsLink( $skin );
$links[] = $this->getUnblockLink( $skin );
$links[] = $this->getBlockListLink( $skin );
- $links[] = $skin->makeLink ( 'MediaWiki:Ipbreason-dropdown', wfMsgHtml( 'ipb-edit-dropdown' ) );
- return '<p class="mw-ipb-conveniencelinks">' . implode( ' | ', $links ) . '</p>';
+ $title = Title::makeTitle( NS_MEDIAWIKI, 'Ipbreason-dropdown' );
+ $links[] = $skin->link(
+ $title,
+ wfMsgHtml( 'ipb-edit-dropdown' ),
+ array(),
+ array( 'action' => 'edit' )
+ );
+ return '<p class="mw-ipb-conveniencelinks">' . $wgLang->pipeList( $links ) . '</p>';
}
/**
*/
private function getUnblockLink( $skin ) {
$list = SpecialPage::getTitleFor( 'Ipblocklist' );
+ $query = array( 'action' => 'unblock' );
+
if( $this->BlockAddress ) {
$addr = htmlspecialchars( strtr( $this->BlockAddress, '_', ' ' ) );
- return $skin->makeKnownLinkObj( $list, wfMsgHtml( 'ipb-unblock-addr', $addr ),
- 'action=unblock&ip=' . urlencode( $this->BlockAddress ) );
+ $message = wfMsgHtml( 'ipb-unblock-addr', $addr );
+ $query['ip'] = $this->BlockAddress;
} else {
- return $skin->makeKnownLinkObj( $list, wfMsgHtml( 'ipb-unblock' ), 'action=unblock' );
+ $message = wfMsgHtml( 'ipb-unblock' );
}
+ return $skin->linkKnown(
+ $list,
+ $message,
+ array(),
+ $query
+ );
}
/**
*/
private function getBlockListLink( $skin ) {
$list = SpecialPage::getTitleFor( 'Ipblocklist' );
+ $query = array();
+
if( $this->BlockAddress ) {
$addr = htmlspecialchars( strtr( $this->BlockAddress, '_', ' ' ) );
- return $skin->makeKnownLinkObj( $list, wfMsgHtml( 'ipb-blocklist-addr', $addr ),
- 'ip=' . urlencode( $this->BlockAddress ) );
+ $message = wfMsgHtml( 'ipb-blocklist-addr', $addr );
+ $query['ip'] = $this->BlockAddress;
} else {
- return $skin->makeKnownLinkObj( $list, wfMsgHtml( 'ipb-blocklist' ) );
+ $message = wfMsgHtml( 'ipb-blocklist' );
}
+
+ return $skin->linkKnown(
+ $list,
+ $message,
+ array(),
+ $query
+ );
}
/**