New "Asirra" module, from the Asirra extension by Bachsau
authorYaron Koren <yaron@users.mediawiki.org>
Tue, 12 Jul 2011 17:26:26 +0000 (17:26 +0000)
committerYaron Koren <yaron@users.mediawiki.org>
Tue, 12 Jul 2011 17:26:26 +0000 (17:26 +0000)
Asirra.class.php [new file with mode: 0644]
Asirra.i18n.php [new file with mode: 0644]
Asirra.php [new file with mode: 0644]
asirra_contentloaded.js [new file with mode: 0644]
asirra_humanverify.js [new file with mode: 0644]

diff --git a/Asirra.class.php b/Asirra.class.php
new file mode 100644 (file)
index 0000000..85f1dfa
--- /dev/null
@@ -0,0 +1,118 @@
+<?php
+/**
+ * @author Bachsau
+ */
+
+class Asirra extends SimpleCaptcha
+{
+       // Asirra URLs
+       public $asirra_localpath = '';
+       public $asirra_clientscript = 'http://challenge.asirra.com/js/AsirraClientSide.js';
+       public $asirra_apiscript = 'http://challenge.asirra.com/cgi/Asirra';
+
+       // As we don't have to store anything but some other things to do,
+       // we're going to replace that constructor completely.
+       function __construct()
+       {
+               global $wgScriptPath, $wgAsirraScriptPath;
+
+               // WTF isn't this in ConfirmEdit_body.php?
+               wfLoadExtensionMessages('ConfirmEdit');
+               wfLoadExtensionMessages('Asirra');
+
+               // Try to find $asirra_localpath if not set
+               if (!$this -> asirra_localpath = $wgAsirraScriptPath)
+               {
+                       if (strpos(__FILE__, $_SERVER['DOCUMENT_ROOT']) === 0)
+                       {
+                               $this -> asirra_localpath = preg_replace('/^' . preg_quote($_SERVER['DOCUMENT_ROOT'], '/') . '(\\/*)/s', '/', dirname(__FILE__));
+                       }
+                       else
+                       {
+                               $this -> asirra_localpath = $wgScriptPath . '/extensions/ConfirmEdit';
+                       }
+               }
+       }
+
+       function getForm()
+       {
+               global $wgAsirraEnlargedPosition, $wgAsirraCellsPerRow, $wgOut;
+
+               return '
+                       <script type="text/javascript" src="' . $this -> asirra_clientscript . '"></script>
+                       <script type="text/javascript" src="' . $this -> asirra_localpath . '/asirra_contentloaded.js"></script>
+                       <script type="text/javascript" src="' . $this -> asirra_localpath . '/asirra_humanverify.js"></script>
+                       <script type="text/javascript">
+                               asirraState.SetEnlargedPosition("' . $wgAsirraEnlargedPosition . '");
+                               asirraState.SetCellsPerRow(' . $wgAsirraCellsPerRow . ');
+                               var asirra_js_failed = "' . $this -> getMessage('createaccount-fail') . '"
+                       </script>
+                       <noscript>' . $wgOut -> parse($this -> getMessage('nojs')) . '</noscript>
+               ';
+       }
+
+       function getMessage( $action )
+       {
+               $name = 'asirra-' . $action;
+               $text = wfMsg($name);
+               // Obtain a more tailored message, if possible, otherwise, fall back to
+               // the default for edits
+               return wfEmptyMsg($name, $text) ? wfMsg('asirra-edit') : $text;
+       }
+
+       // This is where the party goes on...
+       function passCaptcha()
+       {
+               global $wgRequest, $wgAsirra;
+
+               $ticket = $wgRequest -> getVal('Asirra_Ticket');
+               $url = $this -> asirra_apiscript . '?action=ValidateTicket&ticket=' . $ticket;
+
+               $ch = curl_init();
+               curl_setopt($ch, CURLOPT_URL, $url);
+               curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
+               curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 5);
+               $resultXml = curl_exec($ch);
+               curl_close($ch);
+
+               $xml_parser = xml_parser_create();
+               xml_set_element_handler($xml_parser, 'AsirraXmlParser::startElement', 'AsirraXmlParser::endElement');
+               xml_set_character_data_handler($xml_parser, 'AsirraXmlParser::characterData');
+               xml_parse($xml_parser, $resultXml, 1);
+               xml_parser_free($xml_parser);
+
+               if ($wgAsirra['passed'])
+               {
+                       return true;
+
+               }
+               return false;
+       }
+}
+
+class AsirraXmlParser
+{
+       static function startElement($parser, $name, $attrs)
+       {
+               global $wgAsirra;
+
+               $wgAsirra['inResult'] = ($name=="RESULT");
+       }
+
+       static function endElement($name)
+       {
+               global $wgAsirra;
+
+               $wgAsirra['inResult'] = 0;
+       }
+
+       static function characterData($parer, $data)
+       {
+               global $wgAsirra;
+
+               if ($wgAsirra['inResult'] && $data == "Pass")
+               {
+                       $wgAsirra['passed'] = 1;
+               }
+       }
+}
diff --git a/Asirra.i18n.php b/Asirra.i18n.php
new file mode 100644 (file)
index 0000000..5a42d82
--- /dev/null
@@ -0,0 +1,35 @@
+<?php
+/**
+ * Internationalisation file for the Asirra module of the ConfirmEdit
+ * extension.
+ *
+ * @file
+ * @ingroup Extensions
+ */
+
+$messages = array();
+
+/* English */
+$messages['en'] = array(
+       'asirra-desc' => 'Asirra module for ConfirmEdit',
+        'asirra-edit' => 'To help protect against automated edit spam, please select just the cat photos in the box below:', 
+        'asirra-addurl' => 'Your edit includes new external links. To help protect against automated spam, please select just the cat photos in the box below:',
+       'asirra-badpass' => 'To help protect against automated password cracking, please select just the cat photos in the box below:',
+       'asirra-createaccount' => 'To help protect against automated account creation, please select just the cat photos in the box below:',
+       'asirra-createaccount-fail' => "Please correctly identify the cats.",
+       'asirra-create' => 'To help protect against automated page creation, please select just the cat photos in the box below:', 
+       'asirra-nojs' => '\'\'\'Please enable JavaScript and resubmit the page.\'\'\''
+);
+
+
+/** German (Deutsch) */
+$messages['de'] = array(
+       'asirra-desc' => 'Asirra-Modul für ConfirmEdit',
+       'asirra-edit' => 'Zum Schutz vor automatisiertem Spam, wähle bitte nur die Katzen im untenstehenden Feld aus:',
+       'asirra-addurl' => 'Deine Bearbeitung enthält neue externe Links. Zum Schutz vor automatisiertem Spam wähle bitte nur die Katzen im untenstehenden Feld aus:',
+       'asirra-badpass' => 'Zum Schutz gegen automatisiertes Knacken von Passwörtern, wähle bitte nur die Katzen im untenstehenden Feld aus:',
+       'asirra-createaccount' => 'Zum Schutz gegen automatisierte Erstellung von Benutzerkonten wähle bitte nur die Katzen im untenstehenden Feld aus:',
+       'asirra-createaccount-fail' => 'Bitte wähle nur Katzen aus.',
+       'asirra-create' => 'Zum Schutz gegen automatisierte Erstellung von Seiten, wähle bitte nur die Katzen im untenstehenden Feld aus:',
+       'asirra-nojs' => '\'\'\'Bitte aktiviere JavaScript und sende die Seite noch einmal ab.\'\'\''
+);
diff --git a/Asirra.php b/Asirra.php
new file mode 100644 (file)
index 0000000..3f1b325
--- /dev/null
@@ -0,0 +1,43 @@
+<?php
+/**
+ * Asirra CAPTCHA module for the ConfirmEdit MediaWiki extension.
+ * @author Bachsau
+ *
+ * Makes use of the Asirra (Animal Species Image Recognition for
+ * Restricting Access) CAPTCHA service, developed by John Douceur, Jeremy
+ * Elson and Jon Howell at Microsoft Research.
+ *
+ * Asirra uses a large set of images from http://petfinder.com.
+ *
+ * For more information about Asirra, see:
+ * http://research.microsoft.com/en-us/um/redmond/projects/asirra/
+ *
+ * This MediaWiki code is released into the public domain, without any
+ * warranty. YOU CAN DO WITH IT WHATEVER YOU LIKE!
+ *
+ * @file
+ * @ingroup Extensions
+ */
+
+if ( !defined( 'MEDIAWIKI' ) ) {
+       exit;
+}
+
+require_once dirname( __FILE__ ) . '/ConfirmEdit.php';
+$wgCaptchaClass = 'Asirra';
+
+// Default Asirra options.
+// Use LocalSettings.php for any changes
+$wgAsirraEnlargedPosition = 'bottom';
+$wgAsirraCellsPerRow = '6';
+$wgAsirraScriptPath = '';
+
+// AsirraXmlParser initial values
+$wgAsirra = array
+(
+       'inResult' => 0,
+       'passed'   => 0
+);
+
+$wgExtensionMessagesFiles['Asirra'] = dirname( __FILE__ ) . '/Asirra.i18n.php';
+$wgAutoloadClasses['Asirra'] = dirname( __FILE__ ) . '/Asirra.class.php';
diff --git a/asirra_contentloaded.js b/asirra_contentloaded.js
new file mode 100644 (file)
index 0000000..0cf0ee8
--- /dev/null
@@ -0,0 +1,50 @@
+/*!
+ * contentloaded.js
+ *
+ * Author: Diego Perini (diego.perini at gmail.com)
+ * Summary: cross-browser wrapper for DOMContentLoaded
+ * Updated: 20101020
+ * License: MIT
+ * Version: 1.2
+ *
+ * URL:
+ * http://javascript.nwbox.com/ContentLoaded/
+ * http://javascript.nwbox.com/ContentLoaded/MIT-LICENSE
+ *
+ */
+
+// @win window reference
+// @fn function reference
+function contentLoaded(win, fn) {
+
+       var done = false, top = true,
+
+       doc = win.document, root = doc.documentElement,
+
+       add = doc.addEventListener ? 'addEventListener' : 'attachEvent',
+       rem = doc.addEventListener ? 'removeEventListener' : 'detachEvent',
+       pre = doc.addEventListener ? '' : 'on',
+
+       init = function(e) {
+               if (e.type == 'readystatechange' && doc.readyState != 'complete') return;
+               (e.type == 'load' ? win : doc)[rem](pre + e.type, init, false);
+               if (!done && (done = true)) fn.call(win, e.type || e);
+       },
+
+       poll = function() {
+               try { root.doScroll('left'); } catch(e) { setTimeout(poll, 50); return; }
+               init('poll');
+       };
+
+       if (doc.readyState == 'complete') fn.call(win, 'lazy');
+       else {
+               if (doc.createEventObject && root.doScroll) {
+                       try { top = !win.frameElement; } catch(e) { }
+                       if (top) poll();
+               }
+               doc[add](pre + 'DOMContentLoaded', init, false);
+               doc[add](pre + 'readystatechange', init, false);
+               win[add](pre + 'load', init, false);
+       }
+
+}
diff --git a/asirra_humanverify.js b/asirra_humanverify.js
new file mode 100644 (file)
index 0000000..8b1a052
--- /dev/null
@@ -0,0 +1,62 @@
+/*======================================================================*\
+|| #################################################################### ||
+|| # Asirra module for ConfirmEdit by Bachsau                         # ||
+|| # ---------------------------------------------------------------- # ||
+|| # This code is released into public domain, in the hope that it    # ||
+|| # will be useful, but without any warranty.                        # ||
+|| # ------------ YOU CAN DO WITH IT WHATEVER YOU LIKE! ------------- # ||
+|| #################################################################### ||
+\*======================================================================*/
+
+var asirra_js_failed = "Please correctly identify the cats.";
+var asirraform = document.forms[document.forms.length - 1];
+var submitButtonClicked = document.createElement("input");
+var passThroughFormSubmit = false;
+
+function PrepareSubmit()
+{
+       submitButtonClicked.type = "hidden";
+       var inputFields = asirraform.getElementsByTagName("input");
+       for (var i=0; i<inputFields.length; i++)
+       {
+               if (inputFields[i].type == "submit")
+               {
+                       inputFields[i].onclick = function(event)
+                       {
+                               submitButtonClicked.name = this.name;
+                               submitButtonClicked.value = this.value;
+                       }
+               }
+       }
+
+       asirraform.onsubmit = function(event)
+       {
+               return MySubmitForm();
+       }
+}
+
+function MySubmitForm()
+{
+       if (passThroughFormSubmit)
+       {
+               return true;
+       }
+       Asirra_CheckIfHuman(HumanCheckComplete);
+       return false;
+}
+
+function HumanCheckComplete(isHuman)
+{
+       if (!isHuman)
+       {
+               alert(asirra_js_failed);
+       }
+       else
+       {
+               asirraform.appendChild(submitButtonClicked);
+               passThroughFormSubmit = true;
+               asirraform.submit();
+       }
+}
+
+contentLoaded(window,PrepareSubmit);