Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 165
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 / 165
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 / 87
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 MediaWiki\Config\HashConfig;
26use MediaWiki\Json\FormatJson;
27use MediaWiki\MainConfigNames;
28use MediaWiki\MediaWikiServices;
29use MediaWiki\Parser\Sanitizer;
30use MediaWiki\Password\UserPasswordPolicy;
31use MediaWiki\Title\Title;
32use MediaWiki\User\User;
33use MediaWiki\User\UserRigorOptions;
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            // TODO: validate wgServer on the client side
73            $this->parent->getTextBox( [
74                'var' => 'wgServer',
75                'label' => 'config-server',
76                'help' => $this->parent->getHelpBox( 'config-server-help' )
77            ] ) .
78            $this->parent->getTextBox( [
79                'var' => 'wgSitename',
80                'label' => 'config-site-name',
81                'help' => $this->parent->getHelpBox( 'config-site-name-help' )
82            ] ) .
83            // getRadioSet() builds a set of labeled radio buttons.
84            // For grep: The following messages are used as the item labels:
85            // config-ns-site-name, config-ns-generic, config-ns-other
86            $this->parent->getRadioSet( [
87                'var' => '_NamespaceType',
88                'label' => 'config-project-namespace',
89                'itemLabelPrefix' => 'config-ns-',
90                'values' => [ 'site-name', 'generic', 'other' ],
91                'commonAttribs' => [ 'class' => 'enableForOther',
92                    'rel' => 'config_wgMetaNamespace' ],
93                'help' => $this->parent->getHelpBox( 'config-project-namespace-help' )
94            ] ) .
95            $this->parent->getTextBox( [
96                'var' => 'wgMetaNamespace',
97                'label' => '', // @todo Needs a label?
98                'attribs' => [ 'class' => 'enabledByOther' ]
99            ] ) .
100            $this->getFieldsetStart( 'config-admin-box' ) .
101            $this->parent->getTextBox( [
102                'var' => '_AdminName',
103                'label' => 'config-admin-name',
104                'help' => $this->parent->getHelpBox( 'config-admin-help' )
105            ] ) .
106            $this->parent->getPasswordBox( [
107                'var' => '_AdminPassword',
108                'label' => 'config-admin-password',
109            ] ) .
110            $this->parent->getPasswordBox( [
111                'var' => '_AdminPasswordConfirm',
112                'label' => 'config-admin-password-confirm'
113            ] ) .
114            $this->parent->getTextBox( [
115                'var' => '_AdminEmail',
116                'attribs' => [
117                    'dir' => 'ltr',
118                ],
119                'label' => 'config-admin-email',
120                'help' => $this->parent->getHelpBox( 'config-admin-email-help' )
121            ] ) .
122            $this->parent->getCheckBox( [
123                'var' => '_Subscribe',
124                'label' => 'config-subscribe',
125                'help' => $this->parent->getHelpBox( 'config-subscribe-help' )
126            ] ) .
127            $this->parent->getCheckBox( [
128                'var' => 'wgPingback',
129                'label' => 'config-pingback',
130                'help' => $this->parent->getHelpBox(
131                    'config-pingback-help',
132                    FormatJson::encode( $pingbackInfo, true )
133                ),
134                'value' => true,
135            ] ) .
136            $this->getFieldsetEnd() .
137            $this->parent->getInfoBox( wfMessage( 'config-almost-done' )->plain() ) .
138            // getRadioSet() builds a set of labeled radio buttons.
139            // For grep: The following messages are used as the item labels:
140            // config-optional-continue, config-optional-skip
141            $this->parent->getRadioSet( [
142                'var' => '_SkipOptional',
143                'itemLabelPrefix' => 'config-optional-',
144                'values' => [ 'continue', 'skip' ]
145            ] )
146        );
147
148        // Restore the default value
149        $this->setVar( 'wgMetaNamespace', $metaNS );
150
151        $this->endForm();
152
153        return 'output';
154    }
155
156    /**
157     * @return bool
158     */
159    public function submit() {
160        global $wgPasswordPolicy;
161
162        $retVal = true;
163        $this->parent->setVarsFromRequest( [ 'wgServer', 'wgSitename', '_NamespaceType',
164            '_AdminName', '_AdminPassword', '_AdminPasswordConfirm', '_AdminEmail',
165            '_Subscribe', '_SkipOptional', 'wgMetaNamespace', 'wgPingback' ] );
166
167        // Validate site name
168        if ( strval( $this->getVar( 'wgSitename' ) ) === '' ) {
169            $this->parent->showError( 'config-site-name-blank' );
170            $retVal = false;
171        }
172
173        // Fetch namespace
174        $nsType = $this->getVar( '_NamespaceType' );
175        if ( $nsType == 'site-name' ) {
176            $name = $this->getVar( 'wgSitename' );
177            // Sanitize for namespace
178            // This algorithm should match the JS one in WebInstallerOutput.php
179            $name = preg_replace( '/[\[\]\{\}|#<>%+? ]/', '_', $name );
180            $name = str_replace( '&', '&amp;', $name );
181            $name = preg_replace( '/__+/', '_', $name );
182            $name = ucfirst( trim( $name, '_' ) );
183        } elseif ( $nsType == 'generic' ) {
184            $name = wfMessage( 'config-ns-generic' )->text();
185        } else { // other
186            $name = $this->getVar( 'wgMetaNamespace' );
187        }
188
189        // Validate namespace
190        if ( strpos( $name, ':' ) !== false ) {
191            $good = false;
192        } else {
193            // Title-style validation
194            $title = Title::newFromText( $name );
195            if ( !$title ) {
196                $good = $nsType == 'site-name';
197            } else {
198                $name = $title->getDBkey();
199                $good = true;
200            }
201        }
202        if ( !$good ) {
203            $this->parent->showError( 'config-ns-invalid', $name );
204            $retVal = false;
205        }
206
207        // Make sure it won't conflict with any existing namespaces
208        $nsIndex = MediaWikiServices::getInstance()->getContentLanguage()->getNsIndex( $name );
209        if ( $nsIndex !== false && $nsIndex !== NS_PROJECT ) {
210            $this->parent->showError( 'config-ns-conflict', $name );
211            $retVal = false;
212        }
213
214        $this->setVar( 'wgMetaNamespace', $name );
215
216        // Validate username for creation
217        $name = $this->getVar( '_AdminName' );
218        if ( strval( $name ) === '' ) {
219            $this->parent->showError( 'config-admin-name-blank' );
220            $cname = $name;
221            $retVal = false;
222        } else {
223            $userNameUtils = MediaWikiServices::getInstance()->getUserNameUtils();
224            $cname = $userNameUtils->getCanonical( $name, UserRigorOptions::RIGOR_CREATABLE );
225            if ( $cname === false ) {
226                $this->parent->showError( 'config-admin-name-invalid', $name );
227                $retVal = false;
228            } else {
229                $this->setVar( '_AdminName', $cname );
230            }
231        }
232
233        // Validate password
234        $msg = false;
235        $pwd = $this->getVar( '_AdminPassword' );
236        $user = User::newFromName( $cname );
237        if ( $user ) {
238            $upp = new UserPasswordPolicy(
239                $wgPasswordPolicy['policies'],
240                $wgPasswordPolicy['checks']
241            );
242            $status = $upp->checkUserPasswordForGroups(
243                $user,
244                $pwd,
245                [ 'bureaucrat', 'sysop', 'interface-admin' ]  // per Installer::createSysop()
246            );
247            $valid = $status->isGood() ? true : $status->getMessage();
248        } else {
249            $valid = 'config-admin-name-invalid';
250        }
251        if ( strval( $pwd ) === '' ) {
252            // Provide a more specific and helpful message if password field is left blank
253            $msg = 'config-admin-password-blank';
254        } elseif ( $pwd !== $this->getVar( '_AdminPasswordConfirm' ) ) {
255            $msg = 'config-admin-password-mismatch';
256        } elseif ( $valid !== true ) {
257            $msg = $valid;
258        }
259        if ( $msg !== false ) {
260            $this->parent->showError( $msg );
261            $this->setVar( '_AdminPassword', '' );
262            $this->setVar( '_AdminPasswordConfirm', '' );
263            $retVal = false;
264        }
265
266        // Validate e-mail if provided
267        $email = $this->getVar( '_AdminEmail' );
268        if ( $email && !Sanitizer::validateEmail( $email ) ) {
269            $this->parent->showError( 'config-admin-error-bademail' );
270            $retVal = false;
271        }
272        // If they asked to subscribe to mediawiki-announce but didn't give
273        // an e-mail, show an error. T31332
274        if ( !$email && $this->getVar( '_Subscribe' ) ) {
275            $this->parent->showError( 'config-subscribe-noemail' );
276            $retVal = false;
277        }
278
279        return $retVal;
280    }
281
282}