Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 68
0.00% covered (danger)
0.00%
0 / 3
CRAP
0.00% covered (danger)
0.00%
0 / 1
MigrateGuSalt
0.00% covered (danger)
0.00%
0 / 62
0.00% covered (danger)
0.00%
0 / 3
72
0.00% covered (danger)
0.00%
0 / 1
 __construct
0.00% covered (danger)
0.00%
0 / 8
0.00% covered (danger)
0.00%
0 / 1
2
 getUpdateKey
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 doDBUpdates
0.00% covered (danger)
0.00%
0 / 53
0.00% covered (danger)
0.00%
0 / 1
42
1<?php
2/**
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation; either version 2 of the License, or
6 * (at your option) any later version.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License along
14 * with this program; if not, write to the Free Software Foundation, Inc.,
15 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
16 * http://www.gnu.org/copyleft/gpl.html
17 *
18 * @file
19 * @ingroup Maintenance
20 */
21
22use Wikimedia\Rdbms\IExpression;
23use Wikimedia\Rdbms\LikeValue;
24
25$IP = getenv( 'MW_INSTALL_PATH' );
26if ( $IP === false ) {
27    $IP = __DIR__ . '/../../..';
28}
29require_once "$IP/maintenance/Maintenance.php";
30
31class MigrateGuSalt extends LoggedUpdateMaintenance {
32    public function __construct() {
33        parent::__construct();
34        $this->addDescription(
35            'Migrate all old type passwords which have their password stored in the gu_salt column'
36            . ' to have them being stored in the format :B:salt:password in the gu_password column'
37            . ' matching the format of the modern password system.'
38        );
39        $this->setBatchSize( 30 );
40        $this->requireExtension( 'CentralAuth' );
41    }
42
43    /**
44     * @inheritDoc
45     */
46    protected function getUpdateKey() {
47        return 'MigrateGuSalt';
48    }
49
50    /**
51     * @inheritDoc
52     */
53    public function doDBUpdates() {
54        $dbw = $this->getDB( DB_PRIMARY );
55
56        if ( !$dbw->tableExists( 'globaluser', __METHOD__ ) ) {
57            $this->output( "The globaluser table does not seem to exist.\n" );
58            return true;
59        }
60
61        if ( !$dbw->fieldExists( 'globaluser', 'gu_salt', __METHOD__ ) ) {
62            $this->output( "The gu_salt column does not seem to exist.\n" );
63            return true;
64        }
65
66        $typeCond = [
67            $dbw->expr( 'gu_salt', '!=', '' ),
68            $dbw->expr( 'gu_password', IExpression::NOT_LIKE, new LikeValue( ':', $dbw->anyString() ) ),
69        ];
70        $batchSize = $this->getBatchSize();
71
72        $count = 0;
73        $minUserId = 0;
74        while ( true ) {
75            $start = microtime( true );
76            $this->beginTransaction( $dbw, __METHOD__ );
77            $res = $dbw->newSelectQueryBuilder()
78                ->select( [ 'gu_id', 'gu_password', 'gu_salt' ] )
79                ->from( 'globaluser' )
80                ->where( $dbw->expr( 'gu_id', '>', $minUserId ) )
81                ->andWhere( $typeCond )
82                ->orderBy( 'gu_id' )
83                ->limit( $batchSize )
84                ->lockInShareMode()
85                ->caller( __METHOD__ )
86                ->fetchResultSet();
87
88            if ( $res->numRows() === 0 ) {
89                $this->commitTransaction( $dbw, __METHOD__ );
90                break;
91            }
92
93            foreach ( $res as $row ) {
94                $minUserId = $row->gu_id;
95                $count++;
96                $dbw->newUpdateQueryBuilder()
97                    ->update( 'globaluser' )
98                    ->set( [
99                        'gu_password' => ':B:' . $row->gu_salt . ':' . $row->gu_password,
100                        'gu_salt' => ''
101                    ] )
102                    ->where( [ 'gu_id' => $row->gu_id ] )
103                    ->caller( __METHOD__ )
104                    ->execute();
105            }
106
107            $this->commitTransaction( $dbw, __METHOD__ );
108
109            $this->output( "Last id processed: $minUserId; Actually updated: $count...\n" );
110            $delta = microtime( true ) - $start;
111            $this->output( sprintf(
112                "%4d password salts migrated in %6.2fms (%6.2fms each)\n",
113                $res->numRows(),
114                $delta * 1000.0,
115                ( $delta / $res->numRows() ) * 1000.0
116            ) );
117        }
118
119        $this->output( "$count users rows updated.\n" );
120        return true;
121    }
122}
123
124$maintClass = MigrateGuSalt::class;
125require_once RUN_MAINTENANCE_IF_MAIN;