Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 160
0.00% covered (danger)
0.00%
0 / 2
CRAP
0.00% covered (danger)
0.00%
0 / 1
WebInstallerName
0.00% covered (danger)
0.00%
0 / 160
0.00% covered (danger)
0.00%
0 / 2
650
0.00% covered (danger)
0.00%
0 / 1
 execute
0.00% covered (danger)
0.00%
0 / 82
0.00% covered (danger)
0.00%
0 / 1
20
 submit
0.00% covered (danger)
0.00%
0 / 78
0.00% covered (danger)
0.00%
0 / 1
462
1<?php
2
3/**
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License along
15 * with this program; if not, write to the Free Software Foundation, Inc.,
16 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 * http://www.gnu.org/copyleft/gpl.html
18 *
19 * @file
20 * @ingroup Installer
21 */
22
23namespace MediaWiki\Installer;
24
25use FormatJson;
26use MediaWiki\Config\HashConfig;
27use MediaWiki\MainConfigNames;
28use MediaWiki\MediaWikiServices;
29use MediaWiki\Parser\Sanitizer;
30use MediaWiki\Title\Title;
31use MediaWiki\User\User;
32use MediaWiki\User\UserRigorOptions;
33use UserPasswordPolicy;
34
35class WebInstallerName extends WebInstallerPage {
36
37    /**
38     * @return string
39     */
40    public function execute() {
41        $r = $this->parent->request;
42        if ( $r->wasPosted() && $this->submit() ) {
43            return 'continue';
44        }
45
46        $this->startForm();
47
48        // Encourage people to not name their site 'MediaWiki' by blanking the
49        // field. I think that was the intent with the original $GLOBALS['wgSitename']
50        // but these two always were the same so had the effect of making the
51        // installer forget $wgSitename when navigating back to this page.
52        if ( $this->getVar( 'wgSitename' ) == 'MediaWiki' ) {
53            $this->setVar( 'wgSitename', '' );
54        }
55
56        // Set wgMetaNamespace to something valid before we show the form.
57        // $wgMetaNamespace defaults to $wgSiteName which is 'MediaWiki'
58        $metaNS = $this->getVar( 'wgMetaNamespace' );
59        $this->setVar(
60            'wgMetaNamespace',
61            wfMessage( 'config-ns-other-default' )->inContentLanguage()->text()
62        );
63
64        // Database isn't available in config yet, so take it
65        // from the installer
66        $pingbackConf = new HashConfig( [
67            MainConfigNames::DBtype => $this->getVar( 'wgDBtype' ),
68        ] );
69        $pingbackInfo = Pingback::getSystemInfo( $pingbackConf );
70
71        $this->addHTML(
72            $this->parent->getTextBox( [
73                'var' => 'wgSitename',
74                'label' => 'config-site-name',
75                'help' => $this->parent->getHelpBox( 'config-site-name-help' )
76            ] ) .
77            // getRadioSet() builds a set of labeled radio buttons.
78            // For grep: The following messages are used as the item labels:
79            // config-ns-site-name, config-ns-generic, config-ns-other
80            $this->parent->getRadioSet( [
81                'var' => '_NamespaceType',
82                'label' => 'config-project-namespace',
83                'itemLabelPrefix' => 'config-ns-',
84                'values' => [ 'site-name', 'generic', 'other' ],
85                'commonAttribs' => [ 'class' => 'enableForOther',
86                    'rel' => 'config_wgMetaNamespace' ],
87                'help' => $this->parent->getHelpBox( 'config-project-namespace-help' )
88            ] ) .
89            $this->parent->getTextBox( [
90                'var' => 'wgMetaNamespace',
91                'label' => '', // @todo Needs a label?
92                'attribs' => [ 'class' => 'enabledByOther' ]
93            ] ) .
94            $this->getFieldsetStart( 'config-admin-box' ) .
95            $this->parent->getTextBox( [
96                'var' => '_AdminName',
97                'label' => 'config-admin-name',
98                'help' => $this->parent->getHelpBox( 'config-admin-help' )
99            ] ) .
100            $this->parent->getPasswordBox( [
101                'var' => '_AdminPassword',
102                'label' => 'config-admin-password',
103            ] ) .
104            $this->parent->getPasswordBox( [
105                'var' => '_AdminPasswordConfirm',
106                'label' => 'config-admin-password-confirm'
107            ] ) .
108            $this->parent->getTextBox( [
109                'var' => '_AdminEmail',
110                'attribs' => [
111                    'dir' => 'ltr',
112                ],
113                'label' => 'config-admin-email',
114                'help' => $this->parent->getHelpBox( 'config-admin-email-help' )
115            ] ) .
116            $this->parent->getCheckBox( [
117                'var' => '_Subscribe',
118                'label' => 'config-subscribe',
119                'help' => $this->parent->getHelpBox( 'config-subscribe-help' )
120            ] ) .
121            $this->parent->getCheckBox( [
122                'var' => 'wgPingback',
123                'label' => 'config-pingback',
124                'help' => $this->parent->getHelpBox(
125                    'config-pingback-help',
126                    FormatJson::encode( $pingbackInfo, true )
127                ),
128                'value' => true,
129            ] ) .
130            $this->getFieldsetEnd() .
131            $this->parent->getInfoBox( wfMessage( 'config-almost-done' )->plain() ) .
132            // getRadioSet() builds a set of labeled radio buttons.
133            // For grep: The following messages are used as the item labels:
134            // config-optional-continue, config-optional-skip
135            $this->parent->getRadioSet( [
136                'var' => '_SkipOptional',
137                'itemLabelPrefix' => 'config-optional-',
138                'values' => [ 'continue', 'skip' ]
139            ] )
140        );
141
142        // Restore the default value
143        $this->setVar( 'wgMetaNamespace', $metaNS );
144
145        $this->endForm();
146
147        return 'output';
148    }
149
150    /**
151     * @return bool
152     */
153    public function submit() {
154        global $wgPasswordPolicy;
155
156        $retVal = true;
157        $this->parent->setVarsFromRequest( [ 'wgSitename', '_NamespaceType',
158            '_AdminName', '_AdminPassword', '_AdminPasswordConfirm', '_AdminEmail',
159            '_Subscribe', '_SkipOptional', 'wgMetaNamespace', 'wgPingback' ] );
160
161        // Validate site name
162        if ( strval( $this->getVar( 'wgSitename' ) ) === '' ) {
163            $this->parent->showError( 'config-site-name-blank' );
164            $retVal = false;
165        }
166
167        // Fetch namespace
168        $nsType = $this->getVar( '_NamespaceType' );
169        if ( $nsType == 'site-name' ) {
170            $name = $this->getVar( 'wgSitename' );
171            // Sanitize for namespace
172            // This algorithm should match the JS one in WebInstallerOutput.php
173            $name = preg_replace( '/[\[\]\{\}|#<>%+? ]/', '_', $name );
174            $name = str_replace( '&', '&amp;', $name );
175            $name = preg_replace( '/__+/', '_', $name );
176            $name = ucfirst( trim( $name, '_' ) );
177        } elseif ( $nsType == 'generic' ) {
178            $name = wfMessage( 'config-ns-generic' )->text();
179        } else { // other
180            $name = $this->getVar( 'wgMetaNamespace' );
181        }
182
183        // Validate namespace
184        if ( strpos( $name, ':' ) !== false ) {
185            $good = false;
186        } else {
187            // Title-style validation
188            $title = Title::newFromText( $name );
189            if ( !$title ) {
190                $good = $nsType == 'site-name';
191            } else {
192                $name = $title->getDBkey();
193                $good = true;
194            }
195        }
196        if ( !$good ) {
197            $this->parent->showError( 'config-ns-invalid', $name );
198            $retVal = false;
199        }
200
201        // Make sure it won't conflict with any existing namespaces
202        $nsIndex = MediaWikiServices::getInstance()->getContentLanguage()->getNsIndex( $name );
203        if ( $nsIndex !== false && $nsIndex !== NS_PROJECT ) {
204            $this->parent->showError( 'config-ns-conflict', $name );
205            $retVal = false;
206        }
207
208        $this->setVar( 'wgMetaNamespace', $name );
209
210        // Validate username for creation
211        $name = $this->getVar( '_AdminName' );
212        if ( strval( $name ) === '' ) {
213            $this->parent->showError( 'config-admin-name-blank' );
214            $cname = $name;
215            $retVal = false;
216        } else {
217            $userNameUtils = MediaWikiServices::getInstance()->getUserNameUtils();
218            $cname = $userNameUtils->getCanonical( $name, UserRigorOptions::RIGOR_CREATABLE );
219            if ( $cname === false ) {
220                $this->parent->showError( 'config-admin-name-invalid', $name );
221                $retVal = false;
222            } else {
223                $this->setVar( '_AdminName', $cname );
224            }
225        }
226
227        // Validate password
228        $msg = false;
229        $pwd = $this->getVar( '_AdminPassword' );
230        $user = User::newFromName( $cname );
231        if ( $user ) {
232            $upp = new UserPasswordPolicy(
233                $wgPasswordPolicy['policies'],
234                $wgPasswordPolicy['checks']
235            );
236            $status = $upp->checkUserPasswordForGroups(
237                $user,
238                $pwd,
239                [ 'bureaucrat', 'sysop', 'interface-admin' ]  // per Installer::createSysop()
240            );
241            $valid = $status->isGood() ? true : $status->getMessage();
242        } else {
243            $valid = 'config-admin-name-invalid';
244        }
245        if ( strval( $pwd ) === '' ) {
246            // Provide a more specific and helpful message if password field is left blank
247            $msg = 'config-admin-password-blank';
248        } elseif ( $pwd !== $this->getVar( '_AdminPasswordConfirm' ) ) {
249            $msg = 'config-admin-password-mismatch';
250        } elseif ( $valid !== true ) {
251            $msg = $valid;
252        }
253        if ( $msg !== false ) {
254            call_user_func( [ $this->parent, 'showError' ], $msg );
255            $this->setVar( '_AdminPassword', '' );
256            $this->setVar( '_AdminPasswordConfirm', '' );
257            $retVal = false;
258        }
259
260        // Validate e-mail if provided
261        $email = $this->getVar( '_AdminEmail' );
262        if ( $email && !Sanitizer::validateEmail( $email ) ) {
263            $this->parent->showError( 'config-admin-error-bademail' );
264            $retVal = false;
265        }
266        // If they asked to subscribe to mediawiki-announce but didn't give
267        // an e-mail, show an error. T31332
268        if ( !$email && $this->getVar( '_Subscribe' ) ) {
269            $this->parent->showError( 'config-subscribe-noemail' );
270            $retVal = false;
271        }
272
273        return $retVal;
274    }
275
276}