Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 61
0.00% covered (danger)
0.00%
0 / 3
CRAP
0.00% covered (danger)
0.00%
0 / 1
ResetGlobalUserTokens
0.00% covered (danger)
0.00%
0 / 55
0.00% covered (danger)
0.00%
0 / 3
56
0.00% covered (danger)
0.00%
0 / 1
 __construct
0.00% covered (danger)
0.00%
0 / 9
0.00% covered (danger)
0.00%
0 / 1
2
 execute
0.00% covered (danger)
0.00%
0 / 42
0.00% covered (danger)
0.00%
0 / 1
30
 updateUser
0.00% covered (danger)
0.00%
0 / 4
0.00% covered (danger)
0.00%
0 / 1
2
1<?php
2/**
3 * Reset the user_token for all users on the wiki. Useful if you believe
4 * that your user table was acidentally leaked to an external source.
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License along
17 * with this program; if not, write to the Free Software Foundation, Inc.,
18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19 * http://www.gnu.org/copyleft/gpl.html
20 *
21 * This is mostly taken from core's maintenance/resetUserTokens.php
22 *
23 * @file
24 * @ingroup Maintenance
25 * @author Chris Steipp <csteipp@wikimedia.org>
26 */
27
28$IP = getenv( 'MW_INSTALL_PATH' );
29if ( $IP === false ) {
30    $IP = __DIR__ . '/../../..';
31}
32require_once "$IP/maintenance/Maintenance.php";
33
34use MediaWiki\Extension\CentralAuth\CentralAuthServices;
35use MediaWiki\Extension\CentralAuth\User\CentralAuthUser;
36
37/**
38 * Maintenance script to reset the user_token for all users on the wiki.
39 *
40 * @ingroup Maintenance
41 */
42class ResetGlobalUserTokens extends Maintenance {
43    public function __construct() {
44        parent::__construct();
45        $this->requireExtension( 'CentralAuth' );
46        $this->addDescription( 'Reset the user_token of all users on the wiki. ' .
47            'Note that this may log some of them out.' );
48        $this->addOption( 'nowarn', "Hides the 5 seconds warning", false, false );
49        $this->addOption( 'minid', "Start processing after this gu_id, default is 0", false, true );
50        $this->addOption( 'maxid', "Stop processing after this gu_id, " .
51            "default is MAX(gu_id) in globalusers", false, true );
52        $this->setBatchSize( 1000 );
53    }
54
55    public function execute() {
56        if ( !$this->getOption( 'nowarn' ) ) {
57            $this->output(
58                "The script is about to reset the user_token for ALL USERS in the database.\n"
59            );
60            $this->output(
61                "This may log some of them out and is not necessary unless you believe your\n"
62            );
63            $this->output( "user table has been compromised.\n" );
64            $this->output( "\n" );
65            $this->output(
66                "Abort with control-c in the next five seconds " .
67                    "(skip this countdown with --nowarn) ... "
68            );
69            $this->countDown( 5 );
70        }
71
72        $databaseManager = CentralAuthServices::getDatabaseManager();
73        // We list user by user_id from one of the replica database
74        $dbr = $databaseManager->getCentralReplicaDB();
75        $maxid = $this->getOption( 'maxid', -1 );
76
77        if ( $maxid == -1 ) {
78            $maxid = $dbr->newSelectQueryBuilder()
79                ->select( 'MAX(gu_id)' )
80                ->from( 'globaluser' )
81                ->caller( __METHOD__ )
82                ->fetchField();
83        }
84        $min = $this->getOption( 'minid', 0 );
85        $max = $min + $this->mBatchSize;
86
87        do {
88            $result = $dbr->newSelectQueryBuilder()
89                ->select( [ 'gu_id', 'gu_name' ] )
90                ->from( 'globaluser' )
91                ->where( [
92                    $dbr->expr( 'gu_id', '>', $min ),
93                    $dbr->expr( 'gu_id', '<=', $max )
94                ] )
95                ->caller( __METHOD__ )
96                ->fetchResultSet();
97
98            foreach ( $result as $user ) {
99                $this->updateUser( $user->gu_name );
100            }
101
102            $min = $max;
103            $max = $min + $this->mBatchSize;
104
105            if ( $max > $maxid ) {
106                $max = $maxid;
107            }
108
109            $databaseManager->waitForReplication();
110
111        } while ( $min < $maxid );
112    }
113
114    /**
115     * @param string $username
116     */
117    private function updateUser( $username ) {
118        $user = new CentralAuthUser( $username, IDBAccessObject::READ_LATEST );
119        $this->output( 'Resetting user_token for "' . $username . '": ' );
120        // Change value
121        $user->resetAuthToken();
122        $this->output( " OK\n" );
123    }
124}
125
126$maintClass = ResetGlobalUserTokens::class;
127require_once RUN_MAINTENANCE_IF_MAIN;