r23587 MediaWiki - Code Review archive

Repository:MediaWiki
Revision:r23586‎ | r23587 | r23588 >
Date:10:15, 30 June 2007
Author:aaron
Status:old
Tags:
Comment:
*Add $wgCURecordCookieData, an option to record cookies, add cuc_cookie_user column and patch file, make actiontext compatible with RC schema changes when used
Modified paths:
  • /trunk/extensions/CheckUser/CheckUser.i18n.php (modified) (history)
  • /trunk/extensions/CheckUser/CheckUser.php (modified) (history)
  • /trunk/extensions/CheckUser/CheckUser_body.php (modified) (history)
  • /trunk/extensions/CheckUser/cu_changes.sql (modified) (history)
  • /trunk/extensions/CheckUser/patch-cu_cookies.sql (added) (history)

Diff [purge]

Index: trunk/extensions/CheckUser/cu_changes.sql
@@ -51,6 +51,9 @@
5252 -- User agent
5353 cuc_agent VARCHAR(255) BINARY default NULL,
5454
 55+ -- Last username from session/cookie data
 56+ cuc_cookie_user VARCHAR(255) BINARY default NULL,
 57+
5558 PRIMARY KEY cuc_id (cuc_id),
5659 INDEX cuc_ip_hex_time (cuc_ip_hex,cuc_timestamp),
5760 INDEX cuc_user_time (cuc_user,cuc_timestamp),
Index: trunk/extensions/CheckUser/patch-cu_cookies.sql
@@ -0,0 +1,6 @@
 2+-- Adds the cookie data column needed to enable $wgCURecordCookies
 3+-- vim: autoindent syn=mysql sts=2 sw=2
 4+-- Replace /*$wgDBprefix*/ with the proper prefix
 5+
 6+ALTER TABLE /*$wgDBprefix*/cu_changes
 7+ ADD cuc_cookie_user VARCHAR(255) BINARY default NULL;
Property changes on: trunk/extensions/CheckUser/patch-cu_cookies.sql
___________________________________________________________________
Added: svn:eol-style
18 + native
Index: trunk/extensions/CheckUser/CheckUser_body.php
@@ -120,6 +120,19 @@
121121 # Output form
122122 $wgOut->addHTML( $form );
123123 }
 124+
 125+ /**
 126+ * As we use the same small set of messages in various methods and that
 127+ * they are called often, we call them once and save them in $this->message
 128+ */
 129+ function preCacheMessages() {
 130+ // Precache various messages
 131+ if( !isset( $this->message ) ) {
 132+ foreach( explode(' ', 'diff hist minoreditletter newpageletter blocklink checkuser-pagelogs' ) as $msg ) {
 133+ $this->message[$msg] = wfMsgExt( $msg, array( 'escape') );
 134+ }
 135+ }
 136+ }
124137
125138 /**
126139 * @param string $ip
@@ -181,24 +194,11 @@
182195 }
183196
184197 /**
185 - * As we use the same small set of messages in various methods and that
186 - * they are called often, we call them once and save them in $this->message
187 - */
188 - function preCacheMessages() {
189 - // Precache various messages
190 - if( !isset( $this->message ) ) {
191 - foreach( explode(' ', 'diff hist minoreditletter newpageletter blocklink log' ) as $msg ) {
192 - $this->message[$msg] = wfMsgExt( $msg, array( 'escape') );
193 - }
194 - }
195 - }
196 -
197 - /**
198198 * @param $row
199199 * @return a streamlined recent changes line with IP data
200200 */
201201 function CUChangesLine( $row ) {
202 - global $wgLang;
 202+ global $wgLang, $wgCURecordCookieData;
203203
204204 # Add date headers
205205 $date = $wgLang->date( $row->cuc_timestamp, true, true );
@@ -226,21 +226,27 @@
227227 $line .= $this->skin->commentBlock( $row->cuc_comment );
228228
229229 $cuTitle = SpecialPage::getTitleFor( 'CheckUser' );
230 - $line .= '<br/>&nbsp; &nbsp; &nbsp; &nbsp; <small>';
231 - # IP
232 - $line .= ' <strong>IP</strong>: '.$this->skin->makeKnownLinkObj( $cuTitle,
233 - htmlspecialchars( $row->cuc_ip ),
234 - "user=" . urlencode( $row->cuc_ip ) );
235 - # XFF
 230+ $line .= '<br/>&nbsp;&nbsp;&nbsp;<small>';
 231+ # IP address
 232+ $line .= ' <strong>' . wfMsgHtml('checkuser-ip') . '</strong> ' .
 233+ $this->skin->makeKnownLinkObj( $cuTitle, htmlspecialchars($row->cuc_ip),
 234+ "user=" . urlencode($row->cuc_ip) );
 235+ # XFF chain
236236 if( $row->cuc_xff !=null ) {
237237 # Flag our trusted proxies
238238 list($client,$trusted) = wfGetClientIPfromXFF($row->cuc_xff,$row->cuc_ip);
239239 $c = $trusted ? '#F0FFF0' : '#FFFFCC';
240 - $line .= '</span>&nbsp;&nbsp;&nbsp;<span style="background-color: '.$c.'"><strong>XFF</strong>: ';
 240+ $line .= '</span>&nbsp;&nbsp;&nbsp;<span style="background-color: '.$c.'">' .
 241+ '<strong>' . wfMsgHtml('checkuser-xff') . '</strong> ';
241242 $line .= $this->skin->makeKnownLinkObj( $cuTitle,
242243 htmlspecialchars( $row->cuc_xff ),
243244 "user=" . urlencode( $client ) . "/xff" )."</span>";
244245 }
 246+ # Previous username
 247+ if( $wgCURecordCookieData && $row->cuc_cookie_user !=null ) {
 248+ $line .= '&nbsp;&nbsp;&nbsp;<strong>' . wfMsgHtml('checkuser-prev-name') . '</strong> ' .
 249+ $this->skin->userLink( -1, $row->cuc_cookie_user );
 250+ }
245251 $line .= "</small></li>\n";
246252
247253 return $line;
@@ -252,19 +258,22 @@
253259 */
254260 function getLinkFromRow( $row ) {
255261 if( $row->cuc_type == RC_LOG && $row->cuc_namespace == NS_SPECIAL ) {
256 - //Log items (old format) and events to logs
 262+ // Log items (old format) and events to logs
257263 list( $specialName, $logtype ) = SpecialPage::resolveAliasWithSubpage( $row->cuc_title );
258264 $logname = LogPage::logName( $logtype );
259265 $title = Title::makeTitle( $row->cuc_namespace, $row->cuc_title );
260266 $links = '(' . $this->skin->makeKnownLinkObj( $title, $logname ) . ')';
261267 } elseif( $row->cuc_type == RC_LOG ) {
262 - //Log items
 268+ // Log items
263269 $specialTitle = SpecialPage::getTitleFor( 'Log' );
264270 $title = Title::makeTitle( $row->cuc_namespace, $row->cuc_title );
265 - $links = '(' . $this->skin->makeKnownLinkObj( $specialTitle, $this->message['log'],
 271+ $links = '(' . $this->skin->makeKnownLinkObj( $specialTitle, $this->message['checkuser-pagelogs'],
266272 wfArrayToCGI( array('page' => $title->getPrefixedText() ) ) ) . ')';
 273+ } elseif( $row->cuc_type == CU_ALT_LOGIN ) {
 274+ // Login events
 275+ $links = '(' . wfMsg('checkuser-login') . ')';
267276 } elseif( !is_null( $row->cuc_this_oldid ) ) {
268 - //Everything else
 277+ // Everything else
269278 $title = Title::makeTitle( $row->cuc_namespace, $row->cuc_title );
270279 #new pages
271280 if( $row->cuc_type == RC_NEW ) {
@@ -397,7 +406,7 @@
398407 # Flag our trusted proxies
399408 list($client,$trusted) = wfGetClientIPfromXFF($set[1],$set[0]);
400409 $c = $trusted ? '#F0FFF0' : '#FFFFCC';
401 - $s .= '&nbsp;&nbsp;&nbsp;<span style="background-color: '.$c.'"><strong>XFF</strong>: ';
 410+ $s .= '&nbsp;&nbsp;&nbsp;<span style="background-color: '.$c.'"><strong>'.wfMsgHtml('checkuser-ip').'</strong> ';
402411 $s .= $sk->makeKnownLinkObj( $wgTitle,
403412 htmlspecialchars( $set[1] ),
404413 "user=" . urlencode( $client ) . "/xff" )."</span>";
Index: trunk/extensions/CheckUser/CheckUser.i18n.php
@@ -31,6 +31,11 @@
3232 'checkuser-log-fail' => 'Unable to add log entry',
3333 'checkuser-nolog' => 'No log file found.',
3434 'checkuser-blocked' => 'Blocked',
 35+ 'checkuser-login' => 'Logged in, but had a valid session for another account',
 36+ 'checkuser-xff' => 'XFF:',
 37+ 'checkuser-ip' => 'IP:',
 38+ 'checkuser-prev-name' => 'Previous session:',
 39+ 'checkuser-pagelogs' => 'page logs',
3540 );
3641 $wgCheckUserMessages['ar'] = array(
3742 'checkuser' => 'افحص مستخدم',
Index: trunk/extensions/CheckUser/CheckUser.php
@@ -6,6 +6,9 @@
77 exit(1);
88 }
99
 10+# RC_MOVE not used in this table, so no overlap
 11+define( 'CU_ALT_LOGIN', 2);
 12+
1013 # Internationalisation file
1114 require_once( 'CheckUser.i18n.php' );
1215
@@ -23,53 +26,75 @@
2427
2528 # How long to keep CU data?
2629 $wgCUDMaxAge = 3 * 30 * 24 * 3600;
 30+# If set to true, usernames from leftover sessions for IP edits will be stored.
 31+# It will also be stored during login if the old session data for the usre is
 32+# for a different account. (Note that user renames can cause this).
 33+# If you have an older version of checkuser without the cuc_cookie_user column,
 34+# run patch-cu_cookies.sql before enabling this
 35+$wgCURecordCookieData = false;
2736
2837 #Recent changes data hook
2938 global $wgHooks;
3039 $wgHooks['RecentChange_save'][] = 'efUpdateCheckUserData';
3140 $wgHooks['ParserTestTables'][] = 'efCheckUserParserTestTables';
 41+$wgHooks['LoginAuthenticateAudit'][] = 'efCheckUserRecordLogin';
3242
3343 /**
3444 * Hook function for RecentChange_save
3545 * Saves user data into the cu_changes table
3646 */
3747 function efUpdateCheckUserData( $rc ) {
38 - $dbw = wfGetDB( DB_MASTER );
 48+ global $wgUser, $wgCURecordCookieData;
 49+ // Extract params
3950 extract( $rc->mAttribs );
40 -
41 - // Convert all IPs to IPv6 if needed
 51+ // Get IP
4252 $ip = wfGetIP();
43 -
 53+ // Get XFF header
4454 $xff = wfGetForwardedFor();
45 - list($xff_ip,$trusted) = wfGetClientIPfromXFF( $xff );
 55+ list($xff_ip,$trusted) = efGetClientIPfromXFF( $xff );
4656 // Our squid XFFs can flood this up sometimes
47 - $isSquidOnly = wfXFFChainIsSquid( $xff );
48 -
 57+ $isSquidOnly = efXFFChainIsSquid( $xff );
 58+ // Get agent
4959 $agent = wfGetAgent();
50 -
51 - $dbw->insert( 'cu_changes',
52 - array(
53 - 'cuc_namespace' => $rc_namespace,
54 - 'cuc_title' => $rc_title,
55 - 'cuc_minor' => $rc_minor,
56 - 'cuc_user' => $rc_user,
57 - 'cuc_user_text' => $rc_user_text,
58 - 'cuc_actiontext' => '',
59 - 'cuc_comment' => $rc_comment,
60 - 'cuc_page_id' => $rc_cur_id,
61 - 'cuc_this_oldid' => $rc_this_oldid,
62 - 'cuc_last_oldid' => $rc_last_oldid,
63 - 'cuc_type' => $rc_type,
64 - 'cuc_timestamp' => $rc_timestamp,
65 - 'cuc_ip' => $ip,
66 - 'cuc_ip_hex' => $ip ? IP::toHex( $ip ) : null,
67 - 'cuc_xff' => !$isSquidOnly ? $xff : '',
68 - 'cuc_xff_hex' => ($xff_ip && !$isSquidOnly) ? IP::toHex( $xff_ip ) : null,
69 - 'cuc_agent' => $agent,
70 - ), __METHOD__
 60+ // Store the log action text for log events
 61+ // $rc_comment should just be the log_comment
 62+ // BC: check if log_type and log_action exists
 63+ // If not, then $rc_comment is the actiontext and comment
 64+ if( isset($rc_log_type) && $rc_type==RC_LOG ) {
 65+ $target = Title::makeTitle( $rc_namespace, $rc_title );
 66+ $actionText = LogPage::actionText( $rc_log_type, $rc_log_action, $target, NULL, explode('\n',$rc_params) );
 67+ } else {
 68+ $actionText = '';
 69+ }
 70+
 71+ $rcRow = array(
 72+ 'cuc_namespace' => $rc_namespace,
 73+ 'cuc_title' => $rc_title,
 74+ 'cuc_minor' => $rc_minor,
 75+ 'cuc_user' => $rc_user,
 76+ 'cuc_user_text' => $rc_user_text,
 77+ 'cuc_actiontext' => $actionText,
 78+ 'cuc_comment' => $rc_comment,
 79+ 'cuc_page_id' => $rc_cur_id,
 80+ 'cuc_this_oldid' => $rc_this_oldid,
 81+ 'cuc_last_oldid' => $rc_last_oldid,
 82+ 'cuc_type' => $rc_type,
 83+ 'cuc_timestamp' => $rc_timestamp,
 84+ 'cuc_ip' => $ip,
 85+ 'cuc_ip_hex' => $ip ? IP::toHex( $ip ) : null,
 86+ 'cuc_xff' => !$isSquidOnly ? $xff : '',
 87+ 'cuc_xff_hex' => ($xff_ip && !$isSquidOnly) ? IP::toHex( $xff_ip ) : null,
 88+ 'cuc_agent' => $agent
7189 );
 90+ // Fetch and add user cookie data
 91+ if( $wgCURecordCookieData && $wgUser->isAnon() ) {
 92+ $rcRow['cuc_cookie_user'] = efGetUsernameFromCookie();
 93+ }
7294
73 - # Every 1000th edit, prune the checkuser changes table.
 95+ $dbw = wfGetDB( DB_MASTER );
 96+ $dbw->insert( 'cu_changes', $rcRow, __METHOD__ );
 97+
 98+ # Every 100th edit, prune the checkuser changes table.
7499 wfSeedRandom();
75100 if ( 0 == mt_rand( 0, 99 ) ) {
76101 # Periodically flush old entries from the recentchanges table.
@@ -85,13 +110,63 @@
86111 return true;
87112 }
88113
 114+function efCheckUserRecordLogin( &$user, &$mPassword, &$retval ) {
 115+ global $wgCURecordCookieData, $wgUser;
 116+ // $wgCURecordCookieData must be enabled
 117+ // Also, we only care for valid login attempts
 118+ if( !$wgCURecordCookieData || $retval != LoginForm::SUCCESS )
 119+ return true;
 120+ // Do not record re-logins
 121+ if( $wgUser->getName() != $user->getName() )
 122+ return true;
 123+ // Get IP
 124+ $ip = wfGetIP();
 125+ // Get XFF header
 126+ $xff = wfGetForwardedFor();
 127+ list($xff_ip,$trusted) = efGetClientIPfromXFF( $xff );
 128+ // Our squid XFFs can flood this up sometimes
 129+ $isSquidOnly = efXFFChainIsSquid( $xff );
 130+ // Get agent
 131+ $agent = wfGetAgent();
 132+ // Get cookie data
 133+ $cuc_cookie_name = efGetUsernameFromCookie();
 134+ if( $cuc_cookie_name == $user->getName() )
 135+ return true; // Nothing special...
 136+
 137+ $rcRow = array(
 138+ 'cuc_namespace' => NS_USER,
 139+ 'cuc_title' => $user->getName(),
 140+ 'cuc_minor' => 0,
 141+ 'cuc_user' => $user->getId(),
 142+ 'cuc_user_text' => $user->getName(),
 143+ 'cuc_actiontext' => '',
 144+ 'cuc_comment' => '',
 145+ 'cuc_page_id' => 0,
 146+ 'cuc_this_oldid' => 0,
 147+ 'cuc_last_oldid' => 0,
 148+ 'cuc_type' => CU_RC_LOGIN,
 149+ 'cuc_timestamp' => wfTimestampNow(),
 150+ 'cuc_ip' => $ip,
 151+ 'cuc_ip_hex' => $ip ? IP::toHex( $ip ) : null,
 152+ 'cuc_xff' => !$isSquidOnly ? $xff : '',
 153+ 'cuc_xff_hex' => ($xff_ip && !$isSquidOnly) ? IP::toHex( $xff_ip ) : null,
 154+ 'cuc_agent' => $agent,
 155+ 'cuc_cookie_user' => efGetUsernameFromCookie()
 156+ );
 157+
 158+ $dbw = wfGetDB( DB_MASTER );
 159+ $dbw->insert( 'cu_changes', $rcRow, __METHOD__ );
 160+
 161+ return true;
 162+}
 163+
89164 /**
90165 * Locates the client IP within a given XFF string
91166 * @param string $xff
92167 * @param string $address, the ip that sent this header (optional)
93168 * @return array( string, bool )
94169 */
95 -function wfGetClientIPfromXFF( $xff, $address=NULL ) {
 170+function efGetClientIPfromXFF( $xff, $address=NULL ) {
96171 if ( !$xff ) return array(null, false);
97172 // Avoid annoyingly long xff hacks
98173 $xff = trim( substr( $xff, 0, 255 ) );
@@ -121,7 +196,12 @@
122197 return array( $client, $trusted );
123198 }
124199
125 -function wfXFFChainIsSquid( $xff ) {
 200+/**
 201+ * Determines if an XFF string is just local squid IPs
 202+ * @param string $xff
 203+ * @return bool
 204+ */
 205+function efXFFChainIsSquid( $xff ) {
126206 global $wgSquidServers, $wgSquidServersNoPurge;
127207
128208 if ( !$xff ) false;
@@ -147,6 +227,41 @@
148228 }
149229
150230 /**
 231+ * Gets the username from client cookie
 232+ * If the token is invalid for this user, this will return false
 233+ * @return string
 234+ */
 235+function efGetUsernameFromCookie() {
 236+ global $wgCookiePrefix;
 237+
 238+ // Try to get name from session
 239+ if( isset( $_SESSION['wsUserName'] ) ) {
 240+ $name = $_SESSION['wsUserName'];
 241+ // Try cookie
 242+ } else if( isset( $_COOKIE["{$wgCookiePrefix}UserName"] ) ) {
 243+ $name = $_COOKIE["{$wgCookiePrefix}UserName"];
 244+ } else {
 245+ return false;
 246+ }
 247+ // Load the supposed user
 248+ $u = User::newFromName( $name );
 249+ $u->load();
 250+ // Validate the token
 251+ if( isset( $_SESSION['wsToken'] ) ) {
 252+ $passwordCorrect = $_SESSION['wsToken'] == $u->mToken;
 253+ } else if( isset( $_COOKIE["{$wgCookiePrefix}Token"] ) ) {
 254+ $passwordCorrect = $u->mToken == $_COOKIE["{$wgCookiePrefix}Token"];
 255+ } else {
 256+ return false;
 257+ }
 258+ // User must have proper credentials
 259+ if( !$passwordCorrect )
 260+ return false;
 261+
 262+ return $name;
 263+}
 264+
 265+/**
151266 * Tell the parser test engine to create a stub cu_changes table,
152267 * or temporary pages won't save correctly during the test run.
153268 */
@@ -159,5 +274,3 @@
160275 require( dirname(__FILE__) . '/../ExtensionFunctions.php' );
161276 }
162277 extAddSpecialPage( dirname(__FILE__) . '/CheckUser_body.php', 'CheckUser', 'CheckUser' );
163 -
164 -

Status & tagging log