]> scripts.mit.edu Git - autoinstallsdev/mediawiki.git/blob - extensions/TitleBlacklist/TitleBlacklist.hooks.php
MediaWiki 1.30.2
[autoinstallsdev/mediawiki.git] / extensions / TitleBlacklist / TitleBlacklist.hooks.php
1 <?php
2 /**
3  * Hooks for Title Blacklist
4  * @author Victor Vasiliev
5  * @copyright © 2007-2010 Victor Vasiliev et al
6  * @license GNU General Public License 2.0 or later
7  */
8
9 use MediaWiki\Auth\AuthManager;
10
11 /**
12  * Hooks for the TitleBlacklist class
13  *
14  * @ingroup Extensions
15  */
16 class TitleBlacklistHooks {
17
18         /**
19          * Called right after configuration variables have been set.
20          */
21         public static function onRegistration() {
22                 global $wgDisableAuthManager, $wgAuthManagerAutoConfig;
23
24                 if ( class_exists( AuthManager::class ) && !$wgDisableAuthManager ) {
25                         $wgAuthManagerAutoConfig['preauth'][TitleBlacklistPreAuthenticationProvider::class] =
26                                 [ 'class' => TitleBlacklistPreAuthenticationProvider::class ];
27                 } else {
28                         Hooks::register( 'AbortNewAccount', 'TitleBlacklistHooks::abortNewAccount' );
29                         Hooks::register( 'AbortAutoAccount', 'TitleBlacklistHooks::abortAutoAccount' );
30                         Hooks::register( 'UserCreateForm', 'TitleBlacklistHooks::addOverrideCheckbox' );
31                         Hooks::register( 'APIGetAllowedParams', 'TitleBlacklistHooks::onAPIGetAllowedParams' );
32                         Hooks::register( 'AddNewAccountApiForm',
33                                 'TitleBlacklistHooks::onAddNewAccountApiForm' );
34                 }
35         }
36
37         /**
38          * getUserPermissionsErrorsExpensive hook
39          *
40          * @param Title $title
41          * @param User $user
42          * @param string $action
43          * @param array &$result
44          * @return bool
45          */
46         public static function userCan( $title, $user, $action, &$result ) {
47                 # Some places check createpage, while others check create.
48                 # As it stands, upload does createpage, but normalize both
49                 # to the same action, to stop future similar bugs.
50                 if ( $action === 'createpage' || $action === 'createtalk' ) {
51                         $action = 'create';
52                 }
53                 if ( $action == 'create' || $action == 'edit' || $action == 'upload' ) {
54                         $blacklisted = TitleBlacklist::singleton()->userCannot( $title, $user, $action );
55                         if ( $blacklisted instanceof TitleBlacklistEntry ) {
56                                 $errmsg = $blacklisted->getErrorMessage( 'edit' );
57                                 $params = [
58                                         $blacklisted->getRaw(),
59                                         $title->getFullText()
60                                 ];
61                                 ApiResult::setIndexedTagName( $params, 'param' );
62                                 $result = ApiMessage::create(
63                                         wfMessage(
64                                                 $errmsg,
65                                                 htmlspecialchars( $blacklisted->getRaw() ),
66                                                 $title->getFullText()
67                                         ),
68                                         'titleblacklist-forbidden',
69                                         [
70                                                 'message' => [
71                                                         'key' => $errmsg,
72                                                         'params' => $params,
73                                                 ],
74                                                 'line' => $blacklisted->getRaw(),
75                                                 // As $errmsg usually represents a non-default message here, and ApiBase
76                                                 // uses ->inLanguage( 'en' )->useDatabase( false ) for all messages, it will
77                                                 // never result in useful 'info' text in the API. Try this, extra data seems
78                                                 // to override the default.
79                                                 'info' => 'TitleBlacklist prevents this title from being created',
80                                         ]
81                                 );
82                                 return false;
83                         }
84                 }
85                 return true;
86         }
87
88         /**
89          * Display a notice if a user is only able to create or edit a page
90          * because they have tboverride.
91          *
92          * @param Title $title
93          * @param int $oldid
94          * @param array &$notices
95          * @return true
96          */
97         public static function displayBlacklistOverrideNotice( Title $title, $oldid, array &$notices ) {
98                 if ( !RequestContext::getMain()->getUser()->isAllowed( 'tboverride' ) ) {
99                         return true;
100                 }
101
102                 $blacklisted = TitleBlacklist::singleton()->isBlacklisted(
103                         $title,
104                         $title->exists() ? 'edit' : 'create'
105                 );
106                 if ( !$blacklisted ) {
107                         return true;
108                 }
109
110                 $params = $blacklisted->getParams();
111                 if ( isset( $params['autoconfirmed'] ) ) {
112                         return true;
113                 }
114
115                 $msg = wfMessage( 'titleblacklist-warning' );
116                 $notices['titleblacklist'] = $msg->rawParams(
117                         htmlspecialchars( $blacklisted->getRaw() ) )->parseAsBlock();
118                 return true;
119         }
120
121         /**
122          * MovePageCheckPermissions hook (1.25+)
123          *
124          * @param Title $oldTitle
125          * @param Title $newTitle
126          * @param User $user
127          * @param string $reason
128          * @param Status $status
129          * @return bool
130          */
131         public static function onMovePageCheckPermissions(
132                 Title $oldTitle, Title $newTitle, User $user, $reason, Status $status
133         ) {
134                 $titleBlacklist = TitleBlacklist::singleton();
135                 $blacklisted = $titleBlacklist->userCannot( $newTitle, $user, 'move' );
136                 if ( !$blacklisted ) {
137                         $blacklisted = $titleBlacklist->userCannot( $oldTitle, $user, 'edit' );
138                 }
139                 if ( $blacklisted instanceof TitleBlacklistEntry ) {
140                         $status->fatal( ApiMessage::create( [
141                                 $blacklisted->getErrorMessage( 'move' ),
142                                 $blacklisted->getRaw(),
143                                 $oldTitle->getFullText(),
144                                 $newTitle->getFullText()
145                         ] ) );
146                         return false;
147                 }
148
149                 return true;
150         }
151
152         /**
153          * Check whether a user name is acceptable,
154          * and set a message if unacceptable.
155          *
156          * Used by abortNewAccount and centralAuthAutoCreate.
157          * May also be called externally to vet alternate account names.
158          *
159          * @param string $userName
160          * @param User $permissionsUser
161          * @param string &$err
162          * @param bool $override
163          * @param bool $log
164          * @return bool Acceptable
165          */
166         public static function acceptNewUserName(
167                 $userName, $permissionsUser, &$err, $override = true, $log = false
168         ) {
169                 $sv = self::testUserName( $userName, $permissionsUser, $override, $log );
170                 if ( !$sv->isGood() ) {
171                         $err = Status::wrap( $sv )->getMessage()->parse();
172                 }
173                 return $sv->isGood();
174         }
175
176         /**
177          * Check whether a user name is acceptable for account creation or autocreation, and explain
178          * why not if that's the case.
179          *
180          * @param string $userName
181          * @param User $creatingUser
182          * @param bool $override Should the test be skipped, if the user has sufficient privileges?
183          * @param bool $log Log blacklist hits to Special:Log
184          * @return StatusValue
185          */
186         public static function testUserName(
187                 $userName, User $creatingUser, $override = true, $log = false
188         ) {
189                 $title = Title::makeTitleSafe( NS_USER, $userName );
190                 $blacklisted = TitleBlacklist::singleton()->userCannot( $title, $creatingUser,
191                         'new-account', $override );
192                 if ( $blacklisted instanceof TitleBlacklistEntry ) {
193                         if ( $log ) {
194                                 self::logFilterHitUsername( $creatingUser, $title, $blacklisted->getRaw() );
195                         }
196                         $message = $blacklisted->getErrorMessage( 'new-account' );
197                         $params = [
198                                 $blacklisted->getRaw(),
199                                 $userName,
200                         ];
201                         ApiResult::setIndexedTagName( $params, 'param' );
202                         return StatusValue::newFatal( ApiMessage::create(
203                                 [ $message, $blacklisted->getRaw(), $userName ],
204                                 'titleblacklist-forbidden',
205                                 [
206                                         'message' => [
207                                                 'key' => $message,
208                                                 'params' => $params,
209                                         ],
210                                         'line' => $blacklisted->getRaw(),
211                                         // The text of the message probably isn't useful API info, so do this instead
212                                         'info' => 'TitleBlacklist prevents this username from being created',
213                                 ]
214                         ) );
215                 }
216                 return StatusValue::newGood();
217         }
218
219         /**
220          * AbortNewAccount hook
221          *
222          * @param User $user
223          * @param string &$message
224          * @param Status &$status
225          * @return bool
226          */
227         public static function abortNewAccount( $user, &$message, &$status ) {
228                 global $wgUser, $wgRequest;
229                 $override = $wgRequest->getCheck( 'wpIgnoreTitleBlacklist' );
230                 $sv = self::testUserName( $user->getName(), $wgUser, $override, true );
231                 if ( !$sv->isGood() ) {
232                         $status = Status::wrap( $sv );
233                         $message = $status->getMessage()->parse();
234                 }
235                 return $sv->isGood();
236         }
237
238         /**
239          * AbortAutoAccount hook
240          *
241          * @param User $user
242          * @param string &$message
243          * @return bool
244          */
245         public static function abortAutoAccount( $user, &$message ) {
246                 global $wgTitleBlacklistBlockAutoAccountCreation;
247                 if ( $wgTitleBlacklistBlockAutoAccountCreation ) {
248                         return self::abortNewAccount( $user, $message );
249                 }
250                 return true;
251         }
252
253         /**
254          * EditFilter hook
255          *
256          * @param EditPage $editor
257          * @param string $text
258          * @param string $section
259          * @param string &$error
260          * @return true
261          */
262         public static function validateBlacklist( $editor, $text, $section, &$error ) {
263                 $title = $editor->getTitle();
264
265                 if ( $title->getNamespace() == NS_MEDIAWIKI && $title->getDBkey() == 'Titleblacklist' ) {
266                         $blackList = TitleBlacklist::singleton();
267                         $bl = $blackList->parseBlacklist( $text, 'page' );
268                         $ok = $blackList->validate( $bl );
269                         if ( count( $ok ) == 0 ) {
270                                 return true;
271                         }
272
273                         $errmsg = wfMessage( 'titleblacklist-invalid' )->numParams( count( $ok ) )->text();
274                         $errlines = '* <code>' .
275                                 implode( "</code>\n* <code>", array_map( 'wfEscapeWikiText', $ok ) ) .
276                                 '</code>';
277                         $error = Html::openElement( 'div', [ 'class' => 'errorbox' ] ) .
278                                 $errmsg .
279                                 "\n" .
280                                 $errlines .
281                                 Html::closeElement( 'div' ) . "\n" .
282                                 Html::element( 'br', [ 'clear' => 'all' ] ) . "\n";
283
284                         // $error will be displayed by the edit class
285                 }
286                 return true;
287         }
288
289         /**
290          * PageContentSaveComplete hook
291          *
292          * @param Article &$article
293          * @param User &$user
294          * @param Content $content
295          * @param string $summary
296          * @param bool $isminor
297          * @param bool $iswatch
298          * @param string $section
299          * @return true
300          */
301         public static function clearBlacklist( &$article, &$user,
302                 $content, $summary, $isminor, $iswatch, $section
303         ) {
304                 $title = $article->getTitle();
305                 if ( $title->getNamespace() == NS_MEDIAWIKI && $title->getDBkey() == 'Titleblacklist' ) {
306                         TitleBlacklist::singleton()->invalidate();
307                 }
308                 return true;
309         }
310
311         /**
312          * UserCreateForm hook based on the one from AntiSpoof extension
313          * @param UsercreateTemplate &$template
314          * @return true
315          */
316         public static function addOverrideCheckbox( &$template ) {
317                 global $wgRequest, $wgUser;
318
319                 if ( TitleBlacklist::userCanOverride( $wgUser, 'new-account' ) ) {
320                         $template->addInputItem( 'wpIgnoreTitleBlacklist',
321                                 $wgRequest->getCheck( 'wpIgnoreTitleBlacklist' ),
322                                 'checkbox', 'titleblacklist-override' );
323                 }
324                 return true;
325         }
326
327         /**
328          * @param ApiBase &$module
329          * @param array &$params
330          * @return bool
331          */
332         public static function onAPIGetAllowedParams( ApiBase &$module, array &$params ) {
333                 if ( $module instanceof ApiCreateAccount ) {
334                         $params['ignoretitleblacklist'] = [
335                                 ApiBase::PARAM_TYPE => 'boolean',
336                                 ApiBase::PARAM_DFLT => false
337                         ];
338                 }
339
340                 return true;
341         }
342
343         /**
344          * Pass API parameter on to the login form when using
345          * API account creation.
346          *
347          * @param ApiBase $apiModule
348          * @param LoginForm $loginForm
349          * @return bool Always true
350          */
351         public static function onAddNewAccountApiForm( ApiBase $apiModule, LoginForm $loginForm ) {
352                 global $wgRequest;
353                 $main = $apiModule->getMain();
354
355                 if ( $main->getVal( 'ignoretitleblacklist' ) !== null ) {
356                         $wgRequest->setVal( 'wpIgnoreTitleBlacklist', '1' );
357
358                         // Suppress "unrecognized parameter" warning:
359                         $main->getVal( 'wpIgnoreTitleBlacklist' );
360                 }
361
362                 return true;
363         }
364
365         /**
366          * Logs the filter username hit to Special:Log if
367          * $wgTitleBlacklistLogHits is enabled.
368          *
369          * @param User $user
370          * @param Title $title
371          * @param string $entry
372          */
373         public static function logFilterHitUsername( $user, $title, $entry ) {
374                 global $wgTitleBlacklistLogHits;
375                 if ( $wgTitleBlacklistLogHits ) {
376                         $logEntry = new ManualLogEntry( 'titleblacklist', 'hit-username' );
377                         $logEntry->setPerformer( $user );
378                         $logEntry->setTarget( $title );
379                         $logEntry->setParameters( [
380                                 '4::entry' => $entry,
381                         ] );
382                         $logid = $logEntry->insert();
383                         $logEntry->publish( $logid );
384                 }
385         }
386
387         /**
388          * External Lua library for Scribunto
389          *
390          * @param string $engine
391          * @param array &$extraLibraries
392          * @return bool
393          */
394         public static function scribuntoExternalLibraries( $engine, array &$extraLibraries ) {
395                 if ( $engine == 'lua' ) {
396                         $extraLibraries['mw.ext.TitleBlacklist'] = 'Scribunto_LuaTitleBlacklistLibrary';
397                 }
398                 return true;
399         }
400 }