Index: trunk/extensions/CheckUser/CheckUser.php |
— | — | @@ -61,15 +61,15 @@ |
62 | 62 | $wgCheckUserStyleVersion = 5; |
63 | 63 | |
64 | 64 | # 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'; |
70 | 70 | |
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'; |
74 | 74 | |
75 | 75 | $wgResourceModules['ext.checkUser'] = array( |
76 | 76 | 'scripts' => 'checkuser.js', |
— | — | @@ -78,385 +78,9 @@ |
79 | 79 | 'remoteExtPath' => 'CheckUser', |
80 | 80 | ); |
81 | 81 | |
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 | | - |
440 | 82 | // Set up the new special page |
441 | 83 | $wgSpecialPages['CheckUser'] = 'CheckUser'; |
442 | 84 | $wgSpecialPageGroups['CheckUser'] = 'users'; |
443 | | -$wgAutoloadClasses['CheckUser'] = dirname( __FILE__ ) . '/CheckUser_body.php'; |
444 | 85 | |
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 |
1 | 362 | + native |
Added: svn:keywords |
2 | 363 | + Author Date Id Revision LastChangedDate LastChangedRevision |