MediaWiki  1.34.0
TitleBlacklist.php
Go to the documentation of this file.
1 <?php
11 
21  private $mBlacklist = null;
22 
24  private $mWhitelist = null;
25 
27  protected static $instance = null;
28 
29  const VERSION = 3; // Blacklist format
30 
36  public static function singleton() {
37  if ( self::$instance === null ) {
38  self::$instance = new self;
39  }
40  return self::$instance;
41  }
42 
49  public static function destroySingleton() {
50  if ( !defined( 'MW_PHPUNIT_TEST' ) ) {
51  throw new MWException(
52  'Can not invoke ' . __METHOD__ . '() ' .
53  'out of tests (MW_PHPUNIT_TEST not set).'
54  );
55  }
56 
57  self::$instance = null;
58  }
59 
63  public function load() {
64  global $wgTitleBlacklistSources, $wgTitleBlacklistCaching;
65 
66  $cache = MediaWikiServices::getInstance()->getMainWANObjectCache();
67  // Try to find something in the cache
68  $cachedBlacklist = $cache->get( $cache->makeKey( 'title_blacklist_entries' ) );
69  if ( is_array( $cachedBlacklist ) && count( $cachedBlacklist ) > 0
70  && ( $cachedBlacklist[0]->getFormatVersion() == self::VERSION )
71  ) {
72  $this->mBlacklist = $cachedBlacklist;
73  return;
74  }
75 
76  $sources = $wgTitleBlacklistSources;
77  $sources['local'] = [ 'type' => 'message' ];
78  $this->mBlacklist = [];
79  foreach ( $sources as $sourceName => $source ) {
80  $this->mBlacklist = array_merge(
81  $this->mBlacklist,
82  self::parseBlacklist( self::getBlacklistText( $source ), $sourceName )
83  );
84  }
85  $cache->set( $cache->makeKey( 'title_blacklist_entries' ),
86  $this->mBlacklist, $wgTitleBlacklistCaching['expiry'] );
87  wfDebugLog( 'TitleBlacklist-cache', 'Updated ' . $cache->makeKey( 'title_blacklist_entries' )
88  . ' with ' . count( $this->mBlacklist ) . ' entries.' );
89  }
90 
94  public function loadWhitelist() {
95  global $wgTitleBlacklistCaching;
96 
97  $cache = MediaWikiServices::getInstance()->getMainWANObjectCache();
98  $cachedWhitelist = $cache->get( $cache->makeKey( 'title_whitelist_entries' ) );
99  if ( is_array( $cachedWhitelist ) && count( $cachedWhitelist ) > 0
100  && ( $cachedWhitelist[0]->getFormatVersion() != self::VERSION )
101  ) {
102  $this->mWhitelist = $cachedWhitelist;
103  return;
104  }
105  $this->mWhitelist = self::parseBlacklist( wfMessage( 'titlewhitelist' )
106  ->inContentLanguage()->text(), 'whitelist' );
107  $cache->set( $cache->makeKey( 'title_whitelist_entries' ),
108  $this->mWhitelist, $wgTitleBlacklistCaching['expiry'] );
109  }
110 
117  private static function getBlacklistText( $source ) {
118  if ( !is_array( $source ) || count( $source ) <= 0 ) {
119  return ''; // Return empty string in error case
120  }
121 
122  if ( $source['type'] == 'message' ) {
123  return wfMessage( 'titleblacklist' )->inContentLanguage()->text();
124  } elseif ( $source['type'] == 'localpage' && count( $source ) >= 2 ) {
125  $title = Title::newFromText( $source['src'] );
126  if ( is_null( $title ) ) {
127  return '';
128  }
129  if ( $title->getNamespace() == NS_MEDIAWIKI ) {
130  $msg = wfMessage( $title->getText() )->inContentLanguage();
131  if ( !$msg->isDisabled() ) {
132  return $msg->text();
133  } else {
134  return '';
135  }
136  } else {
137  $page = WikiPage::factory( $title );
138  if ( $page->exists() ) {
139  return ContentHandler::getContentText( $page->getContent() );
140  }
141  }
142  } elseif ( $source['type'] == 'url' && count( $source ) >= 2 ) {
143  return self::getHttp( $source['src'] );
144  } elseif ( $source['type'] == 'file' && count( $source ) >= 2 ) {
145  if ( file_exists( $source['src'] ) ) {
146  return file_get_contents( $source['src'] );
147  } else {
148  return '';
149  }
150  }
151 
152  return '';
153  }
154 
162  public static function parseBlacklist( $list, $sourceName ) {
163  $lines = preg_split( "/\r?\n/", $list );
164  $result = [];
165  foreach ( $lines as $line ) {
166  $entry = TitleBlacklistEntry::newFromString( $line, $sourceName );
167  if ( $entry ) {
168  $result[] = $entry;
169  }
170  }
171 
172  return $result;
173  }
174 
186  public function userCannot( $title, $user, $action = 'edit', $override = true ) {
187  $entry = $this->isBlacklisted( $title, $action );
188  if ( !$entry ) {
189  return false;
190  }
191  $params = $entry->getParams();
192  if ( isset( $params['autoconfirmed'] ) && $user->isAllowed( 'autoconfirmed' ) ) {
193  return false;
194  }
195  if ( $override && self::userCanOverride( $user, $action ) ) {
196  return false;
197  }
198  return $entry;
199  }
200 
210  public function isBlacklisted( $title, $action = 'edit' ) {
211  if ( !( $title instanceof Title ) ) {
213  if ( !( $title instanceof Title ) ) {
214  // The fact that the page name is invalid will stop whatever
215  // action is going through. No sense in doing more work here.
216  return false;
217  }
218  }
219  $blacklist = $this->getBlacklist();
220  $autoconfirmedItem = false;
221  foreach ( $blacklist as $item ) {
222  if ( $item->matches( $title->getFullText(), $action ) ) {
223  if ( $this->isWhitelisted( $title, $action ) ) {
224  return false;
225  }
226  $params = $item->getParams();
227  if ( !isset( $params['autoconfirmed'] ) ) {
228  return $item;
229  }
230  if ( !$autoconfirmedItem ) {
231  $autoconfirmedItem = $item;
232  }
233  }
234  }
235  return $autoconfirmedItem;
236  }
237 
246  public function isWhitelisted( $title, $action = 'edit' ) {
247  if ( !( $title instanceof Title ) ) {
249  }
250  $whitelist = $this->getWhitelist();
251  foreach ( $whitelist as $item ) {
252  if ( $item->matches( $title->getFullText(), $action ) ) {
253  return true;
254  }
255  }
256  return false;
257  }
258 
264  public function getBlacklist() {
265  if ( is_null( $this->mBlacklist ) ) {
266  $this->load();
267  }
268  return $this->mBlacklist;
269  }
270 
276  public function getWhitelist() {
277  if ( is_null( $this->mWhitelist ) ) {
278  $this->loadWhitelist();
279  }
280  return $this->mWhitelist;
281  }
282 
289  private static function getHttp( $url ) {
290  global $messageMemc, $wgTitleBlacklistCaching;
291 
292  $key = 'title_blacklist_source:' . md5( $url ); // Global shared
293  $warnkey = $messageMemc->makeKey( 'titleblacklistwarning', md5( $url ) );
294  $result = $messageMemc->get( $key );
295  $warn = $messageMemc->get( $warnkey );
296 
297  if ( !is_string( $result )
298  || ( !$warn && !mt_rand( 0, $wgTitleBlacklistCaching['warningchance'] ) )
299  ) {
300  $result = Http::get( $url );
301  $messageMemc->set( $warnkey, 1, $wgTitleBlacklistCaching['warningexpiry'] );
302  $messageMemc->set( $key, $result, $wgTitleBlacklistCaching['expiry'] );
303  }
304 
305  return $result;
306  }
307 
311  public function invalidate() {
312  $cache = MediaWikiServices::getInstance()->getMainWANObjectCache();
313  $cache->delete( $cache->makeKey( 'title_blacklist_entries' ) );
314  }
315 
323  public function validate( array $blacklist ) {
324  $badEntries = [];
325  foreach ( $blacklist as $e ) {
326  Wikimedia\suppressWarnings();
327  $regex = $e->getRegex();
328  if ( preg_match( "/{$regex}/u", '' ) === false ) {
329  $badEntries[] = $e->getRaw();
330  }
331  Wikimedia\restoreWarnings();
332  }
333  return $badEntries;
334  }
335 
344  public static function userCanOverride( $user, $action ) {
345  return $user->isAllowed( 'tboverride' ) ||
346  ( $action == 'new-account' && $user->isAllowed( 'tboverride-account' ) );
347  }
348 }
Title\newFromText
static newFromText( $text, $defaultNamespace=NS_MAIN)
Create a new Title from text, such as what one would find in a link.
Definition: Title.php:316
TitleBlacklist\singleton
static singleton()
Get an instance of this class.
Definition: TitleBlacklist.php:36
MediaWiki\MediaWikiServices
MediaWikiServices is the service locator for the application scope of MediaWiki.
Definition: MediaWikiServices.php:117
wfMessage
wfMessage( $key,... $params)
This is the function for getting translated interface messages.
Definition: GlobalFunctions.php:1264
TitleBlacklist\destroySingleton
static destroySingleton()
Destroy/reset the current singleton instance.
Definition: TitleBlacklist.php:49
wfDebugLog
wfDebugLog( $logGroup, $text, $dest='all', array $context=[])
Send a line to a supplementary debug log file, if configured, or main debug log if not.
Definition: GlobalFunctions.php:1007
MWException
MediaWiki exception.
Definition: MWException.php:26
WikiPage\factory
static factory(Title $title)
Create a WikiPage object of the appropriate class for the given title.
Definition: WikiPage.php:142
TitleBlacklist\$mBlacklist
TitleBlacklistEntry[] $mBlacklist
Definition: TitleBlacklist.php:21
TitleBlacklist\getWhitelist
getWhitelist()
Get the current whitelist.
Definition: TitleBlacklist.php:276
Http\get
static get( $url, array $options=[], $caller=__METHOD__)
Simple wrapper for Http::request( 'GET' )
Definition: Http.php:64
TitleBlacklistEntry
Represents a title blacklist entry.
Definition: TitleBlacklistEntry.php:19
$lines
$lines
Definition: router.php:61
$title
$title
Definition: testCompression.php:34
TitleBlacklist\getBlacklist
getBlacklist()
Get the current blacklist.
Definition: TitleBlacklist.php:264
$line
$line
Definition: cdb.php:59
TitleBlacklist\getHttp
static getHttp( $url)
Get the text of a blacklist source via HTTP.
Definition: TitleBlacklist.php:289
TitleBlacklistEntry\newFromString
static newFromString( $line, $source)
Create a new TitleBlacklistEntry from a line of text.
Definition: TitleBlacklistEntry.php:162
$messageMemc
$messageMemc
Definition: Setup.php:792
TitleBlacklist\userCannot
userCannot( $title, $user, $action='edit', $override=true)
Check whether the blacklist restricts given user performing a specific action on the given Title.
Definition: TitleBlacklist.php:186
TitleBlacklist\VERSION
const VERSION
Definition: TitleBlacklist.php:29
TitleBlacklist\parseBlacklist
static parseBlacklist( $list, $sourceName)
Parse blacklist from a string.
Definition: TitleBlacklist.php:162
TitleBlacklist\getBlacklistText
static getBlacklistText( $source)
Get the text of a blacklist from a specified source.
Definition: TitleBlacklist.php:117
TitleBlacklist\loadWhitelist
loadWhitelist()
Load local whitelist.
Definition: TitleBlacklist.php:94
TitleBlacklist\userCanOverride
static userCanOverride( $user, $action)
Inidcates whether user can override blacklist on certain action.
Definition: TitleBlacklist.php:344
TitleBlacklist\invalidate
invalidate()
Invalidate the blacklist cache.
Definition: TitleBlacklist.php:311
Title
Represents a title within MediaWiki.
Definition: Title.php:42
TitleBlacklist\isWhitelisted
isWhitelisted( $title, $action='edit')
Check whether it has been explicitly whitelisted that the current User may perform a specific action ...
Definition: TitleBlacklist.php:246
ContentHandler\getContentText
static getContentText(Content $content=null)
Convenience function for getting flat text from a Content object.
Definition: ContentHandler.php:85
TitleBlacklist\load
load()
Load all configured blacklist sources.
Definition: TitleBlacklist.php:63
$cache
$cache
Definition: mcc.php:33
TitleBlacklist\$instance
static TitleBlacklist $instance
Definition: TitleBlacklist.php:27
TitleBlacklist\validate
validate(array $blacklist)
Validate a new blacklist.
Definition: TitleBlacklist.php:323
$source
$source
Definition: mwdoc-filter.php:34
TitleBlacklist\$mWhitelist
TitleBlacklistEntry[] $mWhitelist
Definition: TitleBlacklist.php:24
TitleBlacklist
Implements a title blacklist for MediaWiki.
Definition: TitleBlacklist.php:19
NS_MEDIAWIKI
const NS_MEDIAWIKI
Definition: Defines.php:68
TitleBlacklist\isBlacklisted
isBlacklisted( $title, $action='edit')
Check whether the blacklist restricts performing a specific action on the given Title.
Definition: TitleBlacklist.php:210