/** * Unblocks the specified user or provides the reason the unblock failed. */ public function execute() { $user = $this->getUser(); $params = $this->extractRequestParams(); if (is_null($params['id']) && is_null($params['user'])) { $this->dieUsageMsg('unblock-notarget'); } if (!is_null($params['id']) && !is_null($params['user'])) { $this->dieUsageMsg('unblock-idanduser'); } if (!$user->isAllowed('block')) { $this->dieUsageMsg('cantunblock'); } # bug 15810: blocked admins should have limited access here if ($user->isBlocked()) { $status = SpecialBlock::checkUnblockSelf($params['user'], $user); if ($status !== true) { $this->dieUsageMsg($status); } } $data = array('Target' => is_null($params['id']) ? $params['user'] : "******", 'Reason' => $params['reason']); $block = Block::newFromTarget($data['Target']); $retval = SpecialUnblock::processUnblock($data, $this->getContext()); if ($retval !== true) { $this->dieUsageMsg($retval[0]); } $res['id'] = $block->getId(); $target = $block->getType() == Block::TYPE_AUTO ? '' : $block->getTarget(); $res['user'] = $target instanceof User ? $target->getName() : $target; $res['userid'] = $target instanceof User ? $target->getId() : 0; $res['reason'] = $params['reason']; $this->getResult()->addValue(null, $this->getModuleName(), $res); }
/** * Blocks the user specified in the parameters for the given expiry, with the * given reason, and with all other settings provided in the params. If the block * succeeds, produces a result containing the details of the block and notice * of success. If it fails, the result will specify the nature of the error. */ public function execute() { global $wgContLang; $user = $this->getUser(); $params = $this->extractRequestParams(); if (!$user->isAllowed('block')) { $this->dieUsageMsg('cantblock'); } # bug 15810: blocked admins should have limited access here if ($user->isBlocked()) { $status = SpecialBlock::checkUnblockSelf($params['user'], $user); if ($status !== true) { $msg = $this->parseMsg($status); $this->dieUsage($msg['info'], $msg['code'], 0, ['blockinfo' => ApiQueryUserInfo::getBlockInfo($user->getBlock())]); } } $target = User::newFromName($params['user']); // Bug 38633 - if the target is a user (not an IP address), but it // doesn't exist or is unusable, error. if ($target instanceof User && ($target->isAnon() || !User::isUsableName($target->getName()))) { $this->dieUsageMsg(['nosuchuser', $params['user']]); } if ($params['hidename'] && !$user->isAllowed('hideuser')) { $this->dieUsageMsg('canthide'); } if ($params['noemail'] && !SpecialBlock::canBlockEmail($user)) { $this->dieUsageMsg('cantblock-email'); } $data = ['PreviousTarget' => $params['user'], 'Target' => $params['user'], 'Reason' => [$params['reason'], 'other', $params['reason']], 'Expiry' => $params['expiry'], 'HardBlock' => !$params['anononly'], 'CreateAccount' => $params['nocreate'], 'AutoBlock' => $params['autoblock'], 'DisableEmail' => $params['noemail'], 'HideUser' => $params['hidename'], 'DisableUTEdit' => !$params['allowusertalk'], 'Reblock' => $params['reblock'], 'Watch' => $params['watchuser'], 'Confirm' => true]; $retval = SpecialBlock::processForm($data, $this->getContext()); if ($retval !== true) { // We don't care about multiple errors, just report one of them $this->dieUsageMsg($retval); } list($target, ) = SpecialBlock::getTargetAndType($params['user']); $res['user'] = $params['user']; $res['userID'] = $target instanceof User ? $target->getId() : 0; $block = Block::newFromTarget($target, null, true); if ($block instanceof Block) { $res['expiry'] = $wgContLang->formatExpiry($block->mExpiry, TS_ISO_8601, 'infinite'); $res['id'] = $block->getId(); } else { # should be unreachable $res['expiry'] = ''; $res['id'] = ''; } $res['reason'] = $params['reason']; $res['anononly'] = $params['anononly']; $res['nocreate'] = $params['nocreate']; $res['autoblock'] = $params['autoblock']; $res['noemail'] = $params['noemail']; $res['hidename'] = $params['hidename']; $res['allowusertalk'] = $params['allowusertalk']; $res['watchuser'] = $params['watchuser']; $this->getResult()->addValue(null, $this->getModuleName(), $res); }
/** * This test has probably always been broken and use an invalid token * Bug tracking brokenness is https://phabricator.wikimedia.org/T37646 * * Root cause is https://gerrit.wikimedia.org/r/3434 * Which made the Block/Unblock API to actually verify the token * previously always considered valid (T36212). */ public function testMakeNormalBlock() { $tokens = $this->getTokens(); $user = User::newFromName('UTApiBlockee'); if (!$user->getId()) { $this->markTestIncomplete("The user UTApiBlockee does not exist"); } if (!array_key_exists('blocktoken', $tokens)) { $this->markTestIncomplete("No block token found"); } $this->doApiRequest(array('action' => 'block', 'user' => 'UTApiBlockee', 'reason' => 'Some reason', 'token' => $tokens['blocktoken']), null, false, self::$users['sysop']->getUser()); $block = Block::newFromTarget('UTApiBlockee'); $this->assertTrue(!is_null($block), 'Block is valid'); $this->assertEquals('UTApiBlockee', (string) $block->getTarget()); $this->assertEquals('Some reason', $block->mReason); $this->assertEquals('infinity', $block->mExpiry); }
private function getBlockedUser() { $user = \User::newFromName('UTBlockee'); if ($user->getID() == 0) { $user->addToDatabase(); \TestUser::setPasswordForUser($user, 'UTBlockeePassword'); $user->saveSettings(); } $oldBlock = \Block::newFromTarget('UTBlockee'); if ($oldBlock) { // An old block will prevent our new one from saving. $oldBlock->delete(); } $blockOptions = ['address' => 'UTBlockee', 'user' => $user->getID(), 'reason' => __METHOD__, 'expiry' => time() + 100500, 'createAccount' => true]; $block = new \Block($blockOptions); $block->insert(); return $user; }
/** * This test has probably always been broken and use an invalid token * Bug tracking brokenness is https://bugzilla.wikimedia.org/35646 * * Root cause is https://gerrit.wikimedia.org/r/3434 * Which made the Block/Unblock API to actually verify the token * previously always considered valid (bug 34212). */ function testMakeNormalBlock() { $data = $this->getTokens(); $user = User::newFromName('UTApiBlockee'); if (!$user->getId()) { $this->markTestIncomplete("The user UTApiBlockee does not exist"); } if (!isset($data[0]['query']['pages'])) { $this->markTestIncomplete("No block token found"); } $keys = array_keys($data[0]['query']['pages']); $key = array_pop($keys); $pageinfo = $data[0]['query']['pages'][$key]; $this->doApiRequest(array('action' => 'block', 'user' => 'UTApiBlockee', 'reason' => 'Some reason', 'token' => $pageinfo['blocktoken']), null, false, self::$users['sysop']->user); $block = Block::newFromTarget('UTApiBlockee'); $this->assertTrue(!is_null($block), 'Block is valid'); $this->assertEquals('UTApiBlockee', (string) $block->getTarget()); $this->assertEquals('Some reason', $block->mReason); $this->assertEquals('infinity', $block->mExpiry); }
/** * Unblocks the specified user or provides the reason the unblock failed. */ public function execute() { $user = $this->getUser(); $params = $this->extractRequestParams(); if (is_null($params['id']) && is_null($params['user'])) { $this->dieUsageMsg('unblock-notarget'); } if (!is_null($params['id']) && !is_null($params['user'])) { $this->dieUsageMsg('unblock-idanduser'); } if (!$user->isAllowed('block')) { $this->dieUsageMsg('cantunblock'); } # bug 15810: blocked admins should have limited access here if ($user->isBlocked()) { $status = SpecialBlock::checkUnblockSelf($params['user'], $user); if ($status !== true) { $msg = $this->parseMsg($status); $this->dieUsage($msg['info'], $msg['code'], 0, ['blockinfo' => ApiQueryUserInfo::getBlockInfo($user->getBlock())]); } } // Check if user can add tags if (!is_null($params['tags'])) { $ableToTag = ChangeTags::canAddTagsAccompanyingChange($params['tags'], $user); if (!$ableToTag->isOK()) { $this->dieStatus($ableToTag); } } $data = ['Target' => is_null($params['id']) ? $params['user'] : "******", 'Reason' => $params['reason'], 'Tags' => $params['tags']]; $block = Block::newFromTarget($data['Target']); $retval = SpecialUnblock::processUnblock($data, $this->getContext()); if ($retval !== true) { $this->dieUsageMsg($retval[0]); } $res['id'] = $block->getId(); $target = $block->getType() == Block::TYPE_AUTO ? '' : $block->getTarget(); $res['user'] = $target instanceof User ? $target->getName() : $target; $res['userid'] = $target instanceof User ? $target->getId() : 0; $res['reason'] = $params['reason']; $this->getResult()->addValue(null, $this->getModuleName(), $res); }
/** * Unblocks the specified user or provides the reason the unblock failed. */ public function execute() { $user = $this->getUser(); $params = $this->extractRequestParams(); if ($params['gettoken']) { // If we're in JSON callback mode, no tokens can be obtained if (!is_null($this->getMain()->getRequest()->getVal('callback'))) { $this->dieUsage('Cannot get token when using a callback', 'aborted'); } $res['unblocktoken'] = $user->getEditToken('', $this->getMain()->getRequest()); $this->getResult()->addValue(null, $this->getModuleName(), $res); return; } if (is_null($params['id']) && is_null($params['user'])) { $this->dieUsageMsg('unblock-notarget'); } if (!is_null($params['id']) && !is_null($params['user'])) { $this->dieUsageMsg('unblock-idanduser'); } if (!$user->isAllowed('block')) { $this->dieUsageMsg('cantunblock'); } # bug 15810: blocked admins should have limited access here if ($user->isBlocked()) { $status = SpecialBlock::checkUnblockSelf($params['user'], $user); if ($status !== true) { $this->dieUsageMsg($status); } } $data = array('Target' => is_null($params['id']) ? $params['user'] : "******", 'Reason' => is_null($params['reason']) ? '' : $params['reason']); $block = Block::newFromTarget($data['Target']); $retval = SpecialUnblock::processUnblock($data, $this->getContext()); if ($retval !== true) { $this->dieUsageMsg($retval[0]); } $res['id'] = $block->getId(); $target = $block->getType() == Block::TYPE_AUTO ? '' : $block->getTarget(); $res['user'] = $target instanceof User ? $target->getName() : $target; $res['reason'] = $params['reason']; $this->getResult()->addValue(null, $this->getModuleName(), $res); }
/** * Unblocks the specified user or provides the reason the unblock failed. */ public function execute() { global $wgUser; $params = $this->extractRequestParams(); if ($params['gettoken']) { $res['unblocktoken'] = $wgUser->editToken('', $this->getMain()->getRequest()); $this->getResult()->addValue(null, $this->getModuleName(), $res); return; } if (is_null($params['id']) && is_null($params['user'])) { $this->dieUsageMsg('unblock-notarget'); } if (!is_null($params['id']) && !is_null($params['user'])) { $this->dieUsageMsg('unblock-idanduser'); } if (!$wgUser->isAllowed('block')) { $this->dieUsageMsg('cantunblock'); } # bug 15810: blocked admins should have limited access here if ($wgUser->isBlocked()) { $status = SpecialBlock::checkUnblockSelf($params['user']); if ($status !== true) { $this->dieUsageMsg($status); } } $data = array('Target' => is_null($params['id']) ? $params['user'] : "******", 'Reason' => is_null($params['reason']) ? '' : $params['reason']); $block = Block::newFromTarget($data['Target']); $retval = SpecialUnblock::processUnblock($data); if ($retval !== true) { $this->dieUsageMsg($retval[0]); } $res['id'] = $block->getId(); $res['user'] = $block->getType() == Block::TYPE_AUTO ? '' : $block->getTarget(); $res['reason'] = $params['reason']; $this->getResult()->addValue(null, $this->getModuleName(), $res); }
/** * Generates the subheading with links * @param User $userObj User object for the target * @return string Appropriately-escaped HTML to be output literally */ function getSubTitle($userObj) { $linkRenderer = $this->getLinkRenderer(); if ($userObj->isAnon()) { $user = htmlspecialchars($userObj->getName()); } else { $user = $linkRenderer->makeLink($userObj->getUserPage(), $userObj->getName()); } $links = ''; $nt = $userObj->getUserPage(); $talk = $nt->getTalkPage(); if ($talk) { $tools = SpecialContributions::getUserLinks($this, $userObj); # Link to contributions $insert['contribs'] = $linkRenderer->makeKnownLink(SpecialPage::getTitleFor('Contributions', $nt->getDBkey()), $this->msg('sp-deletedcontributions-contribs')->text()); // Swap out the deletedcontribs link for our contribs one $tools = wfArrayInsertAfter($tools, $insert, 'deletedcontribs'); unset($tools['deletedcontribs']); $links = $this->getLanguage()->pipeList($tools); // Show a note if the user is blocked and display the last block log entry. $block = Block::newFromTarget($userObj, $userObj); if (!is_null($block) && $block->getType() != Block::TYPE_AUTO) { if ($block->getType() == Block::TYPE_RANGE) { $nt = MWNamespace::getCanonicalName(NS_USER) . ':' . $block->getTarget(); } // LogEventsList::showLogExtract() wants the first parameter by ref $out = $this->getOutput(); LogEventsList::showLogExtract($out, 'block', $nt, '', ['lim' => 1, 'showIfEmpty' => false, 'msgKey' => ['sp-contributions-blocked-notice', $userObj->getName()], 'offset' => '']); } } return $this->msg('contribsub2')->rawParams($user, $links)->params($userObj->getName()); }
/** * Process the form * @return Array( Array(message key, parameters) ) on failure, True on success */ public static function processUnblock(array $data) { global $wgUser; $target = $data['Target']; $block = Block::newFromTarget($data['Target']); if (!$block instanceof Block) { return array(array('ipb_cant_unblock', $target)); } # If the specified IP is a single address, and the block is a range block, don't # unblock the whole range. list($target, $type) = SpecialBlock::getTargetAndType($target); if ($block->getType() == Block::TYPE_RANGE && $type == Block::TYPE_IP) { $range = $block->getTarget(); return array(array('ipb_blocked_as_range', $target, $range)); } # If the name was hidden and the blocking user cannot hide # names, then don't allow any block removals... if (!$wgUser->isAllowed('hideuser') && $block->mHideName) { return array('unblock-hideuser'); } # Delete block if (!$block->delete()) { return array('ipb_cant_unblock', htmlspecialchars($block->getTarget())); } # Unset _deleted fields as needed if ($block->mHideName) { # Something is deeply FUBAR if this is not a User object, but who knows? $id = $block->getTarget() instanceof User ? $block->getTarget()->getID() : User::idFromName($block->getTarget()); RevisionDeleteUser::unsuppressUserName($block->getTarget(), $id); } # Redact the name (IP address) for autoblocks if ($block->getType() == Block::TYPE_AUTO) { $page = Title::makeTitle(NS_USER, '#' . $block->getId()); } else { $page = $block->getTarget() instanceof User ? $block->getTarget()->getUserpage() : Title::makeTitle(NS_USER, $block->getTarget()); } # Make log entry $log = new LogPage('block'); $log->addEntry('unblock', $page, $data['Reason']); return true; }
/** * Show the error text for a missing article. For articles in the MediaWiki * namespace, show the default message text. To be called from Article::view(). */ public function showMissingArticle() { global $wgSend404Code; $outputPage = $this->getContext()->getOutput(); // Whether the page is a root user page of an existing user (but not a subpage) $validUserPage = false; $title = $this->getTitle(); # Show info in user (talk) namespace. Does the user exist? Is he blocked? if ($title->getNamespace() == NS_USER || $title->getNamespace() == NS_USER_TALK) { $parts = explode('/', $title->getText()); $rootPart = $parts[0]; $user = User::newFromName($rootPart, false); $ip = User::isIP($rootPart); $block = Block::newFromTarget($user, $user); if (!($user && $user->isLoggedIn()) && !$ip) { # User does not exist $outputPage->wrapWikiMsg("<div class=\"mw-userpage-userdoesnotexist error\">\n\$1\n</div>", array('userpage-userdoesnotexist-view', wfEscapeWikiText($rootPart))); } elseif (!is_null($block) && $block->getType() != Block::TYPE_AUTO) { # Show log extract if the user is currently blocked LogEventsList::showLogExtract($outputPage, 'block', MWNamespace::getCanonicalName(NS_USER) . ':' . $block->getTarget(), '', array('lim' => 1, 'showIfEmpty' => false, 'msgKey' => array('blocked-notice-logextract', $user->getName()))); $validUserPage = !$title->isSubpage(); } else { $validUserPage = !$title->isSubpage(); } } Hooks::run('ShowMissingArticle', array($this)); # Show delete and move logs if there were any such events. # The logging query can DOS the site when bots/crawlers cause 404 floods, # so be careful showing this. 404 pages must be cheap as they are hard to cache. $cache = ObjectCache::getMainStashInstance(); $key = wfMemcKey('page-recent-delete', md5($title->getPrefixedText())); $loggedIn = $this->getContext()->getUser()->isLoggedIn(); if ($loggedIn || $cache->get($key)) { $logTypes = array('delete', 'move'); $conds = array("log_action != 'revision'"); // Give extensions a chance to hide their (unrelated) log entries Hooks::run('Article::MissingArticleConditions', array(&$conds, $logTypes)); LogEventsList::showLogExtract($outputPage, $logTypes, $title, '', array('lim' => 10, 'conds' => $conds, 'showIfEmpty' => false, 'msgKey' => array($loggedIn ? 'moveddeleted-notice' : 'moveddeleted-notice-recent'))); } if (!$this->mPage->hasViewableContent() && $wgSend404Code && !$validUserPage) { // If there's no backing content, send a 404 Not Found // for better machine handling of broken links. $this->getContext()->getRequest()->response()->statusHeader(404); } // Also apply the robot policy for nonexisting pages (even if a 404 was used for sanity) $policy = $this->getRobotPolicy('view'); $outputPage->setIndexPolicy($policy['index']); $outputPage->setFollowPolicy($policy['follow']); $hookResult = Hooks::run('BeforeDisplayNoArticleText', array($this)); if (!$hookResult) { return; } # Show error message $oldid = $this->getOldID(); if (!$oldid && $title->getNamespace() === NS_MEDIAWIKI && $title->hasSourceText()) { $outputPage->addParserOutput($this->getContentObject()->getParserOutput($title)); } else { if ($oldid) { $text = wfMessage('missing-revision', $oldid)->plain(); } elseif ($title->quickUserCan('create', $this->getContext()->getUser()) && $title->quickUserCan('edit', $this->getContext()->getUser())) { $message = $this->getContext()->getUser()->isLoggedIn() ? 'noarticletext' : 'noarticletextanon'; $text = wfMessage($message)->plain(); } else { $text = wfMessage('noarticletext-nopermission')->plain(); } $dir = $this->getContext()->getLanguage()->getDir(); $lang = $this->getContext()->getLanguage()->getCode(); $outputPage->addWikiText(Xml::openElement('div', array('class' => "noarticletext mw-content-{$dir}", 'dir' => $dir, 'lang' => $lang)) . "\n{$text}\n</div>"); } }
/** * Process the form * * @param $data Array * @param $context IContextSource * @throws ErrorPageError * @return Array( Array(message key, parameters) ) on failure, True on success */ public static function processUnblock(array $data, IContextSource $context) { $performer = $context->getUser(); $target = $data['Target']; $block = Block::newFromTarget($data['Target']); if (!$block instanceof Block) { return array(array('ipb_cant_unblock', $target)); } # bug 15810: blocked admins should have limited access here. This # won't allow sysops to remove autoblocks on themselves, but they # should have ipblock-exempt anyway $status = SpecialBlock::checkUnblockSelf($target, $performer); if ($status !== true) { throw new ErrorPageError('badaccess', $status); } # If the specified IP is a single address, and the block is a range block, don't # unblock the whole range. list($target, $type) = SpecialBlock::getTargetAndType($target); if ($block->getType() == Block::TYPE_RANGE && $type == Block::TYPE_IP) { $range = $block->getTarget(); return array(array('ipb_blocked_as_range', $target, $range)); } # If the name was hidden and the blocking user cannot hide # names, then don't allow any block removals... if (!$performer->isAllowed('hideuser') && $block->mHideName) { return array('unblock-hideuser'); } # Delete block if (!$block->delete()) { return array('ipb_cant_unblock', htmlspecialchars($block->getTarget())); } # Unset _deleted fields as needed if ($block->mHideName) { # Something is deeply FUBAR if this is not a User object, but who knows? $id = $block->getTarget() instanceof User ? $block->getTarget()->getID() : User::idFromName($block->getTarget()); RevisionDeleteUser::unsuppressUserName($block->getTarget(), $id); } # Redact the name (IP address) for autoblocks if ($block->getType() == Block::TYPE_AUTO) { $page = Title::makeTitle(NS_USER, '#' . $block->getId()); } else { $page = $block->getTarget() instanceof User ? $block->getTarget()->getUserpage() : Title::makeTitle(NS_USER, $block->getTarget()); } # Make log entry $log = new LogPage('block'); $log->addEntry('unblock', $page, $data['Reason'], array(), $performer); return true; }
/** * Given the form data, actually implement a block * @param $data Array * @param $context IContextSource * @return Bool|String */ public static function processForm(array $data, IContextSource $context) { global $wgBlockAllowsUTEdit; $performer = $context->getUser(); // Handled by field validator callback // self::validateTargetField( $data['Target'] ); # This might have been a hidden field or a checkbox, so interesting data # can come from it $data['Confirm'] = !in_array($data['Confirm'], array('', '0', null, false), true); list($target, $type) = self::getTargetAndType($data['Target']); if ($type == Block::TYPE_USER) { $user = $target; $target = $user->getName(); $userId = $user->getId(); # Give admins a heads-up before they go and block themselves. Much messier # to do this for IPs, but it's pretty unlikely they'd ever get the 'block' # permission anyway, although the code does allow for it. # Note: Important to use $target instead of $data['Target'] # since both $data['PreviousTarget'] and $target are normalized # but $data['target'] gets overriden by (non-normalized) request variable # from previous request. if ($target === $performer->getName() && ($data['PreviousTarget'] !== $target || !$data['Confirm'])) { return array('ipb-blockingself'); } } elseif ($type == Block::TYPE_RANGE) { $userId = 0; } elseif ($type == Block::TYPE_IP) { $target = $target->getName(); $userId = 0; } else { # This should have been caught in the form field validation return array('badipaddress'); } if (strlen($data['Expiry']) == 0 || strlen($data['Expiry']) > 50 || !self::parseExpiryInput($data['Expiry'])) { return array('ipb_expiry_invalid'); } if (!isset($data['DisableEmail'])) { $data['DisableEmail'] = false; } # 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'])) { $data['HideUser'] = false; } if ($data['HideUser']) { if (!$performer->isAllowed('hideuser')) { # this codepath is unreachable except by a malicious user spoofing forms, # or by race conditions (user has oversight and sysop, loads block form, # and is de-oversighted before submission); so need to fail completely # rather than just silently disable hiding return array('badaccess-group0'); } # Recheck params here... if ($type != Block::TYPE_USER) { $data['HideUser'] = false; # IP users should not be hidden } elseif (!in_array($data['Expiry'], array('infinite', 'infinity', 'indefinite'))) { # Bad expiry. return array('ipb_expiry_temp'); } elseif ($user->getEditCount() > 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'); } elseif (!$data['Confirm']) { return array('ipb-confirmhideuser'); } } # Create block object. $block = new Block(); $block->setTarget($target); $block->setBlocker($performer); $block->mReason = $data['Reason'][0]; $block->mExpiry = self::parseExpiryInput($data['Expiry']); $block->prevents('createaccount', $data['CreateAccount']); $block->prevents('editownusertalk', !$wgBlockAllowsUTEdit || $data['DisableUTEdit']); $block->prevents('sendemail', $data['DisableEmail']); $block->isHardblock($data['HardBlock']); $block->isAutoblocking($data['AutoBlock']); $block->mHideName = $data['HideUser']; if (!wfRunHooks('BlockIp', array(&$block, &$performer))) { return array('hookaborted'); } # Try to insert block. Is there a conflicting block? $status = $block->insert(); if (!$status) { # Show form unless the user is already aware of this... if (!$data['Confirm'] || array_key_exists('PreviousTarget', $data) && $data['PreviousTarget'] !== $target) { return array(array('ipb_already_blocked', $block->getTarget())); # 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 $currentBlock = Block::newFromTarget($target); if ($block->equals($currentBlock)) { return array(array('ipb_already_blocked', $block->getTarget())); } # If the name was hidden and the blocking user cannot hide # names, then don't allow any block changes... if ($currentBlock->mHideName && !$performer->isAllowed('hideuser')) { return array('cant-see-hidden-user'); } $currentBlock->delete(); $status = $block->insert(); $logaction = 'reblock'; # Unset _deleted fields if requested if ($currentBlock->mHideName && !$data['HideUser']) { RevisionDeleteUser::unsuppressUserName($target, $userId); } # If hiding/unhiding a name, this should go in the private logs if ((bool) $currentBlock->mHideName) { $data['HideUser'] = true; } } } else { $logaction = 'block'; } wfRunHooks('BlockIpComplete', array($block, $performer)); # Set *_deleted fields if requested if ($data['HideUser']) { RevisionDeleteUser::suppressUserName($target, $userId); } # Can't watch a rangeblock if ($type != Block::TYPE_RANGE && $data['Watch']) { $performer->addWatch(Title::makeTitle(NS_USER, $target)); } # Block constructor sanitizes certain block options on insert $data['BlockEmail'] = $block->prevents('sendemail'); $data['AutoBlock'] = $block->isAutoblocking(); # Prepare log parameters $logParams = array(); $logParams[] = $data['Expiry']; $logParams[] = self::blockLogFlags($data, $type); # Make log entry, if the name is hidden, put it in the oversight log $log_type = $data['HideUser'] ? 'suppress' : 'block'; $log = new LogPage($log_type); $log_id = $log->addEntry($logaction, Title::makeTitle(NS_USER, $target), $data['Reason'][0], $logParams); # Relate log ID to block IDs (bug 25763) $blockIds = array_merge(array($status['id']), $status['autoIds']); $log->addRelations('ipb_id', $blockIds, $log_id); # Report to the user return true; }
/** * Generates the subheading with links * @param User $userObj User object for the target * @return string Appropriately-escaped HTML to be output literally * @todo FIXME: Almost the same as getSubTitle in SpecialDeletedContributions.php. * Could be combined. */ protected function contributionsSub($userObj) { if ($userObj->isAnon()) { // Show a warning message that the user being searched for doesn't exists if (!User::isIP($userObj->getName())) { $this->getOutput()->wrapWikiMsg("<div class=\"mw-userpage-userdoesnotexist error\">\n\$1\n</div>", ['contributions-userdoesnotexist', wfEscapeWikiText($userObj->getName())]); if (!$this->including()) { $this->getOutput()->setStatusCode(404); } } $user = htmlspecialchars($userObj->getName()); } else { $user = $this->getLinkRenderer()->makeLink($userObj->getUserPage(), $userObj->getName()); } $nt = $userObj->getUserPage(); $talk = $userObj->getTalkPage(); $links = ''; if ($talk) { $tools = self::getUserLinks($this, $userObj); $links = $this->getLanguage()->pipeList($tools); // Show a note if the user is blocked and display the last block log entry. // Do not expose the autoblocks, since that may lead to a leak of accounts' IPs, // and also this will display a totally irrelevant log entry as a current block. if (!$this->including()) { $block = Block::newFromTarget($userObj, $userObj); if (!is_null($block) && $block->getType() != Block::TYPE_AUTO) { if ($block->getType() == Block::TYPE_RANGE) { $nt = MWNamespace::getCanonicalName(NS_USER) . ':' . $block->getTarget(); } $out = $this->getOutput(); // showLogExtract() wants first parameter by reference LogEventsList::showLogExtract($out, 'block', $nt, '', ['lim' => 1, 'showIfEmpty' => false, 'msgKey' => [$userObj->isAnon() ? 'sp-contributions-blocked-notice-anon' : 'sp-contributions-blocked-notice', $userObj->getName()], 'offset' => '']); } } } return $this->msg('contribsub2')->rawParams($user, $links)->params($userObj->getName()); }
public function testDeprecatedConstructor() { $this->hideDeprecated('Block::__construct with multiple arguments'); $username = '******'; $reason = 'being irrational'; # Set up the target $u = User::newFromName($username); if ($u->getID() == 0) { $u->addToDatabase(); TestUser::setPasswordForUser($u, 'TotallyObvious'); } unset($u); # Make sure the user isn't blocked $this->assertNull(Block::newFromTarget($username), "{$username} should not be blocked"); # Perform the block $block = new Block($username, 0, 0, $reason, 0, false, 0); $block->insert(); # Check target $this->assertEquals($block->getTarget()->getName(), $username, "Target should be set properly"); # Check supplied parameter $this->assertEquals($block->mReason, $reason, "Reason should be non-default"); # Check default parameter $this->assertFalse((bool) $block->prevents('createaccount'), "Account creation should not be blocked by default"); }
/** * Blocks the user specified in the parameters for the given expiry, with the * given reason, and with all other settings provided in the params. If the block * succeeds, produces a result containing the details of the block and notice * of success. If it fails, the result will specify the nature of the error. */ public function execute() { $user = $this->getUser(); $params = $this->extractRequestParams(); if ( !$user->isAllowed( 'block' ) ) { $this->dieUsageMsg( 'cantblock' ); } # bug 15810: blocked admins should have limited access here if ( $user->isBlocked() ) { $status = SpecialBlock::checkUnblockSelf( $params['user'], $user ); if ( $status !== true ) { $this->dieUsageMsg( array( $status ) ); } } $target = User::newFromName( $params['user'] ); // Bug 38633 - if the target is a user (not an IP address), but it doesn't exist or is unusable, error. if ( $target instanceof User && ( $target->isAnon() /* doesn't exist */ || !User::isUsableName( $target->getName() ) ) ) { $this->dieUsageMsg( array( 'nosuchuser', $params['user'] ) ); } if ( $params['hidename'] && !$user->isAllowed( 'hideuser' ) ) { $this->dieUsageMsg( 'canthide' ); } if ( $params['noemail'] && !SpecialBlock::canBlockEmail( $user ) ) { $this->dieUsageMsg( 'cantblock-email' ); } $data = array( 'PreviousTarget' => $params['user'], 'Target' => $params['user'], 'Reason' => array( $params['reason'], 'other', $params['reason'] ), 'Expiry' => $params['expiry'] == 'never' ? 'infinite' : $params['expiry'], 'HardBlock' => !$params['anononly'], 'CreateAccount' => $params['nocreate'], 'AutoBlock' => $params['autoblock'], 'DisableEmail' => $params['noemail'], 'HideUser' => $params['hidename'], 'DisableUTEdit' => !$params['allowusertalk'], 'Reblock' => $params['reblock'], 'Watch' => $params['watchuser'], 'Confirm' => true, ); $retval = SpecialBlock::processForm( $data, $this->getContext() ); if ( $retval !== true ) { // We don't care about multiple errors, just report one of them $this->dieUsageMsg( $retval ); } list( $target, /*...*/ ) = SpecialBlock::getTargetAndType( $params['user'] ); $res['user'] = $params['user']; $res['userID'] = $target instanceof User ? $target->getId() : 0; $block = Block::newFromTarget( $target ); if ( $block instanceof Block ) { $res['expiry'] = $block->mExpiry == $this->getDB()->getInfinity() ? 'infinite' : wfTimestamp( TS_ISO_8601, $block->mExpiry ); $res['id'] = $block->getId(); } else { # should be unreachable $res['expiry'] = ''; $res['id'] = ''; } $res['reason'] = $params['reason']; if ( $params['anononly'] ) { $res['anononly'] = ''; } if ( $params['nocreate'] ) { $res['nocreate'] = ''; } if ( $params['autoblock'] ) { $res['autoblock'] = ''; } if ( $params['noemail'] ) { $res['noemail'] = ''; } if ( $params['hidename'] ) { $res['hidename'] = ''; } if ( $params['allowusertalk'] ) { $res['allowusertalk'] = ''; } if ( $params['watchuser'] ) { $res['watchuser'] = ''; } $this->getResult()->addValue( null, $this->getModuleName(), $res ); }
/** * CheckUser since being changed to use Block::newFromTarget started failing * because the new function didn't accept empty strings like Block::load() * had. Regression bug 29116. * * @dataProvider dataBug29116 */ function testBug29116NewFromTargetWithEmptyIp($vagueTarget) { $block = Block::newFromTarget('UTBlockee', $vagueTarget); $this->assertTrue($this->block->equals($block), "newFromTarget() returns the same block as the one that was made when given empty vagueTarget param " . var_export($vagueTarget, true)); }
/** * Show the error text for a missing article. For articles in the MediaWiki * namespace, show the default message text. To be called from Article::view(). */ public function showMissingArticle() { global $wgSend404Code; $outputPage = $this->getContext()->getOutput(); // Whether the page is a root user page of an existing user (but not a subpage) $validUserPage = false; $title = $this->getTitle(); # Show info in user (talk) namespace. Does the user exist? Is he blocked? if ($title->getNamespace() == NS_USER || $title->getNamespace() == NS_USER_TALK) { $parts = explode('/', $title->getText()); $rootPart = $parts[0]; $user = User::newFromName($rootPart, false); $ip = User::isIP($rootPart); $block = Block::newFromTarget($user, $user); if (!($user && $user->isLoggedIn()) && !$ip) { # User does not exist $outputPage->wrapWikiMsg("<div class=\"mw-userpage-userdoesnotexist error\">\n\$1\n</div>", array('userpage-userdoesnotexist-view', wfEscapeWikiText($rootPart))); } elseif (!is_null($block) && $block->getType() != Block::TYPE_AUTO) { # Show log extract if the user is currently blocked LogEventsList::showLogExtract($outputPage, 'block', MWNamespace::getCanonicalName(NS_USER) . ':' . $block->getTarget(), '', array('lim' => 1, 'showIfEmpty' => false, 'msgKey' => array('blocked-notice-logextract', $user->getName()))); $validUserPage = !$title->isSubpage(); } else { $validUserPage = !$title->isSubpage(); } } Hooks::run('ShowMissingArticle', array($this)); // Give extensions a chance to hide their (unrelated) log entries $logTypes = array('delete', 'move'); $conds = array("log_action != 'revision'"); Hooks::run('Article::MissingArticleConditions', array(&$conds, $logTypes)); # Show delete and move logs LogEventsList::showLogExtract($outputPage, $logTypes, $title, '', array('lim' => 10, 'conds' => $conds, 'showIfEmpty' => false, 'msgKey' => array('moveddeleted-notice'))); if (!$this->mPage->hasViewableContent() && $wgSend404Code && !$validUserPage) { // If there's no backing content, send a 404 Not Found // for better machine handling of broken links. $this->getContext()->getRequest()->response()->header("HTTP/1.1 404 Not Found"); } // Also apply the robot policy for nonexisting pages (even if a 404 was used for sanity) $policy = $this->getRobotPolicy('view'); $outputPage->setIndexPolicy($policy['index']); $outputPage->setFollowPolicy($policy['follow']); $hookResult = Hooks::run('BeforeDisplayNoArticleText', array($this)); if (!$hookResult) { return; } # Show error message $oldid = $this->getOldID(); if ($oldid) { $text = wfMessage('missing-revision', $oldid)->plain(); } elseif ($title->getNamespace() === NS_MEDIAWIKI) { // Use the default message text $text = $title->getDefaultMessageText(); } elseif ($title->quickUserCan('create', $this->getContext()->getUser()) && $title->quickUserCan('edit', $this->getContext()->getUser())) { $message = $this->getContext()->getUser()->isLoggedIn() ? 'noarticletext' : 'noarticletextanon'; $text = wfMessage($message)->plain(); } else { $text = wfMessage('noarticletext-nopermission')->plain(); } $text = "<div class='noarticletext'>\n{$text}\n</div>"; $outputPage->addWikiText($text); }
public function testCheckAccountCreatePermissions() { global $wgGroupPermissions; $this->stashMwGlobals(['wgGroupPermissions']); $this->initializeManager(true); $wgGroupPermissions['*']['createaccount'] = true; $this->assertEquals(\Status::newGood(), $this->manager->checkAccountCreatePermissions(new \User())); $this->setMwGlobals(['wgReadOnly' => 'Because']); $this->assertEquals(\Status::newFatal('readonlytext', 'Because'), $this->manager->checkAccountCreatePermissions(new \User())); $this->setMwGlobals(['wgReadOnly' => false]); $wgGroupPermissions['*']['createaccount'] = false; $status = $this->manager->checkAccountCreatePermissions(new \User()); $this->assertFalse($status->isOK()); $this->assertTrue($status->hasMessage('badaccess-groups')); $wgGroupPermissions['*']['createaccount'] = true; $user = \User::newFromName('UTBlockee'); if ($user->getID() == 0) { $user->addToDatabase(); \TestUser::setPasswordForUser($user, 'UTBlockeePassword'); $user->saveSettings(); } $oldBlock = \Block::newFromTarget('UTBlockee'); if ($oldBlock) { // An old block will prevent our new one from saving. $oldBlock->delete(); } $blockOptions = ['address' => 'UTBlockee', 'user' => $user->getID(), 'reason' => __METHOD__, 'expiry' => time() + 100500, 'createAccount' => true]; $block = new \Block($blockOptions); $block->insert(); $status = $this->manager->checkAccountCreatePermissions($user); $this->assertFalse($status->isOK()); $this->assertTrue($status->hasMessage('cantcreateaccount-text')); $blockOptions = ['address' => '127.0.0.0/24', 'reason' => __METHOD__, 'expiry' => time() + 100500, 'createAccount' => true]; $block = new \Block($blockOptions); $block->insert(); $scopeVariable = new \ScopedCallback([$block, 'delete']); $status = $this->manager->checkAccountCreatePermissions(new \User()); $this->assertFalse($status->isOK()); $this->assertTrue($status->hasMessage('cantcreateaccount-range-text')); \ScopedCallback::consume($scopeVariable); $this->setMwGlobals(['wgEnableDnsBlacklist' => true, 'wgDnsBlacklistUrls' => ['local.wmftest.net'], 'wgProxyWhitelist' => []]); $status = $this->manager->checkAccountCreatePermissions(new \User()); $this->assertFalse($status->isOK()); $this->assertTrue($status->hasMessage('sorbs_create_account_reason')); $this->setMwGlobals('wgProxyWhitelist', ['127.0.0.1']); $status = $this->manager->checkAccountCreatePermissions(new \User()); $this->assertTrue($status->isGood()); }
function revertAction($action, $result) { switch ($action) { case 'block': $block = Block::newFromTarget(User::whoIs($result['userid'])); if (!$block || $block->getBy() != AbuseFilter::getFilterUser()->getId()) { return false; // Not blocked by abuse filter. } $block->delete(); $log = new LogPage('block'); $log->addEntry('unblock', Title::makeTitle(NS_USER, $result['user']), wfMsgForContent('abusefilter-revert-reason', $this->mPage->mFilter, $this->mReason)); break; case 'blockautopromote': global $wgMemc; $wgMemc->delete(AbuseFilter::autopromoteBlockKey(User::newFromId($result['userid']))); break; case 'degroup': // Pull the user's groups from the vars. $oldGroups = $result['vars']['USER_GROUPS']; $oldGroups = explode(',', $oldGroups); $oldGroups = array_diff($oldGroups, array_intersect($oldGroups, User::getImplicitGroups())); $rows = array(); foreach ($oldGroups as $group) { $rows[] = array('ug_user' => $result['userid'], 'ug_group' => $group); } // Cheat a little bit. User::addGroup repeatedly is too slow. $user = User::newFromId($result['userid']); $currentGroups = $user->getGroups(); $newGroups = array_merge($oldGroups, $currentGroups); // Don't do anything if there are no groups to add. if (!count(array_diff($newGroups, $currentGroups))) { return; } $dbw = wfGetDB(DB_MASTER); $dbw->insert('user_groups', $rows, __METHOD__, array('IGNORE')); $user->invalidateCache(); $log = new LogPage('rights'); $log->addEntry('rights', $user->getUserPage(), wfMsgForContent('abusefilter-revert-reason', $this->mPage->mFilter, $this->mReason), array(implode(',', $currentGroups), implode(',', $newGroups))); } }
protected function userBlockFlags($ip, $userId, $user) { static $logs, $blocklist; $logs = SpecialPage::getTitleFor('Log'); $blocklist = SpecialPage::getTitleFor('BlockList'); $block = Block::newFromTarget($user, $ip, false); $flags = array(); if ($block instanceof Block) { // Range blocked? if ($block->getType() == Block::TYPE_RANGE) { $userpage = Title::makeTitle(NS_USER, $block->getTarget()); $blocklog = $this->sk->makeKnownLinkObj($logs, wfMsgHtml('checkuser-blocked'), 'type=block&page=' . urlencode($userpage->getPrefixedText())); $flags[] = '<strong>(' . $blocklog . ' - ' . $block->getTarget() . ')</strong>'; // Auto blocked? } elseif ($block->getType() == Block::TYPE_AUTO) { $blocklog = $this->sk->makeKnownLinkObj($blocklist, wfMsgHtml('checkuser-blocked'), 'ip=' . urlencode("#{$block->getId()}")); $flags[] = '<strong>(' . $blocklog . ')</strong>'; } else { $userpage = $user->getUserPage(); $blocklog = $this->sk->makeKnownLinkObj($logs, wfMsgHtml('checkuser-blocked'), 'type=block&page=' . urlencode($userpage->getPrefixedText())); $flags[] = '<strong>(' . $blocklog . ')</strong>'; } // IP that is blocked on all wikis? } elseif ($ip == $user->getName() && $user->isBlockedGlobally($ip)) { $flags[] = '<strong>(' . wfMsgHtml('checkuser-gblocked') . ')</strong>'; } elseif (self::userWasBlocked($user->getName())) { $userpage = $user->getUserPage(); $blocklog = $this->sk->makeKnownLinkObj($logs, wfMsgHtml('checkuser-wasblocked'), 'type=block&page=' . urlencode($userpage->getPrefixedText())); $flags[] = '<strong>(' . $blocklog . ')</strong>'; } return $flags; }
/** * Generates the subheading with links * @param User $userObj User object for the target * @return string Appropriately-escaped HTML to be output literally * @todo FIXME: Almost the same as contributionsSub in SpecialContributions.php. Could be combined. */ function getSubTitle($userObj) { if ($userObj->isAnon()) { $user = htmlspecialchars($userObj->getName()); } else { $user = Linker::link($userObj->getUserPage(), htmlspecialchars($userObj->getName())); } $links = ''; $nt = $userObj->getUserPage(); $id = $userObj->getID(); $talk = $nt->getTalkPage(); if ($talk) { # Talk page link $tools[] = Linker::link($talk, $this->msg('sp-contributions-talk')->escaped()); if ($id !== null || $id === null && IP::isIPAddress($nt->getText())) { # Block / Change block / Unblock links if ($this->getUser()->isAllowed('block')) { if ($userObj->isBlocked()) { $tools[] = Linker::linkKnown(SpecialPage::getTitleFor('Block', $nt->getDBkey()), $this->msg('change-blocklink')->escaped()); $tools[] = Linker::linkKnown(SpecialPage::getTitleFor('BlockList'), $this->msg('unblocklink')->escaped(), array(), array('action' => 'unblock', 'ip' => $nt->getDBkey())); } else { # User is not blocked $tools[] = Linker::linkKnown(SpecialPage::getTitleFor('Block', $nt->getDBkey()), $this->msg('blocklink')->escaped()); } } # Block log link $tools[] = Linker::linkKnown(SpecialPage::getTitleFor('Log'), $this->msg('sp-contributions-blocklog')->escaped(), array(), array('type' => 'block', 'page' => $nt->getPrefixedText())); # Suppression log link (bug 59120) if ($this->getUser()->isAllowed('suppressionlog')) { $tools[] = Linker::linkKnown(SpecialPage::getTitleFor('Log', 'suppress'), $this->msg('sp-contributions-suppresslog')->escaped(), array(), array('offender' => $userObj->getName())); } } # Uploads $tools[] = Linker::linkKnown(SpecialPage::getTitleFor('Listfiles', $userObj->getName()), $this->msg('sp-contributions-uploads')->escaped()); # Other logs link $tools[] = Linker::linkKnown(SpecialPage::getTitleFor('Log'), $this->msg('sp-contributions-logs')->escaped(), array(), array('user' => $nt->getText())); # Link to contributions $tools[] = Linker::linkKnown(SpecialPage::getTitleFor('Contributions', $nt->getDBkey()), $this->msg('sp-deletedcontributions-contribs')->escaped()); # Add a link to change user rights for privileged users $userrightsPage = new UserrightsPage(); $userrightsPage->setContext($this->getContext()); if ($userrightsPage->userCanChangeRights($userObj)) { $tools[] = Linker::linkKnown(SpecialPage::getTitleFor('Userrights', $nt->getDBkey()), $this->msg('sp-contributions-userrights')->escaped()); } Hooks::run('ContributionsToolLinks', array($id, $nt, &$tools)); $links = $this->getLanguage()->pipeList($tools); // Show a note if the user is blocked and display the last block log entry. $block = Block::newFromTarget($userObj, $userObj); if (!is_null($block) && $block->getType() != Block::TYPE_AUTO) { if ($block->getType() == Block::TYPE_RANGE) { $nt = MWNamespace::getCanonicalName(NS_USER) . ':' . $block->getTarget(); } // LogEventsList::showLogExtract() wants the first parameter by ref $out = $this->getOutput(); LogEventsList::showLogExtract($out, 'block', $nt, '', array('lim' => 1, 'showIfEmpty' => false, 'msgKey' => array('sp-contributions-blocked-notice', $userObj->getName()), 'offset' => '')); } } return $this->msg('contribsub2')->rawParams($user, $links)->params($userObj->getName()); }
/** * Autoblocks the given IP, referring to this Block. * * @param string $autoblockIP The IP to autoblock. * @return int|bool Block ID if an autoblock was inserted, false if not. */ public function doAutoblock($autoblockIP) { # If autoblocks are disabled, go away. if (!$this->isAutoblocking()) { return false; } # Check for presence on the autoblock whitelist. if (self::isWhitelistedFromAutoblocks($autoblockIP)) { return false; } # Allow hooks to cancel the autoblock. if (!wfRunHooks('AbortAutoblock', array($autoblockIP, &$this))) { wfDebug("Autoblock aborted by hook.\n"); return false; } # It's okay to autoblock. Go ahead and insert/update the block... # Do not add a *new* block if the IP is already blocked. $ipblock = Block::newFromTarget($autoblockIP); if ($ipblock) { # Check if the block is an autoblock and would exceed the user block # if renewed. If so, do nothing, otherwise prolong the block time... if ($ipblock->mAuto && $this->mExpiry > Block::getAutoblockExpiry($ipblock->mTimestamp)) { # Reset block timestamp to now and its expiry to # $wgAutoblockExpiry in the future $ipblock->updateTimestamp(); } return false; } # Make a new block object with the desired properties. $autoblock = new Block(); wfDebug("Autoblocking {$this->getTarget()}@" . $autoblockIP . "\n"); $autoblock->setTarget($autoblockIP); $autoblock->setBlocker($this->getBlocker()); $autoblock->mReason = wfMessage('autoblocker', $this->getTarget(), $this->mReason)->inContentLanguage()->plain(); $timestamp = wfTimestampNow(); $autoblock->mTimestamp = $timestamp; $autoblock->mAuto = 1; $autoblock->prevents('createaccount', $this->prevents('createaccount')); # Continue suppressing the name if needed $autoblock->mHideName = $this->mHideName; $autoblock->prevents('editownusertalk', $this->prevents('editownusertalk')); $autoblock->mParentBlockId = $this->mId; if ($this->mExpiry == 'infinity') { # Original block was indefinite, start an autoblock now $autoblock->mExpiry = Block::getAutoblockExpiry($timestamp); } else { # If the user is already blocked with an expiry date, we don't # want to pile on top of that. $autoblock->mExpiry = min($this->mExpiry, Block::getAutoblockExpiry($timestamp)); } # Insert the block... $status = $autoblock->insert(); return $status ? $status['id'] : false; }
/** * Blocks the user specified in the parameters for the given expiry, with the * given reason, and with all other settings provided in the params. If the block * succeeds, produces a result containing the details of the block and notice * of success. If it fails, the result will specify the nature of the error. */ public function execute() { global $wgUser; $params = $this->extractRequestParams(); if ($params['gettoken']) { $res['blocktoken'] = $wgUser->editToken('', $this->getMain()->getRequest()); $this->getResult()->addValue(null, $this->getModuleName(), $res); return; } if (!$wgUser->isAllowed('block')) { $this->dieUsageMsg('cantblock'); } # bug 15810: blocked admins should have limited access here if ($wgUser->isBlocked()) { $status = SpecialBlock::checkUnblockSelf($params['user']); if ($status !== true) { $this->dieUsageMsg(array($status)); } } if ($params['hidename'] && !$wgUser->isAllowed('hideuser')) { $this->dieUsageMsg('canthide'); } if ($params['noemail'] && !SpecialBlock::canBlockEmail($wgUser)) { $this->dieUsageMsg('cantblock-email'); } $data = array('Target' => $params['user'], 'Reason' => array(is_null($params['reason']) ? '' : $params['reason'], 'other', is_null($params['reason']) ? '' : $params['reason']), 'Expiry' => $params['expiry'] == 'never' ? 'infinite' : $params['expiry'], 'HardBlock' => !$params['anononly'], 'CreateAccount' => $params['nocreate'], 'AutoBlock' => $params['autoblock'], 'DisableEmail' => $params['noemail'], 'HideUser' => $params['hidename'], 'DisableUTEdit' => $params['allowusertalk'], 'AlreadyBlocked' => $params['reblock'], 'Watch' => $params['watchuser'], 'Confirm' => true); $retval = SpecialBlock::processForm($data); if ($retval !== true) { // We don't care about multiple errors, just report one of them $this->dieUsageMsg($retval); } list($target, ) = SpecialBlock::getTargetAndType($params['user']); $res['user'] = $params['user']; $res['userID'] = $target instanceof User ? $target->getId() : 0; $block = Block::newFromTarget($target); if ($block instanceof Block) { $res['expiry'] = $block->mExpiry == wfGetDB(DB_SLAVE)->getInfinity() ? 'infinite' : wfTimestamp(TS_ISO_8601, $block->mExpiry); } else { # should be unreachable $res['expiry'] = ''; } $res['reason'] = $params['reason']; if ($params['anononly']) { $res['anononly'] = ''; } if ($params['nocreate']) { $res['nocreate'] = ''; } if ($params['autoblock']) { $res['autoblock'] = ''; } if ($params['noemail']) { $res['noemail'] = ''; } if ($params['hidename']) { $res['hidename'] = ''; } if ($params['allowusertalk']) { $res['allowusertalk'] = ''; } if ($params['watchuser']) { $res['watchuser'] = ''; } $this->getResult()->addValue(null, $this->getModuleName(), $res); }
/** * Get the robot policy to be used for the current view * @param $action String the action= GET parameter * @param $pOutput ParserOutput * @return Array the policy that should be set * TODO: actions other than 'view' */ public function getRobotPolicy($action, $pOutput) { global $wgArticleRobotPolicies, $wgNamespaceRobotPolicies, $wgDefaultRobotPolicy; $ns = $this->getTitle()->getNamespace(); if ($ns == NS_USER || $ns == NS_USER_TALK) { # Don't index user and user talk pages for blocked users (bug 11443) if (!$this->getTitle()->isSubpage()) { if (Block::newFromTarget(null, $this->getTitle()->getText()) instanceof Block) { return array('index' => 'noindex', 'follow' => 'nofollow'); } } } if ($this->mPage->getID() === 0 || $this->getOldID()) { # Non-articles (special pages etc), and old revisions return array('index' => 'noindex', 'follow' => 'nofollow'); } elseif ($this->getContext()->getOutput()->isPrintable()) { # Discourage indexing of printable versions, but encourage following return array('index' => 'noindex', 'follow' => 'follow'); } elseif ($this->getContext()->getRequest()->getInt('curid')) { # For ?curid=x urls, disallow indexing return array('index' => 'noindex', 'follow' => 'follow'); } # Otherwise, construct the policy based on the various config variables. $policy = self::formatRobotPolicy($wgDefaultRobotPolicy); if (isset($wgNamespaceRobotPolicies[$ns])) { # Honour customised robot policies for this namespace $policy = array_merge($policy, self::formatRobotPolicy($wgNamespaceRobotPolicies[$ns])); } if ($this->getTitle()->canUseNoindex() && is_object($pOutput) && $pOutput->getIndexPolicy()) { # __INDEX__ and __NOINDEX__ magic words, if allowed. Incorporates # a final sanity check that we have really got the parser output. $policy = array_merge($policy, array('index' => $pOutput->getIndexPolicy())); } if (isset($wgArticleRobotPolicies[$this->getTitle()->getPrefixedText()])) { # (bug 14900) site config can override user-defined __INDEX__ or __NOINDEX__ $policy = array_merge($policy, self::formatRobotPolicy($wgArticleRobotPolicies[$this->getTitle()->getPrefixedText()])); } return $policy; }
/** * Show all applicable editing introductions */ protected function showIntro() { global $wgOut, $wgUser; if ($this->suppressIntro) { return; } $namespace = $this->mTitle->getNamespace(); if ($namespace == NS_MEDIAWIKI) { # Show a warning if editing an interface message $wgOut->wrapWikiMsg("<div class='mw-editinginterface'>\n\$1\n</div>", 'editinginterface'); } elseif ($namespace == NS_FILE) { # Show a hint to shared repo $file = wfFindFile($this->mTitle); if ($file && !$file->isLocal()) { $descUrl = $file->getDescriptionUrl(); # there must be a description url to show a hint to shared repo if ($descUrl) { if (!$this->mTitle->exists()) { $wgOut->wrapWikiMsg("<div class=\"mw-sharedupload-desc-create\">\n\$1\n</div>", array('sharedupload-desc-create', $file->getRepo()->getDisplayName(), $descUrl)); } else { $wgOut->wrapWikiMsg("<div class=\"mw-sharedupload-desc-edit\">\n\$1\n</div>", array('sharedupload-desc-edit', $file->getRepo()->getDisplayName(), $descUrl)); } } } } # Show a warning message when someone creates/edits a user (talk) page but the user does not exist # Show log extract when the user is currently blocked if ($namespace == NS_USER || $namespace == NS_USER_TALK) { $parts = explode('/', $this->mTitle->getText(), 2); $username = $parts[0]; $user = User::newFromName($username, false); $ip = User::isIP($username); $block = Block::newFromTarget($user, $user); if (!($user && $user->isLoggedIn()) && !$ip) { # User does not exist $wgOut->wrapWikiMsg("<div class=\"mw-userpage-userdoesnotexist error\">\n\$1\n</div>", array('userpage-userdoesnotexist', wfEscapeWikiText($username))); } elseif (!is_null($block) && $block->getType() != Block::TYPE_AUTO) { # Show log extract if the user is currently blocked LogEventsList::showLogExtract($wgOut, 'block', MWNamespace::getCanonicalName(NS_USER) . ':' . $block->getTarget(), '', array('lim' => 1, 'showIfEmpty' => false, 'msgKey' => array('blocked-notice-logextract', $user->getName()))); } } # Try to add a custom edit intro, or use the standard one if this is not possible. if (!$this->showCustomIntro() && !$this->mTitle->exists()) { $helpLink = wfExpandUrl(Skin::makeInternalOrExternalUrl(wfMessage('helppage')->inContentLanguage()->text())); if ($wgUser->isLoggedIn()) { $wgOut->wrapWikiMsg("<div class=\"mw-newarticletext plainlinks\">\n\$1\n</div>", array('newarticletext', $helpLink)); } else { $wgOut->wrapWikiMsg("<div class=\"mw-newarticletextanon plainlinks\">\n\$1\n</div>", array('newarticletextanon', $helpLink)); } } # Give a notice if the user is editing a deleted/moved page... if (!$this->mTitle->exists()) { LogEventsList::showLogExtract($wgOut, array('delete', 'move'), $this->mTitle, '', array('lim' => 10, 'conds' => array("log_action != 'revision'"), 'showIfEmpty' => false, 'msgKey' => array('recreate-moveddeleted-warn'))); } }
/** * @covers Block::insert */ public function testCrappyCrossWikiBlocks() { // Delete the last round's block if it's still there $oldBlock = Block::newFromTarget('UserOnForeignWiki'); if ($oldBlock) { // An old block will prevent our new one from saving. $oldBlock->delete(); } // Foreign perspective (blockee not on current wiki)... $block = new Block('UserOnForeignWiki', 14146, 0, 'crosswiki block...', wfTimestampNow(), false, $this->db->getInfinity(), false, true, true, true, true, false, 'MetaWikiUser'); $res = $block->insert($this->db); $this->assertTrue((bool) $res['id'], 'Block succeeded'); // Local perspective (blockee on current wiki)... $user = User::newFromName('UserOnForeignWiki'); $user->addToDatabase(); // Set user ID to match the test value $this->db->update('user', array('user_id' => 14146), array('user_id' => $user->getId())); $user = null; // clear $block = Block::newFromID($res['id']); $this->assertEquals('UserOnForeignWiki', $block->getTarget()->getName(), 'Correct blockee name'); $this->assertEquals('14146', $block->getTarget()->getId(), 'Correct blockee id'); $this->assertEquals('MetaWikiUser', $block->getBlocker(), 'Correct blocker name'); $this->assertEquals('MetaWikiUser', $block->getByName(), 'Correct blocker name'); $this->assertEquals(0, $block->getBy(), 'Correct blocker id'); }
/** * Given the form data, actually implement a block. This is also called from ApiBlock. * * @param array $data * @param IContextSource $context * @return bool|string */ public static function processForm(array $data, IContextSource $context) { global $wgBlockAllowsUTEdit, $wgHideUserContribLimit, $wgContLang; $performer = $context->getUser(); // Handled by field validator callback // self::validateTargetField( $data['Target'] ); # This might have been a hidden field or a checkbox, so interesting data # can come from it $data['Confirm'] = !in_array($data['Confirm'], ['', '0', null, false], true); /** @var User $target */ list($target, $type) = self::getTargetAndType($data['Target']); if ($type == Block::TYPE_USER) { $user = $target; $target = $user->getName(); $userId = $user->getId(); # Give admins a heads-up before they go and block themselves. Much messier # to do this for IPs, but it's pretty unlikely they'd ever get the 'block' # permission anyway, although the code does allow for it. # Note: Important to use $target instead of $data['Target'] # since both $data['PreviousTarget'] and $target are normalized # but $data['target'] gets overridden by (non-normalized) request variable # from previous request. if ($target === $performer->getName() && ($data['PreviousTarget'] !== $target || !$data['Confirm'])) { return ['ipb-blockingself', 'ipb-confirmaction']; } } elseif ($type == Block::TYPE_RANGE) { $userId = 0; } elseif ($type == Block::TYPE_IP) { $target = $target->getName(); $userId = 0; } else { # This should have been caught in the form field validation return ['badipaddress']; } $expiryTime = self::parseExpiryInput($data['Expiry']); if (strlen($data['Expiry']) == 0 || strlen($data['Expiry']) > 50 || !$expiryTime) { return ['ipb_expiry_invalid']; } // an expiry time should be in the future, not in the // past (wouldn't make any sense) - bug T123069 if ($expiryTime < wfTimestampNow()) { return ['ipb_expiry_old']; } if (!isset($data['DisableEmail'])) { $data['DisableEmail'] = false; } # 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'])) { $data['HideUser'] = false; } if ($data['HideUser']) { if (!$performer->isAllowed('hideuser')) { # this codepath is unreachable except by a malicious user spoofing forms, # or by race conditions (user has hideuser and block rights, loads block form, # and loses hideuser rights before submission); so need to fail completely # rather than just silently disable hiding return ['badaccess-group0']; } # Recheck params here... if ($type != Block::TYPE_USER) { $data['HideUser'] = false; # IP users should not be hidden } elseif (!wfIsInfinity($data['Expiry'])) { # Bad expiry. return ['ipb_expiry_temp']; } elseif ($wgHideUserContribLimit !== false && $user->getEditCount() > $wgHideUserContribLimit) { # Typically, the user should have a handful of edits. # Disallow hiding users with many edits for performance. return [['ipb_hide_invalid', Message::numParam($wgHideUserContribLimit)]]; } elseif (!$data['Confirm']) { return ['ipb-confirmhideuser', 'ipb-confirmaction']; } } # Create block object. $block = new Block(); $block->setTarget($target); $block->setBlocker($performer); # Truncate reason for whole multibyte characters $block->mReason = $wgContLang->truncate($data['Reason'][0], 255); $block->mExpiry = $expiryTime; $block->prevents('createaccount', $data['CreateAccount']); $block->prevents('editownusertalk', !$wgBlockAllowsUTEdit || $data['DisableUTEdit']); $block->prevents('sendemail', $data['DisableEmail']); $block->isHardblock($data['HardBlock']); $block->isAutoblocking($data['AutoBlock']); $block->mHideName = $data['HideUser']; $reason = ['hookaborted']; if (!Hooks::run('BlockIp', [&$block, &$performer, &$reason])) { return $reason; } # Try to insert block. Is there a conflicting block? $status = $block->insert(); if (!$status) { # Indicates whether the user is confirming the block and is aware of # the conflict (did not change the block target in the meantime) $blockNotConfirmed = !$data['Confirm'] || array_key_exists('PreviousTarget', $data) && $data['PreviousTarget'] !== $target; # Special case for API - bug 32434 $reblockNotAllowed = array_key_exists('Reblock', $data) && !$data['Reblock']; # Show form unless the user is already aware of this... if ($blockNotConfirmed || $reblockNotAllowed) { return [['ipb_already_blocked', $block->getTarget()]]; # 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 $currentBlock = Block::newFromTarget($target); if ($block->equals($currentBlock)) { return [['ipb_already_blocked', $block->getTarget()]]; } # If the name was hidden and the blocking user cannot hide # names, then don't allow any block changes... if ($currentBlock->mHideName && !$performer->isAllowed('hideuser')) { return ['cant-see-hidden-user']; } $currentBlock->isHardblock($block->isHardblock()); $currentBlock->prevents('createaccount', $block->prevents('createaccount')); $currentBlock->mExpiry = $block->mExpiry; $currentBlock->isAutoblocking($block->isAutoblocking()); $currentBlock->mHideName = $block->mHideName; $currentBlock->prevents('sendemail', $block->prevents('sendemail')); $currentBlock->prevents('editownusertalk', $block->prevents('editownusertalk')); $currentBlock->mReason = $block->mReason; $status = $currentBlock->update(); $logaction = 'reblock'; # Unset _deleted fields if requested if ($currentBlock->mHideName && !$data['HideUser']) { RevisionDeleteUser::unsuppressUserName($target, $userId); } # If hiding/unhiding a name, this should go in the private logs if ((bool) $currentBlock->mHideName) { $data['HideUser'] = true; } } } else { $logaction = 'block'; } Hooks::run('BlockIpComplete', [$block, $performer]); # Set *_deleted fields if requested if ($data['HideUser']) { RevisionDeleteUser::suppressUserName($target, $userId); } # Can't watch a rangeblock if ($type != Block::TYPE_RANGE && $data['Watch']) { WatchAction::doWatch(Title::makeTitle(NS_USER, $target), $performer, User::IGNORE_USER_RIGHTS); } # Block constructor sanitizes certain block options on insert $data['BlockEmail'] = $block->prevents('sendemail'); $data['AutoBlock'] = $block->isAutoblocking(); # Prepare log parameters $logParams = []; $logParams['5::duration'] = $data['Expiry']; $logParams['6::flags'] = self::blockLogFlags($data, $type); # Make log entry, if the name is hidden, put it in the suppression log $log_type = $data['HideUser'] ? 'suppress' : 'block'; $logEntry = new ManualLogEntry($log_type, $logaction); $logEntry->setTarget(Title::makeTitle(NS_USER, $target)); $logEntry->setComment($data['Reason'][0]); $logEntry->setPerformer($performer); $logEntry->setParameters($logParams); # Relate log ID to block IDs (bug 25763) $blockIds = array_merge([$status['id']], $status['autoIds']); $logEntry->setRelations(['ipb_id' => $blockIds]); $logId = $logEntry->insert(); $logEntry->publish($logId); # Report to the user return true; }
/** * Get whether the user is explicitly blocked from account creation. * @return Bool|Block */ public function isBlockedFromCreateAccount() { $this->getBlockedStatus(); if ($this->mBlock && $this->mBlock->prevents('createaccount')) { return $this->mBlock; } # bug 13611: if the IP address the user is trying to create an account from is # blocked with createaccount disabled, prevent new account creation there even # when the user is logged in if ($this->mBlockedFromCreateAccount === false) { $this->mBlockedFromCreateAccount = Block::newFromTarget(null, $this->getRequest()->getIP()); } return $this->mBlockedFromCreateAccount instanceof Block && $this->mBlockedFromCreateAccount->prevents('createaccount') ? $this->mBlockedFromCreateAccount : false; }
static function banUser($user, $banningUser, $spammer, $um) { $ret = null; if (!is_object($user)) { /* Skip this one */ } elseif ($user->getID() != 0 && $um) { $ret = $um->merge($user, $spammer, "block", $banningUser); } else { if (!Block::newFromTarget($user->getName())) { $blk = new Block($user->getName(), $user->getId(), $banningUser->getID(), wfMsg('blockandnuke-message'), wfTimestamp(), 0, wfGetDB(DB_SLAVE)->getInfinity(), 0, 1, 0, 0, 1); $blk->isAutoBlocking(true); if ($ret = $blk->insert()) { $log = new LogPage('block'); $log->addEntry('block', Title::makeTitle(NS_USER, $user->getName()), 'Blocked through Special:BlockandNuke', array('infinite', $user->getName(), 'nocreate')); } } } return $ret; }