/** * * @param string $name * @param int $amount * @return boolean false if failed */ private function credit($name = null, $amount = 0) { $output = $this->getOutput(); $output->addWikiText("=== Credit (name, amount) ==="); $output->addWikiText("name = {$name}"); $output->addWikiText("amount = {$amount}"); $user = User::newFromName($name); if (!$user || $user->getId() == 0) { $output->addWikiText("=== ERROR: Invalid UserName ==="); return false; } $output->addWikiText("=== User ==="); $output->addWikiText("user_id = " . $user->getId()); $output->addWikiText("user_name = " . $user->getName()); $output->addWikiText("user_realname = " . $user->getRealName()); $output->addWikiText("user_email = " . $user->getEmail()); $output->addWikiText("=== Transaction ==="); $output->addWikiText("True balance before = " . TMRecord::getTrueBalanceFromDB($user->getId())); if (!is_int($amount) || $amount <= 0 || $amount > 1000) { $output->addWikiText("=== ERROR: Invalid Amount ==="); return false; } $tmr = array('tmr_type' => TM_REFUND_TYPE, 'tmr_user_id' => $user->getId(), 'tmr_mail' => $user->getEmail(), 'tmr_ip' => IP::sanitizeIP(wfGetIP()), 'tmr_amount' => $amount, 'tmr_currency' => 'EUR', 'tmr_desc' => 'tm-refund', 'tmr_status' => 'OK'); wfRunHooks('CreateTransaction', array(&$tmr)); $output->addWikiText("==== DONE ===="); $output->addWikiText("True balance after = " . TMRecord::getTrueBalanceFromDB($user->getId())); $output->addWikiText("== SUCCESS =="); }
public function execute($subpage) { global $wgRequest, $wgOut; $this->checkPermissions(); $this->setHeaders(); $user = $wgRequest->getText('user') ? $wgRequest->getText('user') : $wgRequest->getText('ip'); $user = trim($user); $reason = $wgRequest->getText('reason'); $blockreason = $wgRequest->getText('blockreason'); $checktype = $wgRequest->getVal('checktype'); $period = $wgRequest->getInt('period'); $users = $wgRequest->getArray('users'); $tag = $wgRequest->getBool('usetag') ? trim($wgRequest->getVal('tag')) : ''; $talkTag = $wgRequest->getBool('usettag') ? trim($wgRequest->getVal('talktag')) : ''; $m = array(); # An IPv4? An IPv6? CIDR included? if (IP::isIPAddress($user)) { $ip = IP::sanitizeIP($user); $name = ''; $xff = ''; # An IPv4/IPv6 XFF string? CIDR included? } elseif (preg_match('/^(.+)\\/xff$/', $user, $m) && IP::isIPAddress($m[1])) { $ip = ''; $name = ''; $xff = IP::sanitizeIP($m[1]); # A user? } else { $ip = ''; $name = $user; $xff = ''; } $this->showForm($user, $reason, $checktype, $ip, $xff, $name, $period); # Perform one of the various submit operations... if ($wgRequest->wasPosted()) { if (!$this->getUser()->matchEditToken($wgRequest->getVal('wpEditToken'))) { $wgOut->wrapWikiMsg('<div class="error">$1</div>', 'checkuser-token-fail'); } elseif ($wgRequest->getVal('action') === 'block') { $this->doMassUserBlock($users, $blockreason, $tag, $talkTag); } elseif (!$this->checkReason($reason)) { $wgOut->addWikiMsg('checkuser-noreason'); } elseif ($checktype == 'subuserips') { $this->doUserIPsRequest($name, $reason, $period); } elseif ($xff && $checktype == 'subedits') { $this->doIPEditsRequest($xff, true, $reason, $period); } elseif ($ip && $checktype == 'subedits') { $this->doIPEditsRequest($ip, false, $reason, $period); } elseif ($name && $checktype == 'subedits') { $this->doUserEditsRequest($user, $reason, $period); } elseif ($xff && $checktype == 'subipusers') { $this->doIPUsersRequest($xff, true, $reason, $period, $tag, $talkTag); } elseif ($checktype == 'subipusers') { $this->doIPUsersRequest($ip, false, $reason, $period, $tag, $talkTag); } } # Add CIDR calculation convenience form $this->addJsCIDRForm(); $wgOut->addModules('ext.checkUser'); // JS }
public function onRecentChange_save(&$rc) { global $wgPutIPinRC; if (!$wgPutIPinRC) { return; } $dbw = wfGetDB(DB_MASTER); $dbw->update('recentchanges', array('rc_ip' => IP::sanitizeIP($this->ip)), array('rc_id' => $rc->mAttribs['rc_id']), __METHOD__); }
/** * Hook function for RecentChange_save * Saves user data into the cu_changes table */ function efUpdateCheckUserData($rc) { global $wgUser; // Extract params extract($rc->mAttribs); // Get IP $ip = wfGetIP(); // Get XFF header $xff = wfGetForwardedFor(); list($xff_ip, $trusted) = efGetClientIPfromXFF($xff); // Our squid XFFs can flood this up sometimes $isSquidOnly = efXFFChainIsSquid($xff); // Get agent $agent = wfGetAgent(); // Store the log action text for log events // $rc_comment should just be the log_comment // BC: check if log_type and log_action exists // If not, then $rc_comment is the actiontext and comment if (isset($rc_log_type) && $rc_type == RC_LOG) { $target = Title::makeTitle($rc_namespace, $rc_title); $actionText = LogPage::actionText($rc_log_type, $rc_log_action, $target, NULL, explode('\\n', $rc_params)); } else { $actionText = ''; } $dbw = wfGetDB(DB_MASTER); $cuc_id = $dbw->nextSequenceValue('cu_changes_cu_id_seq'); $rcRow = array('cuc_id' => $cuc_id, 'cuc_namespace' => $rc_namespace, 'cuc_title' => $rc_title, 'cuc_minor' => $rc_minor, 'cuc_user' => $rc_user, 'cuc_user_text' => $rc_user_text, 'cuc_actiontext' => $actionText, 'cuc_comment' => $rc_comment, 'cuc_this_oldid' => $rc_this_oldid, 'cuc_last_oldid' => $rc_last_oldid, 'cuc_type' => $rc_type, 'cuc_timestamp' => $rc_timestamp, 'cuc_ip' => IP::sanitizeIP($ip), 'cuc_ip_hex' => $ip ? IP::toHex($ip) : null, 'cuc_xff' => !$isSquidOnly ? $xff : '', 'cuc_xff_hex' => $xff_ip && !$isSquidOnly ? IP::toHex($xff_ip) : null, 'cuc_agent' => $agent); ## On PG, MW unsets cur_id due to schema incompatibilites. So it may not be set! if (isset($rc_cur_id)) { $rcRow['cuc_page_id'] = $rc_cur_id; } $dbw->insert('cu_changes', $rcRow, __METHOD__); # Every 100th edit, prune the checkuser changes table. wfSeedRandom(); if (0 == mt_rand(0, 99)) { # Periodically flush old entries from the recentchanges table. global $wgCUDMaxAge; $cutoff = $dbw->timestamp(time() - $wgCUDMaxAge); $recentchanges = $dbw->tableName('cu_changes'); $sql = "DELETE FROM {$recentchanges} WHERE cuc_timestamp < '{$cutoff}'"; $dbw->query($sql); } return true; }
public function index() { wfProfileIn(__METHOD__); if (!$this->getUser()->isAllowed('coppatool')) { wfProfileOut(__METHOD__); $this->displayRestrictionError(); return false; } $this->specialPage->setHeaders(); $this->response->setTemplateEngine(WikiaResponse::TEMPLATE_ENGINE_MUSTACHE); $this->userName = trim($this->getVal('username', $this->getPar())); $this->isIP = false; $this->validUser = false; if (IP::isIPAddress($this->userName)) { $this->userName = IP::sanitizeIP($this->userName); $this->isIP = true; $this->validUser = true; } else { $userObj = User::newFromName($this->userName); if (!$userObj || $userObj->getId() === 0) { $this->validUser = false; } else { $this->userName = $userObj->getName(); $this->validUser = true; } } $this->userForm = $this->app->renderView('WikiaStyleGuideForm', 'index', ['form' => ['isInvalid' => $this->validUser || $this->userName === '' ? false : true, 'errorMsg' => $this->validUser || $this->userName === '' ? '' : $this->msg('coppatool-nosuchuser', $this->userName)->escaped(), 'inputs' => [['type' => 'text', 'name' => 'username', 'isRequired' => true, 'label' => $this->msg('coppatool-label-username')->escaped(), 'value' => Sanitizer::encodeAttribute($this->userName)], ['type' => 'submit', 'value' => $this->msg('coppatool-submit')->escaped()]], 'method' => 'GET', 'action' => $this->getTitle()->getLocalUrl()]]); if ($this->validUser) { $this->getOutput()->addModules('ext.coppaTool'); $this->buttons = []; $this->blankImgUrl = wfBlankImgUrl(); $this->formHeading = $this->msg('coppatool-form-header')->escaped(); if (!$this->isIP) { $this->buttons[] = ['buttonAction' => 'disable-account', 'buttonLink' => Html::element('a', ['href' => '#'], $this->msg('coppatool-disable')->escaped()), 'done' => $userObj->getGlobalFlag('disabled', false)]; $this->buttons[] = ['buttonAction' => 'blank-profile', 'buttonLink' => Html::element('a', ['href' => '#'], $this->msg('coppatool-blank-user-profile')->escaped())]; $this->buttons[] = ['buttonAction' => 'delete-userpages', 'buttonLink' => Html::element('a', ['href' => '#'], $this->msg('coppatool-delete-user-pages')->escaped())]; $this->buttons[] = ['buttonAction' => 'coppa-imagereview', 'buttonLink' => Linker::link(Title::newFromText('CoppaImageReview', NS_SPECIAL), $this->msg('coppatool-imagereview')->escaped(), ['target' => '_blank'], ['username' => $this->userName], ['known', 'noclasses'])]; } else { $this->buttons[] = ['buttonAction' => 'phalanx-ip', 'buttonLink' => Linker::link(Title::newFromText('Phalanx', NS_SPECIAL), $this->msg('coppatool-phalanx-ip')->escaped(), ['target' => '_blank'], ['type' => Phalanx::TYPE_USER, 'wpPhalanxCheckBlocker' => $this->userName, 'target' => $this->userName], ['known', 'noclasses'])]; $this->buttons[] = ['buttonAction' => 'rename-ip', 'buttonLink' => Html::element('a', ['href' => '#'], $this->msg('coppatool-rename-ip')->escaped())]; } } wfProfileOut(__METHOD__); }
function fnGetGeoIP($ip_address = null) { if (!isset($ip_address)) { $ip_address = IP::sanitizeIP(wfGetIP()); } if (isset($_GET['ip'])) { $ip_address = IP::sanitizeIP($_GET['ip']); } if (!IP::isIPv4($ip_address)) { throw new UnsupportedGeoIP('Only IPv4 addresses are supported.'); } $dbr = wfGetDB(DB_SLAVE); $long_ip = IP::toUnsigned($ip_address); $conditions = array('begin_ip_long <= ' . $long_ip, $long_ip . ' <= end_ip_long'); $country_code = $dbr->selectField('geoip', 'country_code', $conditions, __METHOD__); if (!$country_code) { throw new NotFoundGeoIP('Could not identify the country for the provided IP address.'); } return $country_code; }
function __construct($address = '', $user = 0, $by = 0, $reason = '', $timestamp = '', $auto = 0, $expiry = '', $anonOnly = 0, $createAccount = 0, $enableAutoblock = 0, $hideName = 0, $blockEmail = 0) { $this->mId = 0; # Expand valid IPv6 addresses $address = IP::sanitizeIP($address); $this->mAddress = $address; $this->mUser = $user; $this->mBy = $by; $this->mReason = $reason; $this->mTimestamp = wfTimestamp(TS_MW, $timestamp); $this->mAuto = $auto; $this->mAnonOnly = $anonOnly; $this->mCreateAccount = $createAccount; $this->mExpiry = self::decodeExpiry($expiry); $this->mEnableAutoblock = $enableAutoblock; $this->mHideName = $hideName; $this->mBlockEmail = $blockEmail; $this->mForUpdate = false; $this->mFromMaster = false; $this->mByName = false; $this->initialiseRange(); }
function loadParameters() { global $wgAbuseFilterIsCentral; $request = $this->getRequest(); $this->mSearchUser = trim($request->getText('wpSearchUser')); if ($wgAbuseFilterIsCentral) { $this->mSearchWiki = $request->getText('wpSearchWiki'); } $u = User::newFromName($this->mSearchUser); if ($u) { $this->mSearchUser = $u->getName(); // Username normalisation } elseif (IP::isIPAddress($this->mSearchUser)) { // It's an IP $this->mSearchUser = IP::sanitizeIP($this->mSearchUser); } else { $this->mSearchUser = null; } $this->mSearchTitle = $request->getText('wpSearchTitle'); $this->mSearchFilter = null; if (self::canSeeDetails()) { $this->mSearchFilter = $request->getText('wpSearchFilter'); } }
/** * Secure and split - main initialisation function for this object * * Assumes that mDbkeyform has been set, and is urldecoded * and uses underscores, but not otherwise munged. This function * removes illegal characters, splits off the interwiki and * namespace prefixes, sets the other forms, and canonicalizes * everything. * * @return Bool true on success */ private function secureAndSplit() { global $wgContLang, $wgLocalInterwiki; # Initialisation $this->mInterwiki = $this->mFragment = ''; $this->mNamespace = $this->mDefaultNamespace; # Usually NS_MAIN $dbkey = $this->mDbkeyform; # Strip Unicode bidi override characters. # Sometimes they slip into cut-n-pasted page titles, where the # override chars get included in list displays. $dbkey = preg_replace('/\\xE2\\x80[\\x8E\\x8F\\xAA-\\xAE]/S', '', $dbkey); # Clean up whitespace # Note: use of the /u option on preg_replace here will cause # input with invalid UTF-8 sequences to be nullified out in PHP 5.2.x, # conveniently disabling them. $dbkey = preg_replace('/[ _\\xA0\\x{1680}\\x{180E}\\x{2000}-\\x{200A}\\x{2028}\\x{2029}\\x{202F}\\x{205F}\\x{3000}]+/u', '_', $dbkey); $dbkey = trim($dbkey, '_'); if ($dbkey == '') { return false; } if (false !== strpos($dbkey, UTF8_REPLACEMENT)) { # Contained illegal UTF-8 sequences or forbidden Unicode chars. return false; } $this->mDbkeyform = $dbkey; # Initial colon indicates main namespace rather than specified default # but should not create invalid {ns,title} pairs such as {0,Project:Foo} if (':' == $dbkey[0]) { $this->mNamespace = NS_MAIN; $dbkey = substr($dbkey, 1); # remove the colon but continue processing $dbkey = trim($dbkey, '_'); # remove any subsequent whitespace } # Namespace or interwiki prefix $firstPass = true; $prefixRegexp = "/^(.+?)_*:_*(.*)\$/S"; do { $m = array(); if (preg_match($prefixRegexp, $dbkey, $m)) { $p = $m[1]; if (($ns = $wgContLang->getNsIndex($p)) !== false) { # Ordinary namespace $dbkey = $m[2]; $this->mNamespace = $ns; # For Talk:X pages, check if X has a "namespace" prefix if ($ns == NS_TALK && preg_match($prefixRegexp, $dbkey, $x)) { if ($wgContLang->getNsIndex($x[1])) { # Disallow Talk:File:x type titles... return false; } elseif (Interwiki::isValidInterwiki($x[1])) { # Disallow Talk:Interwiki:x type titles... return false; } } } elseif (Interwiki::isValidInterwiki($p)) { if (!$firstPass) { # Can't make a local interwiki link to an interwiki link. # That's just crazy! return false; } # Interwiki link $dbkey = $m[2]; $this->mInterwiki = $wgContLang->lc($p); # Redundant interwiki prefix to the local wiki if ($wgLocalInterwiki !== false && 0 == strcasecmp($this->mInterwiki, $wgLocalInterwiki)) { if ($dbkey == '') { # Can't have an empty self-link return false; } $this->mInterwiki = ''; $firstPass = false; # Do another namespace split... continue; } # If there's an initial colon after the interwiki, that also # resets the default namespace if ($dbkey !== '' && $dbkey[0] == ':') { $this->mNamespace = NS_MAIN; $dbkey = substr($dbkey, 1); } } # If there's no recognized interwiki or namespace, # then let the colon expression be part of the title. } break; } while (true); # We already know that some pages won't be in the database! if ($this->mInterwiki != '' || NS_SPECIAL == $this->mNamespace) { $this->mArticleID = 0; } $fragment = strstr($dbkey, '#'); if (false !== $fragment) { $this->setFragment($fragment); $dbkey = substr($dbkey, 0, strlen($dbkey) - strlen($fragment)); # remove whitespace again: prevents "Foo_bar_#" # becoming "Foo_bar_" $dbkey = preg_replace('/_*$/', '', $dbkey); } # Reject illegal characters. $rxTc = self::getTitleInvalidRegex(); if (preg_match($rxTc, $dbkey)) { return false; } # Pages with "/./" or "/../" appearing in the URLs will often be un- # reachable due to the way web browsers deal with 'relative' URLs. # Also, they conflict with subpage syntax. Forbid them explicitly. if (strpos($dbkey, '.') !== false && ($dbkey === '.' || $dbkey === '..' || strpos($dbkey, './') === 0 || strpos($dbkey, '../') === 0 || strpos($dbkey, '/./') !== false || strpos($dbkey, '/../') !== false || substr($dbkey, -2) == '/.' || substr($dbkey, -3) == '/..')) { return false; } # Magic tilde sequences? Nu-uh! if (strpos($dbkey, '~~~') !== false) { return false; } # Limit the size of titles to 255 bytes. This is typically the size of the # underlying database field. We make an exception for special pages, which # don't need to be stored in the database, and may edge over 255 bytes due # to subpage syntax for long titles, e.g. [[Special:Block/Long name]] if ($this->mNamespace != NS_SPECIAL && strlen($dbkey) > 255 || strlen($dbkey) > 512) { return false; } # Normally, all wiki links are forced to have an initial capital letter so [[foo]] # and [[Foo]] point to the same place. Don't force it for interwikis, since the # other site might be case-sensitive. $this->mUserCaseDBKey = $dbkey; if ($this->mInterwiki == '') { $dbkey = self::capitalize($dbkey, $this->mNamespace); } # Can't make a link to a namespace alone... "empty" local links can only be # self-links with a fragment identifier. if ($dbkey == '' && $this->mInterwiki == '' && $this->mNamespace != NS_MAIN) { return false; } // Allow IPv6 usernames to start with '::' by canonicalizing IPv6 titles. // IP names are not allowed for accounts, and can only be referring to // edits from the IP. Given '::' abbreviations and caps/lowercaps, // there are numerous ways to present the same IP. Having sp:contribs scan // them all is silly and having some show the edits and others not is // inconsistent. Same for talk/userpages. Keep them normalized instead. $dbkey = $this->mNamespace == NS_USER || $this->mNamespace == NS_USER_TALK ? IP::sanitizeIP($dbkey) : $dbkey; // Any remaining initial :s are illegal. if ($dbkey !== '' && ':' == $dbkey[0]) { return false; } # Fill fields $this->mDbkeyform = $dbkey; $this->mUrlform = wfUrlencode($dbkey); $this->mTextform = str_replace('_', ' ', $dbkey); return true; }
/** * Secure and split - main initialisation function for this object * * Assumes that mDbkeyform has been set, and is urldecoded * and uses underscores, but not otherwise munged. This function * removes illegal characters, splits off the interwiki and * namespace prefixes, sets the other forms, and canonicalizes * everything. * @return bool true on success */ private function secureAndSplit() { global $wgContLang, $wgLocalInterwiki, $wgCapitalLinks; # Initialisation static $rxTc = false; if (!$rxTc) { # Matching titles will be held as illegal. $rxTc = '/' . '[^' . Title::legalChars() . ']' . '|%[0-9A-Fa-f]{2}' . '|&[A-Za-z0-9\\x80-\\xff]+;' . '|&#[0-9]+;' . '|&#x[0-9A-Fa-f]+;' . '/S'; } $this->mInterwiki = $this->mFragment = ''; $this->mNamespace = $this->mDefaultNamespace; # Usually NS_MAIN $dbkey = $this->mDbkeyform; # Strip Unicode bidi override characters. # Sometimes they slip into cut-n-pasted page titles, where the # override chars get included in list displays. $dbkey = str_replace("", '', $dbkey); // 200E LEFT-TO-RIGHT MARK $dbkey = str_replace("", '', $dbkey); // 200F RIGHT-TO-LEFT MARK # Clean up whitespace # // XXCHANGED don't replace _ with - screws up namespaces $dbkey = preg_replace('/[ ]+/', '-', $this->mDbkeyform); $dbkey = trim($dbkey, '-'); if ('' == $dbkey) { return false; } if (false !== strpos($dbkey, UTF8_REPLACEMENT)) { # Contained illegal UTF-8 sequences or forbidden Unicode chars. return false; } $this->mDbkeyform = $dbkey; # Initial colon indicates main namespace rather than specified default # but should not create invalid {ns,title} pairs such as {0,Project:Foo} if (':' == $dbkey[0]) { $this->mNamespace = NS_MAIN; $dbkey = substr($dbkey, 1); # remove the colon but continue processing $dbkey = trim($dbkey, '-'); # remove any subsequent whitespace } # Namespace or interwiki prefix $firstPass = true; do { $m = array(); if (preg_match("/^(.+?)_*:_*(.*)\$/S", $dbkey, $m)) { $p = $m[1]; if ($ns = $wgContLang->getNsIndex($p)) { # Ordinary namespace $dbkey = $m[2]; $this->mNamespace = $ns; } elseif ($this->getInterwikiLink($p)) { if (!$firstPass) { # Can't make a local interwiki link to an interwiki link. # That's just crazy! return false; } # Interwiki link $dbkey = $m[2]; $this->mInterwiki = $wgContLang->lc($p); # Redundant interwiki prefix to the local wiki if (0 == strcasecmp($this->mInterwiki, $wgLocalInterwiki)) { if ($dbkey == '') { # Can't have an empty self-link return false; } $this->mInterwiki = ''; $firstPass = false; # Do another namespace split... continue; } # If there's an initial colon after the interwiki, that also # resets the default namespace if ($dbkey !== '' && $dbkey[0] == ':') { $this->mNamespace = NS_MAIN; $dbkey = substr($dbkey, 1); } } # If there's no recognized interwiki or namespace, # then let the colon expression be part of the title. } break; } while (true); # We already know that some pages won't be in the database! # if ('' != $this->mInterwiki || NS_SPECIAL == $this->mNamespace) { $this->mArticleID = 0; } $fragment = strstr($dbkey, '#'); if (false !== $fragment) { $this->setFragment($fragment); $dbkey = substr($dbkey, 0, strlen($dbkey) - strlen($fragment)); # remove whitespace again: prevents "Foo_bar_#" # becoming "Foo_bar_" $dbkey = preg_replace('/_*$/', '', $dbkey); } # Reject illegal characters. # if (preg_match($rxTc, $dbkey)) { return false; } /** * Pages with "/./" or "/../" appearing in the URLs will * often be unreachable due to the way web browsers deal * with 'relative' URLs. Forbid them explicitly. */ if (strpos($dbkey, '.') !== false && ($dbkey === '.' || $dbkey === '..' || strpos($dbkey, './') === 0 || strpos($dbkey, '../') === 0 || strpos($dbkey, '/./') !== false || strpos($dbkey, '/../') !== false || substr($dbkey, -2) == '/.' || substr($dbkey, -3) == '/..')) { return false; } /** * Magic tilde sequences? Nu-uh! */ if (strpos($dbkey, '~~~') !== false) { return false; } /** * Limit the size of titles to 255 bytes. * This is typically the size of the underlying database field. * We make an exception for special pages, which don't need to be stored * in the database, and may edge over 255 bytes due to subpage syntax * for long titles, e.g. [[Special:Block/Long name]] */ if ($this->mNamespace != NS_SPECIAL && strlen($dbkey) > 255 || strlen($dbkey) > 512) { return false; } /** * Normally, all wiki links are forced to have * an initial capital letter so [[foo]] and [[Foo]] * point to the same place. * * Don't force it for interwikis, since the other * site might be case-sensitive. */ $this->mUserCaseDBKey = $dbkey; // INTL: By default, capitalize first letter of titles with namespace of NS_MEDIAWIKI. A little bit of a hack // to get around the fact that we set wgCapitalLinks to false to international sites. We do this because not all // languages capitalize the first letter of a title if ($this->mNamespace == NS_MEDIAWIKI || $wgCapitalLinks && $this->mInterwiki == '') { $dbkey = $wgContLang->ucfirst($dbkey); } /** * Can't make a link to a namespace alone... * "empty" local links can only be self-links * with a fragment identifier. */ if ($dbkey == '' && $this->mInterwiki == '' && $this->mNamespace != NS_MAIN) { return false; } // Allow IPv6 usernames to start with '::' by canonicalizing IPv6 titles. // IP names are not allowed for accounts, and can only be referring to // edits from the IP. Given '::' abbreviations and caps/lowercaps, // there are numerous ways to present the same IP. Having sp:contribs scan // them all is silly and having some show the edits and others not is // inconsistent. Same for talk/userpages. Keep them normalized instead. $dbkey = $this->mNamespace == NS_USER || $this->mNamespace == NS_USER_TALK ? IP::sanitizeIP($dbkey) : $dbkey; // Any remaining initial :s are illegal. if ($dbkey !== '' && ':' == $dbkey[0]) { return false; } # Fill fields $this->mDbkeyform = $dbkey; $this->mUrlform = wfUrlencode($dbkey); //XXCHANGED $this->mTextform = str_replace('-', ' ', $dbkey); return true; }
/** * Get the user name, or the IP for anons */ function getName() { if (!$this->mDataLoaded && $this->mFrom == 'name') { # Special case optimisation return $this->mName; } else { $this->load(); if ($this->mName === false) { # Clean up IPs $this->mName = IP::sanitizeIP(wfGetIP()); } return $this->mName; } }
/** * From an existing Block, get the target and the type of target. * Note that, except for null, it is always safe to treat the target * as a string; for User objects this will return User::__toString() * which in turn gives User::getName(). * * @param string|int|User|null $target * @return array( User|String|null, Block::TYPE_ constant|null ) */ public static function parseTarget($target) { # We may have been through this before if ($target instanceof User) { if (IP::isValid($target->getName())) { return array($target, self::TYPE_IP); } else { return array($target, self::TYPE_USER); } } elseif ($target === null) { return array(null, null); } $target = trim($target); if (IP::isValid($target)) { # We can still create a User if it's an IP address, but we need to turn # off validation checking (which would exclude IP addresses) return array(User::newFromName(IP::sanitizeIP($target), false), Block::TYPE_IP); } elseif (IP::isValidBlock($target)) { # Can't create a User from an IP range return array(IP::sanitizeRange($target), Block::TYPE_RANGE); } # Consider the possibility that this is not a username at all # but actually an old subpage (bug #29797) if (strpos($target, '/') !== false) { # An old subpage, drill down to the user behind it $parts = explode('/', $target); $target = $parts[0]; } $userObj = User::newFromName($target); if ($userObj instanceof User) { # Note that since numbers are valid usernames, a $target of "12345" will be # considered a User. If you want to pass a block ID, prepend a hash "#12345", # since hash characters are not valid in usernames or titles generally. return array($userObj, Block::TYPE_USER); } elseif (preg_match('/^#\\d+$/', $target)) { # Autoblock reference in the form "#12345" return array(substr($target, 1), Block::TYPE_AUTO); } else { # WTF? return array(null, null); } }
/** * * @global OutputPage $wgOut * @param string $action * @param PonyDocsProduct $product * @param mixed $manual PonyDocsManual or NULL */ private function processImportForm($action, $product, $manual) { global $wgOut, $wgUser; $importer = new PonyDocsStaticDocImporter(PONYDOCS_STATIC_DIR); if (isset($_POST['version']) && isset($_POST['product']) && (is_null($manual) || isset($_POST['manual']))) { switch ($action) { case "add": if (PonyDocsProductVersion::IsVersion($_POST['product'], $_POST['version'])) { $wgOut->addHTML('<h3>Results of Import</h3>'); // Okay, let's make sure we have file provided if (!isset($_FILES['archivefile']) || $_FILES['archivefile']['error'] != 0) { $wgOut->addHTML('There was a problem using your uploaded file. Make sure you uploaded a file and try again.'); } else { try { if (is_null($manual)) { $importer->importFile($_FILES['archivefile']['tmp_name'], $_POST['product'], $_POST['version']); $wgOut->addHTML("Success: imported archive for {$_POST['product']} version {$_POST['version']}"); } else { $importer->importFile($_FILES['archivefile']['tmp_name'], $_POST['product'], $_POST['version'], $_POST['manual']); $wgOut->addHTML("Success: imported archive for {$_POST['product']} version {$_POST['version']}" . " manual {$_POST['manual']}"); } } catch (Exception $e) { $wgOut->addHTML('Error: ' . $e->getMessage()); error_log('WARNING [ponydocs] [staticdocs] [' . __METHOD__ . '] action="add" status="error"' . ' message="' . addcslashes($e->getMessage(), '"') . '"'); } } } break; case "remove": //Loading product versions for WEB-10732 PonyDocsProductVersion::LoadVersionsForProduct($_POST['product']); if (PonyDocsProductVersion::IsVersion($_POST['product'], $_POST['version'])) { $wgOut->addHTML('<h3>Results of Deletion</h3>'); try { if (is_null($manual)) { $importer->removeVersion($_POST['product'], $_POST['version']); $wgOut->addHTML("Successfully deleted {$_POST['product']} version {$_POST['version']}"); } else { $importer->removeVersion($_POST['product'], $_POST['version'], $_POST['manual']); $wgOut->addHTML("Successfully deleted {$_POST['product']} version {$_POST['version']}" . " manual {$_POST['manual']}"); } } catch (Exception $e) { $wgOut->addHTML('Error: ' . $e->getMessage()); error_log('WARNING [ponydocs] [staticdocs] [' . __METHOD__ . '] action="remove" status="error"' . ' message="' . addcslashes($e->getMessage(), '"') . '"'); } } else { $wgOut->addHTML("Error: Version {$_POST['version']} does not exist, or is not accessible"); error_log('WARNING [ponydocs] [staticdocs] [' . __METHOD__ . '] action="remove" status="error"' . ' message="version ' . $_POST['version'] . ' does not exist, or is not accessible"' . ' username="******"' . ' ip="' . IP::sanitizeIP(wfGetIP()) . '"'); } break; } $this->clearProductCache($_POST['product'], $_POST['version']); } }
protected function addXffBlocks() { static $inited = false; if ($inited) { return; } $inited = true; $blockList = array(array('target' => '70.2.0.0/16', 'type' => Block::TYPE_RANGE, 'desc' => 'Range Hardblock', 'ACDisable' => false, 'isHardblock' => true, 'isAutoBlocking' => false), array('target' => '2001:4860:4001::/48', 'type' => Block::TYPE_RANGE, 'desc' => 'Range6 Hardblock', 'ACDisable' => false, 'isHardblock' => true, 'isAutoBlocking' => false), array('target' => '60.2.0.0/16', 'type' => Block::TYPE_RANGE, 'desc' => 'Range Softblock with AC Disabled', 'ACDisable' => true, 'isHardblock' => false, 'isAutoBlocking' => false), array('target' => '50.2.0.0/16', 'type' => Block::TYPE_RANGE, 'desc' => 'Range Softblock', 'ACDisable' => false, 'isHardblock' => false, 'isAutoBlocking' => false), array('target' => '50.1.1.1', 'type' => Block::TYPE_IP, 'desc' => 'Exact Softblock', 'ACDisable' => false, 'isHardblock' => false, 'isAutoBlocking' => false)); foreach ($blockList as $insBlock) { $target = $insBlock['target']; if ($insBlock['type'] === Block::TYPE_IP) { $target = User::newFromName(IP::sanitizeIP($target), false)->getName(); } elseif ($insBlock['type'] === Block::TYPE_RANGE) { $target = IP::sanitizeRange($target); } $block = new Block(); $block->setTarget($target); $block->setBlocker('testblocker@global'); $block->mReason = $insBlock['desc']; $block->mExpiry = 'infinity'; $block->prevents('createaccount', $insBlock['ACDisable']); $block->isHardblock($insBlock['isHardblock']); $block->isAutoblocking($insBlock['isAutoBlocking']); $block->insert(); } }
public function renameIPAddress() { wfProfileIn(__METHOD__); if (!$this->checkRequest()) { wfProfileOut(__METHOD__); return; } $ipAddr = $this->request->getVal('user'); if (!IP::isIPAddress($ipAddr)) { $this->response->setVal('success', false); $this->response->setVal('errorMsg', wfMessage('coppatool-invalid-ip')->plain()); wfProfileOut(__METHOD__); return; } $ipAddr = IP::sanitizeIP($ipAddr); $newIpAddr = '0.0.0.0'; $wikiIDs = RenameUserHelper::lookupIPActivity($ipAddr); $taskParams = ['requestor_id' => $this->wg->User->getID(), 'requestor_name' => $this->wg->User->getName(), 'rename_user_id' => 0, 'rename_old_name' => $ipAddr, 'rename_new_name' => $newIpAddr, 'rename_ip' => true, 'notify_renamed' => false, 'reason' => wfMessage('coppatool-reason')->plain()]; $task = (new UserRenameTask())->setPriority(\Wikia\Tasks\Queues\PriorityQueue::NAME); $task->call('renameUser', $wikiIDs, $taskParams); $taskID = $task->queue(); $this->response->setVal('success', true); $this->response->setVal('resultMsg', wfMessage('coppatool-rename-ip-success', $taskID)->plain()); wfProfileOut(__METHOD__); }
public function execute() { $params = $this->extractRequestParams(); $db = $this->getDB(); $prop = array_flip($params['prop']); $this->fld_ids = isset($prop['ids']); $this->fld_title = isset($prop['title']); $this->fld_type = isset($prop['type']); $this->fld_action = isset($prop['action']); $this->fld_user = isset($prop['user']); $this->fld_userid = isset($prop['userid']); $this->fld_timestamp = isset($prop['timestamp']); $this->fld_comment = isset($prop['comment']); $this->fld_parsedcomment = isset($prop['parsedcomment']); $this->fld_details = isset($prop['details']); $this->fld_tags = isset($prop['tags']); $hideLogs = LogEventsList::getExcludeClause($db, 'user', $this->getUser()); if ($hideLogs !== false) { $this->addWhere($hideLogs); } // Order is significant here $this->addTables(array('logging', 'user', 'page')); $this->addOption('STRAIGHT_JOIN'); $this->addJoinConds(array('user' => array('LEFT JOIN', 'user_id=log_user'), 'page' => array('LEFT JOIN', array('log_namespace=page_namespace', 'log_title=page_title')))); $this->addFields(array('log_type', 'log_action', 'log_timestamp', 'log_deleted')); $this->addFieldsIf(array('log_id', 'page_id'), $this->fld_ids); $this->addFieldsIf(array('log_user', 'log_user_text', 'user_name'), $this->fld_user); $this->addFieldsIf('log_user', $this->fld_userid); $this->addFieldsIf(array('log_namespace', 'log_title'), $this->fld_title || $this->fld_parsedcomment); $this->addFieldsIf('log_comment', $this->fld_comment || $this->fld_parsedcomment); $this->addFieldsIf('log_params', $this->fld_details); if ($this->fld_tags) { $this->addTables('tag_summary'); $this->addJoinConds(array('tag_summary' => array('LEFT JOIN', 'log_id=ts_log_id'))); $this->addFields('ts_tags'); } if (!is_null($params['tag'])) { $this->addTables('change_tag'); $this->addJoinConds(array('change_tag' => array('INNER JOIN', array('log_id=ct_log_id')))); $this->addWhereFld('ct_tag', $params['tag']); } if (!is_null($params['action'])) { list($type, $action) = explode('/', $params['action']); $this->addWhereFld('log_type', $type); $this->addWhereFld('log_action', $action); } elseif (!is_null($params['type'])) { $this->addWhereFld('log_type', $params['type']); } $this->addTimestampWhereRange('log_timestamp', $params['dir'], $params['start'], $params['end']); $limit = $params['limit']; $this->addOption('LIMIT', $limit + 1); $user = $params['user']; if (!is_null($user)) { $userid = User::idFromName($user); if ($userid) { $this->addWhereFld('log_user', $userid); } else { $this->addWhereFld('log_user_text', IP::sanitizeIP($user)); } } $title = $params['title']; if (!is_null($title)) { $titleObj = Title::newFromText($title); if (is_null($titleObj)) { $this->dieUsage("Bad title value '{$title}'", 'param_title'); } $this->addWhereFld('log_namespace', $titleObj->getNamespace()); $this->addWhereFld('log_title', $titleObj->getDBkey()); } $prefix = $params['prefix']; if (!is_null($prefix)) { global $wgMiserMode; if ($wgMiserMode) { $this->dieUsage('Prefix search disabled in Miser Mode', 'prefixsearchdisabled'); } $title = Title::newFromText($prefix); if (is_null($title)) { $this->dieUsage("Bad title value '{$prefix}'", 'param_prefix'); } $this->addWhereFld('log_namespace', $title->getNamespace()); $this->addWhere('log_title ' . $db->buildLike($title->getDBkey(), $db->anyString())); } // Paranoia: avoid brute force searches (bug 17342) if (!is_null($title) || !is_null($user)) { if (!$this->getUser()->isAllowed('deletedhistory')) { $titleBits = LogPage::DELETED_ACTION; $userBits = LogPage::DELETED_USER; } elseif (!$this->getUser()->isAllowed('suppressrevision')) { $titleBits = LogPage::DELETED_ACTION | LogPage::DELETED_RESTRICTED; $userBits = LogPage::DELETED_USER | LogPage::DELETED_RESTRICTED; } else { $titleBits = 0; $userBits = 0; } if (!is_null($title) && $titleBits) { $this->addWhere($db->bitAnd('log_deleted', $titleBits) . " != {$titleBits}"); } if (!is_null($user) && $userBits) { $this->addWhere($db->bitAnd('log_deleted', $userBits) . " != {$userBits}"); } } $count = 0; $res = $this->select(__METHOD__); $result = $this->getResult(); foreach ($res as $row) { if (++$count > $limit) { // We've reached the one extra which shows that there are // additional pages to be had. Stop here... $this->setContinueEnumParameter('start', wfTimestamp(TS_ISO_8601, $row->log_timestamp)); break; } $vals = $this->extractRowInfo($row); if (!$vals) { continue; } $fit = $result->addValue(array('query', $this->getModuleName()), null, $vals); if (!$fit) { $this->setContinueEnumParameter('start', wfTimestamp(TS_ISO_8601, $row->log_timestamp)); break; } } $result->setIndexedTagName_internal(array('query', $this->getModuleName()), 'item'); }
/** * Backend block code. * $userID and $expiry will be filled accordingly * @return array(message key, arguments) on failure, empty array on success */ function doBlock(&$userId = null, &$expiry = null) { global $wgUser, $wgSysopUserBans, $wgSysopRangeBans; $userId = 0; # Expand valid IPv6 addresses, usernames are left as is $this->BlockAddress = IP::sanitizeIP($this->BlockAddress); # isIPv4() and IPv6() are used for final validation $rxIP4 = '\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}'; $rxIP6 = '\\w{1,4}:\\w{1,4}:\\w{1,4}:\\w{1,4}:\\w{1,4}:\\w{1,4}:\\w{1,4}:\\w{1,4}'; $rxIP = "({$rxIP4}|{$rxIP6})"; # Check for invalid specifications if (!preg_match("/^{$rxIP}\$/", $this->BlockAddress)) { $matches = array(); if (preg_match("/^({$rxIP4})\\/(\\d{1,2})\$/", $this->BlockAddress, $matches)) { # IPv4 if ($wgSysopRangeBans) { if (!IP::isIPv4($this->BlockAddress) || $matches[2] < 16 || $matches[2] > 32) { return array('ip_range_invalid'); } $this->BlockAddress = Block::normaliseRange($this->BlockAddress); } else { # Range block illegal return array('range_block_disabled'); } } 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) { return array('ip_range_invalid'); } $this->BlockAddress = Block::normaliseRange($this->BlockAddress); } else { # Range block illegal return array('range_block_disabled'); } } else { # Username block if ($wgSysopUserBans) { $user = User::newFromName($this->BlockAddress); if (!is_null($user) && $user->getID()) { # Use canonical name $userId = $user->getID(); $this->BlockAddress = $user->getName(); } else { return array('nosuchusershort', htmlspecialchars($user ? $user->getName() : $this->BlockAddress)); } } else { return array('badipaddress'); } } } } $reasonstr = $this->BlockReasonList; if ($reasonstr != 'other' && $this->BlockReason != '') { // Entry from drop down menu + additional comment $reasonstr .= ': ' . $this->BlockReason; } elseif ($reasonstr == 'other') { $reasonstr = $this->BlockReason; } $expirestr = $this->BlockExpiry; if ($expirestr == 'other') { $expirestr = $this->BlockOther; } if (strlen($expirestr) == 0) { return array('ipb_expiry_invalid'); } if ($expirestr == 'infinite' || $expirestr == 'indefinite') { $expiry = Block::infinity(); } else { # Convert GNU-style date, on error returns -1 for PHP <5.1 and false for PHP >=5.1 $expiry = strtotime($expirestr); if ($expiry < 0 || $expiry === false) { return array('ipb_expiry_invalid'); } $expiry = wfTimestamp(TS_MW, $expiry); } # Create block # 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); if (wfRunHooks('BlockIp', array(&$block, &$wgUser))) { if (!$block->insert()) { return array('ipb_already_blocked', htmlspecialchars($this->BlockAddress)); } wfRunHooks('BlockIpComplete', array($block, $wgUser)); # 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 ? 'oversight' : 'block'; $log = new LogPage($log_type); $log->addEntry('block', Title::makeTitle(NS_USER, $this->BlockAddress), $reasonstr, $logParams); # Report to the user return array(); } else { return array('hookaborted'); } }
/** * Work out the IP address based on various globals * For trusted proxies, use the XFF client IP (first of the chain) * * @since 1.19 * * @throws MWException * @return string */ public function getIP() { global $wgUsePrivateIPs; # Return cached result if ( $this->ip !== null ) { return $this->ip; } # collect the originating ips $ip = $this->getRawIP(); # Append XFF $forwardedFor = $this->getHeader( 'X-Forwarded-For' ); if ( $forwardedFor !== false ) { $ipchain = array_map( 'trim', explode( ',', $forwardedFor ) ); $ipchain = array_reverse( $ipchain ); if ( $ip ) { array_unshift( $ipchain, $ip ); } # Step through XFF list and find the last address in the list which is a # trusted server. Set $ip to the IP address given by that trusted server, # unless the address is not sensible (e.g. private). However, prefer private # IP addresses over proxy servers controlled by this site (more sensible). foreach ( $ipchain as $i => $curIP ) { $curIP = IP::sanitizeIP( IP::canonicalize( $curIP ) ); if ( wfIsTrustedProxy( $curIP ) && isset( $ipchain[$i + 1] ) ) { if ( wfIsConfiguredProxy( $curIP ) || // bug 48919; treat IP as sane IP::isPublic( $ipchain[$i + 1] ) || $wgUsePrivateIPs ) { $nextIP = IP::canonicalize( $ipchain[$i + 1] ); if ( !$nextIP && wfIsConfiguredProxy( $ip ) ) { // We have not yet made it past CDN/proxy servers of this site, // so either they are misconfigured or there is some IP spoofing. throw new MWException( "Invalid IP given in XFF '$forwardedFor'." ); } $ip = $nextIP; continue; } } break; } } # Allow extensions to improve our guess wfRunHooks( 'GetIP', array( &$ip ) ); if ( !$ip ) { throw new MWException( "Unable to determine IP." ); } wfDebug( "IP: $ip\n" ); $this->ip = $ip; return $ip; }
public function execute() { $params = $this->extractRequestParams(); $db = $this->getDB(); $this->requireMaxOneParameter($params, 'title', 'prefix', 'namespace'); $prop = array_flip($params['prop']); $this->fld_ids = isset($prop['ids']); $this->fld_title = isset($prop['title']); $this->fld_type = isset($prop['type']); $this->fld_user = isset($prop['user']); $this->fld_userid = isset($prop['userid']); $this->fld_timestamp = isset($prop['timestamp']); $this->fld_comment = isset($prop['comment']); $this->fld_parsedcomment = isset($prop['parsedcomment']); $this->fld_details = isset($prop['details']); $this->fld_tags = isset($prop['tags']); $hideLogs = LogEventsList::getExcludeClause($db, 'user', $this->getUser()); if ($hideLogs !== false) { $this->addWhere($hideLogs); } // Order is significant here $this->addTables(array('logging', 'user', 'page')); $this->addJoinConds(array('user' => array('LEFT JOIN', 'user_id=log_user'), 'page' => array('LEFT JOIN', array('log_namespace=page_namespace', 'log_title=page_title')))); $this->addFields(array('log_id', 'log_type', 'log_action', 'log_timestamp', 'log_deleted')); $this->addFieldsIf('page_id', $this->fld_ids); // log_page is the page_id saved at log time, whereas page_id is from a // join at query time. This leads to different results in various // scenarios, e.g. deletion, recreation. $this->addFieldsIf('log_page', $this->fld_ids); $this->addFieldsIf(array('log_user', 'log_user_text', 'user_name'), $this->fld_user); $this->addFieldsIf('log_user', $this->fld_userid); $this->addFieldsIf(array('log_namespace', 'log_title'), $this->fld_title || $this->fld_parsedcomment); $this->addFieldsIf('log_comment', $this->fld_comment || $this->fld_parsedcomment); $this->addFieldsIf('log_params', $this->fld_details); if ($this->fld_tags) { $this->addTables('tag_summary'); $this->addJoinConds(array('tag_summary' => array('LEFT JOIN', 'log_id=ts_log_id'))); $this->addFields('ts_tags'); } if (!is_null($params['tag'])) { $this->addTables('change_tag'); $this->addJoinConds(array('change_tag' => array('INNER JOIN', array('log_id=ct_log_id')))); $this->addWhereFld('ct_tag', $params['tag']); } if (!is_null($params['action'])) { // Do validation of action param, list of allowed actions can contains wildcards // Allow the param, when the actions is in the list or a wildcard version is listed. $logAction = $params['action']; if (strpos($logAction, '/') === false) { // all items in the list have a slash $valid = false; } else { $logActions = array_flip($this->getAllowedLogActions()); list($type, $action) = explode('/', $logAction, 2); $valid = isset($logActions[$logAction]) || isset($logActions[$type . '/*']); } if (!$valid) { $valueName = $this->encodeParamName('action'); $this->dieUsage("Unrecognized value for parameter '{$valueName}': {$logAction}", "unknown_{$valueName}"); } $this->addWhereFld('log_type', $type); $this->addWhereFld('log_action', $action); } elseif (!is_null($params['type'])) { $this->addWhereFld('log_type', $params['type']); } $this->addTimestampWhereRange('log_timestamp', $params['dir'], $params['start'], $params['end']); // Include in ORDER BY for uniqueness $this->addWhereRange('log_id', $params['dir'], null, null); if (!is_null($params['continue'])) { $cont = explode('|', $params['continue']); $this->dieContinueUsageIf(count($cont) != 2); $op = $params['dir'] === 'newer' ? '>' : '<'; $continueTimestamp = $db->addQuotes($db->timestamp($cont[0])); $continueId = (int) $cont[1]; $this->dieContinueUsageIf($continueId != $cont[1]); $this->addWhere("log_timestamp {$op} {$continueTimestamp} OR " . "(log_timestamp = {$continueTimestamp} AND " . "log_id {$op}= {$continueId})"); } $limit = $params['limit']; $this->addOption('LIMIT', $limit + 1); $user = $params['user']; if (!is_null($user)) { $userid = User::idFromName($user); if ($userid) { $this->addWhereFld('log_user', $userid); } else { $this->addWhereFld('log_user_text', IP::sanitizeIP($user)); } } $title = $params['title']; if (!is_null($title)) { $titleObj = Title::newFromText($title); if (is_null($titleObj)) { $this->dieUsage("Bad title value '{$title}'", 'param_title'); } $this->addWhereFld('log_namespace', $titleObj->getNamespace()); $this->addWhereFld('log_title', $titleObj->getDBkey()); } if ($params['namespace'] !== null) { $this->addWhereFld('log_namespace', $params['namespace']); } $prefix = $params['prefix']; if (!is_null($prefix)) { if ($this->getConfig()->get('MiserMode')) { $this->dieUsage('Prefix search disabled in Miser Mode', 'prefixsearchdisabled'); } $title = Title::newFromText($prefix); if (is_null($title)) { $this->dieUsage("Bad title value '{$prefix}'", 'param_prefix'); } $this->addWhereFld('log_namespace', $title->getNamespace()); $this->addWhere('log_title ' . $db->buildLike($title->getDBkey(), $db->anyString())); } // Paranoia: avoid brute force searches (bug 17342) if ($params['namespace'] !== null || !is_null($title) || !is_null($user)) { if (!$this->getUser()->isAllowed('deletedhistory')) { $titleBits = LogPage::DELETED_ACTION; $userBits = LogPage::DELETED_USER; } elseif (!$this->getUser()->isAllowedAny('suppressrevision', 'viewsuppressed')) { $titleBits = LogPage::DELETED_ACTION | LogPage::DELETED_RESTRICTED; $userBits = LogPage::DELETED_USER | LogPage::DELETED_RESTRICTED; } else { $titleBits = 0; $userBits = 0; } if (($params['namespace'] !== null || !is_null($title)) && $titleBits) { $this->addWhere($db->bitAnd('log_deleted', $titleBits) . " != {$titleBits}"); } if (!is_null($user) && $userBits) { $this->addWhere($db->bitAnd('log_deleted', $userBits) . " != {$userBits}"); } } $count = 0; $res = $this->select(__METHOD__); $result = $this->getResult(); foreach ($res as $row) { if (++$count > $limit) { // We've reached the one extra which shows that there are // additional pages to be had. Stop here... $this->setContinueEnumParameter('continue', "{$row->log_timestamp}|{$row->log_id}"); break; } $vals = $this->extractRowInfo($row); $fit = $result->addValue(array('query', $this->getModuleName()), null, $vals); if (!$fit) { $this->setContinueEnumParameter('continue', "{$row->log_timestamp}|{$row->log_id}"); break; } } $result->addIndexedTagName(array('query', $this->getModuleName()), 'item'); }
/** * Get the user name, or the IP of an anonymous user * @return String User's name or IP address */ public function getName() { if ($this->isItemLoaded('name', 'only')) { # Special case optimisation return $this->mName; } else { $this->load(); if ($this->mName === false) { # Clean up IPs $this->mName = IP::sanitizeIP($this->getRequest()->getIP()); } return $this->mName; } }
public function execute() { $user = $this->getUser(); $errors = $this->getTitle()->getUserPermissionsErrors('abusefilter-log', $user); if (count($errors)) { $this->dieUsageMsg($errors[0]); return; } $params = $this->extractRequestParams(); $prop = array_flip($params['prop']); $fld_ids = isset($prop['ids']); $fld_filter = isset($prop['filter']); $fld_user = isset($prop['user']); $fld_ip = isset($prop['ip']); $fld_title = isset($prop['title']); $fld_action = isset($prop['action']); $fld_details = isset($prop['details']); $fld_result = isset($prop['result']); $fld_timestamp = isset($prop['timestamp']); $fld_hidden = isset($prop['hidden']); $fld_revid = isset($prop['revid']); if ($fld_ip && !$user->isAllowed('abusefilter-private')) { $this->dieUsage('You don\'t have permission to view IP addresses', 'permissiondenied'); } if ($fld_details && !$user->isAllowed('abusefilter-log-detail')) { $this->dieUsage('You don\'t have permission to view detailed abuse log entries', 'permissiondenied'); } // Match permissions for viewing events on private filters to SpecialAbuseLog (bug 42814) if ($params['filter'] && !(AbuseFilterView::canViewPrivate() || $user->isAllowed('abusefilter-log-private'))) { // A specific filter parameter is set but the user isn't allowed to view all filters if (!is_array($params['filter'])) { $params['filter'] = array($params['filter']); } foreach ($params['filter'] as $filter) { if (AbuseFilter::filterHidden($filter)) { $this->dieUsage('You don\'t have permission to view log entries for private filters', 'permissiondenied'); } } } $result = $this->getResult(); $this->addTables('abuse_filter_log'); $this->addFields('afl_timestamp'); $this->addFields('afl_rev_id'); $this->addFields('afl_deleted'); $this->addFields('afl_filter'); $this->addFieldsIf('afl_id', $fld_ids); $this->addFieldsIf('afl_user_text', $fld_user); $this->addFieldsIf('afl_ip', $fld_ip); $this->addFieldsIf(array('afl_namespace', 'afl_title'), $fld_title); $this->addFieldsIf('afl_action', $fld_action); $this->addFieldsIf('afl_var_dump', $fld_details); $this->addFieldsIf('afl_actions', $fld_result); if ($fld_filter) { $this->addTables('abuse_filter'); $this->addFields('af_public_comments'); $this->addJoinConds(array('abuse_filter' => array('LEFT JOIN', 'af_id=afl_filter'))); } $this->addOption('LIMIT', $params['limit'] + 1); $this->addWhereRange('afl_timestamp', $params['dir'], $params['start'], $params['end']); $db = $this->getDB(); $notDeletedCond = SpecialAbuseLog::getNotDeletedCond($db); if (isset($params['user'])) { $u = User::newFromName($params['user']); if ($u) { // Username normalisation $params['user'] = $u->getName(); $userId = $u->getId(); } elseif (IP::isIPAddress($params['user'])) { // It's an IP, sanitize it $params['user'] = IP::sanitizeIP($params['user']); $userId = 0; } if (isset($userId)) { // Only add the WHERE for user in case it's either a valid user (but not necessary an existing one) or an IP $this->addWhere(array('afl_user' => $userId, 'afl_user_text' => $params['user'])); } } $this->addWhereIf(array('afl_filter' => $params['filter']), isset($params['filter'])); $this->addWhereIf($notDeletedCond, !SpecialAbuseLog::canSeeHidden($user)); $title = $params['title']; if (!is_null($title)) { $titleObj = Title::newFromText($title); if (is_null($titleObj)) { $this->dieUsageMsg(array('invalidtitle', $title)); } $this->addWhereFld('afl_namespace', $titleObj->getNamespace()); $this->addWhereFld('afl_title', $titleObj->getDBkey()); } $res = $this->select(__METHOD__); $count = 0; foreach ($res as $row) { if (++$count > $params['limit']) { // We've had enough $ts = new MWTimestamp($row->afl_timestamp); $this->setContinueEnumParameter('start', $ts->getTimestamp(TS_ISO_8601)); break; } if (SpecialAbuseLog::isHidden($row) && !SpecialAbuseLog::canSeeHidden($user)) { continue; } $canSeeDetails = SpecialAbuseLog::canSeeDetails($row->afl_filter); $entry = array(); if ($fld_ids) { $entry['id'] = intval($row->afl_id); $entry['filter_id'] = ''; if ($canSeeDetails) { $entry['filter_id'] = $row->afl_filter; } } if ($fld_filter) { $entry['filter'] = $row->af_public_comments; } if ($fld_user) { $entry['user'] = $row->afl_user_text; } if ($fld_ip) { $entry['ip'] = $row->afl_ip; } if ($fld_title) { $title = Title::makeTitle($row->afl_namespace, $row->afl_title); ApiQueryBase::addTitleInfo($entry, $title); } if ($fld_action) { $entry['action'] = $row->afl_action; } if ($fld_result) { $entry['result'] = $row->afl_actions; } if ($fld_revid && !is_null($row->afl_rev_id)) { $entry['revid'] = ''; if ($canSeeDetails) { $entry['revid'] = $row->afl_rev_id; } } if ($fld_timestamp) { $ts = new MWTimestamp($row->afl_timestamp); $entry['timestamp'] = $ts->getTimestamp(TS_ISO_8601); } if ($fld_details) { $entry['details'] = array(); if ($canSeeDetails) { $vars = AbuseFilter::loadVarDump($row->afl_var_dump); if ($vars instanceof AbuseFilterVariableHolder) { $entry['details'] = $vars->exportAllVars(); } else { $entry['details'] = array_change_key_case($vars, CASE_LOWER); } } } if ($fld_hidden) { $val = SpecialAbuseLog::isHidden($row); if ($val) { $entry['hidden'] = $val; } } if ($entry) { $fit = $result->addValue(array('query', $this->getModuleName()), null, $entry); if (!$fit) { $ts = new MWTimestamp($row->afl_timestamp); $this->setContinueEnumParameter('start', $ts->getTimestamp(TS_ISO_8601)); break; } } } $result->setIndexedTagName_internal(array('query', $this->getModuleName()), 'item'); }
/** * Handler for non-standard (edit/log) entries that need IP data * * @param $context IContextSource * @param $data Array * @return bool */ protected static function onLoggableUserIPData(IContextSource $context, array $data) { $user = $context->getUser(); $request = $context->getRequest(); // Get IP address $ip = $request->getIP(); // Get XFF header $xff = $request->getHeader('X-Forwarded-For'); list($xff_ip, $isSquidOnly) = IP::getClientIPfromXFF($xff); // Get agent $agent = $request->getHeader('User-Agent'); $dbw = wfGetDB(DB_MASTER); $cuc_id = $dbw->nextSequenceValue('cu_changes_cu_id_seq'); $rcRow = array('cuc_id' => $cuc_id, 'cuc_page_id' => $data['pageid'], 'cuc_namespace' => $data['namespace'], 'cuc_title' => $data['title'], 'cuc_minor' => 0, 'cuc_user' => $user->getId(), 'cuc_user_text' => $user->getName(), 'cuc_actiontext' => $data['action'], 'cuc_comment' => $data['comment'], 'cuc_this_oldid' => 0, 'cuc_last_oldid' => 0, 'cuc_type' => RC_LOG, 'cuc_timestamp' => $dbw->timestamp($data['timestamp']), 'cuc_ip' => IP::sanitizeIP($ip), 'cuc_ip_hex' => $ip ? IP::toHex($ip) : null, 'cuc_xff' => !$isSquidOnly ? $xff : '', 'cuc_xff_hex' => $xff_ip && !$isSquidOnly ? IP::toHex($xff_ip) : null, 'cuc_agent' => $agent); $dbw->insert('cu_changes', $rcRow, __METHOD__); return true; }
/** * Work out the IP address based on various globals * For trusted proxies, use the XFF client IP (first of the chain) * * @since 1.19 * * @throws MWException * @return string */ public function getIP() { global $wgUsePrivateIPs; # Return cached result if ($this->ip !== null) { return $this->ip; } # collect the originating ips $ip = $this->getRawIP(); if (!$ip) { throw new MWException('Unable to determine IP.'); } # Append XFF $forwardedFor = $this->getHeader('X-Forwarded-For'); if ($forwardedFor !== false) { $isConfigured = IP::isConfiguredProxy($ip); $ipchain = array_map('trim', explode(',', $forwardedFor)); $ipchain = array_reverse($ipchain); array_unshift($ipchain, $ip); # Step through XFF list and find the last address in the list which is a # trusted server. Set $ip to the IP address given by that trusted server, # unless the address is not sensible (e.g. private). However, prefer private # IP addresses over proxy servers controlled by this site (more sensible). # Note that some XFF values might be "unknown" with Squid/Varnish. foreach ($ipchain as $i => $curIP) { $curIP = IP::sanitizeIP(IP::canonicalize($curIP)); if (!$curIP || !isset($ipchain[$i + 1]) || $ipchain[$i + 1] === 'unknown' || !IP::isTrustedProxy($curIP)) { break; // IP is not valid/trusted or does not point to anything } if (IP::isPublic($ipchain[$i + 1]) || $wgUsePrivateIPs || IP::isConfiguredProxy($curIP)) { // Follow the next IP according to the proxy $nextIP = IP::canonicalize($ipchain[$i + 1]); if (!$nextIP && $isConfigured) { // We have not yet made it past CDN/proxy servers of this site, // so either they are misconfigured or there is some IP spoofing. throw new MWException("Invalid IP given in XFF '{$forwardedFor}'."); } $ip = $nextIP; // keep traversing the chain continue; } break; } } # Allow extensions to improve our guess Hooks::run('GetIP', array(&$ip)); if (!$ip) { throw new MWException("Unable to determine IP."); } wfDebug("IP: {$ip}\n"); $this->ip = $ip; return $ip; }
private function constructAttempt($alldata) { $user = $this->getUser(); $epm['epo_user_id'] = $user->getId(); $epm['epm_date_message'] = date("Y-m-d H:i:s"); $epm['epo_amount'] = $epm['epo_amount_bank_format'] = number_format($alldata['amount'], 2, '.', ''); #How much? $epm['epo_currency'] = 'EUR'; #Of what $epm['epo_mail'] = $user->getEmail(); if ($epm['epo_mail'] == '') { $epm['epo_mail'] = $alldata['mail']; } $epm['epm_ip'] = IP::sanitizeIP(wfGetIP()); $epm['epo_language'] = $this->assignEPTLanguage(); $epm['epo_status'] = 'PE'; return EPMessage::create('out', $epm); }
/** * Given a string range in a number of formats, return the * start and end of the range in hexadecimal. For IPv6. * * Formats are: * 2001:0db8:85a3::7344/96 CIDR * 2001:0db8:85a3::7344 - 2001:0db8:85a3::7344 Explicit range * 2001:0db8:85a3::7344/96 Single IP * * @param string $range * * @return array(string, string) */ private static function parseRange6($range) { # Expand any IPv6 IP $range = IP::sanitizeIP($range); // CIDR notation... if (strpos($range, '/') !== false) { list($network, $bits) = self::parseCIDR6($range); if ($network === false) { $start = $end = false; } else { $start = Wikimedia\base_convert($network, 10, 16, 32, false); # Turn network to binary (again) $end = Wikimedia\base_convert($network, 10, 2, 128); # Truncate the last (128-$bits) bits and replace them with ones $end = str_pad(substr($end, 0, $bits), 128, 1, STR_PAD_RIGHT); # Convert to hex $end = Wikimedia\base_convert($end, 2, 16, 32, false); # see toHex() comment $start = "v6-{$start}"; $end = "v6-{$end}"; } // Explicit range notation... } elseif (strpos($range, '-') !== false) { list($start, $end) = array_map('trim', explode('-', $range, 2)); $start = self::toHex($start); $end = self::toHex($end); if ($start > $end) { $start = $end = false; } } else { # Single IP $start = $end = self::toHex($range); } if ($start === false || $end === false) { return array(false, false); } else { return array($start, $end); } }
/** * @covers IP::sanitizeIP * @dataProvider provideSanitizeIP */ public function testSanitizeIP($expected, $input) { $result = IP::sanitizeIP($input); $this->assertEquals($expected, $result); }
/** * Improve IP::sanitizeIP() code coverage * @todo Most probably incomplete */ public function testSanitizeIP() { $this->assertNull(IP::sanitizeIP('')); $this->assertNull(IP::sanitizeIP(' ')); }
/** * Normalizes and splits a title string. * * This function removes illegal characters, splits off the interwiki and * namespace prefixes, sets the other forms, and canonicalizes * everything. * * @todo this method is only exposed as a temporary measure to ease refactoring. * It was copied with minimal changes from Title::secureAndSplit(). * * @todo This method should be split up and an appropriate interface * defined for use by the Title class. * * @param string $text * @param int $defaultNamespace * * @throws MalformedTitleException If $text is not a valid title string. * @return array A mapp with the fields 'interwiki', 'fragment', 'namespace', * 'user_case_dbkey', and 'dbkey'. */ public function splitTitleString($text, $defaultNamespace = NS_MAIN) { $dbkey = str_replace(' ', '_', $text); # Initialisation $parts = array('interwiki' => '', 'local_interwiki' => false, 'fragment' => '', 'namespace' => $defaultNamespace, 'dbkey' => $dbkey, 'user_case_dbkey' => $dbkey); # Strip Unicode bidi override characters. # Sometimes they slip into cut-n-pasted page titles, where the # override chars get included in list displays. $dbkey = preg_replace('/\\xE2\\x80[\\x8E\\x8F\\xAA-\\xAE]/S', '', $dbkey); # Clean up whitespace # Note: use of the /u option on preg_replace here will cause # input with invalid UTF-8 sequences to be nullified out in PHP 5.2.x, # conveniently disabling them. $dbkey = preg_replace('/[ _\\xA0\\x{1680}\\x{180E}\\x{2000}-\\x{200A}\\x{2028}\\x{2029}\\x{202F}\\x{205F}\\x{3000}]+/u', '_', $dbkey); $dbkey = trim($dbkey, '_'); if (strpos($dbkey, UtfNormal\Constants::UTF8_REPLACEMENT) !== false) { # Contained illegal UTF-8 sequences or forbidden Unicode chars. throw new MalformedTitleException('title-invalid-utf8', $text); } $parts['dbkey'] = $dbkey; # Initial colon indicates main namespace rather than specified default # but should not create invalid {ns,title} pairs such as {0,Project:Foo} if ($dbkey !== '' && ':' == $dbkey[0]) { $parts['namespace'] = NS_MAIN; $dbkey = substr($dbkey, 1); # remove the colon but continue processing $dbkey = trim($dbkey, '_'); # remove any subsequent whitespace } if ($dbkey == '') { throw new MalformedTitleException('title-invalid-empty', $text); } # Namespace or interwiki prefix $prefixRegexp = "/^(.+?)_*:_*(.*)\$/S"; do { $m = array(); if (preg_match($prefixRegexp, $dbkey, $m)) { $p = $m[1]; if (($ns = $this->language->getNsIndex($p)) !== false) { # Ordinary namespace $dbkey = $m[2]; $parts['namespace'] = $ns; # For Talk:X pages, check if X has a "namespace" prefix if ($ns == NS_TALK && preg_match($prefixRegexp, $dbkey, $x)) { if ($this->language->getNsIndex($x[1])) { # Disallow Talk:File:x type titles... throw new MalformedTitleException('title-invalid-talk-namespace', $text); } elseif (Interwiki::isValidInterwiki($x[1])) { // TODO: get rid of global state! # Disallow Talk:Interwiki:x type titles... throw new MalformedTitleException('title-invalid-talk-namespace', $text); } } } elseif (Interwiki::isValidInterwiki($p)) { # Interwiki link $dbkey = $m[2]; $parts['interwiki'] = $this->language->lc($p); # Redundant interwiki prefix to the local wiki foreach ($this->localInterwikis as $localIW) { if (0 == strcasecmp($parts['interwiki'], $localIW)) { if ($dbkey == '') { # Empty self-links should point to the Main Page, to ensure # compatibility with cross-wiki transclusions and the like. $mainPage = Title::newMainPage(); return array('interwiki' => $mainPage->getInterwiki(), 'local_interwiki' => true, 'fragment' => $mainPage->getFragment(), 'namespace' => $mainPage->getNamespace(), 'dbkey' => $mainPage->getDBkey(), 'user_case_dbkey' => $mainPage->getUserCaseDBKey()); } $parts['interwiki'] = ''; # local interwikis should behave like initial-colon links $parts['local_interwiki'] = true; # Do another namespace split... continue 2; } } # If there's an initial colon after the interwiki, that also # resets the default namespace if ($dbkey !== '' && $dbkey[0] == ':') { $parts['namespace'] = NS_MAIN; $dbkey = substr($dbkey, 1); } } # If there's no recognized interwiki or namespace, # then let the colon expression be part of the title. } break; } while (true); $fragment = strstr($dbkey, '#'); if (false !== $fragment) { $parts['fragment'] = str_replace('_', ' ', substr($fragment, 1)); $dbkey = substr($dbkey, 0, strlen($dbkey) - strlen($fragment)); # remove whitespace again: prevents "Foo_bar_#" # becoming "Foo_bar_" $dbkey = preg_replace('/_*$/', '', $dbkey); } # Reject illegal characters. $rxTc = self::getTitleInvalidRegex(); $matches = array(); if (preg_match($rxTc, $dbkey, $matches)) { throw new MalformedTitleException('title-invalid-characters', $text, array($matches[0])); } # Pages with "/./" or "/../" appearing in the URLs will often be un- # reachable due to the way web browsers deal with 'relative' URLs. # Also, they conflict with subpage syntax. Forbid them explicitly. if (strpos($dbkey, '.') !== false && ($dbkey === '.' || $dbkey === '..' || strpos($dbkey, './') === 0 || strpos($dbkey, '../') === 0 || strpos($dbkey, '/./') !== false || strpos($dbkey, '/../') !== false || substr($dbkey, -2) == '/.' || substr($dbkey, -3) == '/..')) { throw new MalformedTitleException('title-invalid-relative', $text); } # Magic tilde sequences? Nu-uh! if (strpos($dbkey, '~~~') !== false) { throw new MalformedTitleException('title-invalid-magic-tilde', $text); } # Limit the size of titles to 255 bytes. This is typically the size of the # underlying database field. We make an exception for special pages, which # don't need to be stored in the database, and may edge over 255 bytes due # to subpage syntax for long titles, e.g. [[Special:Block/Long name]] $maxLength = $parts['namespace'] != NS_SPECIAL ? 255 : 512; if (strlen($dbkey) > $maxLength) { throw new MalformedTitleException('title-invalid-too-long', $text, array(Message::numParam($maxLength))); } # Normally, all wiki links are forced to have an initial capital letter so [[foo]] # and [[Foo]] point to the same place. Don't force it for interwikis, since the # other site might be case-sensitive. $parts['user_case_dbkey'] = $dbkey; if ($parts['interwiki'] === '') { $dbkey = Title::capitalize($dbkey, $parts['namespace']); } # Can't make a link to a namespace alone... "empty" local links can only be # self-links with a fragment identifier. if ($dbkey == '' && $parts['interwiki'] === '') { if ($parts['namespace'] != NS_MAIN) { throw new MalformedTitleException('title-invalid-empty', $text); } } // Allow IPv6 usernames to start with '::' by canonicalizing IPv6 titles. // IP names are not allowed for accounts, and can only be referring to // edits from the IP. Given '::' abbreviations and caps/lowercaps, // there are numerous ways to present the same IP. Having sp:contribs scan // them all is silly and having some show the edits and others not is // inconsistent. Same for talk/userpages. Keep them normalized instead. if ($parts['namespace'] == NS_USER || $parts['namespace'] == NS_USER_TALK) { $dbkey = IP::sanitizeIP($dbkey); } // Any remaining initial :s are illegal. if ($dbkey !== '' && ':' == $dbkey[0]) { throw new MalformedTitleException('title-invalid-leading-colon', $text); } # Fill fields $parts['dbkey'] = $dbkey; return $parts; }
/** * Set the log reader to return only entries by the given user. * * @param string $name (In)valid user name * @return void */ private function limitPerformer($name) { if ($name == '') { return; } $usertitle = Title::makeTitleSafe(NS_USER, $name); if (is_null($usertitle)) { return; } /* Fetch userid at first, if known, provides awesome query plan afterwards */ $userid = User::idFromName($name); if (!$userid) { $this->mConds['log_user_text'] = IP::sanitizeIP($name); } else { $this->mConds['log_user'] = $userid; } // Paranoia: avoid brute force searches (bug 17342) $user = $this->getUser(); if (!$user->isAllowed('deletedhistory')) { $this->mConds[] = $this->mDb->bitAnd('log_deleted', LogPage::DELETED_USER) . ' = 0'; } elseif (!$user->isAllowedAny('suppressrevision', 'viewsuppressed')) { $this->mConds[] = $this->mDb->bitAnd('log_deleted', LogPage::SUPPRESSED_USER) . ' != ' . LogPage::SUPPRESSED_USER; } $this->performer = $usertitle->getText(); }
/** * Backend block code. * $userID and $expiry will be filled accordingly * @return array(message key, arguments) on failure, empty array on success */ function doBlock(&$userId = null, &$expiry = null) { global $wgUser, $wgSysopUserBans, $wgSysopRangeBans, $wgBlockAllowsUTEdit, $wgBlockCIDRLimit; $userId = 0; # Expand valid IPv6 addresses, usernames are left as is $this->BlockAddress = IP::sanitizeIP($this->BlockAddress); # isIPv4() and IPv6() are used for final validation $rxIP4 = '\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}'; $rxIP6 = '\\w{1,4}:\\w{1,4}:\\w{1,4}:\\w{1,4}:\\w{1,4}:\\w{1,4}:\\w{1,4}:\\w{1,4}'; $rxIP = "({$rxIP4}|{$rxIP6})"; # Check for invalid specifications if (!preg_match("/^{$rxIP}\$/", $this->BlockAddress)) { $matches = array(); if (preg_match("/^({$rxIP4})\\/(\\d{1,2})\$/", $this->BlockAddress, $matches)) { # IPv4 if ($wgSysopRangeBans) { if (!IP::isIPv4($this->BlockAddress) || $matches[2] > 32) { return array('ip_range_invalid'); } elseif ($matches[2] < $wgBlockCIDRLimit['IPv4']) { return array('ip_range_toolarge', $wgBlockCIDRLimit['IPv4']); } $this->BlockAddress = Block::normaliseRange($this->BlockAddress); } else { # Range block illegal return array('range_block_disabled'); } } elseif (preg_match("/^({$rxIP6})\\/(\\d{1,3})\$/", $this->BlockAddress, $matches)) { # IPv6 if ($wgSysopRangeBans) { if (!IP::isIPv6($this->BlockAddress) || $matches[2] > 128) { return array('ip_range_invalid'); } elseif ($matches[2] < $wgBlockCIDRLimit['IPv6']) { return array('ip_range_toolarge', $wgBlockCIDRLimit['IPv6']); } $this->BlockAddress = Block::normaliseRange($this->BlockAddress); } else { # Range block illegal return array('range_block_disabled'); } } else { # Username block if ($wgSysopUserBans) { $user = User::newFromName($this->BlockAddress); if (!is_null($user) && $user->getId()) { # Use canonical name $userId = $user->getId(); $this->BlockAddress = $user->getName(); } else { return array('nosuchusershort', htmlspecialchars($user ? $user->getName() : $this->BlockAddress)); } } else { return array('badipaddress'); } } } if ($wgUser->isBlocked() && $wgUser->getId() !== $userId) { return array('cant-block-while-blocked'); } $reasonstr = $this->BlockReasonList; if ($reasonstr != 'other' && $this->BlockReason != '') { // Entry from drop down menu + additional comment $reasonstr .= wfMsgForContent('colon-separator') . $this->BlockReason; } elseif ($reasonstr == 'other') { $reasonstr = $this->BlockReason; } $expirestr = $this->BlockExpiry; if ($expirestr == 'other') { $expirestr = $this->BlockOther; } if (strlen($expirestr) == 0 || strlen($expirestr) > 50) { return array('ipb_expiry_invalid'); } if (false === ($expiry = Block::parseExpiryInput($expirestr))) { // Bad expiry. return array('ipb_expiry_invalid'); } if ($this->BlockHideName) { // Recheck params here... if (!$userId || !$wgUser->isAllowed('hideuser')) { $this->BlockHideName = false; // IP users should not be hidden } elseif ($expiry !== 'infinity') { // Bad expiry. return array('ipb_expiry_temp'); } elseif (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 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); # 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 $currentBlock = Block::newFromDB($this->BlockAddress, $userId); 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('cant-see-hidden-user'); } $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)); # 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 = $suppressLog ? 'suppress' : 'block'; $log = new LogPage($log_type); $log->addEntry($log_action, Title::makeTitle(NS_USER, $this->BlockAddress), $reasonstr, $logParams); # Report to the user return array(); } else { return array('hookaborted'); } }