3 # Prelim in-progress code. Proof of concept for framework, not
4 # intended as a real production captcha system!
6 # Loader for simple captcha feature
7 # Include this from LocalSettings.php
9 if ( defined( 'MEDIAWIKI' ) ) {
11 global $wgExtensionFunctions, $wgGroupPermissions;
13 $wgExtensionFunctions[] = 'ceSetup';
15 $wgGroupPermissions['*' ]['skipcaptcha'] = false;
16 $wgGroupPermissions['user' ]['skipcaptcha'] = false;
17 $wgGroupPermissions['bot' ]['skipcaptcha'] = true; // registered bots
18 $wgGroupPermissions['sysop' ]['skipcaptcha'] = true;
20 global $wgCaptcha, $wgCaptchaClass, $wgCaptchaTriggers;
22 $wgCaptchaClass = 'SimpleCaptcha';
24 $wgCaptchaTriggers = array();
25 $wgCaptchaTriggers['edit'] = false; // Would check on every edit
26 $wgCaptchaTriggers['addurl'] = true; // Check on edits that add URLs
29 * Allow users who have confirmed their e-mail addresses to post
30 * URL links without being harassed by the captcha.
32 global $ceAllowConfirmedEmail;
33 $ceAllowConfirmedEmail = false;
36 * Set up message strings for captcha utilities.
39 global $wgMessageCache, $wgHooks, $wgCaptcha, $wgCaptchaClass;
40 $wgMessageCache->addMessage('captcha-short', "Your edit includes new URL links; as a protection
41 against automated spam, you'll need to enter the answer to this
42 simple arithmetic test:" );
44 SpecialPage::addPage( new SpecialPage( 'Captcha', false,
45 /*listed*/ false, /*function*/ false, /*file*/ false ) );
47 $wgCaptcha = new $wgCaptchaClass();
48 $wgHooks['EditFilter'][] = array( &$wgCaptcha, 'confirmEdit' );
52 * Entry point for Special:Captcha
54 function wfSpecialCaptcha( $par = null ) {
58 return $wgCaptcha->showImage();
61 return $wgCaptcha->showHelp();
67 * @param EditPage $editPage
68 * @param string $newtext
69 * @param string $section
70 * @return bool true if the captcha should run
72 function shouldCheck( &$editPage, $newtext, $section ) {
74 if( $wgUser->isAllowed( 'skipcaptcha' ) ) {
75 wfDebug( "SimpleCaptcha: user group allows skipping captcha\n" );
79 global $wgEmailAuthentication, $ceAllowConfirmedEmail;
80 if( $wgEmailAuthentication && $ceAllowConfirmedEmail &&
81 $wgUser->isEmailConfirmed() ) {
82 wfDebug( "SimpleCaptcha: user has confirmed mail, skipping captcha\n" );
86 global $wgCaptchaTriggers;
87 if( !empty( $wgCaptchaTriggers['edit'] ) ) {
89 wfDebug( "SimpleCaptcha: checking all edits...\n" );
93 if( !empty( $wgCaptchaTriggers['addurl'] ) ) {
94 // Only check edits that add URLs
95 $oldtext = $this->loadText( $editPage, $section );
97 $oldLinks = $this->findLinks( $oldtext );
98 $newLinks = $this->findLinks( $newtext );
100 $addedLinks = array_diff( $newLinks, $oldLinks );
101 $numLinks = count( $addedLinks );
103 if( $numLinks > 0 ) {
104 wfDebug( "SimpleCaptcha: found $numLinks new links; triggered...\n" );
112 function confirmEdit( &$editPage, $newtext, $section ) {
113 if( $this->shouldCheck( $editPage, $newtext, $section ) ) {
114 if( $this->keyMatch() ) {
115 wfDebug( "ConfirmEdit given proper key from form, passing.\n" );
118 wfDebug( "ConfirmEdit missing form key, prompting.\n" );
119 $editPage->showEditForm( array( &$this, 'formCallback' ) );
123 wfDebug( "ConfirmEdit: no new links.\n" );
128 function keyMatch() {
129 if( !isset( $_SESSION['ceAnswerVar'] ) ) {
130 wfDebug( "ConfirmEdit no session captcha key set, this is new visitor.\n" );
134 return $wgRequest->getVal( $_SESSION['ceAnswerVar'] ) == $_SESSION['ceAnswer'];
137 function formCallback( &$out ) {
138 $source = 'ceSource' . mt_rand();
139 $dest = 'ceConfirm' . mt_rand();
141 $a = mt_rand(0, 100);
143 $op = mt_rand(0, 1) ? '+' : '-';
146 $answer = ($op == '+') ? ($a + $b) : ($a - $b);
147 $_SESSION['ceAnswer'] = $answer;
148 $_SESSION['ceAnswerVar'] = $dest;
151 $out->addWikiText( wfMsg( "captcha-short" ) );
152 $out->addHTML( <<<END
153 <p><span id="$source">$test</span> = <input name="$dest" id="$dest" /></p>
158 function loadText( $editPage, $section ) {
159 $rev = Revision::newFromTitle( $editPage->mTitle );
160 if( is_null( $rev ) ) {
163 $text = $rev->getText();
164 if( $section != '' ) {
165 return Article::getSection( $text, $section );
172 function findLinks( $text ) {
173 $regex = '/((?:' . HTTP_PROTOCOLS . ')' . EXT_LINK_URL_CLASS . '+)/';
175 if( preg_match_all( $regex, $text, $matches, PREG_PATTERN_ORDER ) ) {
182 function showHelp() {
183 global $wgOut, $ceAllowConfirmedEmail;
184 $wgOut->setPageTitle( 'Captcha help' );
185 $wgOut->addWikiText( <<<END
186 So what's this wacky captcha thing about?
188 It's your enemy. It's here to kill you. RUN WHILE YOU STILL CAN
195 } # End invocation guard