diff --git a/UTIL/kusaba_freshinstall.mysql.sql b/UTIL/kusaba_freshinstall.mysql.sql index 16651b7..b435e61 100644 --- a/UTIL/kusaba_freshinstall.mysql.sql +++ b/UTIL/kusaba_freshinstall.mysql.sql @@ -273,6 +273,7 @@ CREATE TABLE `PREFIX_posts` ( `IS_DELETED` tinyint(1) NOT NULL DEFAULT '0', `bumped` int(20) unsigned NOT NULL DEFAULT '0', `country` varchar(10) NOT NULL DEFAULT 'xx', + `by_new_user` TINYINT(1) NOT NULL DEFAULT '0', PRIMARY KEY (`boardid`,`id`), KEY `parentid` (`parentid`), KEY `bumped` (`bumped`), diff --git a/UTIL/migrate_to_ipless_mode.sql b/UTIL/migrate_to_ipless_mode.sql new file mode 100644 index 0000000..8b3fe6b --- /dev/null +++ b/UTIL/migrate_to_ipless_mode.sql @@ -0,0 +1,2 @@ +ALTER TABLE `posts` + ADD COLUMN `by_new_user` TINYINT(1) NOT NULL DEFAULT '0' AFTER `country`; \ No newline at end of file diff --git a/banned.php b/banned.php index 6e891fd..3028f34 100644 --- a/banned.php +++ b/banned.php @@ -30,11 +30,15 @@ require 'config.php'; require KU_ROOTDIR . 'inc/functions.php'; require KU_ROOTDIR . 'inc/classes/bans.class.php'; +require KU_ROOTDIR . 'inc/classes/posting.class.php'; + +session_start(); $bans_class = new Bans(); +$posting_class = new Posting(); if (isset($_POST['appealmessage']) && KU_APPEAL != '') { - $results = $tc_db->GetAll("SELECT * FROM `".KU_DBPREFIX."banlist` WHERE `type` = '0' AND `ipmd5` = '" . md5($_SERVER['REMOTE_ADDR']) . "' AND `id` = " . $tc_db->qstr($_POST['banid']) . "LIMIT 1"); + $results = $tc_db->GetAll("SELECT * FROM `".KU_DBPREFIX."banlist` WHERE `type` = '0' AND `ipmd5` = '" . $posting_class->user_id_md5 . "' AND `id` = " . $tc_db->qstr($_POST['banid']) . "LIMIT 1"); if (count($results)>0) { foreach($results AS $line) { if ($line['appealat'] > 0 && $line['appealat'] < time()) { @@ -50,6 +54,6 @@ if (isset($_POST['appealmessage']) && KU_APPEAL != '') { } } -$bans_class->BanCheck($_SERVER['REMOTE_ADDR'], '', true); +$bans_class->BanCheck($posting_class->user_id, '', true); ?> \ No newline at end of file diff --git a/board.php b/board.php index 04d3c80..45c55dc 100644 --- a/board.php +++ b/board.php @@ -49,7 +49,6 @@ require KU_ROOTDIR . 'inc/classes/cloud20.class.php'; $bans_class = new Bans(); $parse_class = new Parse(); -$posting_class = new Posting(); function notify($id="???", $newthreadid = '') { $cl20 = new Cloud20(); @@ -140,11 +139,11 @@ if (isset($_POST['board'])) { // A board being supplied is required for this script to function error_redirect(KU_WEBPATH, _gettext('No board provided')); } - - +// Must be declared after board class +$posting_class = new Posting(); // Expired ban removal, and then existing ban check on the current user -$ban_result = $bans_class->BanCheck($_SERVER['REMOTE_ADDR'], $board_class->board['name']); +$ban_result = $bans_class->BanCheck($posting_class->user_id, $board_class->board['name']); if ($ban_result && is_array($ban_result) && $_POST['AJAX']) { exit(json_encode(array( 'error' => _gettext('YOU ARE BANNED'), @@ -195,7 +194,6 @@ if (isset($_POST['makepost'])) { // A more evident way to identify post action, $parse_class->id = $nextid; $ua = ($board_class->board['useragent']) ? htmlspecialchars($_SERVER['HTTP_USER_AGENT']) : false; $dice = ($board_class->board['dice']) ? true : false; - $ipmd5 = md5($_SERVER['REMOTE_ADDR']); // If they are just a normal user, or vip... if ($user_authority <= 0) { // If the thread is locked @@ -204,7 +202,7 @@ if (isset($_POST['makepost'])) { // A more evident way to identify post action, exitWithErrorPage(_gettext('Sorry, this thread is locked and can not be replied to.')); } - $post_message = $parse_class->ParsePost($_POST['message'], $board_class->board['name'], $thread_replyto, $board_class->board['id'], false, $ua, $dice, $ipmd5); + $post_message = $parse_class->ParsePost($_POST['message'], $board_class->board['name'], $thread_replyto, $board_class->board['id'], false, $ua, $dice, $posting_class->user_id_md5); // Or, if they are a moderator/administrator... } else { @@ -219,7 +217,7 @@ if (isset($_POST['makepost'])) { // A more evident way to identify post action, // Otherwise, parse it as usual... } else { - $post_message = $parse_class->ParsePost($_POST['message'], $board_class->board['name'], $thread_replyto, $board_class->board['id'], false, $ua, $dice, $ipmd5); + $post_message = $parse_class->ParsePost($_POST['message'], $board_class->board['name'], $thread_replyto, $board_class->board['id'], false, $ua, $dice, $posting_class->user_id_md5); // (Moved) check against blacklist and detect flood } @@ -293,7 +291,7 @@ if (isset($_POST['makepost'])) { // A more evident way to identify post action, $lock = 0; } - if (!$post_displaystaffstatus && $user_authority > 0) { + if (!$post_displaystaffstatus && $user_authority > 0/* && $user_authority != 3*/) { $user_authority_display = 0; } elseif ($user_authority > 0) { $user_authority_display = $user_authority; @@ -385,7 +383,7 @@ if (isset($_POST['makepost'])) { // A more evident way to identify post action, // $upload_class->file_name, $upload_class->original_file_name, $filetype_withoutdot, $upload_class->file_md5, $upload_class->imgWidth, $upload_class->imgHeight, $upload_class->file_size, $upload_class->imgWidth_thumb, $upload_class->imgHeight_thumb $post_class = new Post(0, $board_class->board['name'], $board_class->board['id'], true); - $post_id = $post_class->Insert($thread_replyto, $post['name'], $post['tripcode'], $post['email'], $post['subject'], addslashes($post['message']), $upload_class->attachments, $post_passwordmd5, time(), time(), $_SERVER['REMOTE_ADDR'], $user_authority_display, $sticky, $lock, $board_class->board['id'], $post['country']); + $post_id = $post_class->Insert($thread_replyto, $post['name'], $post['tripcode'], $post['email'], $post['subject'], addslashes($post['message']), $upload_class->attachments, $post_passwordmd5, time(), time(), $posting_class->user_id, $user_authority_display, $sticky, $lock, $board_class->board['id'], $post['country'], $posting_class->is_new_user); if ($user_authority > 0 && $user_authority != 3) { $modpost_message = 'Modposted #dwoo)) { $this->dwoo = New Dwoo; $this->dwoo_data = new Dwoo_Data(); $this->InitializeDwoo(); } + if (!isset($this->dwoo)) { $this->dwoo = New Dwoo(); $this->dwoo_data = new Dwoo_Data(); $this->InitializeDwoo(); } // $embeds = Array(); $numimages = 0; $embeds = $tc_db->GetAll("SELECT * FROM `" . KU_DBPREFIX . "embeds`"); @@ -1014,11 +1014,33 @@ class Post extends Board { } } - function Insert($parentid, $name, $tripcode, $email, $subject, $message, $attachments, $password, $timestamp, $bumped, $ip, $posterauthority, $stickied, $locked, $boardid, $country) { + function Insert($parentid, $name, $tripcode, $email, $subject, $message, $attachments, $password, $timestamp, $bumped, $ip, $posterauthority, $stickied, $locked, $boardid, $country, $is_new_user) { global $tc_db; + $post_fields = array( + $parentid, + $boardid, + $name, + $tripcode, + $mail, + $subject, + $message, + $password, + $timestamp, + $bumped, + md5_encrypt($ip, KU_RANDOMSEED), + md5($ip), + $posterauthority, + $stickied, + $locked, + $country, + $is_new_user + ); + foreach($post_fields as &$pf) { + $pf = $tc_db->qstr($pf); + } $query = "INSERT INTO `".KU_DBPREFIX."posts` - ( `parentid` , `boardid`, `name` , `tripcode` , `email` , `subject` , `message` , `password` , `timestamp` , `bumped` , `ip` , `ipmd5` , `posterauthority` , `stickied` , `locked`, `country` ) - VALUES ( ".$tc_db->qstr($parentid).", ".$tc_db->qstr($boardid).", ".$tc_db->qstr($name).", ".$tc_db->qstr($tripcode).", ".$tc_db->qstr($email).", ".$tc_db->qstr($subject).", ".$tc_db->qstr($message).", ".$tc_db->qstr($password).", ".$tc_db->qstr($timestamp).", ".$tc_db->qstr($bumped).", ".$tc_db->qstr(md5_encrypt($ip, KU_RANDOMSEED)).", '".md5($ip)."', ".$tc_db->qstr($posterauthority).", ".$tc_db->qstr($stickied).", ".$tc_db->qstr($locked).", ".$tc_db->qstr($country)." )"; + (`parentid` , `boardid`, `name` , `tripcode` , `email` , `subject` , `message` , `password` , `timestamp` , `bumped` , `ip` , `ipmd5` , `posterauthority` , `stickied` , `locked`, `country`, `by_new_user`) + VALUES ( ".implode(', ', $post_fields)." )"; $tc_db->Execute($query); $id = $tc_db->Insert_Id(); $sqlerr = $tc_db->ErrorNo(); diff --git a/inc/classes/posting.class.php b/inc/classes/posting.class.php index ce9d04c..21756f8 100644 --- a/inc/classes/posting.class.php +++ b/inc/classes/posting.class.php @@ -20,28 +20,102 @@ */ class Posting { + function __construct() { + global $tc_db, $board_class; + + $this->ipless_mode = (I0_IPLESS_MODE==true || (I0_IPLESS_MODE=='auto' && $_SERVER['REMOTE_ADDR']=='127.0.0.1')); + + // Set user ID + if ($this->ipless_mode) { + if (isset($_COOKIE['I0_persistent_id'])) { + $this->user_id = $_COOKIE['I0_persistent_id']; + } + else { + $this->user_id = session_id(); + $this->need_cookie = true; + $this->is_new_user = true; + } + } + else { + $this->user_id = $_SERVER['REMOTE_ADDR']; + } + $this->user_id_md5 = md5($this->user_id); + + if (I0_GLOBAL_NEWTHREADDELAY > 0 && !$this->is_new_user) { + // Check if the user has created any threads on this board + $any_threads = $tc_db->GetOne("SELECT COUNT(*) FROM `posts` WHERE `boardid`=? AND `parentid`='0' AND `ipmd5`=?", + array($board_class->board['id'], $this->user_id_md5)); + if ($any_threads) + $this->is_new_user = false; + elseif (I0_REPLIES_TO_RECOGNIZE) { // Check if the user has created a sufficient number of posts on this board + $post_count = $tc_db->GetOne("SELECT COUNT(*) FROM `posts` WHERE `boardid`=? AND `ipmd5`=? LIMIT ?", + array($board_class->board['id'], $this->user_id_md5, I0_REPLIES_TO_RECOGNIZE)); + $this->is_new_user = ($post_count < I0_REPLIES_TO_RECOGNIZE); + } + else + $this->is_new_user = true; + } + + $this->now = time(); + } + function CheckReplyTime() { global $tc_db, $board_class; /* Get the timestamp of the last time a reply was made by this IP address */ - $result = $tc_db->GetOne("SELECT MAX(timestamp) FROM `" . KU_DBPREFIX . "posts` WHERE `boardid` = " . $board_class->board['id'] . " AND `parentid` != 0 AND `ipmd5` = '" . md5($_SERVER['REMOTE_ADDR']) . "' AND `timestamp` > " . (time() - KU_REPLYDELAY)); - /* If they have posted before and it was recorded... */ - if (isset($result)) { - /* If the time was shorter than the minimum time distance */ - if (time() - $result <= KU_REPLYDELAY) { - exitWithErrorPage(_gettext('Please wait a moment before posting again.'), _gettext('You are currently posting faster than the configured minimum post delay allows.')); - } + $result = $tc_db->GetOne("SELECT MAX(timestamp) + FROM `" . KU_DBPREFIX . "posts` + WHERE + `boardid` = " . $board_class->board['id'] . " + AND + `ipmd5` = '" . $this->user_id_md5 . "' + AND + NOT `IS_DELETED` + AND + `timestamp` > " . ($this->now - KU_REPLYDELAY)); + if ($result) { + exitWithErrorPage(sprintf(_gettext('Please wait %d s before posting again.'), KU_REPLYDELAY - ($this->now - $result)), + _gettext('You are currently posting faster than the configured minimum post delay allows.')); } } function CheckNewThreadTime() { global $tc_db, $board_class; - /* Get the timestamp of the last time a new thread was made by this IP address */ - $result = $tc_db->GetOne("SELECT MAX(timestamp) FROM `" . KU_DBPREFIX . "posts` WHERE `boardid` = " . $board_class->board['id'] . " AND `parentid` = 0 AND `ipmd5` = '" . md5($_SERVER['REMOTE_ADDR']) . "' AND `timestamp` > " . (time() - KU_NEWTHREADDELAY)); - /* If they have posted before and it was recorded... */ - if (isset($result)) { - /* If the time was shorter than the minimum time distance */ - if (time() - $result <= KU_NEWTHREADDELAY) { - exitWithErrorPage(_gettext('Please wait a moment before posting again.'), _gettext('You are currently posting faster than the configured minimum post delay allows.')); + /* Check the global new thread delay */ + if (I0_GLOBAL_NEWTHREADDELAY > 0 && $this->is_new_user) { + $result = $tc_db->GetOne("SELECT MAX(timestamp) + FROM `" . KU_DBPREFIX . "posts` + WHERE + `boardid` = " . $board_class->board['id'] . " + AND + `parentid` = 0 + AND + `by_new_user` = '1' + AND + NOT `IS_DELETED` + AND + `timestamp` > " . ($this->now - I0_GLOBAL_NEWTHREADDELAY)); + if ($result) { + exitWithErrorPage(sprintf(_gettext('Please wait %d s before posting again.'), I0_GLOBAL_NEWTHREADDELAY - ($this->now - $result)), + _gettext('Global new thread delay for new users is imposed.')); + } + } + else { + /* Get the timestamp of the last time a new thread was made by this IP address */ + $result = $tc_db->GetOne("SELECT MAX(timestamp) + FROM `" . KU_DBPREFIX . "posts` + WHERE + `boardid` = " . $board_class->board['id'] . " + AND + `parentid` = 0 + AND + `ipmd5` = '" . $this->user_id_md5 . "' + AND + NOT `IS_DELETED` + AND + `timestamp` > " . ($this->now - KU_NEWTHREADDELAY)); + if ($result) { + exitWithErrorPage(sprintf(_gettext('Please wait %d s before posting again.'), KU_NEWTHREADDELAY - ($this->now - $result)), + _gettext('You are currently posting faster than the configured minimum post delay allows.')); } } } @@ -140,8 +214,8 @@ class Posting { WHERE `md5` = " . $tc_db->qstr($attachment['file_md5']) . " LIMIT 1"); if (count($results) > 0) { - $bans_class->BanUser($_SERVER['REMOTE_ADDR'], 'SERVER', '1', $results[0]['bantime'], '', 'Posting a banned file.
' . $results[0]['description'], 0, 0, 1); - $bans_class->BanCheck($_SERVER['REMOTE_ADDR'], $board_class->board['name']); + $bans_class->BanUser($this->user_id, 'SERVER', '1', $results[0]['bantime'], '', 'Posting a banned file.
' . $results[0]['description'], 0, 0, 1); + $bans_class->BanCheck($this->user_id, $board_class->board['name']); die(); // TODO: AJAX response } @@ -308,7 +382,7 @@ class Posting { foreach ($badlinks as $badlink) { if (stripos($_POST['message'], $badlink) !== false) { /* They included a blacklisted link in their post. Ban them for an hour */ - $bans_class->BanUser($_SERVER['REMOTE_ADDR'], 'board.php', 1, 3600, '', _gettext('Posting a blacklisted link.') . ' (' . $badlink . ')', $_POST['message']); + $bans_class->BanUser($this->user_id, 'board.php', 1, 3600, '', _gettext('Posting a blacklisted link.') . ' (' . $badlink . ')', $_POST['message']); exitWithErrorPage(sprintf(_gettext('Blacklisted link ( %s ) detected.'), $badlink)); } } @@ -335,7 +409,7 @@ class Posting { if(!strlen($msg)) return; - $lastmsg = $tc_db->GetAll("SELECT `message` FROM `".KU_DBPREFIX."posts` WHERE `ipmd5` = '" . md5($_SERVER['REMOTE_ADDR']) . "' AND `boardid`='".$boardid."' ORDER BY `timestamp` DESC LIMIT 1"); + $lastmsg = $tc_db->GetAll("SELECT `message` FROM `".KU_DBPREFIX."posts` WHERE `ipmd5` = '" . $this->user_id_md5 . "' AND `boardid`='".$boardid."' ORDER BY `timestamp` DESC LIMIT 1"); $lastmsg = mb_strtolower(strip_tags(str_replace($cyr, $lat, $lastmsg[0][0]))); if($msg == $lastmsg) exitWithErrorPage(_gettext('Flood Detected'), _gettext('You are posting the same message again.')); @@ -357,7 +431,7 @@ class Posting { foreach ($badlinks as $badlink) { if (stripos($msg, mb_strtolower(str_replace($cyr, $lat, $badlink))) !== false) { /* They included a blacklisted link in their post. Ban them for an hour */ - $bans_class->BanUser($_SERVER['REMOTE_ADDR'], 'board.php', 0, 3600, $board, _gettext('Posting a blacklisted link.') . ' (' . $badlink . ')', $_POST['message']); + $bans_class->BanUser($this->user_id, 'board.php', 0, 3600, $board, _gettext('Posting a blacklisted link.') . ' (' . $badlink . ')', $_POST['message']); exitWithErrorPage(sprintf(_gettext('Blacklisted link ( %s ) detected.'), $badlink)); } } diff --git a/inc/lang/ru/LC_MESSAGES/kusaba.po b/inc/lang/ru/LC_MESSAGES/kusaba.po index 1849ae9..5d1219e 100644 --- a/inc/lang/ru/LC_MESSAGES/kusaba.po +++ b/inc/lang/ru/LC_MESSAGES/kusaba.po @@ -862,8 +862,11 @@ msgstr "Выберите доску." msgid "Please select only one image to upload." msgstr "Выберите только изображение для загрузки." -msgid "Please wait a moment before posting again." -msgstr "Подождите перед отправкой нового сообщения." +msgid "Please wait %d s before posting again." +msgstr "Подождите %d с перед отправкой нового сообщения." + +msgid "Global new thread delay for new users is imposed." +msgid "Действует режим глобального ограничения на создание тредов новыми пользователями." msgid "Popular" msgstr "Популярные"