]> scripts.mit.edu Git - autoinstalls/mediawiki.git/blob - maintenance/wrapOldPasswords.php
MediaWiki 1.30.2
[autoinstalls/mediawiki.git] / maintenance / wrapOldPasswords.php
1 <?php
2
3 use MediaWiki\MediaWikiServices;
4
5 /**
6  * Maintenance script to wrap all old-style passwords in a layered type
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 2 of the License, or
11  * (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License along
19  * with this program; if not, write to the Free Software Foundation, Inc.,
20  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
21  * http://www.gnu.org/copyleft/gpl.html
22  *
23  * @file
24  * @ingroup Maintenance
25  */
26 require_once __DIR__ . '/Maintenance.php';
27
28 /**
29  * Maintenance script to wrap all passwords of a certain type in a specified layered
30  * type that wraps around the old type.
31  *
32  * @since 1.24
33  * @ingroup Maintenance
34  */
35 class WrapOldPasswords extends Maintenance {
36         public function __construct() {
37                 parent::__construct();
38                 $this->addDescription( 'Wrap all passwords of a certain type in a new layered type' );
39                 $this->addOption( 'type',
40                         'Password type to wrap passwords in (must inherit LayeredParameterizedPassword)', true, true );
41                 $this->addOption( 'verbose', 'Enables verbose output', false, false, 'v' );
42                 $this->setBatchSize( 100 );
43         }
44
45         public function execute() {
46                 $passwordFactory = new PasswordFactory();
47                 $passwordFactory->init( RequestContext::getMain()->getConfig() );
48
49                 $typeInfo = $passwordFactory->getTypes();
50                 $layeredType = $this->getOption( 'type' );
51
52                 // Check that type exists and is a layered type
53                 if ( !isset( $typeInfo[$layeredType] ) ) {
54                         $this->error( 'Undefined password type', true );
55                 }
56
57                 $passObj = $passwordFactory->newFromType( $layeredType );
58                 if ( !$passObj instanceof LayeredParameterizedPassword ) {
59                         $this->error( 'Layered parameterized password type must be used.', true );
60                 }
61
62                 // Extract the first layer type
63                 $typeConfig = $typeInfo[$layeredType];
64                 $firstType = $typeConfig['types'][0];
65
66                 // Get a list of password types that are applicable
67                 $dbw = $this->getDB( DB_MASTER );
68                 $typeCond = 'user_password' . $dbw->buildLike( ":$firstType:", $dbw->anyString() );
69
70                 $minUserId = 0;
71                 $lbFactory = MediaWikiServices::getInstance()->getDBLoadBalancerFactory();
72                 do {
73                         $this->beginTransaction( $dbw, __METHOD__ );
74
75                         $res = $dbw->select( 'user',
76                                 [ 'user_id', 'user_name', 'user_password' ],
77                                 [
78                                         'user_id > ' . $dbw->addQuotes( $minUserId ),
79                                         $typeCond
80                                 ],
81                                 __METHOD__,
82                                 [
83                                         'ORDER BY' => 'user_id',
84                                         'LIMIT' => $this->mBatchSize,
85                                         'LOCK IN SHARE MODE',
86                                 ]
87                         );
88
89                         /** @var User[] $updateUsers */
90                         $updateUsers = [];
91                         foreach ( $res as $row ) {
92                                 if ( $this->hasOption( 'verbose' ) ) {
93                                         $this->output( "Updating password for user {$row->user_name} ({$row->user_id}).\n" );
94                                 }
95
96                                 $user = User::newFromId( $row->user_id );
97                                 /** @var ParameterizedPassword $password */
98                                 $password = $passwordFactory->newFromCiphertext( $row->user_password );
99                                 /** @var LayeredParameterizedPassword $layeredPassword */
100                                 $layeredPassword = $passwordFactory->newFromType( $layeredType );
101                                 $layeredPassword->partialCrypt( $password );
102
103                                 $updateUsers[] = $user;
104                                 $dbw->update( 'user',
105                                         [ 'user_password' => $layeredPassword->toString() ],
106                                         [ 'user_id' => $row->user_id ],
107                                         __METHOD__
108                                 );
109
110                                 $minUserId = $row->user_id;
111                         }
112
113                         $this->commitTransaction( $dbw, __METHOD__ );
114                         $lbFactory->waitForReplication();
115
116                         // Clear memcached so old passwords are wiped out
117                         foreach ( $updateUsers as $user ) {
118                                 $user->clearSharedCache();
119                         }
120                 } while ( $res->numRows() );
121         }
122 }
123
124 $maintClass = "WrapOldPasswords";
125 require_once RUN_MAINTENANCE_IF_MAIN;