r92121 MediaWiki - Code Review archive

Repository:MediaWiki
Revision:r92120‎ | r92121 | r92122 >
Date:23:01, 13 July 2011
Author:aaron
Status:ok
Tags:
Comment:
* Moved hooks code to its own file
* Added some type hinting
Modified paths:
  • /trunk/extensions/CheckUser/CheckUser.hooks.php (added) (history)
  • /trunk/extensions/CheckUser/CheckUser.php (modified) (history)

Diff [purge]

Index: trunk/extensions/CheckUser/CheckUser.php
@@ -61,15 +61,15 @@
6262 $wgCheckUserStyleVersion = 5;
6363
6464 # Recent changes data hook
65 -$wgHooks['RecentChange_save'][] = 'efUpdateCheckUserData';
66 -$wgHooks['EmailUser'][] = 'efUpdateCUEmailData';
67 -$wgHooks['User::mailPasswordInternal'][] = 'efUpdateCUPasswordResetData';
68 -$wgHooks['AuthPluginAutoCreate'][] = 'efUpdateAutoCreateData';
69 -$wgHooks['AddNewAccount'][] = 'efAddNewAccount';
 65+$wgHooks['RecentChange_save'][] = 'CheckUserHooks::updateCheckUserData';
 66+$wgHooks['EmailUser'][] = 'CheckUserHooks::updateCUEmailData';
 67+$wgHooks['User::mailPasswordInternal'][] = 'CheckUserHooks::updateCUPasswordResetData';
 68+$wgHooks['AuthPluginAutoCreate'][] = 'CheckUserHooks::updateAutoCreateData';
 69+$wgHooks['AddNewAccount'][] = 'CheckUserHooks::addNewAccount';
7070
71 -$wgHooks['ParserTestTables'][] = 'efCheckUserParserTestTables';
72 -$wgHooks['LoadExtensionSchemaUpdates'][] = 'efCheckUserSchemaUpdates';
73 -$wgHooks['ContributionsToolLinks'][] = 'efLoadCheckUserLink';
 71+$wgHooks['ParserTestTables'][] = 'CheckUserHooks::checkUserParserTestTables';
 72+$wgHooks['LoadExtensionSchemaUpdates'][] = 'CheckUserHooks::checkUserSchemaUpdates';
 73+$wgHooks['ContributionsToolLinks'][] = 'CheckUserHooks::loadCheckUserLink';
7474
7575 $wgResourceModules['ext.checkUser'] = array(
7676 'scripts' => 'checkuser.js',
@@ -78,385 +78,9 @@
7979 'remoteExtPath' => 'CheckUser',
8080 );
8181
82 -// TODO: move hooks to CheckUser.hooks.php
83 -
84 -/**
85 - * Hook function for RecentChange_save
86 - * Saves user data into the cu_changes table
87 - */
88 -function efUpdateCheckUserData( $rc ) {
89 - global $wgRequest;
90 -
91 - // Extract params
92 - extract( $rc->mAttribs );
93 - // Get IP
94 - $ip = wfGetIP();
95 - // Get XFF header
96 - $xff = wfGetForwardedFor();
97 - list( $xff_ip, $trusted ) = efGetClientIPfromXFF( $xff );
98 - // Our squid XFFs can flood this up sometimes
99 - $isSquidOnly = efXFFChainIsSquid( $xff );
100 - // Get agent
101 - $agent = $wgRequest->getHeader( 'User-Agent' );
102 - // Store the log action text for log events
103 - // $rc_comment should just be the log_comment
104 - // BC: check if log_type and log_action exists
105 - // If not, then $rc_comment is the actiontext and comment
106 - if ( isset( $rc_log_type ) && $rc_type == RC_LOG ) {
107 - $target = Title::makeTitle( $rc_namespace, $rc_title );
108 - $actionText = LogPage::actionText( $rc_log_type, $rc_log_action, $target,
109 - null, LogPage::extractParams( $rc_params )
110 - );
111 - } else {
112 - $actionText = '';
113 - }
114 -
115 - $dbw = wfGetDB( DB_MASTER );
116 - $cuc_id = $dbw->nextSequenceValue( 'cu_changes_cu_id_seq' );
117 - $rcRow = array(
118 - 'cuc_id' => $cuc_id,
119 - 'cuc_namespace' => $rc_namespace,
120 - 'cuc_title' => $rc_title,
121 - 'cuc_minor' => $rc_minor,
122 - 'cuc_user' => $rc_user,
123 - 'cuc_user_text' => $rc_user_text,
124 - 'cuc_actiontext' => $actionText,
125 - 'cuc_comment' => $rc_comment,
126 - 'cuc_this_oldid' => $rc_this_oldid,
127 - 'cuc_last_oldid' => $rc_last_oldid,
128 - 'cuc_type' => $rc_type,
129 - 'cuc_timestamp' => $rc_timestamp,
130 - 'cuc_ip' => IP::sanitizeIP( $ip ),
131 - 'cuc_ip_hex' => $ip ? IP::toHex( $ip ) : null,
132 - 'cuc_xff' => !$isSquidOnly ? $xff : '',
133 - 'cuc_xff_hex' => ( $xff_ip && !$isSquidOnly ) ? IP::toHex( $xff_ip ) : null,
134 - 'cuc_agent' => $agent
135 - );
136 - # On PG, MW unsets cur_id due to schema incompatibilites. So it may not be set!
137 - if ( isset( $rc_cur_id ) ) {
138 - $rcRow['cuc_page_id'] = $rc_cur_id;
139 - }
140 - $dbw->insert( 'cu_changes', $rcRow, __METHOD__ );
141 -
142 - # Every 100th edit, prune the checkuser changes table.
143 - if ( 0 == mt_rand( 0, 99 ) ) {
144 - # Periodically flush old entries from the recentchanges table.
145 - global $wgCUDMaxAge;
146 - $cutoff = $dbw->timestamp( time() - $wgCUDMaxAge );
147 - $recentchanges = $dbw->tableName( 'cu_changes' );
148 - $sql = "DELETE FROM $recentchanges WHERE cuc_timestamp < '{$cutoff}'";
149 - $dbw->query( $sql, __METHOD__ );
150 - }
151 -
152 - return true;
153 -}
154 -
155 -/**
156 - * Hook function to store password reset
157 - * Saves user data into the cu_changes table
158 - */
159 -function efUpdateCUPasswordResetData( $user, $ip, $account ) {
160 - global $wgRequest;
161 -
162 - // Get XFF header
163 - $xff = wfGetForwardedFor();
164 - list( $xff_ip, $trusted ) = efGetClientIPfromXFF( $xff );
165 - // Our squid XFFs can flood this up sometimes
166 - $isSquidOnly = efXFFChainIsSquid( $xff );
167 - // Get agent
168 - $agent = $wgRequest->getHeader( 'User-Agent' );
169 - $dbw = wfGetDB( DB_MASTER );
170 - $cuc_id = $dbw->nextSequenceValue( 'cu_changes_cu_id_seq' );
171 - $rcRow = array(
172 - 'cuc_id' => $cuc_id,
173 - 'cuc_namespace' => NS_USER,
174 - 'cuc_title' => '',
175 - 'cuc_minor' => 0,
176 - 'cuc_user' => $user->getId(),
177 - 'cuc_user_text' => $user->getName(),
178 - 'cuc_actiontext' => wfMsgForContent( 'checkuser-reset-action', $account->getName() ),
179 - 'cuc_comment' => '',
180 - 'cuc_this_oldid' => 0,
181 - 'cuc_last_oldid' => 0,
182 - 'cuc_type' => RC_LOG,
183 - 'cuc_timestamp' => $dbw->timestamp( wfTimestampNow() ),
184 - 'cuc_ip' => IP::sanitizeIP( $ip ),
185 - 'cuc_ip_hex' => $ip ? IP::toHex( $ip ) : null,
186 - 'cuc_xff' => !$isSquidOnly ? $xff : '',
187 - 'cuc_xff_hex' => ( $xff_ip && !$isSquidOnly ) ? IP::toHex( $xff_ip ) : null,
188 - 'cuc_agent' => $agent
189 - );
190 - $dbw->insert( 'cu_changes', $rcRow, __METHOD__ );
191 -
192 - return true;
193 -}
194 -
195 -/**
196 - * Hook function to store email data
197 - * Saves user data into the cu_changes table
198 - */
199 -function efUpdateCUEmailData( $to, $from, $subject, $text ) {
200 - global $wgSecretKey, $wgRequest;
201 - if ( !$wgSecretKey || $from->name == $to->name ) {
202 - return true;
203 - }
204 - $userFrom = User::newFromName( $from->name );
205 - $userTo = User::newFromName( $to->name );
206 - $hash = md5( $userTo->getEmail() . $userTo->getId() . $wgSecretKey );
207 - // Get IP
208 - $ip = wfGetIP();
209 - // Get XFF header
210 - $xff = wfGetForwardedFor();
211 - list( $xff_ip, $trusted ) = efGetClientIPfromXFF( $xff );
212 - // Our squid XFFs can flood this up sometimes
213 - $isSquidOnly = efXFFChainIsSquid( $xff );
214 - // Get agent
215 - $agent = $wgRequest->getHeader( 'User-Agent' );
216 - $dbw = wfGetDB( DB_MASTER );
217 - $cuc_id = $dbw->nextSequenceValue( 'cu_changes_cu_id_seq' );
218 - $rcRow = array(
219 - 'cuc_id' => $cuc_id,
220 - 'cuc_namespace' => NS_USER,
221 - 'cuc_title' => '',
222 - 'cuc_minor' => 0,
223 - 'cuc_user' => $userFrom->getId(),
224 - 'cuc_user_text' => $userFrom->getName(),
225 - 'cuc_actiontext' => wfMsgForContent( 'checkuser-email-action', $hash ),
226 - 'cuc_comment' => '',
227 - 'cuc_this_oldid' => 0,
228 - 'cuc_last_oldid' => 0,
229 - 'cuc_type' => RC_LOG,
230 - 'cuc_timestamp' => $dbw->timestamp( wfTimestampNow() ),
231 - 'cuc_ip' => IP::sanitizeIP( $ip ),
232 - 'cuc_ip_hex' => $ip ? IP::toHex( $ip ) : null,
233 - 'cuc_xff' => !$isSquidOnly ? $xff : '',
234 - 'cuc_xff_hex' => ( $xff_ip && !$isSquidOnly ) ? IP::toHex( $xff_ip ) : null,
235 - 'cuc_agent' => $agent
236 - );
237 - $dbw->insert( 'cu_changes', $rcRow, __METHOD__ );
238 -
239 - return true;
240 -}
241 -
242 -/**
243 - * Hook function to store autocreation data from the auth plugin
244 - * Saves user data into the cu_changes table
245 - *
246 - * @param $user User
247 - *
248 - * @return true
249 - */
250 -function efUpdateAutoCreateData( $user ) {
251 - return efLogUserAccountCreation( $user, 'checkuser-autocreate-action' );
252 -}
253 -
254 -/**
255 - * @param $user User
256 - * @param $actiontext string
257 - * @return bool
258 - */
259 -function efLogUserAccountCreation( $user, $actiontext ) {
260 - global $wgRequest;
261 -
262 - // Get IP
263 - $ip = wfGetIP();
264 - // Get XFF header
265 - $xff = wfGetForwardedFor();
266 - list( $xff_ip, $trusted ) = efGetClientIPfromXFF( $xff );
267 - // Our squid XFFs can flood this up sometimes
268 - $isSquidOnly = efXFFChainIsSquid( $xff );
269 - // Get agent
270 - $agent = $wgRequest->getHeader( 'User-Agent' );
271 - $dbw = wfGetDB( DB_MASTER );
272 - $cuc_id = $dbw->nextSequenceValue( 'cu_changes_cu_id_seq' );
273 - $rcRow = array(
274 - 'cuc_id' => $cuc_id,
275 - 'cuc_page_id' => 0,
276 - 'cuc_namespace' => NS_USER,
277 - 'cuc_title' => '',
278 - 'cuc_minor' => 0,
279 - 'cuc_user' => $user->getId(),
280 - 'cuc_user_text' => $user->getName(),
281 - 'cuc_actiontext' => wfMsgForContent( $actiontext ),
282 - 'cuc_comment' => '',
283 - 'cuc_this_oldid' => 0,
284 - 'cuc_last_oldid' => 0,
285 - 'cuc_type' => RC_LOG,
286 - 'cuc_timestamp' => $dbw->timestamp( wfTimestampNow() ),
287 - 'cuc_ip' => IP::sanitizeIP( $ip ),
288 - 'cuc_ip_hex' => $ip ? IP::toHex( $ip ) : null,
289 - 'cuc_xff' => !$isSquidOnly ? $xff : '',
290 - 'cuc_xff_hex' => ( $xff_ip && !$isSquidOnly ) ? IP::toHex( $xff_ip ) : null,
291 - 'cuc_agent' => $agent
292 - );
293 - $dbw->insert( 'cu_changes', $rcRow, __METHOD__ );
294 -
295 - return true;
296 -}
297 -
298 -/**
299 - * Hook function to store registration data
300 - * Saves user data into the cu_changes table
301 - *
302 - * @param $user User
303 - * @param $byEmail bool
304 - * @return bool
305 - */
306 -function efAddNewAccount( $user, $byEmail ) {
307 - return efLogUserAccountCreation( $user, 'checkuser-create-action' );
308 -}
309 -
310 -/**
311 - * Locates the client IP within a given XFF string
312 - * @param string $xff
313 - * @param string $address, the ip that sent this header (optional)
314 - * @return array( string, bool )
315 - */
316 -function efGetClientIPfromXFF( $xff, $address = null ) {
317 - if ( !$xff ) {
318 - return array( null, false );
319 - }
320 - // Avoid annoyingly long xff hacks
321 - $xff = trim( substr( $xff, 0, 255 ) );
322 - $client = null;
323 - $trusted = true;
324 - // Check each IP, assuming they are separated by commas
325 - $ips = explode( ',', $xff );
326 - foreach ( $ips as $ip ) {
327 - $ip = trim( $ip );
328 - // If it is a valid IP, not a hash or such
329 - if ( IP::isIPAddress( $ip ) ) {
330 - # The first IP should be the client.
331 - # Start only from the first public IP.
332 - if ( is_null( $client ) ) {
333 - if ( IP::isPublic( $ip ) ) {
334 - $client = $ip;
335 - }
336 - # Check that all servers are trusted
337 - } elseif ( !wfIsTrustedProxy( $ip ) ) {
338 - $trusted = false;
339 - break;
340 - }
341 - }
342 - }
343 - // We still have to test if the IP that sent
344 - // this header is trusted to confirm results
345 - if ( $client != $address && ( !$address || !wfIsTrustedProxy( $address ) ) ) {
346 - $trusted = false;
347 - }
348 -
349 - return array( $client, $trusted );
350 -}
351 -
352 -function efXFFChainIsSquid( $xff ) {
353 - global $wgSquidServers, $wgSquidServersNoPurge;
354 -
355 - if ( !$xff ) {
356 - false;
357 - }
358 - // Avoid annoyingly long xff hacks
359 - $xff = trim( substr( $xff, 0, 255 ) );
360 - $squidOnly = true;
361 - // Check each IP, assuming they are separated by commas
362 - $ips = explode( ',', $xff );
363 - foreach ( $ips as $n => $ip ) {
364 - $ip = trim( $ip );
365 - // If it is a valid IP, not a hash or such
366 - if ( IP::isIPAddress( $ip ) ) {
367 - if ( $n == 0 ) {
368 - // The first IP should be the client...
369 - } elseif ( !in_array( $ip, $wgSquidServers ) && !in_array( $ip, $wgSquidServersNoPurge ) ) {
370 - $squidOnly = false;
371 - break;
372 - }
373 - }
374 - }
375 -
376 - return $squidOnly;
377 -}
378 -
379 -function efCheckUserSchemaUpdates( $updater = null ) {
380 - $base = dirname( __FILE__ );
381 - if ( $updater === null ) {
382 - global $wgDBtype, $wgExtNewIndexes;
383 - efCheckUserCreateTables();
384 - if ( $wgDBtype == 'mysql' ) {
385 - $wgExtNewIndexes[] = array(
386 - 'cu_changes', 'cuc_ip_hex_time',
387 - "$base/archives/patch-cu_changes_indexes.sql"
388 - );
389 - $wgExtNewIndexes[] = array(
390 - 'cu_changes', 'cuc_user_ip_time',
391 - "$base/archives/patch-cu_changes_indexes2.sql"
392 - );
393 - }
394 - } else {
395 - $updater->addExtensionUpdate( array( 'efCheckUserCreateTables' ) );
396 - if ( $updater->getDB()->getType() == 'mysql' ) {
397 - $updater->addExtensionUpdate( array( 'addIndex', 'cu_changes',
398 - 'cuc_ip_hex_time', "$base/archives/patch-cu_changes_indexes.sql", true ) );
399 - $updater->addExtensionUpdate( array( 'addIndex', 'cu_changes',
400 - 'cuc_user_ip_time', "$base/archives/patch-cu_changes_indexes2.sql", true ) );
401 - }
402 - }
403 -
404 - return true;
405 -}
406 -
407 -function efCheckUserCreateTables( $updater = null ) {
408 - if ( $updater === null ) {
409 - $db = wfGetDB( DB_MASTER );
410 - } else {
411 - $db = $updater->getDB();
412 - }
413 -
414 - $base = dirname( __FILE__ );
415 -
416 - if ( $db->tableExists( 'cu_changes' ) ) {
417 - wfOut( "...cu_changes table already exists.\n" );
418 - } else {
419 - require_once "$base/install.inc";
420 - create_cu_changes( $db );
421 - }
422 -
423 - if ( $db->tableExists( 'cu_log' ) ) {
424 - wfOut( "...cu_log table already exists.\n" );
425 - } else {
426 - require_once "$base/install.inc";
427 - create_cu_log( $db );
428 - }
429 -}
430 -
431 -/**
432 - * Tell the parser test engine to create a stub cu_changes table,
433 - * or temporary pages won't save correctly during the test run.
434 - */
435 -function efCheckUserParserTestTables( &$tables ) {
436 - $tables[] = 'cu_changes';
437 - return true;
438 -}
439 -
44082 // Set up the new special page
44183 $wgSpecialPages['CheckUser'] = 'CheckUser';
44284 $wgSpecialPageGroups['CheckUser'] = 'users';
443 -$wgAutoloadClasses['CheckUser'] = dirname( __FILE__ ) . '/CheckUser_body.php';
44485
445 -/**
446 - * Add a link to Special:CheckUser on Special:Contributions/<username> for
447 - * privileged users.
448 - * @param $id Integer: user ID
449 - * @param $nt Title: user page title
450 - * @param $links Array: tool links
451 - * @return true
452 - */
453 -function efLoadCheckUserLink( $id, $nt, &$links ) {
454 - global $wgUser;
455 - if ( $wgUser->isAllowed( 'checkuser' ) ) {
456 - $links[] = $wgUser->getSkin()->makeKnownLinkObj(
457 - SpecialPage::getTitleFor( 'CheckUser' ),
458 - wfMsgHtml( 'checkuser-contribs' ),
459 - 'user=' . urlencode( $nt->getText() )
460 - );
461 - }
462 - return true;
463 -}
 86+$wgAutoloadClasses['CheckUser'] = dirname( __FILE__ ) . '/CheckUser_body.php';
 87+$wgAutoloadClasses['CheckUserHooks'] = dirname( __FILE__ ) . '/CheckUser.hooks.php';
Index: trunk/extensions/CheckUser/CheckUser.hooks.php
@@ -0,0 +1,360 @@
 2+<?php
 3+class CheckUserHooks {
 4+ /**
 5+ * Hook function for RecentChange_save
 6+ * Saves user data into the cu_changes table
 7+ */
 8+ public static function updateCheckUserData( RecentChange $rc ) {
 9+ global $wgRequest, $wgCUDMaxAge;
 10+
 11+ // Extract params
 12+ extract( $rc->mAttribs );
 13+ // Get IP
 14+ $ip = wfGetIP();
 15+ // Get XFF header
 16+ $xff = wfGetForwardedFor();
 17+ list( $xff_ip, $trusted ) = self::getClientIPfromXFF( $xff );
 18+ // Our squid XFFs can flood this up sometimes
 19+ $isSquidOnly = self::XFFChainIsSquid( $xff );
 20+ // Get agent
 21+ $agent = $wgRequest->getHeader( 'User-Agent' );
 22+ // Store the log action text for log events
 23+ // $rc_comment should just be the log_comment
 24+ // BC: check if log_type and log_action exists
 25+ // If not, then $rc_comment is the actiontext and comment
 26+ if ( isset( $rc_log_type ) && $rc_type == RC_LOG ) {
 27+ $target = Title::makeTitle( $rc_namespace, $rc_title );
 28+ $actionText = LogPage::actionText( $rc_log_type, $rc_log_action, $target,
 29+ null, LogPage::extractParams( $rc_params )
 30+ );
 31+ } else {
 32+ $actionText = '';
 33+ }
 34+
 35+ $dbw = wfGetDB( DB_MASTER );
 36+ $cuc_id = $dbw->nextSequenceValue( 'cu_changes_cu_id_seq' );
 37+ $rcRow = array(
 38+ 'cuc_id' => $cuc_id,
 39+ 'cuc_namespace' => $rc_namespace,
 40+ 'cuc_title' => $rc_title,
 41+ 'cuc_minor' => $rc_minor,
 42+ 'cuc_user' => $rc_user,
 43+ 'cuc_user_text' => $rc_user_text,
 44+ 'cuc_actiontext' => $actionText,
 45+ 'cuc_comment' => $rc_comment,
 46+ 'cuc_this_oldid' => $rc_this_oldid,
 47+ 'cuc_last_oldid' => $rc_last_oldid,
 48+ 'cuc_type' => $rc_type,
 49+ 'cuc_timestamp' => $rc_timestamp,
 50+ 'cuc_ip' => IP::sanitizeIP( $ip ),
 51+ 'cuc_ip_hex' => $ip ? IP::toHex( $ip ) : null,
 52+ 'cuc_xff' => !$isSquidOnly ? $xff : '',
 53+ 'cuc_xff_hex' => ( $xff_ip && !$isSquidOnly ) ? IP::toHex( $xff_ip ) : null,
 54+ 'cuc_agent' => $agent
 55+ );
 56+ # On PG, MW unsets cur_id due to schema incompatibilites. So it may not be set!
 57+ if ( isset( $rc_cur_id ) ) {
 58+ $rcRow['cuc_page_id'] = $rc_cur_id;
 59+ }
 60+ $dbw->insert( 'cu_changes', $rcRow, __METHOD__ );
 61+
 62+ # Every 100th edit, prune the checkuser changes table.
 63+ if ( 0 == mt_rand( 0, 99 ) ) {
 64+ # Periodically flush old entries from the recentchanges table.
 65+ $cutoff = $dbw->timestamp( time() - $wgCUDMaxAge );
 66+ $recentchanges = $dbw->tableName( 'cu_changes' );
 67+ $sql = "DELETE FROM $recentchanges WHERE cuc_timestamp < '{$cutoff}'";
 68+ $dbw->query( $sql, __METHOD__ );
 69+ }
 70+
 71+ return true;
 72+ }
 73+
 74+ /**
 75+ * Hook function to store password reset
 76+ * Saves user data into the cu_changes table
 77+ */
 78+ public static function updateCUPasswordResetData( User $user, $ip, $account ) {
 79+ global $wgRequest;
 80+
 81+ // Get XFF header
 82+ $xff = wfGetForwardedFor();
 83+ list( $xff_ip, $trusted ) = self::getClientIPfromXFF( $xff );
 84+ // Our squid XFFs can flood this up sometimes
 85+ $isSquidOnly = self::XFFChainIsSquid( $xff );
 86+ // Get agent
 87+ $agent = $wgRequest->getHeader( 'User-Agent' );
 88+ $dbw = wfGetDB( DB_MASTER );
 89+ $cuc_id = $dbw->nextSequenceValue( 'cu_changes_cu_id_seq' );
 90+ $rcRow = array(
 91+ 'cuc_id' => $cuc_id,
 92+ 'cuc_namespace' => NS_USER,
 93+ 'cuc_title' => '',
 94+ 'cuc_minor' => 0,
 95+ 'cuc_user' => $user->getId(),
 96+ 'cuc_user_text' => $user->getName(),
 97+ 'cuc_actiontext' => wfMsgForContent( 'checkuser-reset-action', $account->getName() ),
 98+ 'cuc_comment' => '',
 99+ 'cuc_this_oldid' => 0,
 100+ 'cuc_last_oldid' => 0,
 101+ 'cuc_type' => RC_LOG,
 102+ 'cuc_timestamp' => $dbw->timestamp( wfTimestampNow() ),
 103+ 'cuc_ip' => IP::sanitizeIP( $ip ),
 104+ 'cuc_ip_hex' => $ip ? IP::toHex( $ip ) : null,
 105+ 'cuc_xff' => !$isSquidOnly ? $xff : '',
 106+ 'cuc_xff_hex' => ( $xff_ip && !$isSquidOnly ) ? IP::toHex( $xff_ip ) : null,
 107+ 'cuc_agent' => $agent
 108+ );
 109+ $dbw->insert( 'cu_changes', $rcRow, __METHOD__ );
 110+
 111+ return true;
 112+ }
 113+
 114+ /**
 115+ * Hook function to store email data
 116+ * Saves user data into the cu_changes table
 117+ */
 118+ public static function updateCUEmailData( $to, $from, $subject, $text ) {
 119+ global $wgSecretKey, $wgRequest;
 120+ if ( !$wgSecretKey || $from->name == $to->name ) {
 121+ return true;
 122+ }
 123+ $userFrom = User::newFromName( $from->name );
 124+ $userTo = User::newFromName( $to->name );
 125+ $hash = md5( $userTo->getEmail() . $userTo->getId() . $wgSecretKey );
 126+ // Get IP
 127+ $ip = wfGetIP();
 128+ // Get XFF header
 129+ $xff = wfGetForwardedFor();
 130+ list( $xff_ip, $trusted ) = self::getClientIPfromXFF( $xff );
 131+ // Our squid XFFs can flood this up sometimes
 132+ $isSquidOnly = self::XFFChainIsSquid( $xff );
 133+ // Get agent
 134+ $agent = $wgRequest->getHeader( 'User-Agent' );
 135+ $dbw = wfGetDB( DB_MASTER );
 136+ $cuc_id = $dbw->nextSequenceValue( 'cu_changes_cu_id_seq' );
 137+ $rcRow = array(
 138+ 'cuc_id' => $cuc_id,
 139+ 'cuc_namespace' => NS_USER,
 140+ 'cuc_title' => '',
 141+ 'cuc_minor' => 0,
 142+ 'cuc_user' => $userFrom->getId(),
 143+ 'cuc_user_text' => $userFrom->getName(),
 144+ 'cuc_actiontext' => wfMsgForContent( 'checkuser-email-action', $hash ),
 145+ 'cuc_comment' => '',
 146+ 'cuc_this_oldid' => 0,
 147+ 'cuc_last_oldid' => 0,
 148+ 'cuc_type' => RC_LOG,
 149+ 'cuc_timestamp' => $dbw->timestamp( wfTimestampNow() ),
 150+ 'cuc_ip' => IP::sanitizeIP( $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+ );
 156+ $dbw->insert( 'cu_changes', $rcRow, __METHOD__ );
 157+
 158+ return true;
 159+ }
 160+
 161+ /**
 162+ * Hook function to store autocreation data from the auth plugin
 163+ * Saves user data into the cu_changes table
 164+ *
 165+ * @param $user User
 166+ *
 167+ * @return true
 168+ */
 169+ public static function updateAutoCreateData( User $user ) {
 170+ return self::logUserAccountCreation( $user, 'checkuser-autocreate-action' );
 171+ }
 172+
 173+ /**
 174+ * @param $user User
 175+ * @param $actiontext string
 176+ * @return bool
 177+ */
 178+ public static function logUserAccountCreation( User $user, $actiontext ) {
 179+ global $wgRequest;
 180+
 181+ // Get IP
 182+ $ip = wfGetIP();
 183+ // Get XFF header
 184+ $xff = wfGetForwardedFor();
 185+ list( $xff_ip, $trusted ) = self::getClientIPfromXFF( $xff );
 186+ // Our squid XFFs can flood this up sometimes
 187+ $isSquidOnly = self::XFFChainIsSquid( $xff );
 188+ // Get agent
 189+ $agent = $wgRequest->getHeader( 'User-Agent' );
 190+ $dbw = wfGetDB( DB_MASTER );
 191+ $cuc_id = $dbw->nextSequenceValue( 'cu_changes_cu_id_seq' );
 192+ $rcRow = array(
 193+ 'cuc_id' => $cuc_id,
 194+ 'cuc_page_id' => 0,
 195+ 'cuc_namespace' => NS_USER,
 196+ 'cuc_title' => '',
 197+ 'cuc_minor' => 0,
 198+ 'cuc_user' => $user->getId(),
 199+ 'cuc_user_text' => $user->getName(),
 200+ 'cuc_actiontext' => wfMsgForContent( $actiontext ),
 201+ 'cuc_comment' => '',
 202+ 'cuc_this_oldid' => 0,
 203+ 'cuc_last_oldid' => 0,
 204+ 'cuc_type' => RC_LOG,
 205+ 'cuc_timestamp' => $dbw->timestamp( wfTimestampNow() ),
 206+ 'cuc_ip' => IP::sanitizeIP( $ip ),
 207+ 'cuc_ip_hex' => $ip ? IP::toHex( $ip ) : null,
 208+ 'cuc_xff' => !$isSquidOnly ? $xff : '',
 209+ 'cuc_xff_hex' => ( $xff_ip && !$isSquidOnly ) ? IP::toHex( $xff_ip ) : null,
 210+ 'cuc_agent' => $agent
 211+ );
 212+ $dbw->insert( 'cu_changes', $rcRow, __METHOD__ );
 213+
 214+ return true;
 215+ }
 216+
 217+ /**
 218+ * Hook function to store registration data
 219+ * Saves user data into the cu_changes table
 220+ *
 221+ * @param $user User
 222+ * @param $byEmail bool
 223+ * @return bool
 224+ */
 225+ public static function addNewAccount( User $user, $byEmail ) {
 226+ return self::logUserAccountCreation( $user, 'checkuser-create-action' );
 227+ }
 228+
 229+ /**
 230+ * Locates the client IP within a given XFF string
 231+ * @param string $xff
 232+ * @param string $address, the ip that sent this header (optional)
 233+ * @return array( string, bool )
 234+ */
 235+ public static function getClientIPfromXFF( $xff, $address = null ) {
 236+ if ( !$xff ) {
 237+ return array( null, false );
 238+ }
 239+ // Avoid annoyingly long xff hacks
 240+ $xff = trim( substr( $xff, 0, 255 ) );
 241+ $client = null;
 242+ $trusted = true;
 243+ // Check each IP, assuming they are separated by commas
 244+ $ips = explode( ',', $xff );
 245+ foreach ( $ips as $ip ) {
 246+ $ip = trim( $ip );
 247+ // If it is a valid IP, not a hash or such
 248+ if ( IP::isIPAddress( $ip ) ) {
 249+ # The first IP should be the client.
 250+ # Start only from the first public IP.
 251+ if ( is_null( $client ) ) {
 252+ if ( IP::isPublic( $ip ) ) {
 253+ $client = $ip;
 254+ }
 255+ # Check that all servers are trusted
 256+ } elseif ( !wfIsTrustedProxy( $ip ) ) {
 257+ $trusted = false;
 258+ break;
 259+ }
 260+ }
 261+ }
 262+ // We still have to test if the IP that sent
 263+ // this header is trusted to confirm results
 264+ if ( $client != $address && ( !$address || !wfIsTrustedProxy( $address ) ) ) {
 265+ $trusted = false;
 266+ }
 267+
 268+ return array( $client, $trusted );
 269+ }
 270+
 271+ public static function XFFChainIsSquid( $xff ) {
 272+ global $wgSquidServers, $wgSquidServersNoPurge;
 273+
 274+ if ( !$xff ) {
 275+ false;
 276+ }
 277+ // Avoid annoyingly long xff hacks
 278+ $xff = trim( substr( $xff, 0, 255 ) );
 279+ $squidOnly = true;
 280+ // Check each IP, assuming they are separated by commas
 281+ $ips = explode( ',', $xff );
 282+ foreach ( $ips as $n => $ip ) {
 283+ $ip = trim( $ip );
 284+ // If it is a valid IP, not a hash or such
 285+ if ( IP::isIPAddress( $ip ) ) {
 286+ if ( $n == 0 ) {
 287+ // The first IP should be the client...
 288+ } elseif ( !in_array( $ip, $wgSquidServers )
 289+ && !in_array( $ip, $wgSquidServersNoPurge ) )
 290+ {
 291+ $squidOnly = false;
 292+ break;
 293+ }
 294+ }
 295+ }
 296+
 297+ return $squidOnly;
 298+ }
 299+
 300+ public static function checkUserSchemaUpdates( DatabaseUpdater $updater ) {
 301+ $base = dirname( __FILE__ );
 302+
 303+ $updater->addExtensionUpdate( array( 'CheckUserHooks::checkUserCreateTables' ) );
 304+ if ( $updater->getDB()->getType() == 'mysql' ) {
 305+ $updater->addExtensionUpdate( array( 'addIndex', 'cu_changes',
 306+ 'cuc_ip_hex_time', "$base/archives/patch-cu_changes_indexes.sql", true ) );
 307+ $updater->addExtensionUpdate( array( 'addIndex', 'cu_changes',
 308+ 'cuc_user_ip_time', "$base/archives/patch-cu_changes_indexes2.sql", true ) );
 309+ }
 310+
 311+ return true;
 312+ }
 313+
 314+ public static function checkUserCreateTables( $updater ) {
 315+ $base = dirname( __FILE__ );
 316+
 317+ $db = $updater->getDB();
 318+ if ( $db->tableExists( 'cu_changes' ) ) {
 319+ $updater->output( "...cu_changes table already exists.\n" );
 320+ } else {
 321+ require_once "$base/install.inc";
 322+ create_cu_changes( $db );
 323+ }
 324+
 325+ if ( $db->tableExists( 'cu_log' ) ) {
 326+ $updater->output( "...cu_log table already exists.\n" );
 327+ } else {
 328+ require_once "$base/install.inc";
 329+ create_cu_log( $db );
 330+ }
 331+ }
 332+
 333+ /**
 334+ * Tell the parser test engine to create a stub cu_changes table,
 335+ * or temporary pages won't save correctly during the test run.
 336+ */
 337+ public static function checkUserParserTestTables( &$tables ) {
 338+ $tables[] = 'cu_changes';
 339+ return true;
 340+ }
 341+
 342+ /**
 343+ * Add a link to Special:CheckUser on Special:Contributions/<username> for
 344+ * privileged users.
 345+ * @param $id Integer: user ID
 346+ * @param $nt Title: user page title
 347+ * @param $links Array: tool links
 348+ * @return true
 349+ */
 350+ public static function loadCheckUserLink( $id, $nt, &$links ) {
 351+ global $wgUser;
 352+ if ( $wgUser->isAllowed( 'checkuser' ) ) {
 353+ $links[] = $wgUser->getSkin()->makeKnownLinkObj(
 354+ SpecialPage::getTitleFor( 'CheckUser' ),
 355+ wfMsgHtml( 'checkuser-contribs' ),
 356+ 'user=' . urlencode( $nt->getText() )
 357+ );
 358+ }
 359+ return true;
 360+ }
 361+}
Property changes on: trunk/extensions/CheckUser/CheckUser.hooks.php
___________________________________________________________________
Added: svn:eol-style
1362 + native
Added: svn:keywords
2363 + Author Date Id Revision LastChangedDate LastChangedRevision

Status & tagging log