1<?php 2if(!defined('DOKU_INC')) define('DOKU_INC',realpath(dirname(__FILE__).'/../../../').'/'); 3if(!defined('DOKU_PLUGIN')) define('DOKU_PLUGIN',DOKU_INC.'lib/plugins/'); 4require_once(DOKU_PLUGIN.'action.php'); 5 6/** 7 * @license GPL 2 (http://www.gnu.org/licenses/gpl2.html) 8 * @author Adrian Schlegel <adrian.schlegel@liip.ch> 9 * @author Robert Bronsdon <reashlin@gmail.com> 10 */ 11 12class action_plugin_recaptcha extends DokuWiki_Action_Plugin { 13 14 private $recaptchaLangs = array('en', 'nl', 'fr', 'de', 'pt', 'ru', 'es', 'tr'); 15 16 /** 17 * register an event hook 18 * 19 */ 20 function register(Doku_Event_Handler $controller) 21 { 22 // only register the hooks if the necessary config paramters exist 23 if($this->getConf('publickey') && $this->getConf('privatekey')) { 24 if($this->getConf('regprotect') || $this->getConf('editprotect')){ 25 $controller->register_hook('ACTION_ACT_PREPROCESS', 26 'BEFORE', 27 $this, 28 'preprocess', 29 array()); 30 } 31 if($this->getConf('regprotect')){ 32 // new hook 33 $controller->register_hook('HTML_REGISTERFORM_OUTPUT', 34 'BEFORE', 35 $this, 36 'insert', 37 array('oldhook' => false)); 38 // old hook 39 $controller->register_hook('HTML_REGISTERFORM_INJECTION', 40 'BEFORE', 41 $this, 42 'insert', 43 array('oldhook' => true)); 44 } 45 if($this->getConf('editprotect')){ 46 // old hook 47 $controller->register_hook('HTML_EDITFORM_INJECTION', 48 'BEFORE', 49 $this, 50 'editform_output', 51 array('editform' => true, 'oldhook' => true)); 52 // new hook 53 $controller->register_hook('HTML_EDITFORM_OUTPUT', 54 'BEFORE', 55 $this, 56 'editform_output', 57 array('editform' => true, 'oldhook' => false)); 58 } 59 } 60 } 61 62 /** 63 * Add reCAPTCHA to edit fields 64 * 65 * @param obj $event 66 * @param array $param 67 */ 68 function editform_output(&$event, $param){ 69 // check if source view -> no captcha needed 70 if(!$param['oldhook']){ 71 // get position of submit button 72 $pos = $event->data->findElementByAttribute('type','submit'); 73 if(!$pos){ 74 return; // no button -> source view mode 75 } 76 } elseif($param['editform'] && !$event->data['writable']){ 77 if($param['editform'] && !$event->data['writable']){ 78 return; 79 } 80 } 81 82 // If users don't need to fill in captcha then end this here. 83 if(!$this->getConf('forusers') && $_SERVER['REMOTE_USER']){ 84 return; 85 } 86 87 $this->insert($event, $param); 88 } 89 90 /** 91 * insert html code for recaptcha into the form 92 * 93 * @param obj $event 94 * @param array $param 95 */ 96 function insert(&$event, $param) { 97 global $conf; 98 99 $helper = plugin_load('helper','recaptcha'); 100 $recaptcha = '<div style="width: 320px;"></div>'; 101 // by default let's assume that protocol is http 102 $use_ssl = false; 103 // trying to find https in current url 104 if(preg_match('/^https:\/\/.*/', DOKU_URL)){ 105 $use_ssl = true; 106 } 107 // see first if a language is defined for the plugin, if not try to use the language defined for dokuwiki 108 $lang = $this->getConf('lang') ? $this->getConf('lang') : (in_array($conf['lang'], $this->recaptchaLangs) ? $conf['lang'] : 'en'); 109 $recaptcha .= "<script type='text/javascript'> 110 var RecaptchaOptions = {"; 111 $recaptcha .= $this->getConf('theme') ? "theme: '".$this->getConf('theme')."'," : ''; 112 $recaptcha .= "lang: '".$lang."'"; 113 $recaptcha .= " 114 }; 115 </script>"; 116 $recaptcha .= $helper->getHTML($use_ssl); 117 118 if($param['oldhook']) { 119 echo $recaptcha; 120 } else { 121 $pos = $event->data->findElementByAttribute('type','submit'); 122 $event->data->insertElement($pos++, $recaptcha); 123 } 124 } 125 126 127 /** 128 * process the answer to the captcha 129 * 130 * @param obj $event 131 * @param array $param 132 * 133 */ 134 function preprocess(&$event, $param) { 135 // get and clean the action 136 $act = $this->_act_clean($event->data); 137 // If users don't need to fill in captcha then end this here. 138 if(!$this->getConf('forusers') && $_SERVER['REMOTE_USER']){ 139 return; 140 } 141 // Check we are either registering or saving a html page 142 if( 143 ($act == 'register' && $this->getConf('regprotect') && $_POST['save'] ) || 144 ($act == 'save' && $this->getConf('editprotect')) 145 ){ 146 147 // Check the recaptcha answer and only submit if correct 148 $helper = plugin_load('helper', 'recaptcha'); 149 $resp = $helper->check(); 150 151 if (!$resp->is_valid) { 152 if($act == 'save'){ 153 // stay in preview mode 154 msg($this->getLang('testfailed'),-1); 155 $event->data = 'preview'; 156 }else{ 157 // stay in register mode, but disable the save parameter 158 msg($this->getLang('testfailed'),-1); 159 $_POST['save'] = false; 160 } 161 } 162 } 163 } 164 165 /** 166 * Pre-Sanitize the action command 167 * 168 * Similar to act_clean in action.php but simplified and without 169 * error messages 170 * (taken from Andreas Gohrs captcha plugin) 171 */ 172 function _act_clean($act){ 173 // check if the action was given as array key 174 if(is_array($act)){ 175 list($act) = array_keys($act); 176 } 177 178 //remove all bad chars 179 $act = strtolower($act); 180 $act = preg_replace('/[^a-z_]+/','',$act); 181 182 return $act; 183 } 184} //end of action class 185