diff options
Diffstat (limited to 'inc')
| -rw-r--r-- | inc/anti-bot.php | 236 | ||||
| -rw-r--r-- | inc/functions.php | 161 | ||||
| -rw-r--r-- | inc/image.php | 1 | ||||
| -rw-r--r-- | inc/lib/Twig/Extensions/Extension/Tinyboard.php | 3 |
4 files changed, 239 insertions, 162 deletions
diff --git a/inc/anti-bot.php b/inc/anti-bot.php new file mode 100644 index 00000000..e8c26113 --- /dev/null +++ b/inc/anti-bot.php @@ -0,0 +1,236 @@ +<?php + +/* + * Copyright (c) 2010-2012 Tinyboard Development Group + */ + +if(realpath($_SERVER['SCRIPT_FILENAME']) == str_replace('\\', '/', __FILE__)) { + // You cannot request this file directly. + exit; +} + +$hidden_inputs_twig = array(); + +class AntiBot { + public $inputs = array(), $index = 0; + private $salt; + + public static function randomString($length, $uppercase = false, $special_chars = false) { + $chars = 'abcdefghijklmnopqrstuvwxyz0123456789'; + if($uppercase) + $chars .= 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'; + if($special_chars) + $chars .= ' ~!@#$%^&*()_+,./;\'[]\\{}|:"<>?=-` '; + + $chars = str_split($chars); + + $ch = array(); + + // fill up $ch until we reach $length + while(count($ch) < $length) { + $n = $length - count($ch); + $keys = array_rand($chars, $n > count($chars) ? count($chars) : $n); + if($n == 1) { + $ch[] = $chars[$keys]; + break; + } + shuffle($keys); + foreach($keys as $key) + $ch[] = $chars[$key]; + } + + $chars = $ch; + + return implode('', $chars); + } + + public static function make_confusing($string) { + $chars = str_split($string); + + foreach($chars as &$c) { + if(rand(0, 2) != 0) + continue; + $c = mb_encode_numericentity($c, array(0, 0xffff, 0, 0xffff), 'UTF-8'); + } + + return implode('', $chars); + } + + public function __construct(array $salt = array()) { + global $config; + + if(!empty($salt)) { + // create a salted hash of the "extra salt" + $this->salt = implode(':', $salt); + } else { + $this->salt = ''; + } + + shuffle($config['spam']['hidden_input_names']); + + $input_count = rand($config['spam']['hidden_inputs_min'], $config['spam']['hidden_inputs_max']); + $hidden_input_names_x = 0; + + for($x = 0; $x < $input_count ; $x++) { + if($hidden_input_names_x === false || rand(0, 2) == 0) { + // Use an obscure name + $name = $this->randomString(rand(10, 40)); + } else { + // Use a pre-defined confusing name + $name = $config['spam']['hidden_input_names'][$hidden_input_names_x++]; + if($hidden_input_names_x >= count($config['spam']['hidden_input_names'])) + $hidden_input_names_x = false; + } + + if(rand(0, 2) == 0) { + // Value must be null + $this->inputs[$name] = ''; + } elseif(rand(0, 4) == 0) { + // Numeric value + $this->inputs[$name] = (string)rand(0, 100); + } else { + // Obscure value + $this->inputs[$name] = $this->randomString(rand(5, 100)); + } + } + } + + public function html($count = false) { + $elements = array( + '<input type="hidden" name="%name%" value="%value%">', + '<input type="hidden" value="%value%" name="%name%">', + '<input style="display:none" type="text" name="%name%" value="%value%">', + '<input style="display:none" type="text" value="%value%" name="%name%">', + '<span style="display:none"><input type="text" name="%name%" value="%value%"></span>', + '<div style="display:none"><input type="text" name="%name%" value="%value%"></div>', + '<div style="display:none"><input type="text" name="%name%" value="%value%"></div>', + '<textarea style="display:none" name="%name%">%value%</textarea>', + '<textarea name="%name%" style="display:none">%value%</textarea>' + ); + + $html = ''; + + if($count == 0) { + // all elements + $inputs = array_slice($this->inputs, $this->index); + } else { + $inputs = array_slice($this->inputs, $this->index, $count); + } + $this->index += count($inputs); + + foreach($inputs as $name => $value) { + $element = false; + while(!$element) { + $element = $elements[array_rand($elements)]; + if(strpos($element, 'textarea') !== false && $value == '') { + // There have been some issues with mobile web browsers and empty <textarea>'s. + $element = false; + } + } + + $element = str_replace('%name%', utf8tohtml($name), $element); + + if(rand(0, 2) == 0) + $value = $this->make_confusing($value); + else + $value = utf8tohtml($value); + + $element = str_replace('%value%', $value, $element); + + $html .= $element; + } + + return $html; + } + + public function hash() { + global $config; + + // This is the tricky part: create a hash to validate it after + // First, sort the keys in alphabetical order (A-Z) + $inputs = $this->inputs; + ksort($inputs); + + $hash = ''; + // Iterate through each input + foreach($inputs as $name => $value) { + $hash .= $name . '=' . $value; + } + // Add a salt to the hash + $hash .= $config['cookies']['salt']; + + // Use SHA1 for the hash + return sha1($hash . $this->salt); + } +};; + + +function hiddenInputs(array $salt, $print_the_rest = false) { + global $hidden_inputs_twig; + + $salt_str = implode(':', $salt); + + if(!isset($hidden_inputs_twig[$salt_str])) + $hidden_inputs_twig[$salt_str] = new AntiBot($salt); + + if($print_the_rest) + return $hidden_inputs_twig[$salt_str]->html(0); + else + return $hidden_inputs_twig[$salt_str]->html(rand(1, 5)); +} + +function hiddenInputsHash(array $salt) { + global $hidden_inputs_twig; + + $salt_str = implode(':', $salt); + + if(!isset($hidden_inputs_twig[$salt_str])) + $hidden_inputs_twig[$salt_str] = new AntiBot($salt); + + return $hidden_inputs_twig[$salt_str]->hash(); +} + +function checkSpam(array $extra_salt = array()) { + global $config; + + if(!isset($_POST['hash'])) + return true; + + $hash = $_POST['hash']; + + if(!empty($extra_salt)) { + // create a salted hash of the "extra salt" + $extra_salt = implode(':', $extra_salt); + } else { + $extra_salt = ''; + } + + // Reconsturct the $inputs array + $inputs = array(); + + foreach($_POST as $name => $value) { + if(in_array($name, $config['spam']['valid_inputs'])) + continue; + + $inputs[$name] = $value; + } + + // Sort the inputs in alphabetical order (A-Z) + ksort($inputs); + + $_hash = ''; + + // Iterate through each input + foreach($inputs as $name => $value) { + $_hash .= $name . '=' . $value; + } + + // Add a salt to the hash + $_hash .= $config['cookies']['salt']; + + // Use SHA1 for the hash + $_hash = sha1($_hash . $extra_salt); + + return $hash != $_hash; +} + diff --git a/inc/functions.php b/inc/functions.php index d7fcc3dd..3761b608 100644 --- a/inc/functions.php +++ b/inc/functions.php @@ -13,6 +13,7 @@ require_once 'inc/display.php'; require_once 'inc/template.php'; require_once 'inc/database.php'; require_once 'inc/events.php'; +require_once 'inc/anti-bot.php'; require_once 'inc/lib/gettext/gettext.inc'; // the user is not currently logged in as a moderator @@ -1160,166 +1161,6 @@ function checkMute() { } } -function createHiddenInputs($extra_salt = array()) { - global $config; - - if(!empty($extra_salt)) { - // create a salted hash of the "extra salt" - $extra_salt = implode(':', $extra_salt); - } else { - $extra_salt = ''; - } - - $inputs = array(); - - shuffle($config['spam']['hidden_input_names']); - $hidden_input_names_x = 0; - - $input_count = rand($config['spam']['hidden_inputs_min'], $config['spam']['hidden_inputs_max']); - for($x=0;$x<$input_count;$x++) { - if(rand(0, 2) == 0 || $hidden_input_names_x < 0) { - // Use an obscure name - $name = strtolower(substr(base64_encode(sha1(rand(), true)), 0, rand(2, 20))); - - } else { - // Use a pre-defined confusing name - $name = $config['spam']['hidden_input_names'][$hidden_input_names_x++]; - if($hidden_input_names_x >= count($config['spam']['hidden_input_names'])) - $hidden_input_names_x = -1; - } - - if(rand(0, 2) == 0) { - // Value must be null - $inputs[$name] = ''; - } elseif(rand(0, 4) == 0) { - // Numeric value - $inputs[$name] = rand(0, 100); - } else { - // Obscure value - $inputs[$name] = substr(base64_encode(sha1(rand(), true) . sha1(rand(), true)), 0, rand(2, 54)); - } - } - - $content = ''; - foreach($inputs as $name => $value) { - $display_type = rand(0, 8); - - switch($display_type) { - case 0: - $content .= '<input type="hidden" name="' . htmlspecialchars($name) . '" value="' . - htmlspecialchars($value) . '" />'; - break; - case 1: - $content .= '<input style="display:none" name="' . htmlspecialchars($name) . '" value="' . - htmlspecialchars($value) . '" />'; - break; - case 2: - $content .= '<input type="hidden" value="' . htmlspecialchars($value) . '" name="' . - htmlspecialchars($name) . '" />'; - break; - case 3: - $content .= '<input type="hidden" name="' . htmlspecialchars($name) . '" value="' . - htmlspecialchars($value) . '" />'; - break; - case 4: - $content .= '<span style="display:none"><input type="text" name="' . htmlspecialchars($name) . '" value="' . - htmlspecialchars($value) .'" /></span>'; - break; - case 5: - $content .= '<div style="display:none"><input type="text" name="' . htmlspecialchars($name) . '" value="' . - htmlspecialchars($value) . '" /></div>'; - break; - case 6: - if(!empty($value)) - $content .= '<textarea style="display:none" name="' . htmlspecialchars($name) . '">' . - htmlspecialchars($value) . '</textarea>'; - else - $content .= '<input type="hidden" name="' . htmlspecialchars($name) . '" value="' . - htmlspecialchars($value) . '" />'; - break; - case 7: - if(!empty($value)) - $content .= '<textarea name="' . htmlspecialchars($name) . '" style="display:none">' . - htmlspecialchars($value) . '</textarea>'; - else - $content .= '<input type="hidden" name="' . htmlspecialchars($name) . '" value="' . - htmlspecialchars($value) . '" />'; - break; - case 8: - $content .= '<div style="display:none"><textarea name="' . htmlspecialchars($name) . '" style="display:none">' . - htmlspecialchars($value) . '</textarea></div>'; - break; - } - } - - // Create a hash to validate it after - // This is the tricky part. - - // First, sort the keys in alphabetical order (A-Z) - ksort($inputs); - - $hash = ''; - - // Iterate through each input - foreach($inputs as $name => $value) { - $hash .= $name . '=' . $value; - } - - // Add a salt to the hash - $hash .= $config['cookies']['salt']; - - // Use SHA1 for the hash - $hash = sha1($hash . $extra_salt); - - // Append it to the HTML - $content .= '<input type="hidden" name="hash" value="' . $hash . '" />'; - - return $content; -} - -function checkSpam($extra_salt = array()) { - global $config; - - if(!isset($_POST['hash'])) - return true; - - $hash = $_POST['hash']; - - if(!empty($extra_salt)) { - // create a salted hash of the "extra salt" - $extra_salt = implode(':', $extra_salt); - } else { - $extra_salt = ''; - } - - // Reconsturct the $inputs array - $inputs = array(); - - foreach($_POST as $name => $value) { - if(in_array($name, $config['spam']['valid_inputs'])) - continue; - - $inputs[$name] = $value; - } - - // Sort the inputs in alphabetical order (A-Z) - ksort($inputs); - - $_hash = ''; - - // Iterate through each input - foreach($inputs as $name => $value) { - $_hash .= $name . '=' . $value; - } - - // Add a salt to the hash - $_hash .= $config['cookies']['salt']; - - // Use SHA1 for the hash - $_hash = sha1($_hash . $extra_salt); - - return $hash != $_hash; -} function buildIndex() { global $board, $config; diff --git a/inc/image.php b/inc/image.php index f6bc3e7c..d1c292dc 100644 --- a/inc/image.php +++ b/inc/image.php @@ -194,7 +194,6 @@ class ImageImagick extends ImageBase { foreach($this->original as $frame) { $delay += $frame->getImageDelay(); - //if($i < $config['thumb_keep_animation_frames']) { if(in_array($i, $keep_frames)) { // $frame->scaleImage($this->width, $this->height, false); $frame->sampleImage($this->width, $this->height); diff --git a/inc/lib/Twig/Extensions/Extension/Tinyboard.php b/inc/lib/Twig/Extensions/Extension/Tinyboard.php index 0cf7705a..7e2149e5 100644 --- a/inc/lib/Twig/Extensions/Extension/Tinyboard.php +++ b/inc/lib/Twig/Extensions/Extension/Tinyboard.php @@ -35,7 +35,8 @@ class Twig_Extensions_Extension_Tinyboard extends Twig_Extension return Array( 'time' => new Twig_Filter_Function('time', array('needs_environment' => false)), 'timezone' => new Twig_Filter_Function('twig_timezone_function', array('needs_environment' => false)), - 'createHiddenInputs' => new Twig_Filter_Function('createHiddenInputs', array('needs_environment' => false)) + 'hiddenInputs' => new Twig_Filter_Function('hiddenInputs', array('needs_environment' => false)), + 'hiddenInputsHash' => new Twig_Filter_Function('hiddenInputsHash', array('needs_environment' => false)) ); } |
