| Index: trunk/extensions/ConfirmEdit/Asirra.i18n.php |
| — | — | @@ -0,0 +1,35 @@ |
| | 2 | +<?php |
| | 3 | +/** |
| | 4 | + * Internationalisation file for the Asirra module of the ConfirmEdit |
| | 5 | + * extension. |
| | 6 | + * |
| | 7 | + * @file |
| | 8 | + * @ingroup Extensions |
| | 9 | + */ |
| | 10 | + |
| | 11 | +$messages = array(); |
| | 12 | + |
| | 13 | +/* English */ |
| | 14 | +$messages['en'] = array( |
| | 15 | + 'asirra-desc' => 'Asirra module for ConfirmEdit', |
| | 16 | + 'asirra-edit' => 'To help protect against automated edit spam, please select just the cat photos in the box below:', |
| | 17 | + 'asirra-addurl' => 'Your edit includes new external links. To help protect against automated spam, please select just the cat photos in the box below:', |
| | 18 | + 'asirra-badpass' => 'To help protect against automated password cracking, please select just the cat photos in the box below:', |
| | 19 | + 'asirra-createaccount' => 'To help protect against automated account creation, please select just the cat photos in the box below:', |
| | 20 | + 'asirra-createaccount-fail' => "Please correctly identify the cats.", |
| | 21 | + 'asirra-create' => 'To help protect against automated page creation, please select just the cat photos in the box below:', |
| | 22 | + 'asirra-nojs' => '\'\'\'Please enable JavaScript and resubmit the page.\'\'\'' |
| | 23 | +); |
| | 24 | + |
| | 25 | + |
| | 26 | +/** German (Deutsch) */ |
| | 27 | +$messages['de'] = array( |
| | 28 | + 'asirra-desc' => 'Asirra-Modul für ConfirmEdit', |
| | 29 | + 'asirra-edit' => 'Zum Schutz vor automatisiertem Spam, wähle bitte nur die Katzen im untenstehenden Feld aus:', |
| | 30 | + 'asirra-addurl' => 'Deine Bearbeitung enthält neue externe Links. Zum Schutz vor automatisiertem Spam wähle bitte nur die Katzen im untenstehenden Feld aus:', |
| | 31 | + 'asirra-badpass' => 'Zum Schutz gegen automatisiertes Knacken von Passwörtern, wähle bitte nur die Katzen im untenstehenden Feld aus:', |
| | 32 | + 'asirra-createaccount' => 'Zum Schutz gegen automatisierte Erstellung von Benutzerkonten wähle bitte nur die Katzen im untenstehenden Feld aus:', |
| | 33 | + 'asirra-createaccount-fail' => 'Bitte wähle nur Katzen aus.', |
| | 34 | + 'asirra-create' => 'Zum Schutz gegen automatisierte Erstellung von Seiten, wähle bitte nur die Katzen im untenstehenden Feld aus:', |
| | 35 | + 'asirra-nojs' => '\'\'\'Bitte aktiviere JavaScript und sende die Seite noch einmal ab.\'\'\'' |
| | 36 | +); |
| Index: trunk/extensions/ConfirmEdit/asirra_contentloaded.js |
| — | — | @@ -0,0 +1,50 @@ |
| | 2 | +/*! |
| | 3 | + * contentloaded.js |
| | 4 | + * |
| | 5 | + * Author: Diego Perini (diego.perini at gmail.com) |
| | 6 | + * Summary: cross-browser wrapper for DOMContentLoaded |
| | 7 | + * Updated: 20101020 |
| | 8 | + * License: MIT |
| | 9 | + * Version: 1.2 |
| | 10 | + * |
| | 11 | + * URL: |
| | 12 | + * http://javascript.nwbox.com/ContentLoaded/ |
| | 13 | + * http://javascript.nwbox.com/ContentLoaded/MIT-LICENSE |
| | 14 | + * |
| | 15 | + */ |
| | 16 | + |
| | 17 | +// @win window reference |
| | 18 | +// @fn function reference |
| | 19 | +function contentLoaded(win, fn) { |
| | 20 | + |
| | 21 | + var done = false, top = true, |
| | 22 | + |
| | 23 | + doc = win.document, root = doc.documentElement, |
| | 24 | + |
| | 25 | + add = doc.addEventListener ? 'addEventListener' : 'attachEvent', |
| | 26 | + rem = doc.addEventListener ? 'removeEventListener' : 'detachEvent', |
| | 27 | + pre = doc.addEventListener ? '' : 'on', |
| | 28 | + |
| | 29 | + init = function(e) { |
| | 30 | + if (e.type == 'readystatechange' && doc.readyState != 'complete') return; |
| | 31 | + (e.type == 'load' ? win : doc)[rem](pre + e.type, init, false); |
| | 32 | + if (!done && (done = true)) fn.call(win, e.type || e); |
| | 33 | + }, |
| | 34 | + |
| | 35 | + poll = function() { |
| | 36 | + try { root.doScroll('left'); } catch(e) { setTimeout(poll, 50); return; } |
| | 37 | + init('poll'); |
| | 38 | + }; |
| | 39 | + |
| | 40 | + if (doc.readyState == 'complete') fn.call(win, 'lazy'); |
| | 41 | + else { |
| | 42 | + if (doc.createEventObject && root.doScroll) { |
| | 43 | + try { top = !win.frameElement; } catch(e) { } |
| | 44 | + if (top) poll(); |
| | 45 | + } |
| | 46 | + doc[add](pre + 'DOMContentLoaded', init, false); |
| | 47 | + doc[add](pre + 'readystatechange', init, false); |
| | 48 | + win[add](pre + 'load', init, false); |
| | 49 | + } |
| | 50 | + |
| | 51 | +} |
| Index: trunk/extensions/ConfirmEdit/Asirra.php |
| — | — | @@ -0,0 +1,43 @@ |
| | 2 | +<?php |
| | 3 | +/** |
| | 4 | + * Asirra CAPTCHA module for the ConfirmEdit MediaWiki extension. |
| | 5 | + * @author Bachsau |
| | 6 | + * |
| | 7 | + * Makes use of the Asirra (Animal Species Image Recognition for |
| | 8 | + * Restricting Access) CAPTCHA service, developed by John Douceur, Jeremy |
| | 9 | + * Elson and Jon Howell at Microsoft Research. |
| | 10 | + * |
| | 11 | + * Asirra uses a large set of images from http://petfinder.com. |
| | 12 | + * |
| | 13 | + * For more information about Asirra, see: |
| | 14 | + * http://research.microsoft.com/en-us/um/redmond/projects/asirra/ |
| | 15 | + * |
| | 16 | + * This MediaWiki code is released into the public domain, without any |
| | 17 | + * warranty. YOU CAN DO WITH IT WHATEVER YOU LIKE! |
| | 18 | + * |
| | 19 | + * @file |
| | 20 | + * @ingroup Extensions |
| | 21 | + */ |
| | 22 | + |
| | 23 | +if ( !defined( 'MEDIAWIKI' ) ) { |
| | 24 | + exit; |
| | 25 | +} |
| | 26 | + |
| | 27 | +require_once dirname( __FILE__ ) . '/ConfirmEdit.php'; |
| | 28 | +$wgCaptchaClass = 'Asirra'; |
| | 29 | + |
| | 30 | +// Default Asirra options. |
| | 31 | +// Use LocalSettings.php for any changes |
| | 32 | +$wgAsirraEnlargedPosition = 'bottom'; |
| | 33 | +$wgAsirraCellsPerRow = '6'; |
| | 34 | +$wgAsirraScriptPath = ''; |
| | 35 | + |
| | 36 | +// AsirraXmlParser initial values |
| | 37 | +$wgAsirra = array |
| | 38 | +( |
| | 39 | + 'inResult' => 0, |
| | 40 | + 'passed' => 0 |
| | 41 | +); |
| | 42 | + |
| | 43 | +$wgExtensionMessagesFiles['Asirra'] = dirname( __FILE__ ) . '/Asirra.i18n.php'; |
| | 44 | +$wgAutoloadClasses['Asirra'] = dirname( __FILE__ ) . '/Asirra.class.php'; |
| Index: trunk/extensions/ConfirmEdit/asirra_humanverify.js |
| — | — | @@ -0,0 +1,62 @@ |
| | 2 | +/*======================================================================*\ |
| | 3 | +|| #################################################################### || |
| | 4 | +|| # Asirra module for ConfirmEdit by Bachsau # || |
| | 5 | +|| # ---------------------------------------------------------------- # || |
| | 6 | +|| # This code is released into public domain, in the hope that it # || |
| | 7 | +|| # will be useful, but without any warranty. # || |
| | 8 | +|| # ------------ YOU CAN DO WITH IT WHATEVER YOU LIKE! ------------- # || |
| | 9 | +|| #################################################################### || |
| | 10 | +\*======================================================================*/ |
| | 11 | + |
| | 12 | +var asirra_js_failed = "Please correctly identify the cats."; |
| | 13 | +var asirraform = document.forms[document.forms.length - 1]; |
| | 14 | +var submitButtonClicked = document.createElement("input"); |
| | 15 | +var passThroughFormSubmit = false; |
| | 16 | + |
| | 17 | +function PrepareSubmit() |
| | 18 | +{ |
| | 19 | + submitButtonClicked.type = "hidden"; |
| | 20 | + var inputFields = asirraform.getElementsByTagName("input"); |
| | 21 | + for (var i=0; i<inputFields.length; i++) |
| | 22 | + { |
| | 23 | + if (inputFields[i].type == "submit") |
| | 24 | + { |
| | 25 | + inputFields[i].onclick = function(event) |
| | 26 | + { |
| | 27 | + submitButtonClicked.name = this.name; |
| | 28 | + submitButtonClicked.value = this.value; |
| | 29 | + } |
| | 30 | + } |
| | 31 | + } |
| | 32 | + |
| | 33 | + asirraform.onsubmit = function(event) |
| | 34 | + { |
| | 35 | + return MySubmitForm(); |
| | 36 | + } |
| | 37 | +} |
| | 38 | + |
| | 39 | +function MySubmitForm() |
| | 40 | +{ |
| | 41 | + if (passThroughFormSubmit) |
| | 42 | + { |
| | 43 | + return true; |
| | 44 | + } |
| | 45 | + Asirra_CheckIfHuman(HumanCheckComplete); |
| | 46 | + return false; |
| | 47 | +} |
| | 48 | + |
| | 49 | +function HumanCheckComplete(isHuman) |
| | 50 | +{ |
| | 51 | + if (!isHuman) |
| | 52 | + { |
| | 53 | + alert(asirra_js_failed); |
| | 54 | + } |
| | 55 | + else |
| | 56 | + { |
| | 57 | + asirraform.appendChild(submitButtonClicked); |
| | 58 | + passThroughFormSubmit = true; |
| | 59 | + asirraform.submit(); |
| | 60 | + } |
| | 61 | +} |
| | 62 | + |
| | 63 | +contentLoaded(window,PrepareSubmit); |
| Index: trunk/extensions/ConfirmEdit/Asirra.class.php |
| — | — | @@ -0,0 +1,118 @@ |
| | 2 | +<?php |
| | 3 | +/** |
| | 4 | + * @author Bachsau |
| | 5 | + */ |
| | 6 | + |
| | 7 | +class Asirra extends SimpleCaptcha |
| | 8 | +{ |
| | 9 | + // Asirra URLs |
| | 10 | + public $asirra_localpath = ''; |
| | 11 | + public $asirra_clientscript = 'http://challenge.asirra.com/js/AsirraClientSide.js'; |
| | 12 | + public $asirra_apiscript = 'http://challenge.asirra.com/cgi/Asirra'; |
| | 13 | + |
| | 14 | + // As we don't have to store anything but some other things to do, |
| | 15 | + // we're going to replace that constructor completely. |
| | 16 | + function __construct() |
| | 17 | + { |
| | 18 | + global $wgScriptPath, $wgAsirraScriptPath; |
| | 19 | + |
| | 20 | + // WTF isn't this in ConfirmEdit_body.php? |
| | 21 | + wfLoadExtensionMessages('ConfirmEdit'); |
| | 22 | + wfLoadExtensionMessages('Asirra'); |
| | 23 | + |
| | 24 | + // Try to find $asirra_localpath if not set |
| | 25 | + if (!$this -> asirra_localpath = $wgAsirraScriptPath) |
| | 26 | + { |
| | 27 | + if (strpos(__FILE__, $_SERVER['DOCUMENT_ROOT']) === 0) |
| | 28 | + { |
| | 29 | + $this -> asirra_localpath = preg_replace('/^' . preg_quote($_SERVER['DOCUMENT_ROOT'], '/') . '(\\/*)/s', '/', dirname(__FILE__)); |
| | 30 | + } |
| | 31 | + else |
| | 32 | + { |
| | 33 | + $this -> asirra_localpath = $wgScriptPath . '/extensions/ConfirmEdit'; |
| | 34 | + } |
| | 35 | + } |
| | 36 | + } |
| | 37 | + |
| | 38 | + function getForm() |
| | 39 | + { |
| | 40 | + global $wgAsirraEnlargedPosition, $wgAsirraCellsPerRow, $wgOut; |
| | 41 | + |
| | 42 | + return ' |
| | 43 | + <script type="text/javascript" src="' . $this -> asirra_clientscript . '"></script> |
| | 44 | + <script type="text/javascript" src="' . $this -> asirra_localpath . '/asirra_contentloaded.js"></script> |
| | 45 | + <script type="text/javascript" src="' . $this -> asirra_localpath . '/asirra_humanverify.js"></script> |
| | 46 | + <script type="text/javascript"> |
| | 47 | + asirraState.SetEnlargedPosition("' . $wgAsirraEnlargedPosition . '"); |
| | 48 | + asirraState.SetCellsPerRow(' . $wgAsirraCellsPerRow . '); |
| | 49 | + var asirra_js_failed = "' . $this -> getMessage('createaccount-fail') . '" |
| | 50 | + </script> |
| | 51 | + <noscript>' . $wgOut -> parse($this -> getMessage('nojs')) . '</noscript> |
| | 52 | + '; |
| | 53 | + } |
| | 54 | + |
| | 55 | + function getMessage( $action ) |
| | 56 | + { |
| | 57 | + $name = 'asirra-' . $action; |
| | 58 | + $text = wfMsg($name); |
| | 59 | + // Obtain a more tailored message, if possible, otherwise, fall back to |
| | 60 | + // the default for edits |
| | 61 | + return wfEmptyMsg($name, $text) ? wfMsg('asirra-edit') : $text; |
| | 62 | + } |
| | 63 | + |
| | 64 | + // This is where the party goes on... |
| | 65 | + function passCaptcha() |
| | 66 | + { |
| | 67 | + global $wgRequest, $wgAsirra; |
| | 68 | + |
| | 69 | + $ticket = $wgRequest -> getVal('Asirra_Ticket'); |
| | 70 | + $url = $this -> asirra_apiscript . '?action=ValidateTicket&ticket=' . $ticket; |
| | 71 | + |
| | 72 | + $ch = curl_init(); |
| | 73 | + curl_setopt($ch, CURLOPT_URL, $url); |
| | 74 | + curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); |
| | 75 | + curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 5); |
| | 76 | + $resultXml = curl_exec($ch); |
| | 77 | + curl_close($ch); |
| | 78 | + |
| | 79 | + $xml_parser = xml_parser_create(); |
| | 80 | + xml_set_element_handler($xml_parser, 'AsirraXmlParser::startElement', 'AsirraXmlParser::endElement'); |
| | 81 | + xml_set_character_data_handler($xml_parser, 'AsirraXmlParser::characterData'); |
| | 82 | + xml_parse($xml_parser, $resultXml, 1); |
| | 83 | + xml_parser_free($xml_parser); |
| | 84 | + |
| | 85 | + if ($wgAsirra['passed']) |
| | 86 | + { |
| | 87 | + return true; |
| | 88 | + |
| | 89 | + } |
| | 90 | + return false; |
| | 91 | + } |
| | 92 | +} |
| | 93 | + |
| | 94 | +class AsirraXmlParser |
| | 95 | +{ |
| | 96 | + static function startElement($parser, $name, $attrs) |
| | 97 | + { |
| | 98 | + global $wgAsirra; |
| | 99 | + |
| | 100 | + $wgAsirra['inResult'] = ($name=="RESULT"); |
| | 101 | + } |
| | 102 | + |
| | 103 | + static function endElement($name) |
| | 104 | + { |
| | 105 | + global $wgAsirra; |
| | 106 | + |
| | 107 | + $wgAsirra['inResult'] = 0; |
| | 108 | + } |
| | 109 | + |
| | 110 | + static function characterData($parer, $data) |
| | 111 | + { |
| | 112 | + global $wgAsirra; |
| | 113 | + |
| | 114 | + if ($wgAsirra['inResult'] && $data == "Pass") |
| | 115 | + { |
| | 116 | + $wgAsirra['passed'] = 1; |
| | 117 | + } |
| | 118 | + } |
| | 119 | +} |