/**
  *
  * @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 ==");
 }
Exemple #2
0
 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__);
 }
Exemple #4
0
/**
 * 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');
     }
 }
Exemple #9
0
 /**
  * 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;
 }
Exemple #10
0
 /**
  * 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;
     }
 }
Exemple #12
0
 /**
  * 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');
 }
Exemple #17
0
 /**
  * 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');
     }
 }
Exemple #18
0
	/**
	 * 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');
 }
Exemple #20
0
 /**
  * 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');
 }
Exemple #22
0
 /**
  * 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;
 }
Exemple #23
0
 /**
  * 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);
 }
Exemple #25
0
 /**
  * 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);
     }
 }
Exemple #26
0
 /**
  * @covers IP::sanitizeIP
  * @dataProvider provideSanitizeIP
  */
 public function testSanitizeIP($expected, $input)
 {
     $result = IP::sanitizeIP($input);
     $this->assertEquals($expected, $result);
 }
Exemple #27
0
 /**
  * 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();
 }
Exemple #30
0
 /**
  * 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');
     }
 }