Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
87.88% covered (warning)
87.88%
29 / 33
66.67% covered (warning)
66.67%
2 / 3
CRAP
0.00% covered (danger)
0.00%
0 / 1
ChangePassword
87.88% covered (warning)
87.88%
29 / 33
66.67% covered (warning)
66.67%
2 / 3
8.11
0.00% covered (danger)
0.00%
0 / 1
 __construct
100.00% covered (success)
100.00%
7 / 7
100.00% covered (success)
100.00%
1 / 1
1
 execute
100.00% covered (success)
100.00%
19 / 19
100.00% covered (success)
100.00%
1 / 1
2
 validatePasswordOption
42.86% covered (danger)
42.86%
3 / 7
0.00% covered (danger)
0.00%
0 / 1
9.66
1<?php
2/**
3 * Change the password of a given user
4 *
5 * Copyright © 2005, Ævar Arnfjörð Bjarmason
6 *
7 * @license GPL-2.0-or-later
8 * @file
9 * @author Ævar Arnfjörð Bjarmason <avarab@gmail.com>
10 * @ingroup Maintenance
11 */
12
13// @codeCoverageIgnoreStart
14require_once __DIR__ . '/Maintenance.php';
15// @codeCoverageIgnoreEnd
16
17use MediaWiki\Logger\LoggerFactory;
18use MediaWiki\Maintenance\Maintenance;
19
20/**
21 * Maintenance script to change the password of a given user.
22 *
23 * @ingroup Maintenance
24 */
25class ChangePassword extends Maintenance {
26    public function __construct() {
27        parent::__construct();
28        $this->addOption( "user", "The username to operate on", false, true );
29        $this->addOption( "userid", "The user id to operate on", false, true );
30        $this->addOption( "password", "The password to use", false, true );
31        // phpcs:ignore Generic.Files.LineLength.TooLong
32        $this->addOption( "passwordstdin", "Makes the script read the password from stdin instead. Cannot be used alongside --password", false, false );
33        $this->addOption( 'reason', 'Reason for the password change (ticket number etc)', false, true );
34        $this->addDescription( "Change a user's password" );
35    }
36
37    public function execute() {
38        $user = $this->validateUserOption( "A \"user\" or \"userid\" must be set to change the password for" );
39        // phpcs:ignore Generic.Files.LineLength.TooLong
40        $password = $this->validatePasswordOption( 'Set either --password or --passwordstdin', 'Either --password or --passwordstdin must be set, not both at once' );
41        $status = $user->changeAuthenticationData( [
42            'username' => $user->getName(),
43            'password' => $password,
44            'retype' => $password,
45        ] );
46        if ( $status->isGood() ) {
47            $this->output( "Password set for " . $user->getName() . "\n" );
48
49            LoggerFactory::getInstance( 'authentication' )->info(
50                'Password for {user} changed via changePassword.php', [
51                    'user' => $user->getName(),
52                    'reason' => $this->getOption( 'reason', '' ),
53                ]
54            );
55
56            $invalidator = $this->createChild( InvalidateUserSessions::class );
57            $invalidator->setOption( 'user', $user->getName() );
58            $invalidator->execute();
59        } else {
60            $this->fatalError( $status );
61        }
62    }
63
64    /**
65     * @param string $errorMsgNoPassword Error message to be displayed if neither --password or --stdin are set
66     * @param string $errorMsgBothPasswords Error message to be displayed if both --password and --stdin are set
67     *
68     * @since 1.44
69     *
70     * @return string The new password
71     */
72    private function validatePasswordOption( $errorMsgNoPassword, $errorMsgBothPasswords ) {
73        if ( $this->hasOption( 'password' ) && $this->hasOption( 'passwordstdin' ) ) {
74            $this->fatalError( $errorMsgBothPasswords );
75        }
76        if ( $this->hasOption( 'password' ) ) {
77            return $this->getOption( 'password' );
78        } elseif ( $this->hasOption( 'passwordstdin' ) ) {
79            return $this->getStdin( Maintenance::STDIN_ALL );
80        } else {
81            $this->fatalError( $errorMsgNoPassword );
82        }
83    }
84}
85
86// @codeCoverageIgnoreStart
87$maintClass = ChangePassword::class;
88require_once RUN_MAINTENANCE_IF_MAIN;
89// @codeCoverageIgnoreEnd