Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
96.72% covered (success)
96.72%
59 / 61
50.00% covered (danger)
50.00%
1 / 2
CRAP
0.00% covered (danger)
0.00%
0 / 1
GloballyBlock
96.72% covered (success)
96.72%
59 / 61
50.00% covered (danger)
50.00%
1 / 2
17
0.00% covered (danger)
0.00%
0 / 1
 __construct
100.00% covered (success)
100.00%
20 / 20
100.00% covered (success)
100.00%
1 / 1
1
 execute
95.12% covered (success)
95.12%
39 / 41
0.00% covered (danger)
0.00%
0 / 1
16
1<?php
2
3namespace MediaWiki\Extension\GlobalBlocking\Maintenance;
4
5use MediaWiki\Extension\GlobalBlocking\GlobalBlockingServices;
6use MediaWiki\Maintenance\Maintenance;
7use MediaWiki\User\User;
8use Wikimedia\IPUtils;
9
10// @codeCoverageIgnoreStart
11$IP = getenv( 'MW_INSTALL_PATH' );
12if ( $IP === false ) {
13    $IP = __DIR__ . '/../../..';
14}
15require_once "$IP/maintenance/Maintenance.php";
16// @codeCoverageIgnoreEnd
17
18class GloballyBlock extends Maintenance {
19    public function __construct() {
20        parent::__construct();
21
22        $this->requireExtension( 'GlobalBlocking' );
23
24        $this->addDescription(
25            'Globally blocks (or unblocks) a list of IPs, IP ranges, and/or usernames. ' .
26            "Specify the block targets using either STDIN by passing a filename as the first argument.\n\n" .
27            'By default, all IP ranges and IPs are hard blocked and all blocks are set to deny account creation. ' .
28            'Use the options to override the defaults.'
29        );
30
31        $this->addArg( 'file', 'File with a list of IPs, IP ranges, and/or usernames to globally block', false );
32        $this->addOption( 'performer', 'User to make the global blocks', false, true );
33        $this->addOption( 'reason', 'Reason for the blocks', false, true );
34        $this->addOption( 'reblock', 'Should the users already globally blocked have their block modified' );
35        $this->addOption( 'unblock', 'If the targets should be unblocked instead of blocked' );
36        $this->addOption( 'expiry', 'Expiry of the global blocks', false, true );
37        $this->addOption( 'allow-createaccount', 'Set the blocks to allow account creation' );
38        $this->addOption( 'block-email', 'If the blocks prevent the use of Special:EmailUser' );
39        $this->addOption(
40            'disable-hardblock',
41            "Don't block logged in accounts from a globally blocked IP address (will still block temporary accounts)"
42        );
43    }
44
45    public function execute() {
46        // Parse the performer given for the global (un)blocks
47        $performerName = $this->getOption( 'performer', false );
48        if ( $performerName ) {
49            $performer = $this->getServiceContainer()->getUserFactory()->newFromName( $performerName );
50        } else {
51            $performer = User::newSystemUser( User::MAINTENANCE_SCRIPT_USER, [ 'steal' => true ] );
52        }
53
54        if ( $performer === null ) {
55            $this->fatalError( "Unable to parse performer's username" );
56        }
57
58        // Get the list of users to be globally (un)blocked
59        if ( $this->hasArg( 'file' ) ) {
60            $file = fopen( $this->getArg( 'file' ), 'r' );
61        } else {
62            $file = $this->getStdin();
63        }
64
65        if ( !$file ) {
66            $this->fatalError( 'Unable to read file, exiting' );
67        }
68
69        // Generate the global block options from the options passed to the maintenance script
70        $options = [];
71        if ( $this->hasOption( 'reblock' ) ) {
72            $options[] = 'modify';
73        }
74
75        if ( $this->hasOption( 'allow-createaccount' ) ) {
76            $options[] = 'allow-account-creation';
77        }
78
79        if ( $this->hasOption( 'block-email' ) ) {
80            $options[] = 'block-email';
81        }
82
83        $unblock = $this->hasOption( 'unblock' );
84        $action = $unblock ? 'unblocking' : 'blocking';
85
86        $reason = $this->getOption( 'reason', '' );
87        $expiry = $this->getOption( 'expiry', 'indefinite' );
88
89        $globalBlockManager = GlobalBlockingServices::wrap( $this->getServiceContainer() )->getGlobalBlockManager();
90
91        // Start globally (un)blocking the target users
92        while ( !feof( $file ) ) {
93            $line = trim( fgets( $file ) );
94            if ( $line == '' ) {
95                continue;
96            }
97
98            if ( $unblock ) {
99                $status = $globalBlockManager->unblock( $line, $reason, $performer );
100            } else {
101                $optionsForThisBlock = $options;
102                // Only apply the 'anon-only' flag if the target is an IP, otherwise GlobalBlockManager::block will
103                // not block user accounts.
104                if ( IPUtils::isIPAddress( $line ) && $this->hasOption( 'disable-hardblock' ) ) {
105                    $optionsForThisBlock[] = 'anon-only';
106                }
107                $status = $globalBlockManager->block( $line, $reason, $expiry, $performer, $optionsForThisBlock );
108            }
109
110            if ( !$status->isOK() ) {
111                $errorTexts = [];
112                foreach ( $status->getMessages() as $error ) {
113                    $errorTexts[] = wfMessage( $error )->text();
114                }
115                $text = implode( ', ', $errorTexts );
116                $this->output( "Globally $action '$line' failed ($text).\n" );
117            } else {
118                $this->output( "Globally $action '$line' succeeded.\n" );
119            }
120            $this->waitForReplication();
121        }
122    }
123}
124
125// @codeCoverageIgnoreStart
126$maintClass = GloballyBlock::class;
127require_once RUN_MAINTENANCE_IF_MAIN;
128// @codeCoverageIgnoreEnd