| 1 | <?php |
|---|
| 2 | /* |
|---|
| 3 | Plugin Name: WordPress Hashcash |
|---|
| 4 | Plugin URI: http://wordpress-plugins.feifei.us/hashcash/ |
|---|
| 5 | Description: Client-side javascript blocks all spam bots. XHTML 1.1 compliant. |
|---|
| 6 | Author: Elliott Back |
|---|
| 7 | Author URI: http://elliottback.com |
|---|
| 8 | Version: 4.3 |
|---|
| 9 | |
|---|
| 10 | This program is free software; you can redistribute it and/or modify |
|---|
| 11 | it under the terms of the GNU General Public License as published by |
|---|
| 12 | the Free Software Foundation; either version 2 of the License, or |
|---|
| 13 | (at your option) any later version. |
|---|
| 14 | |
|---|
| 15 | This program is distributed in the hope that it will be useful, |
|---|
| 16 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
|---|
| 17 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|---|
| 18 | GNU General Public License for more details. |
|---|
| 19 | |
|---|
| 20 | */ |
|---|
| 21 | |
|---|
| 22 | function wphc_option($save = false){ |
|---|
| 23 | if($save) { |
|---|
| 24 | if( function_exists( 'update_site_option' ) ) { |
|---|
| 25 | update_site_option('plugin_wp-hashcash', $save); |
|---|
| 26 | } else { |
|---|
| 27 | update_option('plugin_wp-hashcash', $save); |
|---|
| 28 | } |
|---|
| 29 | |
|---|
| 30 | return $save; |
|---|
| 31 | } else { |
|---|
| 32 | if( function_exists( 'get_site_option' ) ) { |
|---|
| 33 | $options = get_site_option('plugin_wp-hashcash'); |
|---|
| 34 | } else { |
|---|
| 35 | $options = get_option('plugin_wp-hashcash'); |
|---|
| 36 | } |
|---|
| 37 | |
|---|
| 38 | if(!is_array($options)) |
|---|
| 39 | $options = array(); |
|---|
| 40 | |
|---|
| 41 | return $options; |
|---|
| 42 | } |
|---|
| 43 | } |
|---|
| 44 | |
|---|
| 45 | /** |
|---|
| 46 | * Install WP Hashcash |
|---|
| 47 | */ |
|---|
| 48 | |
|---|
| 49 | function wphc_install () { |
|---|
| 50 | // set our default options |
|---|
| 51 | $options = wphc_option(); |
|---|
| 52 | $options['comments-spam'] = $options['comments-spam'] || 0; |
|---|
| 53 | $options['comments-ham'] = $options['comments-ham'] || 0; |
|---|
| 54 | $options['signups-spam'] = $options['signups-spam'] || 0; |
|---|
| 55 | $options['signups-ham'] = $options['signups-ham'] || 0; |
|---|
| 56 | $options['key'] = array(); |
|---|
| 57 | $options['key-date'] = 0; |
|---|
| 58 | $options['refresh'] = 60 * 60 * 24 * 7; |
|---|
| 59 | $options['signup_active'] = 1; |
|---|
| 60 | $options['comments_active'] = 1; |
|---|
| 61 | |
|---|
| 62 | // akismet compat check |
|---|
| 63 | if(function_exists('akismet_init')){ |
|---|
| 64 | $options['moderation'] = 'akismet'; |
|---|
| 65 | } else { |
|---|
| 66 | $options['moderation'] = 'moderate'; |
|---|
| 67 | } |
|---|
| 68 | |
|---|
| 69 | // validate ip / url |
|---|
| 70 | $options['validate-ip'] = true; |
|---|
| 71 | $options['validate-url'] = true; |
|---|
| 72 | |
|---|
| 73 | // logging |
|---|
| 74 | $options['logging'] = true; |
|---|
| 75 | |
|---|
| 76 | // update the key |
|---|
| 77 | wphc_option($options); |
|---|
| 78 | wphc_refresh(); |
|---|
| 79 | } |
|---|
| 80 | |
|---|
| 81 | add_action('activate_wp-hashcash/wp-hashcash.php', 'wphc_install'); |
|---|
| 82 | add_action('activate_wp-hashcash.php', 'wphc_install'); |
|---|
| 83 | |
|---|
| 84 | /** |
|---|
| 85 | * Update the key, if needed |
|---|
| 86 | */ |
|---|
| 87 | |
|---|
| 88 | function wphc_refresh(){ |
|---|
| 89 | $options = wphc_option(); |
|---|
| 90 | |
|---|
| 91 | if( !isset( $options[ 'signup_active' ] ) ) { |
|---|
| 92 | wphc_install(); |
|---|
| 93 | return; |
|---|
| 94 | } |
|---|
| 95 | |
|---|
| 96 | if(time() - $options['key-date'] > $options['refresh']) { |
|---|
| 97 | if(count($options['key']) >= 5) |
|---|
| 98 | array_shift($options['key']); |
|---|
| 99 | |
|---|
| 100 | array_push($options['key'], rand(21474836, 2126008810)); |
|---|
| 101 | |
|---|
| 102 | $options['key-date'] = time(); |
|---|
| 103 | wphc_option($options); |
|---|
| 104 | } |
|---|
| 105 | } |
|---|
| 106 | |
|---|
| 107 | add_action('shutdown', 'wphc_refresh'); |
|---|
| 108 | |
|---|
| 109 | /** |
|---|
| 110 | * Our plugin can also have a widget |
|---|
| 111 | */ |
|---|
| 112 | |
|---|
| 113 | function get_spam_ratio( $ham, $spam ) { |
|---|
| 114 | if($spam + $ham == 0) |
|---|
| 115 | $ratio = 0; |
|---|
| 116 | else |
|---|
| 117 | $ratio = round(100 * ($spam/($ham+$spam)),2); |
|---|
| 118 | |
|---|
| 119 | return $ratio; |
|---|
| 120 | } |
|---|
| 121 | |
|---|
| 122 | function widget_ratio($options){ |
|---|
| 123 | $signups_ham = (int)$options['signups-ham']; |
|---|
| 124 | $signups_spam = (int)$options['signups-spam']; |
|---|
| 125 | $ham = (int)$options['comments-ham']; |
|---|
| 126 | $spam = (int)$options['comments-spam']; |
|---|
| 127 | $ratio = get_spam_ratio( $ham, $spam ); |
|---|
| 128 | $signups_ratio = get_spam_ratio( $signups_ham, $signups_spam ); |
|---|
| 129 | |
|---|
| 130 | $msg = "<p>$spam spam comments blocked out of $ham human comments. " . $ratio ."% of your comments are spam!</p>"; |
|---|
| 131 | if( $signups_ham && $signups_spam ) |
|---|
| 132 | $msg = "<p>$signups_spam spam signups blocked out of $signups_ham human signups. " . $signups_ratio ."% of your signups are spam!</p>"; |
|---|
| 133 | |
|---|
| 134 | return $msg; |
|---|
| 135 | } |
|---|
| 136 | |
|---|
| 137 | function wphc_widget_init () { |
|---|
| 138 | if(!function_exists('register_sidebar_widget')) |
|---|
| 139 | return; |
|---|
| 140 | |
|---|
| 141 | function widget_wphc($args) { |
|---|
| 142 | extract($args); |
|---|
| 143 | $options = wphc_option(); |
|---|
| 144 | |
|---|
| 145 | echo $before_widget . $before_title . '<a href="http://wordpress-plugins.feifei.us/hashcash/">WP Hashcash</a>' . $after_title; |
|---|
| 146 | echo '<ul>'; |
|---|
| 147 | echo '<li><small>By <a href="http://elliottback.com">Elliott Back</a></small></li>'; |
|---|
| 148 | echo "<li>".widget_ratio($options)."</li>"; |
|---|
| 149 | echo '</ul>'; |
|---|
| 150 | echo $after_widget; |
|---|
| 151 | } |
|---|
| 152 | |
|---|
| 153 | register_sidebar_widget(array('WP Hashcash', 'widgets'), 'widget_wphc'); |
|---|
| 154 | } |
|---|
| 155 | |
|---|
| 156 | add_action('widgets_init', 'wphc_widget_init'); |
|---|
| 157 | |
|---|
| 158 | /** |
|---|
| 159 | * Admin Options |
|---|
| 160 | */ |
|---|
| 161 | |
|---|
| 162 | add_action('admin_menu', 'wphc_add_options_to_admin'); |
|---|
| 163 | |
|---|
| 164 | function wphc_add_options_to_admin() { |
|---|
| 165 | if( function_exists( 'is_site_admin' ) && !is_site_admin() ) |
|---|
| 166 | return; |
|---|
| 167 | |
|---|
| 168 | if (function_exists('add_options_page')) { |
|---|
| 169 | if( function_exists( 'is_site_admin' ) ) { |
|---|
| 170 | add_submenu_page('wpmu-admin.php', __('WordPress Hashcash'), __('WordPress Hashcash'), 'manage_options', 'wphc_admin', 'wphc_admin_options'); |
|---|
| 171 | } else { |
|---|
| 172 | add_options_page('Wordpress Hashcash', 'Wordpress Hashcash', 8, basename(__FILE__), 'wphc_admin_options'); |
|---|
| 173 | } |
|---|
| 174 | } |
|---|
| 175 | } |
|---|
| 176 | |
|---|
| 177 | function wphc_admin_options() { |
|---|
| 178 | if( function_exists( 'is_site_admin' ) && !is_site_admin() ) |
|---|
| 179 | return; |
|---|
| 180 | |
|---|
| 181 | $options = wphc_option(); |
|---|
| 182 | |
|---|
| 183 | if( !isset( $options[ 'signup_active' ] ) ) { |
|---|
| 184 | wphc_install(); // MU has no activation hook |
|---|
| 185 | $options = wphc_option(); |
|---|
| 186 | } |
|---|
| 187 | |
|---|
| 188 | // POST HANDLER |
|---|
| 189 | if($_POST['wphc-submit']){ |
|---|
| 190 | check_admin_referer( 'wphc-options' ); |
|---|
| 191 | if ( function_exists('current_user_can') && !current_user_can('manage_options') ) |
|---|
| 192 | die('Current user not authorized to managed options'); |
|---|
| 193 | |
|---|
| 194 | $options['refresh'] = strip_tags(stripslashes($_POST['wphc-refresh'])); |
|---|
| 195 | $options['moderation'] = strip_tags(stripslashes($_POST['wphc-moderation'])); |
|---|
| 196 | $options['validate-ip'] = strip_tags(stripslashes($_POST['wphc-validate-ip'])); |
|---|
| 197 | $options['validate-url'] = strip_tags(stripslashes($_POST['wphc-validate-url'])); |
|---|
| 198 | $options['logging'] = strip_tags(stripslashes($_POST['wphc-logging'])); |
|---|
| 199 | $options['signup_active'] = (int)$_POST['signup_active']; |
|---|
| 200 | $options['comments_active'] = (int)$_POST['comments_active']; |
|---|
| 201 | wphc_option($options); |
|---|
| 202 | } |
|---|
| 203 | |
|---|
| 204 | // MAIN FORM |
|---|
| 205 | echo '<style type="text/css"> |
|---|
| 206 | .wrap h3 { color: black; background-color: #e5f3ff; padding: 4px 8px; } |
|---|
| 207 | |
|---|
| 208 | .sidebar { |
|---|
| 209 | border-right: 2px solid #e5f3ff; |
|---|
| 210 | width: 200px; |
|---|
| 211 | float: left; |
|---|
| 212 | padding: 0px 20px 0px 10px; |
|---|
| 213 | margin: 0px 20px 0px 0px; |
|---|
| 214 | } |
|---|
| 215 | |
|---|
| 216 | .sidebar input { |
|---|
| 217 | background-color: #FFF; |
|---|
| 218 | border: none; |
|---|
| 219 | } |
|---|
| 220 | |
|---|
| 221 | .main { |
|---|
| 222 | float: left; |
|---|
| 223 | width: 600px; |
|---|
| 224 | } |
|---|
| 225 | |
|---|
| 226 | .clear { clear: both; } |
|---|
| 227 | </style>'; |
|---|
| 228 | |
|---|
| 229 | echo '<div class="wrap">'; |
|---|
| 230 | |
|---|
| 231 | echo '<div class="sidebar">'; |
|---|
| 232 | echo '<h3>Plugin</h3>'; |
|---|
| 233 | echo '<ul> |
|---|
| 234 | <li><a href="http://wordpress-plugins.feifei.us/hashcash/">Plugin\'s Homepage</a></li>'; |
|---|
| 235 | if( function_exists( 'is_site_admin' ) && is_site_admin() ) { |
|---|
| 236 | echo '<li><a href="http://mu.wordpress.org/forums/">WordPress MU Forums</a></li>'; |
|---|
| 237 | } |
|---|
| 238 | echo '<li><a href="http://wordpress.org/tags/wp-hashcash">Plugin Support Forum</a></li>'; |
|---|
| 239 | echo '</ul>'; |
|---|
| 240 | echo '<h3>Donation</h3>'; |
|---|
| 241 | echo '<center><form action="https://www.paypal.com/cgi-bin/webscr" method="post"> |
|---|
| 242 | <input type="hidden" name="cmd" value="_s-xclick"> |
|---|
| 243 | <input style="border:none;" type="image" src="https://www.paypal.com/en_US/i/btn/btn_donate_LG.gif" border="0" name="submit" alt="PayPal - The safer, easier way to pay online!"> |
|---|
| 244 | <img alt="" border="0" src="https://www.paypal.com/en_US/i/scr/pixel.gif" width="1" height="1"> |
|---|
| 245 | <input type="hidden" name="encrypted" value="-----BEGIN PKCS7-----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-----END PKCS7-----"></form></center>'; |
|---|
| 246 | echo '<p>Any small donation would be highly appreciated.</p>'; |
|---|
| 247 | echo '<h3>Miscellaneous</h3>'; |
|---|
| 248 | echo '<ul> |
|---|
| 249 | <li><a href="http://wordpress-plugins.feifei.us/">Elliott\'s WP Plugins</a></li> |
|---|
| 250 | <li><a href="http://ocaoimh.ie/wordpress-plugins/">Donncha\'s WP Plugins</a></li> |
|---|
| 251 | </ul>'; |
|---|
| 252 | echo '<h3>Statistics</h3>'; |
|---|
| 253 | echo '<p>'.widget_ratio($options).'</p>'; |
|---|
| 254 | echo '</div>'; |
|---|
| 255 | |
|---|
| 256 | echo '<div class="main">'; |
|---|
| 257 | echo '<h2>WordPress Hashcash</h2>'; |
|---|
| 258 | echo '<p>This is an antispam plugin that eradicates spam signups on WordPress sites. It works because your visitors must use obfuscated |
|---|
| 259 | javascript to submit a proof-of-work that indicates they opened your website in a web browser, not a robot. You can read more about it on the |
|---|
| 260 | <a href="http://wordpress-plugins.feifei.us/hashcash/">WordPress Hashcash plugin page</a> of my site.</p>'; |
|---|
| 261 | |
|---|
| 262 | echo '<h3>Standard Options</h3>'; |
|---|
| 263 | echo '<form method="POST" action="?page=' . $_GET[ 'page' ] . '&updated=true">'; |
|---|
| 264 | wp_nonce_field('wphc-options'); |
|---|
| 265 | if( function_exists( 'is_site_admin' ) ) { // MU only |
|---|
| 266 | $signup_active = (int)$options[ 'signup_active' ]; |
|---|
| 267 | $comments_active = (int)$options[ 'comments_active' ]; |
|---|
| 268 | echo "<p><label>Signup protection enabled: <input type='checkbox' name='signup_active' value='1' " . ( $signup_active == '1' ? ' checked' : '' ) . " /></label></p>"; |
|---|
| 269 | echo "<p><label>Comments protection enabled: <input type='checkbox' name='comments_active' value='1' " . ( $comments_active == '1' ? ' checked' : '' ) . " /></label></p>"; |
|---|
| 270 | } |
|---|
| 271 | // moderation options |
|---|
| 272 | $moderate = htmlspecialchars($options['moderation'], ENT_QUOTES); |
|---|
| 273 | echo '<p><label for="wphc-moderation">' . __('Moderation:', 'wp-hashcash') . '</label>'; |
|---|
| 274 | echo '<select id="wphc-moderation" name="wphc-moderation">'; |
|---|
| 275 | echo '<option value="moderate"'.($moderate=='moderate'?' selected':'').'>Moderate</option>'; |
|---|
| 276 | echo '<option value="akismet"'.($moderate=='akismet'?' selected':'').'>Akismet</option>'; |
|---|
| 277 | echo '<option value="delete"'.($moderate=='delete'?' selected':'').'>Delete</option>'; |
|---|
| 278 | echo '</select>'; |
|---|
| 279 | echo '<br/><span style="color: grey; font-size: 90%;">The default is to place spam comments into the |
|---|
| 280 | akismet/moderation queue. Otherwise, the delete option will immediately discard spam comments.</span>'; |
|---|
| 281 | echo '</p>'; |
|---|
| 282 | |
|---|
| 283 | // refresh interval |
|---|
| 284 | $refresh = htmlspecialchars($options['refresh'], ENT_QUOTES); |
|---|
| 285 | echo '<p><label for="wphc-refresh">' . __('Key Expiry:', 'wp-hashcash').'</label> |
|---|
| 286 | <input style="width: 200px;" id="wphc-refresh" name="wphc-refresh" type="text" value="'.$refresh.'" /> |
|---|
| 287 | <br/><span style="color: grey; font-size: 90%;">Default is one week, or <strong>604800</strong> seconds.</p>'; |
|---|
| 288 | |
|---|
| 289 | // current key |
|---|
| 290 | echo '<p>Your current key is <strong>' . $options['key'][count($options['key']) - 1] . '</strong>.'; |
|---|
| 291 | if(count($options['key']) > 1) |
|---|
| 292 | echo ' Previously you had keys '. join(', ', array_reverse(array_slice($options['key'], 0, count($options['key']) - 1))).'.'; |
|---|
| 293 | echo '</p>'; |
|---|
| 294 | |
|---|
| 295 | // additional options |
|---|
| 296 | echo '<h3>Additional options:</h3>'; |
|---|
| 297 | |
|---|
| 298 | $validate_ip = htmlspecialchars($options['validate-ip'], ENT_QUOTES); |
|---|
| 299 | echo '<p><label for="wphc-validate-ip">Validate IP Address</label> |
|---|
| 300 | <input name="wphc-validate-ip" type="checkbox" id="wphc-validate-ip"'.($validate_ip?' checked':'').'/> |
|---|
| 301 | <br /><span style="color: grey; font-size: 90%;"> |
|---|
| 302 | Checks if the IP address of the trackback sender is equal to the IP address of the webserver the trackback URL is referring to.</span></p>'; |
|---|
| 303 | |
|---|
| 304 | $validate_url = htmlspecialchars($options['validate-url'], ENT_QUOTES); |
|---|
| 305 | echo '<p><label for="wphc-validate-url">Validate URL</label> |
|---|
| 306 | <input name="wphc-validate-url" type="checkbox" id="wphc-validate-url"'.($validate_url?' checked':'').'/> |
|---|
| 307 | <br /><span style="color: grey; font-size: 90%;">Retrieves the web page located at the URL included |
|---|
| 308 | in the trackback to check if it contains a link to your blog. If it does not, it is spam!</span></p>'; |
|---|
| 309 | |
|---|
| 310 | // logging options |
|---|
| 311 | echo '<h3>Logging:</h3>'; |
|---|
| 312 | |
|---|
| 313 | $logging = htmlspecialchars($options['logging'], ENT_QUOTES); |
|---|
| 314 | echo '<p><label for="wphc-logging">Logging</label> |
|---|
| 315 | <input name="wphc-logging" type="checkbox" id="wphc-logging"'.($logging?' checked':'').'/> |
|---|
| 316 | <br /><span style="color: grey; font-size: 90%;">Logs the reason why a given comment failed the spam |
|---|
| 317 | check into the comment body. Works only if moderation / akismet mode is enabled.</span></p>'; |
|---|
| 318 | |
|---|
| 319 | echo '<input type="hidden" id="wphc-submit" name="wphc-submit" value="1" />'; |
|---|
| 320 | echo '<input type="submit" id="wphc-submit-override" name="wphc-submit-override" value="Save WP Hashcash Settings"/>'; |
|---|
| 321 | echo '</form>'; |
|---|
| 322 | echo '</div>'; |
|---|
| 323 | |
|---|
| 324 | echo '<div class="clear">'; |
|---|
| 325 | echo '<p style="text-align: center; font-size: .85em;">© Copyright '.date('Y').' <a href="http://elliottback.com">Elliott Bäck</a></p>'; |
|---|
| 326 | echo '</div>'; |
|---|
| 327 | |
|---|
| 328 | echo '</div>'; |
|---|
| 329 | } |
|---|
| 330 | |
|---|
| 331 | /** |
|---|
| 332 | * Add JS to the header |
|---|
| 333 | */ |
|---|
| 334 | function wphc_posthead() { |
|---|
| 335 | if( function_exists( 'is_site_admin' ) ) { |
|---|
| 336 | $options = wphc_option(); |
|---|
| 337 | if( !$options['comments_active'] ) |
|---|
| 338 | return; |
|---|
| 339 | } |
|---|
| 340 | if((is_single() || is_page())) |
|---|
| 341 | wphc_addhead(); |
|---|
| 342 | } |
|---|
| 343 | add_action('wp_head', 'wphc_posthead'); |
|---|
| 344 | |
|---|
| 345 | function wphc_signuphead() { |
|---|
| 346 | if( function_exists( 'is_site_admin' ) ) { |
|---|
| 347 | $options = wphc_option(); |
|---|
| 348 | if( !$options['signup_active'] ) |
|---|
| 349 | return; |
|---|
| 350 | } |
|---|
| 351 | wphc_addhead(); |
|---|
| 352 | } |
|---|
| 353 | add_action('signup_header', 'wphc_signuphead'); |
|---|
| 354 | |
|---|
| 355 | function wphc_addhead() { |
|---|
| 356 | echo "<script type=\"text/javascript\"><!--\n"; |
|---|
| 357 | echo 'function addLoadEvent(func) { |
|---|
| 358 | var oldonload = window.onload; |
|---|
| 359 | if (typeof window.onload != \'function\') { |
|---|
| 360 | window.onload = func; |
|---|
| 361 | } else { |
|---|
| 362 | window.onload = function() { |
|---|
| 363 | if (oldonload) { |
|---|
| 364 | oldonload(); |
|---|
| 365 | } |
|---|
| 366 | func(); |
|---|
| 367 | } |
|---|
| 368 | } |
|---|
| 369 | } |
|---|
| 370 | '; |
|---|
| 371 | echo wphc_getjs() . "\n"; |
|---|
| 372 | echo "addLoadEvent(function(){document.getElementById('wphc_value').value=wphc();});\n"; |
|---|
| 373 | echo "//--></script>\n"; |
|---|
| 374 | } |
|---|
| 375 | |
|---|
| 376 | function wphc_getjs(){ |
|---|
| 377 | $options = wphc_option(); |
|---|
| 378 | $val = $options['key'][count($options['key']) - 1]; |
|---|
| 379 | $js = 'function wphc_compute(){'; |
|---|
| 380 | |
|---|
| 381 | switch(rand(0, 3)){ |
|---|
| 382 | /* Addition of n times of field value / n, + modulus: |
|---|
| 383 | Time guarantee: 100 iterations or less */ |
|---|
| 384 | case 0: |
|---|
| 385 | $inc = rand($val / 100, $val - 1); |
|---|
| 386 | $n = floor($val / $inc); |
|---|
| 387 | $r = $val % $inc; |
|---|
| 388 | |
|---|
| 389 | $js .= "var wphc_eax = $inc; "; |
|---|
| 390 | for($i = 0; $i < $n - 1; $i++){ |
|---|
| 391 | $js .= "wphc_eax += $inc; "; |
|---|
| 392 | } |
|---|
| 393 | |
|---|
| 394 | $js .= "wphc_eax += $r; "; |
|---|
| 395 | $js .= 'return wphc_eax; '; |
|---|
| 396 | break; |
|---|
| 397 | |
|---|
| 398 | /* Conversion from binary: |
|---|
| 399 | Time guarantee: log(n) iterations or less */ |
|---|
| 400 | case 1: |
|---|
| 401 | $binval = strrev(base_convert($val, 10, 2)); |
|---|
| 402 | $js .= "var wphc_eax = \"$binval\"; "; |
|---|
| 403 | $js .= 'var wphc_ebx = 0; '; |
|---|
| 404 | $js .= 'var wphc_ecx = 0; '; |
|---|
| 405 | $js .= 'while(wphc_ecx < wphc_eax.length){ '; |
|---|
| 406 | $js .= 'if(wphc_eax.charAt(wphc_ecx) == "1") { '; |
|---|
| 407 | $js .= 'wphc_ebx += Math.pow(2, wphc_ecx); '; |
|---|
| 408 | $js .= '} '; |
|---|
| 409 | $js .= 'wphc_ecx++; '; |
|---|
| 410 | $js .= '} '; |
|---|
| 411 | $js .= 'return wphc_ebx;'; |
|---|
| 412 | |
|---|
| 413 | break; |
|---|
| 414 | |
|---|
| 415 | /* Multiplication of square roots: |
|---|
| 416 | Time guarantee: constant time */ |
|---|
| 417 | case 2: |
|---|
| 418 | $sqrt = floor(sqrt($val)); |
|---|
| 419 | $r = $val - ($sqrt * $sqrt); |
|---|
| 420 | $js .= "return $sqrt * $sqrt + $r; "; |
|---|
| 421 | break; |
|---|
| 422 | |
|---|
| 423 | /* Sum of random numbers to the final value: |
|---|
| 424 | Time guarantee: log(n) expected value */ |
|---|
| 425 | case 3: |
|---|
| 426 | $js .= 'return '; |
|---|
| 427 | |
|---|
| 428 | $i = 0; |
|---|
| 429 | while($val > 0){ |
|---|
| 430 | if($i++ > 0) |
|---|
| 431 | $js .= '+'; |
|---|
| 432 | |
|---|
| 433 | $temp = rand(1, $val); |
|---|
| 434 | $val -= $temp; |
|---|
| 435 | $js .= $temp; |
|---|
| 436 | } |
|---|
| 437 | |
|---|
| 438 | $js .= ';'; |
|---|
| 439 | break; |
|---|
| 440 | } |
|---|
| 441 | |
|---|
| 442 | $js .= '} wphc_compute();'; |
|---|
| 443 | |
|---|
| 444 | // pack bytes |
|---|
| 445 | if( !function_exists( 'strToLongs' ) ) { |
|---|
| 446 | function strToLongs($s) { |
|---|
| 447 | $l = array(); |
|---|
| 448 | |
|---|
| 449 | // pad $s to some multiple of 4 |
|---|
| 450 | $s = preg_split('//', $s, -1, PREG_SPLIT_NO_EMPTY); |
|---|
| 451 | |
|---|
| 452 | while(count($s) % 4 != 0){ |
|---|
| 453 | $s [] = ' '; |
|---|
| 454 | } |
|---|
| 455 | |
|---|
| 456 | for ($i = 0; $i < ceil(count($s)/4); $i++) { |
|---|
| 457 | $l[$i] = ord($s[$i*4]) + (ord($s[$i*4+1]) << 8) + (ord($s[$i*4+2]) << 16) + (ord($s[$i*4+3]) << 24); |
|---|
| 458 | } |
|---|
| 459 | |
|---|
| 460 | return $l; |
|---|
| 461 | } |
|---|
| 462 | } |
|---|
| 463 | |
|---|
| 464 | // xor all the bytes with a random key |
|---|
| 465 | $key = rand(21474836, 2126008810); |
|---|
| 466 | $js = strToLongs($js); |
|---|
| 467 | |
|---|
| 468 | for($i = 0; $i < count($js); $i++){ |
|---|
| 469 | $js[$i] = $js[$i] ^ $key; |
|---|
| 470 | } |
|---|
| 471 | |
|---|
| 472 | // libs function encapsulation |
|---|
| 473 | $libs = "function wphc(){\n"; |
|---|
| 474 | |
|---|
| 475 | // write bytes to javascript, xor with key |
|---|
| 476 | $libs .= "\tvar wphc_data = [".join(',',$js)."]; \n"; |
|---|
| 477 | |
|---|
| 478 | // do the xor with key |
|---|
| 479 | $libs .= "\n\tfor (var i=0; i<wphc_data.length; i++){\n"; |
|---|
| 480 | $libs .= "\t\twphc_data[i]=wphc_data[i]^$key;\n"; |
|---|
| 481 | $libs .= "\t}\n"; |
|---|
| 482 | |
|---|
| 483 | // convert bytes back to string |
|---|
| 484 | $libs .= "\n\tvar a = new Array(wphc_data.length); \n"; |
|---|
| 485 | $libs .= "\tfor (var i=0; i<wphc_data.length; i++) { \n"; |
|---|
| 486 | $libs .= "\t\ta[i] = String.fromCharCode(wphc_data[i] & 0xFF, wphc_data[i]>>>8 & 0xFF, "; |
|---|
| 487 | $libs .= "wphc_data[i]>>>16 & 0xFF, wphc_data[i]>>>24 & 0xFF);\n"; |
|---|
| 488 | $libs .= "\t}\n"; |
|---|
| 489 | |
|---|
| 490 | $libs .= "\n\treturn eval(a.join('')); \n"; |
|---|
| 491 | |
|---|
| 492 | // call libs function |
|---|
| 493 | $libs .= "}"; |
|---|
| 494 | |
|---|
| 495 | // return code |
|---|
| 496 | return $libs; |
|---|
| 497 | } |
|---|
| 498 | |
|---|
| 499 | /** |
|---|
| 500 | * Hook into the signups form |
|---|
| 501 | */ |
|---|
| 502 | function wphc_add_signupform(){ |
|---|
| 503 | echo '<input type="hidden" id="wphc_value" name="wphc_value" value=""/>'; |
|---|
| 504 | } |
|---|
| 505 | add_action( 'signup_hidden_fields', 'wphc_add_signupform' ); |
|---|
| 506 | |
|---|
| 507 | function wphc_add_commentform(){ |
|---|
| 508 | $options = wphc_option(); |
|---|
| 509 | |
|---|
| 510 | switch($options['moderation']){ |
|---|
| 511 | case 'delete': |
|---|
| 512 | $verb = 'deleted'; |
|---|
| 513 | break; |
|---|
| 514 | case 'akismet': |
|---|
| 515 | $verb = 'queued in Akismet'; |
|---|
| 516 | break; |
|---|
| 517 | case 'moderate': |
|---|
| 518 | default: |
|---|
| 519 | $verb = 'placed in moderation'; |
|---|
| 520 | break; |
|---|
| 521 | } |
|---|
| 522 | |
|---|
| 523 | echo '<div><input type="hidden" id="wphc_value" name="wphc_value" value=""/></div>'; |
|---|
| 524 | echo '<p>' . __('Powered by', 'wp-hashcash') . ' <a href="http://wordpress-plugins.feifei.us/hashcash/">WP Hashcash</a></p>'; |
|---|
| 525 | echo '<noscript><div><small>Wordpress Hashcash needs javascript to work, but your browser has javascript disabled. Your comment will be '.$verb.'!</small></div></noscript>'; |
|---|
| 526 | } |
|---|
| 527 | |
|---|
| 528 | add_action('comment_form', 'wphc_add_commentform'); |
|---|
| 529 | |
|---|
| 530 | /** |
|---|
| 531 | * Validate our tag |
|---|
| 532 | */ |
|---|
| 533 | |
|---|
| 534 | function wphc_check_signup_hidden_tag( $result ) { |
|---|
| 535 | // get our options |
|---|
| 536 | $options = wphc_option(); |
|---|
| 537 | $spam = false; |
|---|
| 538 | if( !strpos( $_SERVER[ 'PHP_SELF' ], 'wp-signup.php' ) ) |
|---|
| 539 | return $result; |
|---|
| 540 | |
|---|
| 541 | // Check the wphc values against the last five keys |
|---|
| 542 | $spam = !in_array($_POST["wphc_value"], $options['key']); |
|---|
| 543 | |
|---|
| 544 | if($spam){ |
|---|
| 545 | $options['signups-spam'] = ((int) $options['signups-spam']) + 1; |
|---|
| 546 | wphc_option($options); |
|---|
| 547 | $result['errors']->add( 'blogname', __('You did not pass a spam check. Please enable JavaScript in your browser.') ); |
|---|
| 548 | } else { |
|---|
| 549 | $options['signups-ham'] = ((int) $options['signups-ham']) + 1; |
|---|
| 550 | wphc_option($options); |
|---|
| 551 | } |
|---|
| 552 | |
|---|
| 553 | return $result; |
|---|
| 554 | } |
|---|
| 555 | add_filter( 'wpmu_validate_blog_signup', 'wphc_check_signup_hidden_tag' ); |
|---|
| 556 | add_filter( 'wpmu_validate_user_signup', 'wphc_check_signup_hidden_tag' ); |
|---|
| 557 | |
|---|
| 558 | function wphc_check_hidden_tag($comment) { |
|---|
| 559 | // get our options |
|---|
| 560 | $type = $comment['comment_type']; |
|---|
| 561 | $options = wphc_option(); |
|---|
| 562 | $spam = false; |
|---|
| 563 | |
|---|
| 564 | if($type == "trackback" || $type == "pingback"){ |
|---|
| 565 | // check the website's IP against the url it's sending as a trackback |
|---|
| 566 | if($options['validate-ip']){ |
|---|
| 567 | $server_ip = isset($_SERVER['HTTP_X_FORWARDED_FOR']) ? $_SERVER['HTTP_X_FORWARDED_FOR'] : $_SERVER['REMOTE_ADDR']; |
|---|
| 568 | $web_ip = gethostbyname(parse_url($comment['comment_author_url'], PHP_URL_HOST)); |
|---|
| 569 | $ipv = $server_ip != $web_ip; |
|---|
| 570 | $spam = $spam || ($ipv); |
|---|
| 571 | |
|---|
| 572 | if($options['logging'] && $ipv) $comment['comment_content'] .= "\n\n[WORDPRESS HASHCASH] The comment's server IP (".$server_ip.") doesn't match the" |
|---|
| 573 | . " comment's URL host IP (".$web_ip.") and so is spam."; |
|---|
| 574 | } |
|---|
| 575 | |
|---|
| 576 | // look for our link in the page itself |
|---|
| 577 | if(!$spam && $options['validate-url']){ |
|---|
| 578 | if(!class_exists('Snoopy')) |
|---|
| 579 | require_once( ABSPATH . WPINC . '/class-snoopy.php' ); |
|---|
| 580 | |
|---|
| 581 | $permalink = get_permalink($comment['comment_post_ID']); |
|---|
| 582 | $permalink = preg_replace('/\/$/', '', $permalink); |
|---|
| 583 | $snoop = new Snoopy; |
|---|
| 584 | |
|---|
| 585 | if (@$snoop->fetchlinks($comment['comment_author_url'])){ |
|---|
| 586 | $found = false; |
|---|
| 587 | |
|---|
| 588 | if( !empty( $snoop->results ) ) |
|---|
| 589 | { |
|---|
| 590 | foreach($snoop->results as $url){ |
|---|
| 591 | $url = preg_replace('/(\/|\/trackback|\/trackback\/)$/', '', $url); |
|---|
| 592 | if($url == $permalink) |
|---|
| 593 | $found = true; |
|---|
| 594 | } |
|---|
| 595 | } |
|---|
| 596 | |
|---|
| 597 | if($options['logging'] && !$found) |
|---|
| 598 | $comment['comment_content'] .= "\n\n[WORDPRESS HASHCASH] The comment's actual post text did not contain your blog url (".$permalink.") and so is spam."; |
|---|
| 599 | |
|---|
| 600 | $spam = $spam || !$found; |
|---|
| 601 | } else { |
|---|
| 602 | $spam = true; |
|---|
| 603 | if($options['logging']) |
|---|
| 604 | $comment['comment_content'] .= "\n\n[WORDPRESS HASHCASH] Snoopy failed to fetch results for the comment blog url (".$comment['comment_author_url'].") with error '".$snoop->error."' and so is spam."; |
|---|
| 605 | } |
|---|
| 606 | } |
|---|
| 607 | } else { |
|---|
| 608 | // Check the wphc values against the last five keys |
|---|
| 609 | $spam = !in_array($_POST["wphc_value"], $options['key']); |
|---|
| 610 | if($options['logging'] && $spam) |
|---|
| 611 | $comment['comment_content'] .= "\n\n[WORDPRESS HASHCASH] The poster sent us '".intval($_POST["wphc_value"])." which is not a hashcash value."; |
|---|
| 612 | } |
|---|
| 613 | |
|---|
| 614 | if($spam){ |
|---|
| 615 | $options['comments-spam'] = ((int) $options['comments-spam']) + 1; |
|---|
| 616 | wphc_option($options); |
|---|
| 617 | |
|---|
| 618 | switch($options['moderation']){ |
|---|
| 619 | case 'delete': |
|---|
| 620 | add_filter('comment_post', create_function('$id', 'wp_delete_comment($id); die(\'This comment has been deleted by WP Hashcash\');')); |
|---|
| 621 | break; |
|---|
| 622 | case 'akismet': |
|---|
| 623 | add_filter('pre_comment_approved', create_function('$a', 'return \'spam\';')); |
|---|
| 624 | break; |
|---|
| 625 | case 'moderate': |
|---|
| 626 | default: |
|---|
| 627 | add_filter('pre_comment_approved', create_function('$a', 'return 0;')); |
|---|
| 628 | break; |
|---|
| 629 | } |
|---|
| 630 | } else { |
|---|
| 631 | $options['comments-ham'] = ((int) $options['comments-ham']) + 1; |
|---|
| 632 | wphc_option($options); |
|---|
| 633 | } |
|---|
| 634 | |
|---|
| 635 | return $comment; |
|---|
| 636 | } |
|---|
| 637 | |
|---|
| 638 | add_filter('preprocess_comment', 'wphc_check_hidden_tag'); |
|---|
| 639 | ?> |
|---|