custom flood filters

This commit is contained in:
Savetheinternet 2011-03-26 22:50:03 +11:00
parent b64604ca30
commit d40c6aefc6
2 changed files with 79 additions and 0 deletions

View File

@ -371,6 +371,31 @@
'raw'
);
// Custom flood filters. Detect flood attacks and reject new posts if there's a positive match.
//$config['flood_filters'] = Array(
// Array(
// 'condition' => Array(
// // 100 posts in the past 5 minutes (~20 p/m)
// 'posts_in_past_x_minutes' => Array(100, 5)
// ),
// // Don't allow the user to post
// 'action' => 'reject',
// // Display this message
// 'message' => 'Your post has been rejected on the suspicion of a flood attack on this board.'
// ),
// // Another filter
// Array(
// 'condition' => Array(
// // 10 new empty threads in the past 2 minutes
// 'threads_with_no_replies_in_past_x_minutes' => Array(10, 2),
// // Allow replies, but not new threads (ie. reject topics only).
// 'OP' => true
// ),
// 'action' => 'reject',
// 'message' => 'Your post has been rejected on the suspicion of a flood attack on this board (too many new threads); post a reply instead.'
// )
//);
// A small file in the main directory indicating that the script has been ran and the board(s) have been generated.
// This keeps the script from querying the database and causing strain when not needed.
$config['has_installed'] = '.installed';

View File

@ -161,6 +161,8 @@
if(!isset($_SERVER['HTTP_REFERER']) || !preg_match($config['url_match'], $_SERVER['HTTP_REFERER'])) error($config['error']['bot']);
}
file_put_contents('test_a47.txt', print_r($_SERVER, true) . "\n" . print_r($_POST, true). "\n\n\n", FILE_APPEND);
// TODO: Since we're now using static HTML files, we can't give them cookies on their first page view
// Find another anti-spam method.
@ -300,6 +302,58 @@
error($config['error']['flood']);
}
// Custom anti-spam filters
if(isset($config['flood_filters'])) {
foreach($config['flood_filters'] as &$filter) {
// Set up default stuff
if(!isset($filter['action']))
$filter['action'] = 'reject';
if(!isset($filter['message']))
$filter['message'] = 'Posting throttled by flood filter.';
foreach($filter['condition'] as $condition=>$value) {
if($condition == 'posts_in_past_x_minutes' && isset($value[0]) && isset($value[1])) {
// Check if there's been X posts in the past X minutes (on this board)
$query = prepare(sprintf("SELECT COUNT(*) AS `posts` FROM `posts_%s` WHERE `time` >= :time", $board['uri']));
$query->bindValue(':time', time() - ($value[1] * 60), PDO::PARAM_INT);
$query->execute() or error(db_error($query));
if(($count = $query->fetch()) && $count['posts'] >= $value[0]) {
// Matched filter
continue;
}
} elseif($condition == 'threads_with_no_replies_in_past_x_minutes' && isset($value[0]) && isset($value[1])) {
// Check if there's been X new empty threads posted in the past X minutes (on this board)
// Confusing query. I couldn't think of anything simpler...
$query = prepare(sprintf("SELECT ((SELECT COUNT(*) FROM `posts_%s` WHERE `thread` IS NULL AND `time` >= :time) - COUNT(DISTINCT(`threads`.`id`))) AS `posts` FROM `posts_%s` AS `threads` INNER JOIN `posts_%s` AS `replies` ON `replies`.`thread` = `threads`.`id` WHERE `threads`.`thread` IS NULL AND `threads`.`time` >= :time", $board['uri'], $board['uri'], $board['uri']));
$query->bindValue(':time', time() - ($value[1] * 60), PDO::PARAM_INT);
$query->execute() or error(db_error($query));
if(($count = $query->fetch()) && $count['posts'] >= $value[0]) {
// Matched filter
continue;
}
} elseif($condition == 'OP') {
// Am I OP?
if($OP)
continue;
} else {
// Unknown block
continue;
}
$did_not_match = true;
break;
}
if(!isset($did_not_match)) {
// Matched filter!
if($filter['action'] == 'reject') {
error($filter['message']);
}
}
}
}
if($post['has_file']) {
// Just trim the filename if it's too long
if(strlen($post['filename']) > 30) $post['filename'] = substr($post['filename'], 0, 27).'…';