MediaWiki  1.30.0
Captcha.php
Go to the documentation of this file.
1 <?php
2 
5 
9 class SimpleCaptcha {
10  protected static $messagePrefix = 'captcha-';
11 
13  private $captchaSolved = null;
14 
20  protected $action;
21 
23  protected $trigger;
24 
28  public function setAction( $action ) {
29  $this->action = $action;
30  }
31 
35  public function setTrigger( $trigger ) {
36  $this->trigger = $trigger;
37  }
38 
44  public function getError() {
45  return null;
46  }
47 
54  function getCaptcha() {
55  $a = mt_rand( 0, 100 );
56  $b = mt_rand( 0, 10 );
57 
58  /* Minus sign is used in the question. UTF-8,
59  since the api uses text/plain, not text/html */
60  $op = mt_rand( 0, 1 ) ? '+' : '−';
61 
62  // No space before and after $op, to ensure correct
63  // directionality.
64  $test = "$a$op$b";
65  $answer = ( $op == '+' ) ? ( $a + $b ) : ( $a - $b );
66  return [ 'question' => $test, 'answer' => $answer ];
67  }
68 
72  function addCaptchaAPI( &$resultArr ) {
73  $captcha = $this->getCaptcha();
74  $index = $this->storeCaptcha( $captcha );
75  $resultArr['captcha'] = $this->describeCaptchaType();
76  $resultArr['captcha']['id'] = $index;
77  $resultArr['captcha']['question'] = $captcha['question'];
78  }
79 
85  public function describeCaptchaType() {
86  return [
87  'type' => 'simple',
88  'mime' => 'text/plain',
89  ];
90  }
91 
121  public function getFormInformation( $tabIndex = 1 ) {
122  $captcha = $this->getCaptcha();
123  $index = $this->storeCaptcha( $captcha );
124 
125  return [
126  'html' => "<p><label for=\"wpCaptchaWord\">{$captcha['question']} = </label>" .
127  Xml::element( 'input', [
128  'name' => 'wpCaptchaWord',
129  'class' => 'mw-ui-input',
130  'id' => 'wpCaptchaWord',
131  'size' => 5,
132  'autocomplete' => 'off',
133  'tabindex' => $tabIndex ] ) . // tab in before the edit textarea
134  "</p>\n" .
135  Xml::element( 'input', [
136  'type' => 'hidden',
137  'name' => 'wpCaptchaId',
138  'id' => 'wpCaptchaId',
139  'value' => $index ] )
140  ];
141  }
142 
150  public function addFormToOutput( OutputPage $out, $tabIndex = 1 ) {
151  $this->addFormInformationToOutput( $out, $this->getFormInformation( $tabIndex ) );
152  }
153 
161  public function addFormInformationToOutput( OutputPage $out, array $formInformation ) {
162  if ( !$formInformation ) {
163  return;
164  }
165  if ( isset( $formInformation['html'] ) ) {
166  $out->addHTML( $formInformation['html'] );
167  }
168  if ( isset( $formInformation['modules'] ) ) {
169  $out->addModules( $formInformation['modules'] );
170  }
171  if ( isset( $formInformation['modulestyles'] ) ) {
172  $out->addModuleStyles( $formInformation['modulestyles'] );
173  }
174  if ( isset( $formInformation['headitems'] ) ) {
175  $out->addHeadItems( $formInformation['headitems'] );
176  }
177  }
178 
184  public function getCaptchaInfo( $captchaData, $id ) {
185  return $captchaData['question'] . ' =';
186  }
187 
193  function showEditFormFields( &$editPage, &$out ) {
194  $page = $editPage->getArticle()->getPage();
195  if ( !isset( $page->ConfirmEdit_ActivateCaptcha ) ) {
196  return;
197  }
198 
199  if ( $this->action !== 'edit' ) {
200  unset( $page->ConfirmEdit_ActivateCaptcha );
201  $out->addWikiText( $this->getMessage( $this->action )->text() );
202  $this->addFormToOutput( $out );
203  }
204  }
205 
210  function editShowCaptcha( $editPage ) {
211  $context = $editPage->getArticle()->getContext();
212  $page = $editPage->getArticle()->getPage();
213  $out = $context->getOutput();
214  if ( isset( $page->ConfirmEdit_ActivateCaptcha ) ||
215  $this->shouldCheck( $page, '', '', $context )
216  ) {
217  $out->addWikiText( $this->getMessage( $this->action )->text() );
218  $this->addFormToOutput( $out );
219  }
220  unset( $page->ConfirmEdit_ActivateCaptcha );
221  }
222 
230  public function getMessage( $action ) {
231  // one of captcha-edit, captcha-addurl, captcha-badlogin, captcha-createaccount,
232  // captcha-create, captcha-sendemail
233  $name = static::$messagePrefix . $action;
234  $msg = wfMessage( $name );
235  // obtain a more tailored message, if possible, otherwise, fall back to
236  // the default for edits
237  return $msg->isDisabled() ? wfMessage( static::$messagePrefix . 'edit' ) : $msg;
238  }
239 
246  function injectEmailUser( &$form ) {
247  global $wgCaptchaTriggers;
248  $out = $form->getOutput();
249  $user = $form->getUser();
250  if ( $wgCaptchaTriggers['sendemail'] ) {
251  $this->action = 'sendemail';
252  if ( $user->isAllowed( 'skipcaptcha' ) ) {
253  wfDebug( "ConfirmEdit: user group allows skipping captcha on email sending\n" );
254  return true;
255  }
256  $formInformation = $this->getFormInformation();
257  $formMetainfo = $formInformation;
258  unset( $formMetainfo['html'] );
259  $this->addFormInformationToOutput( $out, $formMetainfo );
260  $form->addFooterText(
261  "<div class='captcha'>" .
262  $out->parse( $this->getMessage( 'sendemail' )->text() ) .
263  $formInformation['html'] .
264  "</div>\n" );
265  }
266  return true;
267  }
268 
275  public function increaseBadLoginCounter( $username ) {
276  global $wgCaptchaTriggers, $wgCaptchaBadLoginExpiration,
277  $wgCaptchaBadLoginPerUserExpiration;
279 
280  if ( $wgCaptchaTriggers['badlogin'] ) {
281  $key = $this->badLoginKey();
282  $count = ObjectCache::getLocalClusterInstance()->get( $key );
283  if ( !$count ) {
284  $cache->add( $key, 0, $wgCaptchaBadLoginExpiration );
285  }
286 
287  $cache->incr( $key );
288  }
289 
290  if ( $wgCaptchaTriggers['badloginperuser'] && $username ) {
291  $key = $this->badLoginPerUserKey( $username );
292  $count = $cache->get( $key );
293  if ( !$count ) {
294  $cache->add( $key, 0, $wgCaptchaBadLoginPerUserExpiration );
295  }
296 
297  $cache->incr( $key );
298  }
299  }
300 
305  public function resetBadLoginCounter( $username ) {
306  global $wgCaptchaTriggers;
307 
308  if ( $wgCaptchaTriggers['badloginperuser'] && $username ) {
310  $cache->delete( $this->badLoginPerUserKey( $username ) );
311  }
312  }
313 
320  public function isBadLoginTriggered() {
321  global $wgCaptchaTriggers, $wgCaptchaBadLoginAttempts;
323  return $wgCaptchaTriggers['badlogin']
324  && (int)$cache->get( $this->badLoginKey() ) >= $wgCaptchaBadLoginAttempts;
325  }
326 
333  public function isBadLoginPerUserTriggered( $u ) {
334  global $wgCaptchaTriggers, $wgCaptchaBadLoginPerUserAttempts;
336 
337  if ( is_object( $u ) ) {
338  $u = $u->getName();
339  }
340  return $wgCaptchaTriggers['badloginperuser']
341  && (int)$cache->get( $this->badLoginPerUserKey( $u ) ) >= $wgCaptchaBadLoginPerUserAttempts;
342  }
343 
352  function isIPWhitelisted() {
353  global $wgCaptchaWhitelistIP, $wgRequest;
354  $ip = $wgRequest->getIP();
355 
356  if ( $wgCaptchaWhitelistIP ) {
357  if ( IP::isInRanges( $ip, $wgCaptchaWhitelistIP ) ) {
358  return true;
359  }
360  }
361 
362  $whitelistMsg = wfMessage( 'captcha-ip-whitelist' )->inContentLanguage();
363  if ( !$whitelistMsg->isDisabled() ) {
364  $whitelistedIPs = $this->getWikiIPWhitelist( $whitelistMsg );
365  if ( IP::isInRanges( $ip, $whitelistedIPs ) ) {
366  return true;
367  }
368  }
369 
370  return false;
371  }
372 
380  private function getWikiIPWhitelist( Message $msg ) {
382  $cacheKey = $cache->makeKey( 'confirmedit', 'ipwhitelist' );
383 
384  $cachedWhitelist = $cache->get( $cacheKey );
385  if ( $cachedWhitelist === false ) {
386  // Could not retrieve from cache so build the whitelist directly
387  // from the wikipage
388  $whitelist = $this->buildValidIPs(
389  explode( "\n", $msg->plain() )
390  );
391  // And then store it in cache for one day. This cache is cleared on
392  // modifications to the whitelist page.
393  // @see ConfirmEditHooks::onPageContentSaveComplete()
394  $cache->set( $cacheKey, $whitelist, 86400 );
395  } else {
396  // Whitelist from the cache
397  $whitelist = $cachedWhitelist;
398  }
399 
400  return $whitelist;
401  }
402 
414  private function buildValidIPs( array $input ) {
415  // Remove whitespace and blank lines first
416  $ips = array_map( 'trim', $input );
417  $ips = array_filter( $ips );
418 
419  $validIPs = [];
420  foreach ( $ips as $ip ) {
421  if ( IP::isIPAddress( $ip ) ) {
422  $validIPs[] = $ip;
423  }
424  }
425 
426  return $validIPs;
427  }
428 
433  private function badLoginKey() {
435  $ip = $wgRequest->getIP();
436  return wfGlobalCacheKey( 'captcha', 'badlogin', 'ip', $ip );
437  }
438 
444  private function badLoginPerUserKey( $username ) {
446  return wfGlobalCacheKey( 'captcha', 'badlogin', 'user', md5( $username ) );
447  }
448 
459  function keyMatch( $answer, $info ) {
460  return $answer == $info['answer'];
461  }
462 
463  // ----------------------------------
464 
471  global $wgCaptchaTriggers, $wgCaptchaTriggersOnNamespace;
472  // Special config for this NS?
473  if ( isset( $wgCaptchaTriggersOnNamespace[$title->getNamespace()][$action] ) ) {
474  return $wgCaptchaTriggersOnNamespace[$title->getNamespace()][$action];
475  }
476 
477  return ( !empty( $wgCaptchaTriggers[$action] ) ); // Default
478  }
479 
489  function shouldCheck( WikiPage $page, $content, $section, $context, $oldtext = null ) {
490  global $wgAllowConfirmedEmail;
491 
492  if ( !$context instanceof IContextSource ) {
494  }
495 
496  $request = $context->getRequest();
497  $user = $context->getUser();
498 
499  // captcha check exceptions, which will return always false
500  if ( $user->isAllowed( 'skipcaptcha' ) ) {
501  wfDebug( "ConfirmEdit: user group allows skipping captcha\n" );
502  return false;
503  } elseif ( $this->isIPWhitelisted() ) {
504  wfDebug( "ConfirmEdit: user IP is whitelisted" );
505  return false;
506  } elseif ( $wgAllowConfirmedEmail && $user->isEmailConfirmed() ) {
507  wfDebug( "ConfirmEdit: user has confirmed mail, skipping captcha\n" );
508  return false;
509  }
510 
511  $title = $page->getTitle();
512  $this->trigger = '';
513 
514  if ( $content instanceof Content ) {
515  if ( $content->getModel() == CONTENT_MODEL_WIKITEXT ) {
516  $newtext = $content->getNativeData();
517  } else {
518  $newtext = null;
519  }
520  $isEmpty = $content->isEmpty();
521  } else {
522  $newtext = $content;
523  $isEmpty = $content === '';
524  }
525 
526  if ( $this->captchaTriggers( $title, 'edit' ) ) {
527  // Check on all edits
528  $this->trigger = sprintf( "edit trigger by '%s' at [[%s]]",
529  $user->getName(),
530  $title->getPrefixedText() );
531  $this->action = 'edit';
532  wfDebug( "ConfirmEdit: checking all edits...\n" );
533  return true;
534  }
535 
536  if ( $this->captchaTriggers( $title, 'create' ) && !$title->exists() ) {
537  // Check if creating a page
538  $this->trigger = sprintf( "Create trigger by '%s' at [[%s]]",
539  $user->getName(),
540  $title->getPrefixedText() );
541  $this->action = 'create';
542  wfDebug( "ConfirmEdit: checking on page creation...\n" );
543  return true;
544  }
545 
546  // The following checks are expensive and should be done only,
547  // if we can assume, that the edit will be saved
548  if ( !$request->wasPosted() ) {
549  wfDebug(
550  "ConfirmEdit: request not posted, assuming that no content will be saved -> no CAPTCHA check"
551  );
552  return false;
553  }
554 
555  if ( !$isEmpty && $this->captchaTriggers( $title, 'addurl' ) ) {
556  // Only check edits that add URLs
557  if ( $content instanceof Content ) {
558  // Get links from the database
559  $oldLinks = $this->getLinksFromTracker( $title );
560  // Share a parse operation with Article::doEdit()
561  $editInfo = $page->prepareContentForEdit( $content );
562  if ( $editInfo->output ) {
563  $newLinks = array_keys( $editInfo->output->getExternalLinks() );
564  } else {
565  $newLinks = [];
566  }
567  } else {
568  // Get link changes in the slowest way known to man
569  $oldtext = isset( $oldtext ) ? $oldtext : $this->loadText( $title, $section );
570  $oldLinks = $this->findLinks( $title, $oldtext );
571  $newLinks = $this->findLinks( $title, $newtext );
572  }
573 
574  $unknownLinks = array_filter( $newLinks, [ $this, 'filterLink' ] );
575  $addedLinks = array_diff( $unknownLinks, $oldLinks );
576  $numLinks = count( $addedLinks );
577 
578  if ( $numLinks > 0 ) {
579  $this->trigger = sprintf( "%dx url trigger by '%s' at [[%s]]: %s",
580  $numLinks,
581  $user->getName(),
582  $title->getPrefixedText(),
583  implode( ", ", $addedLinks ) );
584  $this->action = 'addurl';
585  return true;
586  }
587  }
588 
589  global $wgCaptchaRegexes;
590  if ( $newtext !== null && $wgCaptchaRegexes ) {
591  if ( !is_array( $wgCaptchaRegexes ) ) {
592  throw new UnexpectedValueException(
593  '$wgCaptchaRegexes is required to be an array, ' . gettype( $wgCaptchaRegexes ) . ' given.'
594  );
595  }
596  // Custom regex checks. Reuse $oldtext if set above.
597  $oldtext = isset( $oldtext ) ? $oldtext : $this->loadText( $title, $section );
598 
599  foreach ( $wgCaptchaRegexes as $regex ) {
600  $newMatches = [];
601  if ( preg_match_all( $regex, $newtext, $newMatches ) ) {
602  $oldMatches = [];
603  preg_match_all( $regex, $oldtext, $oldMatches );
604 
605  $addedMatches = array_diff( $newMatches[0], $oldMatches[0] );
606 
607  $numHits = count( $addedMatches );
608  if ( $numHits > 0 ) {
609  $this->trigger = sprintf( "%dx %s at [[%s]]: %s",
610  $numHits,
611  $regex,
612  $user->getName(),
613  $title->getPrefixedText(),
614  implode( ", ", $addedMatches ) );
615  $this->action = 'edit';
616  return true;
617  }
618  }
619  }
620  }
621 
622  return false;
623  }
624 
631  function filterLink( $url ) {
632  global $wgCaptchaWhitelist;
633  static $regexes = null;
634 
635  if ( $regexes === null ) {
636  $source = wfMessage( 'captcha-addurl-whitelist' )->inContentLanguage();
637 
638  $regexes = $source->isDisabled()
639  ? []
640  : $this->buildRegexes( explode( "\n", $source->plain() ) );
641 
642  if ( $wgCaptchaWhitelist !== false ) {
643  array_unshift( $regexes, $wgCaptchaWhitelist );
644  }
645  }
646 
647  foreach ( $regexes as $regex ) {
648  if ( preg_match( $regex, $url ) ) {
649  return false;
650  }
651  }
652 
653  return true;
654  }
655 
662  function buildRegexes( $lines ) {
663  # Code duplicated from the SpamBlacklist extension (r19197)
664  # and later modified.
665 
666  # Strip comments and whitespace, then remove blanks
667  $lines = array_filter( array_map( 'trim', preg_replace( '/#.*$/', '', $lines ) ) );
668 
669  # No lines, don't make a regex which will match everything
670  if ( count( $lines ) == 0 ) {
671  wfDebug( "No lines\n" );
672  return [];
673  } else {
674  # Make regex
675  # It's faster using the S modifier even though it will usually only be run once
676  // $regex = 'http://+[a-z0-9_\-.]*(' . implode( '|', $lines ) . ')';
677  // return '/' . str_replace( '/', '\/', preg_replace('|\\\*/|', '/', $regex) ) . '/Si';
678  $regexes = [];
679  $regexStart = [
680  'normal' => '/^(?:https?:)?\/\/+[a-z0-9_\-.]*(?:',
681  'noprotocol' => '/^(?:',
682  ];
683  $regexEnd = [
684  'normal' => ')/Si',
685  'noprotocol' => ')/Si',
686  ];
687  $regexMax = 4096;
688  $build = [];
689  foreach ( $lines as $line ) {
690  # Extract flags from the line
691  $options = [];
692  if ( preg_match( '/^(.*?)\s*<([^<>]*)>$/', $line, $matches ) ) {
693  if ( $matches[1] === '' ) {
694  wfDebug( "Line with empty regex\n" );
695  continue;
696  }
697  $line = $matches[1];
698  $opts = preg_split( '/\s*\|\s*/', trim( $matches[2] ) );
699  foreach ( $opts as $opt ) {
700  $opt = strtolower( $opt );
701  if ( $opt == 'noprotocol' ) {
702  $options['noprotocol'] = true;
703  }
704  }
705  }
706 
707  $key = isset( $options['noprotocol'] ) ? 'noprotocol' : 'normal';
708 
709  // FIXME: not very robust size check, but should work. :)
710  if ( !isset( $build[$key] ) ) {
711  $build[$key] = $line;
712  } elseif ( strlen( $build[$key] ) + strlen( $line ) > $regexMax ) {
713  $regexes[] = $regexStart[$key] .
714  str_replace( '/', '\/', preg_replace( '|\\\*/|', '/', $build[$key] ) ) .
715  $regexEnd[$key];
716  $build[$key] = $line;
717  } else {
718  $build[$key] .= '|' . $line;
719  }
720  }
721  foreach ( $build as $key => $value ) {
722  $regexes[] = $regexStart[$key] .
723  str_replace( '/', '\/', preg_replace( '|\\\*/|', '/', $build[$key] ) ) .
724  $regexEnd[$key];
725  }
726  return $regexes;
727  }
728  }
729 
736  $dbr = wfGetDB( DB_SLAVE );
737  $id = $title->getArticleID(); // should be zero queries
738  $res = $dbr->select( 'externallinks', [ 'el_to' ],
739  [ 'el_from' => $id ], __METHOD__ );
740  $links = [];
741  foreach ( $res as $row ) {
742  $links[] = $row->el_to;
743  }
744  return $links;
745  }
746 
755  private function doConfirmEdit( WikiPage $page, $newtext, $section, IContextSource $context ) {
757  $request = $context->getRequest();
758 
759  // FIXME: Stop using wgRequest in other parts of ConfirmEdit so we can
760  // stop having to duplicate code for it.
761  if ( $request->getVal( 'captchaid' ) ) {
762  $request->setVal( 'wpCaptchaId', $request->getVal( 'captchaid' ) );
763  $wgRequest->setVal( 'wpCaptchaId', $request->getVal( 'captchaid' ) );
764  }
765  if ( $request->getVal( 'captchaword' ) ) {
766  $request->setVal( 'wpCaptchaWord', $request->getVal( 'captchaword' ) );
767  $wgRequest->setVal( 'wpCaptchaWord', $request->getVal( 'captchaword' ) );
768  }
769  if ( $this->shouldCheck( $page, $newtext, $section, $context ) ) {
770  return $this->passCaptchaLimitedFromRequest( $wgRequest, $wgUser );
771  } else {
772  wfDebug( "ConfirmEdit: no need to show captcha.\n" );
773  return true;
774  }
775  }
776 
787  function confirmEditMerged( $context, $content, $status, $summary, $user, $minorEdit ) {
788  if ( !$context->canUseWikiPage() ) {
789  // we check WikiPage only
790  // try to get an appropriate title for this page
791  $title = $context->getTitle();
792  if ( $title instanceof Title ) {
793  $title = $title->getFullText();
794  } else {
795  // otherwise it's an unknown page where this function is called from
796  $title = 'unknown';
797  }
798  // log this error, it could be a problem in another extension,
799  // edits should always have a WikiPage if
800  // they go through EditFilterMergedContent.
801  wfDebug( __METHOD__ . ': Skipped ConfirmEdit check: No WikiPage for title ' . $title );
802  return true;
803  }
804  $page = $context->getWikiPage();
805  if ( !$this->doConfirmEdit( $page, $content, false, $context ) ) {
807  $status->apiHookResult = [];
808  // give an error message for the user to know, what goes wrong here.
809  // this can't be done for addurl trigger, because this requires one "free" save
810  // for the user, which we don't know, when he did it.
811  if ( $this->action === 'edit' ) {
812  $status->fatal(
813  new RawMessage(
815  'div',
816  [ 'class' => 'errorbox' ],
817  $context->msg( 'captcha-edit-fail' )->text()
818  )
819  )
820  );
821  }
822  $this->addCaptchaAPI( $status->apiHookResult );
823  $page->ConfirmEdit_ActivateCaptcha = true;
824  return false;
825  }
826  return true;
827  }
828 
836  public function needCreateAccountCaptcha( User $creatingUser = null ) {
837  global $wgCaptchaTriggers, $wgUser;
838  $creatingUser = $creatingUser ?: $wgUser;
839 
840  if ( $wgCaptchaTriggers['createaccount'] ) {
841  if ( $creatingUser->isAllowed( 'skipcaptcha' ) ) {
842  wfDebug( "ConfirmEdit: user group allows skipping captcha on account creation\n" );
843  return false;
844  }
845  if ( $this->isIPWhitelisted() ) {
846  return false;
847  }
848  return true;
849  }
850  return false;
851  }
852 
862  function confirmEmailUser( $from, $to, $subject, $text, &$error ) {
863  global $wgCaptchaTriggers, $wgUser, $wgRequest;
864 
865  if ( $wgCaptchaTriggers['sendemail'] ) {
866  if ( $wgUser->isAllowed( 'skipcaptcha' ) ) {
867  wfDebug( "ConfirmEdit: user group allows skipping captcha on email sending\n" );
868  return true;
869  }
870  if ( $this->isIPWhitelisted() ) {
871  return true;
872  }
873 
874  if ( defined( 'MW_API' ) ) {
875  # API mode
876  # Asking for captchas in the API is really silly
877  $error = Status::newFatal( 'captcha-disabledinapi' );
878  return false;
879  }
880  $this->trigger = "{$wgUser->getName()} sending email";
881  if ( !$this->passCaptchaLimitedFromRequest( $wgRequest, $wgUser ) ) {
882  $error = Status::newFatal( 'captcha-sendemail-fail' );
883  return false;
884  }
885  }
886  return true;
887  }
888 
893  protected function isAPICaptchaModule( $module ) {
894  return $module instanceof ApiEditPage;
895  }
896 
903  public function APIGetAllowedParams( &$module, &$params, $flags ) {
904  if ( $this->isAPICaptchaModule( $module ) ) {
905  $params['captchaword'] = [
906  ApiBase::PARAM_HELP_MSG => 'captcha-apihelp-param-captchaword',
907  ];
908  $params['captchaid'] = [
909  ApiBase::PARAM_HELP_MSG => 'captcha-apihelp-param-captchaid',
910  ];
911  }
912 
913  return true;
914  }
915 
925  list( $index, $word ) = $this->getCaptchaParamsFromRequest( $request );
926  return $this->passCaptchaLimited( $index, $word, $user );
927  }
928 
934  $index = $request->getVal( 'wpCaptchaId' );
935  $word = $request->getVal( 'wpCaptchaWord' );
936  return [ $index, $word ];
937  }
938 
949  public function passCaptchaLimited( $index, $word, User $user ) {
950  // don't increase pingLimiter here, just check, if CAPTCHA limit exceeded
951  if ( $user->pingLimiter( 'badcaptcha', 0 ) ) {
952  // for debugging add an proper error message, the user just see an false captcha error message
953  $this->log( 'User reached RateLimit, preventing action' );
954  return false;
955  }
956 
957  if ( $this->passCaptcha( $index, $word ) ) {
958  return true;
959  }
960 
961  // captcha was not solved: increase limit and return false
962  $user->pingLimiter( 'badcaptcha' );
963  return false;
964  }
965 
974  list( $index, $word ) = $this->getCaptchaParamsFromRequest( $request );
975  return $this->passCaptcha( $index, $word );
976  }
977 
985  protected function passCaptcha( $index, $word ) {
986  // Don't check the same CAPTCHA twice in one session,
987  // if the CAPTCHA was already checked - Bug T94276
988  if ( isset( $this->captchaSolved ) ) {
989  return $this->captchaSolved;
990  }
991 
992  $info = $this->retrieveCaptcha( $index );
993  if ( $info ) {
994  if ( $this->keyMatch( $word, $info ) ) {
995  $this->log( "passed" );
996  $this->clearCaptcha( $index );
997  $this->captchaSolved = true;
998  return true;
999  } else {
1000  $this->clearCaptcha( $index );
1001  $this->log( "bad form input" );
1002  $this->captchaSolved = false;
1003  return false;
1004  }
1005  } else {
1006  $this->log( "new captcha session" );
1007  return false;
1008  }
1009  }
1010 
1015  function log( $message ) {
1016  wfDebugLog( 'captcha', 'ConfirmEdit: ' . $message . '; ' . $this->trigger );
1017  }
1018 
1030  public function storeCaptcha( $info ) {
1031  if ( !isset( $info['index'] ) ) {
1032  // Assign random index if we're not udpating
1033  $info['index'] = strval( mt_rand() );
1034  }
1035  CaptchaStore::get()->store( $info['index'], $info );
1036  return $info['index'];
1037  }
1038 
1044  public function retrieveCaptcha( $index ) {
1045  return CaptchaStore::get()->retrieve( $index );
1046  }
1047 
1052  public function clearCaptcha( $index ) {
1053  CaptchaStore::get()->clear( $index );
1054  }
1055 
1064  function loadText( $title, $section, $flags = Revision::READ_LATEST ) {
1065  global $wgParser;
1066 
1068  if ( is_null( $rev ) ) {
1069  return "";
1070  }
1071 
1072  $content = $rev->getContent();
1073  $text = ContentHandler::getContentText( $content );
1074  if ( $section !== '' ) {
1075  return $wgParser->getSection( $text, $section );
1076  }
1077 
1078  return $text;
1079  }
1080 
1087  function findLinks( $title, $text ) {
1089 
1090  $options = new ParserOptions();
1091  $text = $wgParser->preSaveTransform( $text, $title, $wgUser, $options );
1092  $out = $wgParser->parse( $text, $title, $options );
1093 
1094  return array_keys( $out->getExternalLinks() );
1095  }
1096 
1100  function showHelp() {
1101  global $wgOut;
1102  $wgOut->setPageTitle( wfMessage( 'captchahelp-title' )->text() );
1103  $wgOut->addWikiMsg( 'captchahelp-text' );
1104  if ( CaptchaStore::get()->cookiesNeeded() ) {
1105  $wgOut->addWikiMsg( 'captchahelp-cookies-needed' );
1106  }
1107  }
1108 
1112  public function createAuthenticationRequest() {
1113  $captchaData = $this->getCaptcha();
1114  $id = $this->storeCaptcha( $captchaData );
1115  return new CaptchaAuthenticationRequest( $id, $captchaData );
1116  }
1117 
1125  public function onAuthChangeFormFields(
1126  array $requests, array $fieldInfo, array &$formDescriptor, $action
1127  ) {
1128  $req = AuthenticationRequest::getRequestByClass( $requests,
1130  if ( !$req ) {
1131  return;
1132  }
1133 
1134  $formDescriptor['captchaWord'] = [
1135  'label-message' => null,
1136  'autocomplete' => false,
1137  'persistent' => false,
1138  'required' => true,
1139  ] + $formDescriptor['captchaWord'];
1140  }
1141 }
ApiEditPage
A module that allows for editing and creating pages.
Definition: ApiEditPage.php:36
SimpleCaptcha\confirmEmailUser
confirmEmailUser( $from, $to, $subject, $text, &$error)
Check the captcha on Special:EmailUser.
Definition: Captcha.php:862
ParserOptions
Set options of the Parser.
Definition: ParserOptions.php:40
CaptchaStore\get
static get()
Get somewhere to store captcha data that will persist between requests.
Definition: CaptchaStore.php:44
$user
please add to it if you re going to add events to the MediaWiki code where normally authentication against an external auth plugin would be creating a account $user
Definition: hooks.txt:244
$wgUser
$wgUser
Definition: Setup.php:809
SimpleCaptcha\badLoginPerUserKey
badLoginPerUserKey( $username)
Cache key for badloginPerUser checks.
Definition: Captcha.php:444
ObjectCache\getLocalClusterInstance
static getLocalClusterInstance()
Get the main cluster-local cache object.
Definition: ObjectCache.php:357
$context
do that in ParserLimitReportFormat instead use this to modify the parameters of the image all existing parser cache entries will be invalid To avoid you ll need to handle that somehow(e.g. with the RejectParserCacheValue hook) because MediaWiki won 't do it for you. & $defaults also a ContextSource after deleting those rows but within the same transaction you ll probably need to make sure the header is varied on and they can depend only on the ResourceLoaderContext $context
Definition: hooks.txt:2581
$wgParser
$wgParser
Definition: Setup.php:824
SimpleCaptcha\loadText
loadText( $title, $section, $flags=Revision::READ_LATEST)
Retrieve the current version of the page or section being edited...
Definition: Captcha.php:1064
SimpleCaptcha\passCaptchaLimitedFromRequest
passCaptchaLimitedFromRequest(WebRequest $request, User $user)
Checks, if the user reached the amount of false CAPTCHAs and give him some vacation or run self::pass...
Definition: Captcha.php:924
IP\isInRanges
static isInRanges( $ip, $ranges)
Determines if an IP address is a list of CIDR a.b.c.d/n ranges.
Definition: IP.php:668
$opt
$opt
Definition: postprocess-phan.php:115
captcha-old.count
count
Definition: captcha-old.py:249
SimpleCaptcha\addFormToOutput
addFormToOutput(OutputPage $out, $tabIndex=1)
Uses getFormInformation() to get the CAPTCHA form and adds it to the given OutputPage object.
Definition: Captcha.php:150
text
design txt This is a brief overview of the new design More thorough and up to date information is available on the documentation wiki at etc Handles the details of getting and saving to the user table of the and dealing with sessions and cookies OutputPage Encapsulates the entire HTML page that will be sent in response to any server request It is used by calling its functions to add text
Definition: design.txt:12
$regexes
if( $wgSpamBlacklistFiles) $regexes
Definition: cleanup.php:88
ApiBase\PARAM_HELP_MSG
const PARAM_HELP_MSG
(string|array|Message) Specify an alternative i18n documentation message for this parameter.
Definition: ApiBase.php:128
MediaWiki\getTitle
getTitle()
Get the Title object that we'll be acting on, as specified in the WebRequest.
Definition: MediaWiki.php:137
$status
Status::newGood()` to allow deletion, and then `return false` from the hook function. Ensure you consume the 'ChangeTagAfterDelete' hook to carry out custom deletion actions. $tag:name of the tag $user:user initiating the action & $status:Status object. See above. 'ChangeTagsListActive':Allows you to nominate which of the tags your extension uses are in active use. & $tags:list of all active tags. Append to this array. 'ChangeTagsAfterUpdateTags':Called after tags have been updated with the ChangeTags::updateTags function. Params:$addedTags:tags effectively added in the update $removedTags:tags effectively removed in the update $prevTags:tags that were present prior to the update $rc_id:recentchanges table id $rev_id:revision table id $log_id:logging table id $params:tag params $rc:RecentChange being tagged when the tagging accompanies the action or null $user:User who performed the tagging when the tagging is subsequent to the action or null 'ChangeTagsAllowedAdd':Called when checking if a user can add tags to a change. & $allowedTags:List of all the tags the user is allowed to add. Any tags the user wants to add( $addTags) that are not in this array will cause it to fail. You may add or remove tags to this array as required. $addTags:List of tags user intends to add. $user:User who is adding the tags. 'ChangeUserGroups':Called before user groups are changed. $performer:The User who will perform the change $user:The User whose groups will be changed & $add:The groups that will be added & $remove:The groups that will be removed 'Collation::factory':Called if $wgCategoryCollation is an unknown collation. $collationName:Name of the collation in question & $collationObject:Null. Replace with a subclass of the Collation class that implements the collation given in $collationName. 'ConfirmEmailComplete':Called after a user 's email has been confirmed successfully. $user:user(object) whose email is being confirmed 'ContentAlterParserOutput':Modify parser output for a given content object. Called by Content::getParserOutput after parsing has finished. Can be used for changes that depend on the result of the parsing but have to be done before LinksUpdate is called(such as adding tracking categories based on the rendered HTML). $content:The Content to render $title:Title of the page, as context $parserOutput:ParserOutput to manipulate 'ContentGetParserOutput':Customize parser output for a given content object, called by AbstractContent::getParserOutput. May be used to override the normal model-specific rendering of page content. $content:The Content to render $title:Title of the page, as context $revId:The revision ID, as context $options:ParserOptions for rendering. To avoid confusing the parser cache, the output can only depend on parameters provided to this hook function, not on global state. $generateHtml:boolean, indicating whether full HTML should be generated. If false, generation of HTML may be skipped, but other information should still be present in the ParserOutput object. & $output:ParserOutput, to manipulate or replace 'ContentHandlerDefaultModelFor':Called when the default content model is determined for a given title. May be used to assign a different model for that title. $title:the Title in question & $model:the model name. Use with CONTENT_MODEL_XXX constants. 'ContentHandlerForModelID':Called when a ContentHandler is requested for a given content model name, but no entry for that model exists in $wgContentHandlers. Note:if your extension implements additional models via this hook, please use GetContentModels hook to make them known to core. $modeName:the requested content model name & $handler:set this to a ContentHandler object, if desired. 'ContentModelCanBeUsedOn':Called to determine whether that content model can be used on a given page. This is especially useful to prevent some content models to be used in some special location. $contentModel:ID of the content model in question $title:the Title in question. & $ok:Output parameter, whether it is OK to use $contentModel on $title. Handler functions that modify $ok should generally return false to prevent further hooks from further modifying $ok. 'ContribsPager::getQueryInfo':Before the contributions query is about to run & $pager:Pager object for contributions & $queryInfo:The query for the contribs Pager 'ContribsPager::reallyDoQuery':Called before really executing the query for My Contributions & $data:an array of results of all contribs queries $pager:The ContribsPager object hooked into $offset:Index offset, inclusive $limit:Exact query limit $descending:Query direction, false for ascending, true for descending 'ContributionsLineEnding':Called before a contributions HTML line is finished $page:SpecialPage object for contributions & $ret:the HTML line $row:the DB row for this line & $classes:the classes to add to the surrounding< li > & $attribs:associative array of other HTML attributes for the< li > element. Currently only data attributes reserved to MediaWiki are allowed(see Sanitizer::isReservedDataAttribute). 'ContributionsToolLinks':Change tool links above Special:Contributions $id:User identifier $title:User page title & $tools:Array of tool links $specialPage:SpecialPage instance for context and services. Can be either SpecialContributions or DeletedContributionsPage. Extensions should type hint against a generic SpecialPage though. 'ConvertContent':Called by AbstractContent::convert when a conversion to another content model is requested. Handler functions that modify $result should generally return false to disable further attempts at conversion. $content:The Content object to be converted. $toModel:The ID of the content model to convert to. $lossy:boolean indicating whether lossy conversion is allowed. & $result:Output parameter, in case the handler function wants to provide a converted Content object. Note that $result->getContentModel() must return $toModel. 'CustomEditor':When invoking the page editor Return true to allow the normal editor to be used, or false if implementing a custom editor, e.g. for a special namespace, etc. $article:Article being edited $user:User performing the edit 'DatabaseOraclePostInit':Called after initialising an Oracle database $db:the DatabaseOracle object 'DeletedContribsPager::reallyDoQuery':Called before really executing the query for Special:DeletedContributions Similar to ContribsPager::reallyDoQuery & $data:an array of results of all contribs queries $pager:The DeletedContribsPager object hooked into $offset:Index offset, inclusive $limit:Exact query limit $descending:Query direction, false for ascending, true for descending 'DeletedContributionsLineEnding':Called before a DeletedContributions HTML line is finished. Similar to ContributionsLineEnding $page:SpecialPage object for DeletedContributions & $ret:the HTML line $row:the DB row for this line & $classes:the classes to add to the surrounding< li > & $attribs:associative array of other HTML attributes for the< li > element. Currently only data attributes reserved to MediaWiki are allowed(see Sanitizer::isReservedDataAttribute). 'DifferenceEngineAfterLoadNewText':called in DifferenceEngine::loadNewText() after the new revision 's content has been loaded into the class member variable $differenceEngine->mNewContent but before returning true from this function. $differenceEngine:DifferenceEngine object 'DifferenceEngineLoadTextAfterNewContentIsLoaded':called in DifferenceEngine::loadText() after the new revision 's content has been loaded into the class member variable $differenceEngine->mNewContent but before checking if the variable 's value is null. This hook can be used to inject content into said class member variable. $differenceEngine:DifferenceEngine object 'DifferenceEngineMarkPatrolledLink':Allows extensions to change the "mark as patrolled" link which is shown both on the diff header as well as on the bottom of a page, usually wrapped in a span element which has class="patrollink". $differenceEngine:DifferenceEngine object & $markAsPatrolledLink:The "mark as patrolled" link HTML(string) $rcid:Recent change ID(rc_id) for this change(int) 'DifferenceEngineMarkPatrolledRCID':Allows extensions to possibly change the rcid parameter. For example the rcid might be set to zero due to the user being the same as the performer of the change but an extension might still want to show it under certain conditions. & $rcid:rc_id(int) of the change or 0 $differenceEngine:DifferenceEngine object $change:RecentChange object $user:User object representing the current user 'DifferenceEngineNewHeader':Allows extensions to change the $newHeader variable, which contains information about the new revision, such as the revision 's author, whether the revision was marked as a minor edit or not, etc. $differenceEngine:DifferenceEngine object & $newHeader:The string containing the various #mw-diff-otitle[1-5] divs, which include things like revision author info, revision comment, RevisionDelete link and more $formattedRevisionTools:Array containing revision tools, some of which may have been injected with the DiffRevisionTools hook $nextlink:String containing the link to the next revision(if any) $status
Definition: hooks.txt:1245
SimpleCaptcha\keyMatch
keyMatch( $answer, $info)
Check if the submitted form matches the captcha session data provided by the plugin when the form was...
Definition: Captcha.php:459
use
as see the revision history and available at free of to any person obtaining a copy of this software and associated documentation to deal in the Software without including without limitation the rights to use
Definition: MIT-LICENSE.txt:10
SimpleCaptcha\editShowCaptcha
editShowCaptcha( $editPage)
Insert the captcha prompt into an edit form.
Definition: Captcha.php:210
$req
this hook is for auditing only $req
Definition: hooks.txt:988
WikiPage
Class representing a MediaWiki article and history.
Definition: WikiPage.php:37
StatusValue\newFatal
static newFatal( $message)
Factory function for fatal errors.
Definition: StatusValue.php:68
$params
$params
Definition: styleTest.css.php:40
SimpleCaptcha\captchaTriggers
captchaTriggers( $title, $action)
Definition: Captcha.php:470
DB_SLAVE
const DB_SLAVE
Definition: Defines.php:37
$res
$res
Definition: database.txt:21
$name
Allows to change the fields on the form that will be generated $name
Definition: hooks.txt:302
SimpleCaptcha\$action
string $action
Used to select the right message.
Definition: Captcha.php:20
CONTENT_MODEL_WIKITEXT
const CONTENT_MODEL_WIKITEXT
Definition: Defines.php:236
SimpleCaptcha\showHelp
showHelp()
Show a page explaining what this wacky thing is.
Definition: Captcha.php:1100
SimpleCaptcha\setAction
setAction( $action)
Definition: Captcha.php:28
SimpleCaptcha\injectEmailUser
injectEmailUser(&$form)
Inject whazawhoo @fixme if multiple thingies insert a header, could break.
Definition: Captcha.php:246
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:1140
SimpleCaptcha\buildRegexes
buildRegexes( $lines)
Build regex from whitelist.
Definition: Captcha.php:662
php
injection txt This is an overview of how MediaWiki makes use of dependency injection The design described here grew from the discussion of RFC T384 The term dependency this means that anything an object needs to operate should be injected from the the object itself should only know narrow no concrete implementation of the logic it relies on The requirement to inject everything typically results in an architecture that based on two main types of and essentially stateless service objects that use other service objects to operate on the value objects As of the beginning MediaWiki is only starting to use the DI approach Much of the code still relies on global state or direct resulting in a highly cyclical dependency which acts as the top level factory for services in MediaWiki which can be used to gain access to default instances of various services MediaWikiServices however also allows new services to be defined and default services to be redefined Services are defined or redefined by providing a callback the instantiator that will return a new instance of the service When it will create an instance of MediaWikiServices and populate it with the services defined in the files listed by thereby bootstrapping the DI framework Per $wgServiceWiringFiles lists includes ServiceWiring php
Definition: injection.txt:35
SimpleCaptcha\getCaptchaInfo
getCaptchaInfo( $captchaData, $id)
Definition: Captcha.php:184
Revision\newFromTitle
static newFromTitle(LinkTarget $linkTarget, $id=0, $flags=0)
Load either the current, or a specified, revision that's attached to a given link target.
Definition: Revision.php:134
SimpleCaptcha\passCaptchaLimited
passCaptchaLimited( $index, $word, User $user)
Checks, if the user reached the amount of false CAPTCHAs and give him some vacation or run self::pass...
Definition: Captcha.php:949
SimpleCaptcha\addCaptchaAPI
addCaptchaAPI(&$resultArr)
Definition: Captcha.php:72
SimpleCaptcha\resetBadLoginCounter
resetBadLoginCounter( $username)
Reset bad login counter after a successful login.
Definition: Captcha.php:305
$title
namespace and then decline to actually register it file or subcat img or subcat $title
Definition: hooks.txt:932
wfGlobalCacheKey
wfGlobalCacheKey()
Make a cache key with database-agnostic prefix.
Definition: GlobalFunctions.php:2794
SimpleCaptcha\getCaptcha
getCaptcha()
Returns an array with 'question' and 'answer' keys.
Definition: Captcha.php:54
SimpleCaptcha\filterLink
filterLink( $url)
Filter callback function for URL whitelisting.
Definition: Captcha.php:631
wfGetDB
wfGetDB( $db, $groups=[], $wiki=false)
Get a Database object.
Definition: GlobalFunctions.php:2856
$input
if(is_array( $mode)) switch( $mode) $input
Definition: postprocess-phan.php:141
$matches
$matches
Definition: NoLocalSettings.php:24
SimpleCaptcha\findLinks
findLinks( $title, $text)
Extract a list of all recognized HTTP links in the text.
Definition: Captcha.php:1087
SimpleCaptcha\getWikiIPWhitelist
getWikiIPWhitelist(Message $msg)
Get the on-wiki IP whitelist stored in [[MediaWiki:Captcha-ip-whitelist]] page from cache if possible...
Definition: Captcha.php:380
WikiPage\getTitle
getTitle()
Get the title object of the article.
Definition: WikiPage.php:239
Xml\element
static element( $element, $attribs=null, $contents='', $allowShortTag=true)
Format an XML element with given attributes and, optionally, text content.
Definition: Xml.php:39
SimpleCaptcha\getCaptchaParamsFromRequest
getCaptchaParamsFromRequest(WebRequest $request)
Definition: Captcha.php:933
$lines
$lines
Definition: router.php:67
global
when a variable name is used in a it is silently declared as a new masking the global
Definition: design.txt:93
SimpleCaptcha\onAuthChangeFormFields
onAuthChangeFormFields(array $requests, array $fieldInfo, array &$formDescriptor, $action)
Modify the apprearance of the captcha field.
Definition: Captcha.php:1125
wfDebug
wfDebug( $text, $dest='all', array $context=[])
Sends a line to the debug log if enabled or, optionally, to a comment in output.
Definition: GlobalFunctions.php:1047
OutputPage
This class should be covered by a general architecture document which does not exist as of January 20...
Definition: OutputPage.php:44
list
deferred txt A few of the database updates required by various functions here can be deferred until after the result page is displayed to the user For updating the view updating the linked to tables after a etc PHP does not yet have any way to tell the server to actually return and disconnect while still running these but it might have such a feature in the future We handle these by creating a deferred update object and putting those objects on a global list
Definition: deferred.txt:11
captcha-old.action
action
Definition: captcha-old.py:212
$request
do that in ParserLimitReportFormat instead use this to modify the parameters of the image all existing parser cache entries will be invalid To avoid you ll need to handle that somehow(e.g. with the RejectParserCacheValue hook) because MediaWiki won 't do it for you. & $defaults also a ContextSource after deleting those rows but within the same transaction you ll probably need to make sure the header is varied on $request
Definition: hooks.txt:2581
SimpleCaptcha\doConfirmEdit
doConfirmEdit(WikiPage $page, $newtext, $section, IContextSource $context)
Backend function for confirmEditMerged()
Definition: Captcha.php:755
SimpleCaptcha\badLoginKey
badLoginKey()
Internal cache key for badlogin checks.
Definition: Captcha.php:433
$line
$line
Definition: cdb.php:58
SimpleCaptcha\confirmEditMerged
confirmEditMerged( $context, $content, $status, $summary, $user, $minorEdit)
An efficient edit filter callback based on the text after section merging.
Definition: Captcha.php:787
SimpleCaptcha\isIPWhitelisted
isIPWhitelisted()
Check if the current IP is allowed to skip captchas.
Definition: Captcha.php:352
SimpleCaptcha\isBadLoginTriggered
isBadLoginTriggered()
Check if a bad login has already been registered for this IP address.
Definition: Captcha.php:320
$value
$value
Definition: styleTest.css.php:45
SimpleCaptcha\setTrigger
setTrigger( $trigger)
Definition: Captcha.php:35
SimpleCaptcha\log
log( $message)
Log the status and any triggering info for debugging or statistics.
Definition: Captcha.php:1015
SimpleCaptcha\retrieveCaptcha
retrieveCaptcha( $index)
Fetch this session's captcha info.
Definition: Captcha.php:1044
SimpleCaptcha\createAuthenticationRequest
createAuthenticationRequest()
Definition: Captcha.php:1112
SimpleCaptcha\needCreateAccountCaptcha
needCreateAccountCaptcha(User $creatingUser=null)
Logic to check if we need to pass a captcha for the current user to create a new account,...
Definition: Captcha.php:836
SimpleCaptcha\$messagePrefix
static $messagePrefix
Definition: Captcha.php:10
SimpleCaptcha\addFormInformationToOutput
addFormInformationToOutput(OutputPage $out, array $formInformation)
Processes the given $formInformation array and adds the options (see getFormInformation()) to the giv...
Definition: Captcha.php:161
SimpleCaptcha
Demo CAPTCHA (not for production usage) and base class for real CAPTCHAs.
Definition: Captcha.php:9
SimpleCaptcha\getError
getError()
Return the error from the last passCaptcha* call.
Definition: Captcha.php:44
SimpleCaptcha\storeCaptcha
storeCaptcha( $info)
Generate a captcha session ID and save the info in PHP's session storage.
Definition: Captcha.php:1030
RequestContext\getMain
static getMain()
Static methods.
Definition: RequestContext.php:470
SimpleCaptcha\getMessage
getMessage( $action)
Show a message asking the user to enter a captcha on edit The result will be treated as wiki text.
Definition: Captcha.php:230
IContextSource
Interface for objects which can provide a MediaWiki context on request.
Definition: IContextSource.php:55
WebRequest
The WebRequest class encapsulates getting at data passed in the URL or via a POSTed form stripping il...
Definition: WebRequest.php:38
SimpleCaptcha\describeCaptchaType
describeCaptchaType()
Describes the captcha type for API clients.
Definition: Captcha.php:85
SimpleCaptcha\isBadLoginPerUserTriggered
isBadLoginPerUserTriggered( $u)
Is the per-user captcha triggered?
Definition: Captcha.php:333
Content
Base interface for content objects.
Definition: Content.php:34
SimpleCaptcha\isAPICaptchaModule
isAPICaptchaModule( $module)
Definition: Captcha.php:893
Title
Represents a title within MediaWiki.
Definition: Title.php:39
SimpleCaptcha\$trigger
string $trigger
Used in log messages.
Definition: Captcha.php:23
ContentHandler\getContentText
static getContentText(Content $content=null)
Convenience function for getting flat text from a Content object.
Definition: ContentHandler.php:79
$dbr
if(! $regexes) $dbr
Definition: cleanup.php:94
SimpleCaptcha\shouldCheck
shouldCheck(WikiPage $page, $content, $section, $context, $oldtext=null)
Definition: Captcha.php:489
$cache
$cache
Definition: mcc.php:33
$options
null means default in associative array with keys and values unescaped Should be merged with default with a value of false meaning to suppress the attribute in associative array with keys and values unescaped & $options
Definition: hooks.txt:1965
ObjectCache\getMainWANInstance
static getMainWANInstance()
Get the main WAN cache object.
Definition: ObjectCache.php:370
SimpleCaptcha\increaseBadLoginCounter
increaseBadLoginCounter( $username)
Increase bad login counter after a failed login.
Definition: Captcha.php:275
SimpleCaptcha\$captchaSolved
boolean null $captchaSolved
Was the CAPTCHA already passed and if yes, with which result?
Definition: Captcha.php:13
SimpleCaptcha\passCaptcha
passCaptcha( $index, $word)
Given a required captcha run, test form input for correct input on the open session.
Definition: Captcha.php:985
$section
usually copyright or history_copyright This message must be in HTML not wikitext if the section is included from a template $section
Definition: hooks.txt:2981
User\getCanonicalName
static getCanonicalName( $name, $validate='valid')
Given unvalidated user input, return a canonical username, or false if the username is invalid.
Definition: User.php:1092
SimpleCaptcha\getLinksFromTracker
getLinksFromTracker( $title)
Load external links from the externallinks table.
Definition: Captcha.php:735
$rev
presenting them properly to the user as errors is done by the caller return true use this to change the list i e etc $rev
Definition: hooks.txt:1750
as
This document is intended to provide useful advice for parties seeking to redistribute MediaWiki to end users It s targeted particularly at maintainers for Linux since it s been observed that distribution packages of MediaWiki often break We ve consistently had to recommend that users seeking support use official tarballs instead of their distribution s and this often solves whatever problem the user is having It would be nice if this could such as
Definition: distributors.txt:9
$requests
Allows to change the fields on the form that will be generated are created Can be used to omit specific feeds from being outputted You must not use this hook to add use OutputPage::addFeedLink() instead. & $feedLinks hooks can tweak the array to change how login etc forms should look $requests
Definition: hooks.txt:304
WikiPage\prepareContentForEdit
prepareContentForEdit(Content $content, $revision=null, User $user=null, $serialFormat=null, $useCache=true)
Prepare content which is about to be saved.
Definition: WikiPage.php:1980
LoggerFactory
MediaWiki Logger LoggerFactory implements a PSR[0] compatible message logging system Named Psr Log LoggerInterface instances can be obtained from the MediaWiki Logger LoggerFactory::getInstance() static method. MediaWiki\Logger\LoggerFactory expects a class implementing the MediaWiki\Logger\Spi interface to act as a factory for new Psr\Log\LoggerInterface instances. The "Spi" in MediaWiki\Logger\Spi stands for "service provider interface". An SPI is an API intended to be implemented or extended by a third party. This software design pattern is intended to enable framework extension and replaceable components. It is specifically used in the MediaWiki\Logger\LoggerFactory service to allow alternate PSR-3 logging implementations to be easily integrated with MediaWiki. The service provider interface allows the backend logging library to be implemented in multiple ways. The $wgMWLoggerDefaultSpi global provides the classname of the default MediaWiki\Logger\Spi implementation to be loaded at runtime. This can either be the name of a class implementing the MediaWiki\Logger\Spi with a zero argument const ructor or a callable that will return an MediaWiki\Logger\Spi instance. Alternately the MediaWiki\Logger\LoggerFactory MediaWiki Logger LoggerFactory
Definition: logger.txt:5
$source
$source
Definition: mwdoc-filter.php:46
wfMessage
either a unescaped string or a HtmlArmor object after in associative array form externallinks including delete and has completed for all link tables whether this was an auto creation default is conds Array Extra conditions for the No matching items in log is displayed if loglist is empty msgKey Array If you want a nice box with a set this to the key of the message First element is the message additional optional elements are parameters for the key that are processed with wfMessage() -> params() ->parseAsBlock() - offset Set to overwrite offset parameter in $wgRequest set to '' to unset offset - wrap String Wrap the message in html(usually something like "&lt
class
you have access to all of the normal MediaWiki so you can get a DB use the etc For full docs on the Maintenance class
Definition: maintenance.txt:52
$wgRequest
if(! $wgDBerrorLogTZ) $wgRequest
Definition: Setup.php:662
Html\element
static element( $element, $attribs=[], $contents='')
Identical to rawElement(), but HTML-escapes $contents (like Xml::element()).
Definition: Html.php:231
RawMessage
Variant of the Message class.
Definition: RawMessage.php:34
SimpleCaptcha\APIGetAllowedParams
APIGetAllowedParams(&$module, &$params, $flags)
Definition: Captcha.php:903
$wgOut
$wgOut
Definition: Setup.php:819
SimpleCaptcha\showEditFormFields
showEditFormFields(&$editPage, &$out)
Show error message for missing or incorrect captcha on EditPage.
Definition: Captcha.php:193
SimpleCaptcha\getFormInformation
getFormInformation( $tabIndex=1)
Insert a captcha prompt into the edit form.
Definition: Captcha.php:121
User
The User object encapsulates all of the user-specific settings (user_id, name, rights,...
Definition: User.php:51
$username
this hook is for auditing only or null if authentication failed before getting that far $username
Definition: hooks.txt:781
SimpleCaptcha\passCaptchaFromRequest
passCaptchaFromRequest(WebRequest $request, User $user)
Given a required captcha run, test form input for correct input on the open session.
Definition: Captcha.php:973
$flags
it s the revision text itself In either if gzip is the revision text is gzipped $flags
Definition: hooks.txt:2801
EditPage\AS_HOOK_ERROR_EXPECTED
const AS_HOOK_ERROR_EXPECTED
Status: A hook function returned an error.
Definition: EditPage.php:66
MediaWiki\Auth\AuthenticationRequest
This is a value object for authentication requests.
Definition: AuthenticationRequest.php:37
IP\isIPAddress
static isIPAddress( $ip)
Determine if a string is as valid IP address or network (CIDR prefix).
Definition: IP.php:77
array
the array() calling protocol came about after MediaWiki 1.4rc1.
CaptchaAuthenticationRequest
Generic captcha authentication request class.
Definition: CaptchaAuthenticationRequest.php:10
SimpleCaptcha\buildValidIPs
buildValidIPs(array $input)
From a list of unvalidated input, get all the valid IP addresses and IP ranges from it.
Definition: Captcha.php:414
$out
this hook is for auditing only or null if authentication failed before getting that far or null if we can t even determine that probably a stub it is not rendered in wiki pages or galleries in category pages allow injecting custom HTML after the section Any uses of the hook need to handle escaping see BaseTemplate::getToolbox and BaseTemplate::makeListItem for details on the format of individual items inside of this array or by returning and letting standard HTTP rendering take place modifiable or by returning false and taking over the output $out
Definition: hooks.txt:781
SimpleCaptcha\clearCaptcha
clearCaptcha( $index)
Clear out existing captcha info from the session, to ensure it can't be reused.
Definition: Captcha.php:1052