Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 89
0.00% covered (danger)
0.00%
0 / 4
CRAP
0.00% covered (danger)
0.00%
0 / 1
SpecialPasswordPolicies
0.00% covered (danger)
0.00%
0 / 88
0.00% covered (danger)
0.00%
0 / 4
240
0.00% covered (danger)
0.00%
0 / 1
 __construct
0.00% covered (danger)
0.00%
0 / 2
0.00% covered (danger)
0.00%
0 / 1
2
 execute
0.00% covered (danger)
0.00%
0 / 51
0.00% covered (danger)
0.00%
0 / 1
42
 formatPolicies
0.00% covered (danger)
0.00%
0 / 34
0.00% covered (danger)
0.00%
0 / 1
56
 getGroupName
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
1<?php
2/**
3 * Implements Special:PasswordPolicies
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18 * http://www.gnu.org/copyleft/gpl.html
19 *
20 * @file
21 * @ingroup SpecialPage
22 */
23
24namespace MediaWiki\Specials;
25
26use MediaWiki\Html\Html;
27use MediaWiki\MainConfigNames;
28use MediaWiki\Parser\Sanitizer;
29use MediaWiki\SpecialPage\SpecialPage;
30use MediaWiki\Title\Title;
31use MediaWiki\User\UserGroupManager;
32use MediaWiki\User\UserGroupMembership;
33use UserPasswordPolicy;
34use Xml;
35
36/**
37 * This special page lists the defined password policies for user groups.
38 * See also @ref $wgPasswordPolicy.
39 *
40 * @ingroup SpecialPage
41 * @since 1.32
42 */
43class SpecialPasswordPolicies extends SpecialPage {
44
45    private UserGroupManager $userGroupManager;
46
47    /**
48     * @param UserGroupManager $userGroupManager
49     */
50    public function __construct( UserGroupManager $userGroupManager ) {
51        parent::__construct( 'PasswordPolicies' );
52        $this->userGroupManager = $userGroupManager;
53    }
54
55    /**
56     * Show the special page
57     * @param string|null $par
58     */
59    public function execute( $par ) {
60        $this->setHeaders();
61        $this->outputHeader();
62
63        $out = $this->getOutput();
64        $out->addModuleStyles( 'mediawiki.special' );
65
66        // TODO: Have specific user documentation page for this feature
67        $this->addHelpLink( 'Manual:$wgPasswordPolicy' );
68
69        $out->addHTML(
70            Xml::openElement( 'table', [ 'class' => 'wikitable mw-passwordpolicies-table' ] ) .
71                '<tr>' .
72                Xml::element( 'th', null, $this->msg( 'passwordpolicies-group' )->text() ) .
73                Xml::element( 'th', null, $this->msg( 'passwordpolicies-policies' )->text() ) .
74                '</tr>'
75        );
76
77        $config = $this->getConfig();
78        $policies = $config->get( MainConfigNames::PasswordPolicy );
79
80        $implicitGroups = $this->userGroupManager->listAllImplicitGroups();
81        $allGroups = array_merge(
82            $this->userGroupManager->listAllGroups(),
83            $implicitGroups
84        );
85        asort( $allGroups );
86
87        $linkRenderer = $this->getLinkRenderer();
88        $lang = $this->getLanguage();
89
90        foreach ( $allGroups as $group ) {
91            if ( $group == '*' ) {
92                continue;
93            }
94
95            $groupnameLocalized = $lang->getGroupName( $group );
96
97            $grouppageLocalizedTitle = UserGroupMembership::getGroupPage( $group )
98                ?: Title::makeTitle( NS_PROJECT, $group );
99
100            $grouppage = $linkRenderer->makeLink(
101                $grouppageLocalizedTitle,
102                $groupnameLocalized
103            );
104
105            if ( $group === 'user' ) {
106                // Link to Special:listusers for implicit group 'user'
107                $grouplink = '<br />' . $linkRenderer->makeKnownLink(
108                    SpecialPage::getTitleFor( 'Listusers' ),
109                    $this->msg( 'listgrouprights-members' )->text()
110                );
111            } elseif ( !in_array( $group, $implicitGroups ) ) {
112                $grouplink = '<br />' . $linkRenderer->makeKnownLink(
113                    SpecialPage::getTitleFor( 'Listusers' ),
114                    $this->msg( 'listgrouprights-members' )->text(),
115                    [],
116                    [ 'group' => $group ]
117                );
118            } else {
119                // No link to Special:listusers for other implicit groups as they are unlistable
120                $grouplink = '';
121            }
122
123            $out->addHTML( Html::rawElement( 'tr', [ 'id' => Sanitizer::escapeIdForAttribute( $group ) ], "
124                <td>$grouppage$grouplink</td>
125                <td>" . $this->formatPolicies( $policies, $group ) . '</td>
126                '
127            ) );
128
129        }
130
131        $out->addHTML( Xml::closeElement( 'table' ) );
132    }
133
134    /**
135     * Create a HTML list of password policies for $group
136     *
137     * @param array $policies Original $wgPasswordPolicy array
138     * @param string $group Group to format password policies for
139     *
140     * @return string HTML list of all applied password policies
141     */
142    private function formatPolicies( $policies, $group ) {
143        $groupPolicies = UserPasswordPolicy::getPoliciesForGroups(
144            $policies['policies'],
145            [ $group ],
146            $policies['policies']['default']
147        );
148
149        $ret = [];
150        foreach ( $groupPolicies as $gp => $settings ) {
151            if ( !is_array( $settings ) ) {
152                $settings = [ 'value' => $settings ];
153            }
154            $val = $settings['value'];
155            $flags = array_diff_key( $settings, [ 'value' => true ] );
156            if ( !$val ) {
157                // Policy isn't enabled, so no need to display it
158                continue;
159            }
160            $msg = $this->msg( 'passwordpolicies-policy-' . strtolower( $gp ) )->numParams( $val );
161            $flagMsgs = [];
162            foreach ( array_filter( $flags ) as $flag => $value ) {
163                $flagMsg = $this->msg( 'passwordpolicies-policyflag-' . strtolower( $flag ) );
164                $flagMsg->params( $value );
165                $flagMsgs[] = $flagMsg;
166            }
167            if ( $flagMsgs ) {
168                $ret[] = $this->msg(
169                    'passwordpolicies-policy-displaywithflags',
170                    $msg,
171                    '<span class="mw-passwordpolicies-policy-name">' . $gp . '</span>',
172                    $this->getLanguage()->commaList( $flagMsgs )
173                )->parse();
174            } else {
175                $ret[] = $this->msg(
176                    'passwordpolicies-policy-display',
177                    $msg,
178                    '<span class="mw-passwordpolicies-policy-name">' . $gp . '</span>'
179                )->parse();
180            }
181        }
182        if ( $ret === [] ) {
183            return '';
184        } else {
185            return '<ul><li>' . implode( "</li>\n<li>", $ret ) . '</li></ul>';
186        }
187    }
188
189    protected function getGroupName() {
190        return 'users';
191    }
192}
193
194/**
195 * Retain the old class name for backwards compatibility.
196 * @deprecated since 1.41
197 */
198class_alias( SpecialPasswordPolicies::class, 'SpecialPasswordPolicies' );