Ejemplo n.º 1
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;
}
Ejemplo n.º 2
0
 /**
  * @param string $ip
  * @param bool $xfor
  * @param string $reason
  * Lists all users in recent changes who used an IP, newest to oldest down
  * Outputs usernames, latest and earliest found edit date, and count
  * List unique IPs used for each user in time order, list corresponding user agent
  */
 function doIPUsersRequest($ip, $xfor = false, $reason = '')
 {
     global $wgUser, $wgOut, $wgLang, $wgTitle, $wgDBname;
     $fname = 'CheckUser::doIPUsersRequest';
     #invalid IPs are passed in as a blank string
     if (!$ip) {
         $s = wfMsgHtml('badipaddress');
         $wgOut->addHTML($s);
         return;
     }
     $logType = 'ipusers';
     if ($xfor) {
         $logType .= '-xff';
     }
     if (!$this->addLogEntry($logType, 'ip', $ip, $reason)) {
         $wgOut->addHTML('<p>' . wfMsgHtml('checkuser-log-fail') . '</p>');
     }
     $dbr = wfGetDB(DB_SLAVE);
     $ip_conds = $dbr->makeList($this->getIpConds($dbr, $ip, $xfor), LIST_AND);
     $cu_changes = $dbr->tableName('cu_changes');
     $index = $xfor ? 'cuc_xff_hex_time' : 'cuc_ip_hex_time';
     # Ordered in descent by timestamp. Can cause large filesorts on range scans.
     # Check how many rows will need sorting ahead of time to see if this is too big.
     if (strpos($ip, '/') !== false) {
         $rangecount = $dbr->estimateRowCount('cu_changes', '*', array($ip_conds), __METHOD__, array('USE INDEX' => $index));
     }
     if (isset($rangecount) && $rangecount > 5000) {
         $use_index = $dbr->useIndexClause($index);
         $sql = "SELECT cuc_ip_hex, COUNT(*) AS count,\n\t\t\t\tMIN(cuc_timestamp) AS first, MAX(cuc_timestamp) AS last \n\t\t\t\tFROM {$cu_changes} {$use_index} WHERE {$ip_conds} \n\t\t\t\tGROUP BY cuc_ip_hex ORDER BY cuc_ip_hex LIMIT 5000";
         $ret = $dbr->query($sql, __METHOD__);
         # List out each IP that has edits
         $s = '<h5>' . wfMsg('checkuser-too-many') . '</h5>';
         $s .= '<ol>';
         while ($row = $ret->fetchObject()) {
             # Convert the IP hexes into normal form
             if (strpos($row->cuc_ip_hex, 'v6-') !== false) {
                 $ip = substr($row->cuc_ip_hex, 3);
                 // Seperate into 8 octets
                 $ip_oct = substr($ip, 0, 4);
                 for ($n = 1; $n < 8; $n++) {
                     $ip_oct .= ':' . substr($ip, 4 * $n, 4);
                 }
                 // NO leading zeroes
                 $ip = preg_replace('/(^|:)0+' . RE_IPV6_WORD . '/', '$1$2', $ip_oct);
             } else {
                 $ip = long2ip(wfBaseConvert($row->cuc_ip_hex, 16, 10, 8));
             }
             $s .= '<li><a href="' . $wgTitle->escapeLocalURL('user='******'&reason=' . urlencode($reason) . '&checktype=subipusers') . '">' . $ip . '</a>';
             if ($row->first == $row->last) {
                 $s .= ' (' . $wgLang->timeanddate($row->first, true) . ') ';
             } else {
                 $s .= ' (' . $wgLang->timeanddate($row->first, true) . ' -- ' . $wgLang->timeanddate($row->last, true) . ') ';
             }
             $s .= " [<strong>" . $row->count . "</strong>]</li>\n";
         }
         $s .= '</ol>';
         $dbr->freeResult($ret);
         $wgOut->addHTML($s);
         return;
     } else {
         if (isset($rangecount) && !$rangecount) {
             $s = wfMsgHtml("checkuser-nomatch") . "\n";
             $wgOut->addHTML($s);
             return;
         }
     }
     # OK, do the real query...
     $use_index = $dbr->useIndexClause($index);
     $sql = "SELECT cuc_user_text, cuc_timestamp, cuc_user, cuc_ip, cuc_agent, cuc_xff \n\t\t\tFROM {$cu_changes} {$use_index} WHERE {$ip_conds} \n\t\t\tORDER BY cuc_timestamp DESC LIMIT 5000";
     $ret = $dbr->query($sql, __METHOD__);
     $users_first = $users_last = $users_edits = $users_ids = array();
     if (!$dbr->numRows($ret)) {
         $s = wfMsgHtml("checkuser-nomatch") . "\n";
     } else {
         while (($row = $dbr->fetchObject($ret)) != false) {
             if (!array_key_exists($row->cuc_user_text, $users_edits)) {
                 $users_last[$row->cuc_user_text] = $row->cuc_timestamp;
                 $users_edits[$row->cuc_user_text] = 0;
                 $users_ids[$row->cuc_user_text] = $row->cuc_user;
                 $users_infosets[$row->cuc_user_text] = array();
                 $users_agentsets[$row->cuc_user_text] = array();
             }
             $users_edits[$row->cuc_user_text] += 1;
             $users_first[$row->cuc_user_text] = $row->cuc_timestamp;
             # Treat blank or NULL xffs as empty strings
             $xff = empty($row->cuc_xff) ? null : $row->cuc_xff;
             $xff_ip_combo = array($row->cuc_ip, $xff);
             # Add this IP/XFF combo for this username if it's not already there
             if (!in_array($xff_ip_combo, $users_infosets[$row->cuc_user_text])) {
                 $users_infosets[$row->cuc_user_text][] = $xff_ip_combo;
             }
             # Add this agent string if it's not already there; 10 max.
             if (count($users_agentsets[$row->cuc_user_text]) < 10) {
                 if (!in_array($row->cuc_agent, $users_agentsets[$row->cuc_user_text])) {
                     $users_agentsets[$row->cuc_user_text][] = $row->cuc_agent;
                 }
             }
         }
         $dbr->freeResult($ret);
         $logs = SpecialPage::getTitleFor('Log');
         $blocklist = SpecialPage::getTitleFor('Ipblocklist');
         $s = '<ul>';
         foreach ($users_edits as $name => $count) {
             $s .= '<li>';
             $s .= $this->sk->userLink(-1, $name) . $this->sk->userToolLinks(-1, $name);
             $s .= ' (<a href="' . $wgTitle->escapeLocalURL('user='******'&reason=' . urlencode($reason)) . '">' . wfMsgHtml('checkuser-check') . '</a>)';
             if ($users_first[$name] == $users_last[$name]) {
                 $s .= ' (' . $wgLang->timeanddate($users_first[$name], true) . ') ';
             } else {
                 $s .= ' (' . $wgLang->timeanddate($users_first[$name], true) . ' -- ' . $wgLang->timeanddate($users_last[$name], true) . ') ';
             }
             $s .= ' [<strong>' . $count . '</strong>]<br />';
             # Check if this user or IP is blocked
             # If so, give a link to the block log
             $block = new Block();
             $block->fromMaster(false);
             // use slaves
             $ip = IP::isIPAddress($name) ? $name : '';
             // only check IP blocks if we have an IP
             if ($block->load($ip, $users_ids[$name])) {
                 if (IP::isIPAddress($block->mAddress) && strpos($block->mAddress, '/')) {
                     $userpage = Title::makeTitle(NS_USER, $block->mAddress);
                     $blocklog = $this->sk->makeKnownLinkObj($logs, wfMsgHtml('checkuser-blocked'), 'type=block&page=' . urlencode($userpage->getPrefixedText()));
                     $s .= ' <strong>(' . $blocklog . ' - ' . $block->mAddress . ')</strong>';
                 } else {
                     if ($block->mAuto) {
                         $blocklog = $this->sk->makeKnownLinkObj($blocklist, wfMsgHtml('checkuser-blocked'), 'ip=' . urlencode("#{$block->mId}"));
                         $s .= ' <strong>(' . $blocklog . ')</strong>';
                     } else {
                         $userpage = Title::makeTitle(NS_USER, $name);
                         $blocklog = $this->sk->makeKnownLinkObj($logs, wfMsgHtml('checkuser-blocked'), 'type=block&page=' . urlencode($userpage->getPrefixedText()));
                         $s .= '<strong>(' . $blocklog . ')</strong>';
                     }
                 }
             }
             $s .= '<ol>';
             # List out each IP/XFF combo for this username
             for ($i = count($users_infosets[$name]) - 1; $i >= 0; $i--) {
                 $set = $users_infosets[$name][$i];
                 # IP link
                 $s .= '<li>';
                 $s .= '<a href="' . $wgTitle->escapeLocalURL('user='******'">' . htmlspecialchars($set[0]) . '</a>';
                 # XFF string, link to /xff search
                 if ($set[1]) {
                     # Flag our trusted proxies
                     list($client, $trusted) = efGetClientIPfromXFF($set[1], $set[0]);
                     $c = $trusted ? '#F0FFF0' : '#FFFFCC';
                     $s .= '&nbsp;&nbsp;&nbsp;<span style="background-color: ' . $c . '"><strong>XFF</strong>: ';
                     $s .= $this->sk->makeKnownLinkObj($wgTitle, htmlspecialchars($set[1]), "user="******"/xff") . "</span>";
                 }
                 $s .= "</li>\n";
             }
             $s .= '</ol><br /><ol>';
             # List out each agent for this username
             for ($i = count($users_agentsets[$name]) - 1; $i >= 0; $i--) {
                 $agent = $users_agentsets[$name][$i];
                 # IP link
                 $s .= "<li><i>" . htmlspecialchars($agent) . "</i></li>\n";
             }
             $s .= '</ol>';
             $s .= '</li>';
         }
         $s .= '</ul>';
     }
     $wgOut->addHTML($s);
 }