From 5ec623e99402d4e1634b91e6d44076422160e517 Mon Sep 17 00:00:00 2001 From: davydovct Date: Fri, 27 Apr 2018 11:49:51 +0500 Subject: [PATCH] release 2.4 --- CleanTalk/Base/CleanTalk.php | 441 ++++++ CleanTalk/Base/cleantalk.class.php | 1263 +++++++++++++++++ CleanTalk/ControllerPublic/CleanTalkForum.php | 16 + CleanTalk/ControllerPublic/CleanTalkMisc.php | 219 +++ CleanTalk/ControllerPublic/CleanTalkPost.php | 16 + .../ControllerPublic/CleanTalkRegister.php | 16 + .../ControllerPublic/CleanTalkThread.php | 16 + CleanTalk/Listener/LoadClassController.php | 34 + CleanTalk/Listener/LoadClassModel.php | 10 + CleanTalk/Model/CleanTalk.php | 349 +++++ README.md | 6 + README.txt | 52 + addon-CleanTalk.xml | 108 ++ 13 files changed, 2546 insertions(+) create mode 100644 CleanTalk/Base/CleanTalk.php create mode 100644 CleanTalk/Base/cleantalk.class.php create mode 100644 CleanTalk/ControllerPublic/CleanTalkForum.php create mode 100644 CleanTalk/ControllerPublic/CleanTalkMisc.php create mode 100644 CleanTalk/ControllerPublic/CleanTalkPost.php create mode 100644 CleanTalk/ControllerPublic/CleanTalkRegister.php create mode 100644 CleanTalk/ControllerPublic/CleanTalkThread.php create mode 100644 CleanTalk/Listener/LoadClassController.php create mode 100644 CleanTalk/Listener/LoadClassModel.php create mode 100644 CleanTalk/Model/CleanTalk.php create mode 100644 README.md create mode 100644 README.txt create mode 100644 addon-CleanTalk.xml diff --git a/CleanTalk/Base/CleanTalk.php b/CleanTalk/Base/CleanTalk.php new file mode 100644 index 0000000..1bad376 --- /dev/null +++ b/CleanTalk/Base/CleanTalk.php @@ -0,0 +1,441 @@ + ' + ALTER TABLE `xf_user` + ADD COLUMN `ct_check` VARCHAR(35) NULL AFTER `is_staff`;', + 'SlashUserTable' => ' + ALTER TABLE `xf_user` + DROP COLUMN `ct_check`;', + 'upgradeUserTable' =>' + SHOW COLUMNS FROM `xf_user` LIKE "ct_check";' + ); + + /* Insatll Hook */ + public static function installHook(){ + $db = XenForo_Application::get('db'); + if (count($db->fetchAll(self::$queries['upgradeUserTable'])) === 0) + $db->query(self::$queries['extendUserTable']); + } + + /* Unnistall Hook */ + public static function uninstallHook(){ + $db = XenForo_Application::get('db'); + $db->query(self::$queries['SlashUserTable']); + } + + public static function CheckUsersOutput($content, $params, $template){ + + $ret_val = ""; + + // If access key is unset + $options = XenForo_Application::getOptions(); + $api_key = $options->get('cleantalk', 'apikey'); + if(empty($api_key)) + $ret_val .= "

Acess key is empty.

"; + + /* Check button */ + $ret_val .= ' +
+
+ +
+
+
+
    + + +
+
+
+ + '; + + /* Showing all found spam users */ + $start_entry = '0'; + if(isset($_GET['start_entry']) && intval($_GET['start_entry'])) + $start_entry = strval(intval($_GET['start_entry'])); + + $on_page = '20'; + $end_entry = strval(intval($start_entry) + intval($on_page)); + + $db = XenForo_Application::get('db'); + + /*Count spam users */ + $spam_users_count = $db->fetchAll(" + SELECT + COUNT(user_id) AS cnt + FROM xf_user + WHERE ct_check = 'spam' + "); + $spam_users_count = $spam_users_count[0]['cnt']; + + /* Get spam users */ + $spam_users = $db->fetchAll(" + SELECT + user.user_id AS id, + user.username AS username, + user.register_date AS register, + user.last_activity AS activity, + user.email AS email, + user.message_count + FROM xf_user user + WHERE ct_check = 'spam' + LIMIT $start_entry, $end_entry; + "); + + if(count($spam_users)){ + $ret_val .= ""; + $ret_val .= " + + + + + + + + + + "; + + foreach($spam_users as $key => $value){ + $ret_val .= " + + + + + + + + + + + "; + }unset($key, $value); + + $ret_val .= '
IDUsernameEmailRegistredLast ActivityPosts
{$value['id']}{$value['username']}{$value['email']}".date('Y-m-d H:i:s', $value['register'])."".date('Y-m-d H:i:s', $value['activity'])."{$value['message_count']}

'; + + $pages = ceil(intval($spam_users_count) / $on_page); + + if($pages > 1){ + $ret_val .= ""; + } + + $ret_val .= ' +
+ + +
+

All user\'s post will be also deleted.

+
+ '; + + }else + $ret_val .= '

No spam-users were found.

'; + + return $ret_val; + + } + + static function CheckUsersCallback($settings, $abc){ + + $options = XenForo_Application::getOptions(); + + if(isset($_POST['cleantalk_check_spam_users']) && $_POST['cleantalk_check_spam_users']){ + + $db = XenForo_Application::get('db'); + + $result = $db->fetchAll(" + SELECT + DISTINCT(user.user_id) AS id, + user.email AS email, + ips.ip as ip + FROM xf_user user + INNER JOIN xf_ip ips + ON user.user_id = ips.user_id; + "); + + $users_data = array(); + $data_to_send = array(); + foreach($result as $key => $value){ + $ip = unpack("Nip", $value['ip']); + $ip = long2ip($ip['ip']); + //*$users_data[$value['id']] = array('email' => $value['email'], 'ip' => $value['ip']); + $users_data[$value['email']] = $value['id']; + $users_data[$ip] = $value['id']; + $data_to_send[] = $value['email']; + $data_to_send[] = $ip; + } + $data_to_send = implode(',',$data_to_send); + + /* Sending the request */ + $request = Array(); + $request['method_name'] = 'spam_check_cms'; + $request['auth_key'] = $options->get('cleantalk', 'apikey'); + $request['data'] = $data_to_send; + $url='https://api.cleantalk.org'; + + if(!function_exists('sendRawRequest')) + require_once('cleantalk.class.php'); + $result = sendRawRequest($url, $request, false, 5); + $result = json_decode($result, true); + + if(isset($result['error_message'])){ + error_log('CleanTalk plugin -> Check users -> Server returns error: '.$result['error_message']); + return true; + }else{ + $spam_users = array(); + $sql_append = ''; + foreach($result['data'] as $key => $value){ + if($value['appears'] == 1){ + if(array_key_exists($key, $users_data)){ + $spam_users[] = $users_data[$key]; + } + } + } + } + + if(count($spam_users)){ + $sql = " + UPDATE xf_user user + SET user.ct_check = 'spam' + WHERE user.user_id = ".$spam_users[0]; + + for($i=1; isset($spam_users[$i]); $i++) + $sql .= " OR user.user_id = ".$spam_users[$i]." "; + + $result = $db->query($sql); + } + } + + if(isset($_POST['cleantalk_delete_spam_users']) && $_POST['cleantalk_delete_spam_users']){ + + if(empty($_POST['users_for_deleting'])){ + return true; + } + + $users_for_deleting = $_POST['users_for_deleting']; + + $db = XenForo_Application::get('db'); + $sql = " + DELETE + FROM xf_user + WHERE user_id = ".$users_for_deleting[0]; + + for($i=1; isset($users_for_deleting[$i]); $i++) + $sql .= " OR user_id = ".$users_for_deleting[$i]." "; + + $result = $db->query($sql); + + $sql = " + DELETE + FROM xf_post + WHERE user_id = ".$users_for_deleting[0]; + + for($i=1; isset($users_for_deleting[$i]); $i++) + $sql .= " OR user_id = ".$users_for_deleting[$i]." "; + + $result = $db->query($sql); + } + + if(isset($_POST['cleantalk_delete_all_spam_users']) && $_POST['cleantalk_delete_all_spam_users']){ + + $db = XenForo_Application::get('db'); + $sql = " + DELETE + xf_user, + xf_post + FROM + xf_user, + xf_post + WHERE + xf_user.ct_check = 'spam' + AND + xf_user.user_id = xf_post.user_id"; + $result = $db->query($sql); + + $sql = " + DELETE + FROM xf_user + WHERE ct_check = 'spam'"; + $result = $db->query($sql); + + } + + return true; + + } + + public static function hookAdminSettings(XenForo_Visitor &$visitor ){ + + if ( + sizeof($_POST) > 0 && + isset($_POST['options']) && + isset($_POST['options']['cleantalk']) && + isset($_POST['options']['cleantalk']['apikey']) && + !empty($_POST['options']['cleantalk']['apikey']) + ) + { + require_once 'CleanTalk/Base/cleantalk.class.php'; + $ct_ws = array( + 'work_url' => 'http://moderate.cleantalk.org', + 'server_url' => 'http://moderate.cleantalk.org', + 'server_ttl' => 0, + 'server_changed' => 0 + ); + $ct = new Cleantalk(); + $ct->work_url = $ct_ws['work_url']; + $ct->server_url = $ct_ws['server_url']; + $ct->server_ttl = $ct_ws['server_ttl']; + $ct->server_changed = $ct_ws['server_changed']; + + $ct_request = new CleantalkRequest(); + $ct_request->auth_key = $_POST['options']['cleantalk']['apikey']; + $ct_request->feedback = '0:xenforo-24'; + $ct->sendFeedback($ct_request); + } + } + + /** Return Array of JS-keys for checking + * + * @return Array + */ + static public function getCheckJSArray() { + $options = XenForo_Application::getOptions(); + $result=Array(); + for($i=-5;$i<=1;$i++) { + $result[]=md5($options->get('cleantalk', 'apikey') . '+' . $options->get('contactEmailAddress') . date("Ymd",time()+86400*$i)); + } + return $result; + } + + static public function getCheckjsDefaultValue() { + return '0'; + } + + static public function getCheckjsValue() { + $options = XenForo_Application::getOptions(); + return md5($options->get('cleantalk', 'apikey') . '+' . $options->get('contactEmailAddress') . date("Ymd",time())); + } + + public static function getTemplateAddon() { + static $show_flag = TRUE; + $ret_val = ''; + $options = XenForo_Application::getOptions(); + + if ($show_flag) { + $show_flag = FALSE; + $field_name = self::getCheckjsName(); + $ct_check_def = self::getCheckjsValue(); + $ct_check_value = self::getCheckjsValue(); + $js_template = ''; + $ret_val = sprintf($js_template, $field_name, $ct_check_value); + if($options->get('cleantalk', 'link')) + { + $ret_val.="
XenForo spam blocked by CleanTalk.
"; + } + } +// XenForo_Application::getSession()->set('ct_submit_comment_time', time()); - got error 'The session has been saved and is now read-only' +// XenForo_Application::setSimpleCacheData('ct_submit_comment_time', time()); + return $ret_val; + } + +} diff --git a/CleanTalk/Base/cleantalk.class.php b/CleanTalk/Base/cleantalk.class.php new file mode 100644 index 0000000..37500d4 --- /dev/null +++ b/CleanTalk/Base/cleantalk.class.php @@ -0,0 +1,1263 @@ + $val) { + if( preg_match($rx_http, $key) ) { + $arh_key = preg_replace($rx_http, '', $key); + $rx_matches = array(); + // do some nasty string manipulations to restore the original letter case + // this should work in most cases + $rx_matches = explode('_', $arh_key); + if( count($rx_matches) > 0 and strlen($arh_key) > 2 ) { + foreach($rx_matches as $ak_key => $ak_val) $rx_matches[$ak_key] = ucfirst($ak_val); + $arh_key = implode('-', $rx_matches); + } + $arh[$arh_key] = $val; + } + } + return( $arh ); + } +} + +/** + * Response class + */ +class CleantalkResponse { + + /** + * Received feedback nubmer + * @var int + */ + public $received = null; + + /** + * Is stop words + * @var int + */ + public $stop_words = null; + + /** + * Cleantalk comment + * @var string + */ + public $comment = null; + + /** + * Is blacklisted + * @var int + */ + public $blacklisted = null; + + /** + * Is allow, 1|0 + * @var int + */ + public $allow = null; + + /** + * Request ID + * @var int + */ + public $id = null; + + /** + * Request errno + * @var int + */ + public $errno = null; + + /** + * Error string + * @var string + */ + public $errstr = null; + + /** + * Is fast submit, 1|0 + * @var string + */ + public $fast_submit = null; + + /** + * Is spam comment + * @var string + */ + public $spam = null; + + /** + * Is JS + * @var type + */ + public $js_disabled = null; + + /** + * Sms check + * @var type + */ + public $sms_allow = null; + + /** + * Sms code result + * @var type + */ + public $sms = null; + + /** + * Sms error code + * @var type + */ + public $sms_error_code = null; + + /** + * Sms error code + * @var type + */ + public $sms_error_text = null; + + /** + * Stop queue message, 1|0 + * @var int + */ + public $stop_queue = null; + + /** + * Account shuld by deactivated after registration, 1|0 + * @var int + */ + public $inactive = null; + + /** + * Account status + * @var int + */ + public $account_status = -1; + + /** + * Create server response + * + * @param type $response + * @param type $obj + */ + function __construct($response = null, $obj = null) { + if ($response && is_array($response) && count($response) > 0) { + foreach ($response as $param => $value) { + $this->{$param} = $value; + } + } else { + $this->errno = $obj->errno; + $this->errstr = $obj->errstr; + + $this->errstr = preg_replace("/.+(\*\*\*.+\*\*\*).+/", "$1", $this->errstr); + + $this->stop_words = isset($obj->stop_words) ? utf8_decode($obj->stop_words) : null; + $this->comment = isset($obj->comment) ? utf8_decode($obj->comment) : null; + $this->blacklisted = (isset($obj->blacklisted)) ? $obj->blacklisted : null; + $this->allow = (isset($obj->allow)) ? $obj->allow : 0; + $this->id = (isset($obj->id)) ? $obj->id : null; + $this->fast_submit = (isset($obj->fast_submit)) ? $obj->fast_submit : 0; + $this->spam = (isset($obj->spam)) ? $obj->spam : 0; + $this->js_disabled = (isset($obj->js_disabled)) ? $obj->js_disabled : 0; + $this->sms_allow = (isset($obj->sms_allow)) ? $obj->sms_allow : null; + $this->sms = (isset($obj->sms)) ? $obj->sms : null; + $this->sms_error_code = (isset($obj->sms_error_code)) ? $obj->sms_error_code : null; + $this->sms_error_text = (isset($obj->sms_error_text)) ? $obj->sms_error_text : null; + $this->stop_queue = (isset($obj->stop_queue)) ? $obj->stop_queue : 0; + $this->inactive = (isset($obj->inactive)) ? $obj->inactive : 0; + $this->account_status = (isset($obj->account_status)) ? $obj->account_status : -1; + $this->received = (isset($obj->received)) ? $obj->received : -1; + + if ($this->errno !== 0 && $this->errstr !== null && $this->comment === null) + $this->comment = '*** ' . $this->errstr . ' Antispam service cleantalk.org ***'; + } + } + +} + +/** + * Request class + */ +class CleantalkRequest { + + /** + * All http request headers + * @var string + */ + public $all_headers = null; + + /** + * IP address of connection + * @var string + */ + //public $remote_addr = null; + + /** + * Last error number + * @var integer + */ + public $last_error_no = null; + + /** + * Last error time + * @var integer + */ + public $last_error_time = null; + + /** + * Last error text + * @var string + */ + public $last_error_text = null; + + /** + * User message + * @var string + */ + public $message = null; + + /** + * Post example with last comments + * @var string + */ + public $example = null; + + /** + * Auth key + * @var string + */ + public $auth_key = null; + + /** + * Engine + * @var string + */ + public $agent = null; + + /** + * Is check for stoplist, + * valid are 0|1 + * @var int + */ + public $stoplist_check = null; + + /** + * Language server response, + * valid are 'en' or 'ru' + * @var string + */ + public $response_lang = null; + + /** + * User IP + * @var strings + */ + public $sender_ip = null; + + /** + * User email + * @var strings + */ + public $sender_email = null; + + /** + * User nickname + * @var string + */ + public $sender_nickname = null; + + /** + * Sender info JSON string + * @var string + */ + public $sender_info = null; + + /** + * Post info JSON string + * @var string + */ + public $post_info = null; + + /** + * Is allow links, email and icq, + * valid are 1|0 + * @var int + */ + public $allow_links = null; + + /** + * Time form filling + * @var int + */ + public $submit_time = null; + + public $x_forwarded_for = ''; + public $x_real_ip = ''; + + /** + * Is enable Java Script, + * valid are 0|1|2 + * Status: + * null - JS html code not inserted into phpBB templates + * 0 - JS disabled at the client browser + * 1 - JS enabled at the client broswer + * @var int + */ + public $js_on = null; + + /** + * user time zone + * @var string + */ + public $tz = null; + + /** + * Feedback string, + * valid are 'requset_id:(1|0)' + * @var string + */ + public $feedback = null; + + /** + * Phone number + * @var type + */ + public $phone = null; + + /** + * Method name + * @var string + */ + public $method_name = 'check_message'; + + /** + * Fill params with constructor + * @param type $params + */ + public function __construct($params = null) { + if (is_array($params) && count($params) > 0) { + foreach ($params as $param => $value) { + $this->{$param} = $value; + } + } + } + +} + +/** + * Cleantalk class create request + */ +class Cleantalk { + + /** + * Debug level + * @var int + */ + public $debug = 0; + + /** + * Maximum data size in bytes + * @var int + */ + private $dataMaxSise = 32768; + + /** + * Data compression rate + * @var int + */ + private $compressRate = 6; + + /** + * Server connection timeout in seconds + * @var int + */ + private $server_timeout = 15; + + /** + * Cleantalk server url + * @var string + */ + public $server_url = null; + + /** + * Last work url + * @var string + */ + public $work_url = null; + + /** + * WOrk url ttl + * @var int + */ + public $server_ttl = null; + + /** + * Time wotk_url changer + * @var int + */ + public $server_changed = null; + + /** + * Flag is change server url + * @var bool + */ + public $server_change = false; + + /** + * Use TRUE when need stay on server. Example: send feedback + * @var bool + */ + public $stay_on_server = false; + + /** + * Codepage of the data + * @var bool + */ + public $data_codepage = null; + + /** + * API version to use + * @var string + */ + public $api_version = '/api2.0'; + + /** + * Use https connection to servers + * @var bool + */ + public $ssl_on = false; + + /** + * Path to SSL certificate + * @var string + */ + public $ssl_path = ''; + + /** + * Minimal server response in miliseconds to catch the server + * + */ + public $min_server_timeout = 50; + + /** + * Function checks whether it is possible to publish the message + * @param CleantalkRequest $request + * @return type + */ + public function isAllowMessage(CleantalkRequest $request) { + $request = $this->filterRequest($request); + $msg = $this->createMsg('check_message', $request); + return $this->httpRequest($msg); + } + + /** + * Function checks whether it is possible to publish the message + * @param CleantalkRequest $request + * @return type + */ + public function isAllowUser(CleantalkRequest $request) { + $request = $this->filterRequest($request); + $msg = $this->createMsg('check_newuser', $request); + return $this->httpRequest($msg); + } + + /** + * Function sends the results of manual moderation + * + * @param CleantalkRequest $request + * @return type + */ + public function sendFeedback(CleantalkRequest $request) { + $request = $this->filterRequest($request); + $msg = $this->createMsg('send_feedback', $request); + return $this->httpRequest($msg); + } + + /** + * Filter request params + * @param CleantalkRequest $request + * @return type + */ + private function filterRequest(CleantalkRequest $request) { + // general and optional + foreach ($request as $param => $value) { + if (in_array($param, array('message', 'example', 'agent', + 'sender_info', 'sender_nickname', 'post_info', 'phone')) && !empty($value)) { + if (!is_string($value) && !is_integer($value)) { + $request->$param = NULL; + } + } + + if (in_array($param, array('stoplist_check', 'allow_links')) && !empty($value)) { + if (!in_array($value, array(1, 2))) { + $request->$param = NULL; + } + } + + if (in_array($param, array('js_on')) && !empty($value)) { + if (!is_integer($value)) { + $request->$param = NULL; + } + } + + if ($param == 'sender_ip' && !empty($value)) { + if (!is_string($value)) { + $request->$param = NULL; + } + } + + if ($param == 'sender_email' && !empty($value)) { + if (!is_string($value)) { + $request->$param = NULL; + } + } + + if ($param == 'submit_time' && !empty($value)) { + if (!is_int($value)) { + $request->$param = NULL; + } + } + } + return $request; + } + + /** + * Compress data and encode to base64 + * @param type string + * @return string + */ + private function compressData($data = null){ + + if (strlen($data) > $this->dataMaxSise && function_exists('gzencode') && function_exists('base64_encode')){ + + $localData = gzencode($data, $this->compressRate, FORCE_GZIP); + + if ($localData === false) + return $data; + + $localData = base64_encode($localData); + + if ($localData === false) + return $data; + + return $localData; + } + + return $data; + } + + /** + * Create msg for cleantalk server + * @param type $method + * @param CleantalkRequest $request + * @return \xmlrpcmsg + */ + private function createMsg($method, CleantalkRequest $request) { + switch ($method) { + case 'check_message': + // Convert strings to UTF8 + $request->message = $this->stringToUTF8($request->message, $this->data_codepage); + $request->example = $this->stringToUTF8($request->example, $this->data_codepage); + $request->sender_email = $this->stringToUTF8($request->sender_email, $this->data_codepage); + $request->sender_nickname = $this->stringToUTF8($request->sender_nickname, $this->data_codepage); + + $request->message = $this->compressData($request->message); + $request->example = $this->compressData($request->example); + break; + + case 'check_newuser': + // Convert strings to UTF8 + $request->sender_email = $this->stringToUTF8($request->sender_email, $this->data_codepage); + $request->sender_nickname = $this->stringToUTF8($request->sender_nickname, $this->data_codepage); + break; + + case 'send_feedback': + if (is_array($request->feedback)) { + $request->feedback = implode(';', $request->feedback); + } + break; + } + + $request->method_name = $method; + + // + // Removing non UTF8 characters from request, because non UTF8 or malformed characters break json_encode(). + // + foreach ($request as $param => $value) { + if (!preg_match('//u', $value)) { + $request->{$param} = 'Nulled. Not UTF8 encoded or malformed.'; + } + } + + return $request; + } + + /** + * Send JSON request to servers + * @param $msg + * @return boolean|\CleantalkResponse + */ + private function sendRequest($data = null, $url, $server_timeout = 3) { + // Convert to array + $data = (array)json_decode(json_encode($data), true); + + //Cleaning from 'null' values + $tmp_data = array(); + foreach($data as $key => $value){ + if($value !== null) + $tmp_data[$key] = $value; + } + $data = $tmp_data; + unset($key, $value, $tmp_data); + + // Convert to JSON + $data = json_encode($data); + + if (isset($this->api_version)) { + $url = $url . $this->api_version; + } + + // Switching to secure connection + if ($this->ssl_on && !preg_match("/^https:/", $url)) { + $url = preg_replace("/^(http)/i", "$1s", $url); + } + + $result = false; + $curl_error = null; + if(function_exists('curl_init')) { + $ch = curl_init(); + curl_setopt($ch, CURLOPT_URL, $url); + curl_setopt($ch, CURLOPT_TIMEOUT, $server_timeout); + curl_setopt($ch, CURLOPT_POST, 1); + curl_setopt($ch, CURLOPT_POSTFIELDS, $data); + // receive server response ... + curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); + // resolve 'Expect: 100-continue' issue + curl_setopt($ch, CURLOPT_HTTPHEADER, array('Expect:')); + // see http://stackoverflow.com/a/23322368 + curl_setopt($ch, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0); + + // Disabling CA cert verivication + // Disabling common name verification + if ($this->ssl_on && $this->ssl_path=='') { + curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); + curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false); + } + else if ($this->ssl_on && $this->ssl_path!='') { + curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, true); + curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, true); + curl_setopt($ch, CURLOPT_CAINFO, $this->ssl_path); + } + + $result = curl_exec($ch); + if (!$result) { + $curl_error = curl_error($ch); + } + + curl_close($ch); + } + + if (!$result) { + $allow_url_fopen = ini_get('allow_url_fopen'); + if (function_exists('file_get_contents') && isset($allow_url_fopen) && $allow_url_fopen == '1') { + $opts = array('http' => + array( + 'method' => 'POST', + 'header' => "Content-Type: text/html\r\n", + 'content' => $data, + 'timeout' => $server_timeout + ) + ); + + $context = stream_context_create($opts); + $result = @file_get_contents($url, false, $context); + } + } + + if (!$result || !cleantalk_is_JSON($result)) { + $response = null; + $response['errno'] = 1; + if ($curl_error) { + $response['errstr'] = sprintf("CURL error: '%s'", $curl_error); + } else { + $response['errstr'] = 'No CURL support compiled in'; + } + $response['errstr'] .= ' or disabled allow_url_fopen in php.ini.'; + $response = json_decode(json_encode($response)); + + return $response; + } + + $errstr = null; + $response = json_decode($result); + if ($result !== false && is_object($response)) { + $response->errno = 0; + $response->errstr = $errstr; + } else { + $errstr = 'Unknown response from ' . $url . '.' . ' ' . $result; + + $response = null; + $response['errno'] = 1; + $response['errstr'] = $errstr; + $response = json_decode(json_encode($response)); + } + + + return $response; + } + + /** + * httpRequest + * @param $msg + * @return boolean|\CleantalkResponse + */ + private function httpRequest($msg) { + $result = false; + + if($msg->method_name != 'send_feedback'){ + $ct_tmp = apache_request_headers(); + + if(isset($ct_tmp['Cookie'])) + $cookie_name = 'Cookie'; + elseif(isset($ct_tmp['cookie'])) + $cookie_name = 'cookie'; + else + $cookie_name = 'COOKIE'; + + $ct_tmp[$cookie_name] = preg_replace(array( + '/\s{0,1}ct_checkjs=[a-z0-9]*[;|$]{0,1}/', + '/\s{0,1}ct_timezone=.{0,1}\d{1,2}[;|$]/', + '/\s{0,1}ct_pointer_data=.*5D[;|$]{0,1}/', + '/;{0,1}\s{0,3}$/' + ), '', $ct_tmp[$cookie_name]); + $msg->all_headers=json_encode($ct_tmp); + } + + //$msg->remote_addr=$_SERVER['REMOTE_ADDR']; + //$msg->sender_info['remote_addr']=$_SERVER['REMOTE_ADDR']; + $si=(array)json_decode($msg->sender_info,true); + if(defined('IN_PHPBB')) + { + global $request; + if(method_exists($request,'server')) + { + $si['remote_addr']=$request->server('REMOTE_ADDR'); + $msg->x_forwarded_for=$request->server('X_FORWARDED_FOR'); + $msg->x_real_ip=$request->server('X_REAL_IP'); + } + } + else + { + $si['remote_addr']=$_SERVER['REMOTE_ADDR']; + $msg->x_forwarded_for=@$_SERVER['X_FORWARDED_FOR']; + $msg->x_real_ip=@$_SERVER['X_REAL_IP']; + } + $msg->sender_info=json_encode($si); + if (((isset($this->work_url) && $this->work_url !== '') && ($this->server_changed + $this->server_ttl > time())) + || $this->stay_on_server == true) { + + $url = (!empty($this->work_url)) ? $this->work_url : $this->server_url; + + $result = $this->sendRequest($msg, $url, $this->server_timeout); + } + + if (($result === false || $result->errno != 0) && $this->stay_on_server == false) { + // Split server url to parts + preg_match("@^(https?://)([^/:]+)(.*)@i", $this->server_url, $matches); + $url_prefix = ''; + if (isset($matches[1])) + $url_prefix = $matches[1]; + + $pool = null; + if (isset($matches[2])) + $pool = $matches[2]; + + $url_suffix = ''; + if (isset($matches[3])) + $url_suffix = $matches[3]; + + if ($url_prefix === '') + $url_prefix = 'http://'; + + if (empty($pool)) { + return false; + } else { + // Loop until find work server + foreach ($this->get_servers_ip($pool) as $server) { + if ($server['host'] === 'localhost' || $server['ip'] === null) { + $work_url = $server['host']; + } else { + $server_host = $server['ip']; + $work_url = $server_host; + } + $work_url = $url_prefix . $work_url; + if (isset($url_suffix)) + $work_url = $work_url . $url_suffix; + + $this->work_url = $work_url; + $this->server_ttl = $server['ttl']; + + $result = $this->sendRequest($msg, $this->work_url, $this->server_timeout); + + if ($result !== false && $result->errno === 0) { + $this->server_change = true; + break; + } + } + } + } + + $response = new CleantalkResponse(null, $result); + + if (!empty($this->data_codepage) && $this->data_codepage !== 'UTF-8') { + if (!empty($response->comment)) + $response->comment = $this->stringFromUTF8($response->comment, $this->data_codepage); + if (!empty($response->errstr)) + $response->errstr = $this->stringFromUTF8($response->errstr, $this->data_codepage); + if (!empty($response->sms_error_text)) + $response->sms_error_text = $this->stringFromUTF8($response->sms_error_text, $this->data_codepage); + } + + return $response; + } + + /** + * Function DNS request + * @param $host + * @return array + */ + public function get_servers_ip($host) { + $response = null; + if (!isset($host)) + return $response; + + if (function_exists('dns_get_record')) { + $records = dns_get_record($host, DNS_A); + + if ($records !== FALSE) { + foreach ($records as $server) { + $response[] = $server; + } + } + } + + if (count($response) == 0 && function_exists('gethostbynamel')) { + $records = gethostbynamel($host); + + if ($records !== FALSE) { + foreach ($records as $server) { + $response[] = array("ip" => $server, + "host" => $host, + "ttl" => $this->server_ttl + ); + } + } + } + + if (count($response) == 0) { + $response[] = array("ip" => null, + "host" => $host, + "ttl" => $this->server_ttl + ); + } else { + // $i - to resolve collisions with localhost + $i = 0; + $r_temp = null; + $fast_server_found = false; + foreach ($response as $server) { + + // Do not test servers because fast work server found + if ($fast_server_found) { + $ping = $this->min_server_timeout; + } else { + $ping = $this->httpPing($server['ip']); + $ping = $ping * 1000; + } + + // -1 server is down, skips not reachable server + if ($ping != -1) { + $r_temp[$ping + $i] = $server; + } + $i++; + + if ($ping < $this->min_server_timeout) { + $fast_server_found = true; + } + } + if (count($r_temp)){ + ksort($r_temp); + $response = $r_temp; + } + } + + return $response; + } + + /** + * Function to get the message hash from Cleantalk.ru comment + * @param $message + * @return null + */ + public function getCleantalkCommentHash($message) { + $matches = array(); + if (preg_match('/\n\n\*\*\*.+([a-z0-9]{32}).+\*\*\*$/', $message, $matches)) + return $matches[1]; + else if (preg_match('/\[\n]{0,1}\[\n]{0,1}\*\*\*.+([a-z0-9]{32}).+\*\*\*$/', $message, $matches)) + return $matches[1]; + + return NULL; + } + + /** + * Function adds to the post comment Cleantalk.ru + * @param $message + * @param $comment + * @return string + */ + public function addCleantalkComment($message, $comment) { + $comment = preg_match('/\*\*\*(.+)\*\*\*/', $comment, $matches) ? $comment : '*** ' . $comment . ' ***'; + return $message . "\n\n" . $comment; + } + + /** + * Function deletes the comment Cleantalk.ru + * @param $message + * @return mixed + */ + public function delCleantalkComment($message) { + $message = preg_replace('/\n\n\*\*\*.+\*\*\*$/', '', $message); + + // DLE sign cut + $message = preg_replace('/\*\*\*.+\*\*\*$/', '', $message); + + $message = preg_replace('/\[\n]{0,1}\[\n]{0,1}\*\*\*.+\*\*\*$/', '', $message); + + return $message; + } + + /** + * Get user IP behind proxy server + */ + public function ct_session_ip( $data_ip ) { + if (!$data_ip || !preg_match("/^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$/", $data_ip)) { + return $data_ip; + } + /*if (isset($_SERVER['HTTP_X_FORWARDED_FOR'])) { + + $forwarded_ip = explode(",", $_SERVER['HTTP_X_FORWARDED_FOR']); + + // Looking for first value in the list, it should be sender real IP address + if (!preg_match("/^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$/", $forwarded_ip[0])) { + return $data_ip; + } + + $private_src_ip = false; + $private_nets = array( + '10.0.0.0/8', + '127.0.0.0/8', + '176.16.0.0/12', + '192.168.0.0/16', + ); + + foreach ($private_nets as $v) { + + // Private IP found + if ($private_src_ip) { + continue; + } + + if ($this->net_match($v, $data_ip)) { + $private_src_ip = true; + } + } + if ($private_src_ip) { + // Taking first IP from the list HTTP_X_FORWARDED_FOR + $data_ip = $forwarded_ip[0]; + } + } + + return $data_ip;*/ + return cleantalk_get_real_ip(); + } + + /** + * From http://php.net/manual/en/function.ip2long.php#82397 + */ + public function net_match($CIDR,$IP) { + list ($net, $mask) = explode ('/', $CIDR); + return ( ip2long ($IP) & ~((1 << (32 - $mask)) - 1) ) == ip2long ($net); + } + + /** + * Function to check response time + * param string + * @return int + */ + function httpPing($host){ + + // Skip localhost ping cause it raise error at fsockopen. + // And return minimun value + if ($host == 'localhost') + return 0.001; + + $starttime = microtime(true); + $file = @fsockopen ($host, 80, $errno, $errstr, $this->server_timeout); + $stoptime = microtime(true); + $status = 0; + if (!$file) { + $status = -1; // Site is down + } else { + fclose($file); + $status = ($stoptime - $starttime); + $status = round($status, 4); + } + + return $status; + } + + /** + * Function convert string to UTF8 and removes non UTF8 characters + * param string + * param string + * @return string + */ + function stringToUTF8($str, $data_codepage = null){ + if (!preg_match('//u', $str) && function_exists('mb_detect_encoding') && function_exists('mb_convert_encoding')) { + + if ($data_codepage !== null) + return mb_convert_encoding($str, 'UTF-8', $data_codepage); + + $encoding = mb_detect_encoding($str); + if ($encoding) + return mb_convert_encoding($str, 'UTF-8', $encoding); + } + + return $str; + } + + /** + * Function convert string from UTF8 + * param string + * param string + * @return string + */ + function stringFromUTF8($str, $data_codepage = null){ + if (preg_match('//u', $str) && function_exists('mb_convert_encoding') && $data_codepage !== null) { + return mb_convert_encoding($str, $data_codepage, 'UTF-8'); + } + + return $str; + } + + /** + * Function gets information about spam active networks + * + * @param string api_key + * @return JSON/array + */ + public function get_2s_blacklists_db ($api_key) { + $request=Array(); + $request['method_name'] = '2s_blacklists_db'; + $request['auth_key'] = $api_key; + $url='https://api.cleantalk.org'; + $result=sendRawRequest($url,$request); + return $result; + } +} + +/** + * Function gets access key automatically + * + * @param string website admin email + * @param string website host + * @param string website platform + * @return type + */ + +if(!function_exists('getAutoKey')) +{ + function getAutoKey($email, $host, $platform) + { + $request=Array(); + $request['method_name'] = 'get_api_key'; + $request['email'] = $email; + $request['website'] = $host; + $request['platform'] = $platform; + $url='https://api.cleantalk.org'; + $result=sendRawRequest($url,$request); + return $result; + } +} + +/** + * Function gets information about renew notice + * + * @param string api_key + * @return type + */ + +function noticePaidTill($api_key) +{ + $request=Array(); + $request['method_name'] = 'notice_paid_till'; + $request['auth_key'] = $api_key; + $url='https://api.cleantalk.org'; + $result=sendRawRequest($url,$request); + return $result; +} + +/** + * Function sends raw request to API server + * + * @param string url of API server + * @param array data to send + * @param boolean is data have to be JSON encoded or not + * @param integer connect timeout + * @return type + */ + +function sendRawRequest($url,$data,$isJSON=false,$timeout=3) +{ + $result=null; + if(!$isJSON) + { + $data=http_build_query($data); + $data=str_replace("&", "&", $data); + } + else + { + $data= json_encode($data); + } + $curl_exec=false; + if (function_exists('curl_init') && function_exists('json_decode')) + { + + $ch = curl_init(); + curl_setopt($ch, CURLOPT_URL, $url); + curl_setopt($ch, CURLOPT_TIMEOUT, $timeout); + curl_setopt($ch, CURLOPT_POST, true); + curl_setopt($ch, CURLOPT_POSTFIELDS, $data); + + // receive server response ... + curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); + // resolve 'Expect: 100-continue' issue + curl_setopt($ch, CURLOPT_HTTPHEADER, array('Expect:')); + + curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); + curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false); + + $result = @curl_exec($ch); + if($result!==false) + { + $curl_exec=true; + } + @curl_close($ch); + } + if(!$curl_exec) + { + $opts = array( + 'http'=>array( + 'method' => "POST", + 'timeout'=> $timeout, + 'content' => $data + ) + ); + $context = stream_context_create($opts); + $result = @file_get_contents($url, 0, $context); + } + return $result; +} + +if( !function_exists('apache_request_headers') ) +{ + function apache_request_headers() + { + $arh = array(); + $rx_http = '/\AHTTP_/'; + if(defined('IN_PHPBB')) + { + global $request; + $request->enable_super_globals(); + } + foreach($_SERVER as $key => $val) + { + if( preg_match($rx_http, $key) ) + { + $arh_key = preg_replace($rx_http, '', $key); + $rx_matches = array(); + $rx_matches = explode('_', $arh_key); + if( count($rx_matches) > 0 and strlen($arh_key) > 2 ) + { + foreach($rx_matches as $ak_key => $ak_val) $rx_matches[$ak_key] = ucfirst($ak_val); + $arh_key = implode('-', $rx_matches); + } + $arh[$arh_key] = $val; + } + } + if(defined('IN_PHPBB')) + { + global $request; + $request->disable_super_globals(); + } + return( $arh ); + } +} + +function cleantalk_get_real_ip() +{ + if(defined('IN_PHPBB')) + { + global $request; + $request->enable_super_globals(); + } + if ( function_exists( 'apache_request_headers' ) ) + { + $headers = apache_request_headers(); + } + else + { + + $headers = $_SERVER; + } + if ( array_key_exists( 'X-Forwarded-For', $headers ) ) + { + $the_ip=explode(",", trim($headers['X-Forwarded-For'])); + $the_ip = trim($the_ip[0]); + } + elseif ( array_key_exists( 'HTTP_X_FORWARDED_FOR', $headers )) + { + $the_ip=explode(",", trim($headers['HTTP_X_FORWARDED_FOR'])); + $the_ip = trim($the_ip[0]); + } + else + { + $the_ip = filter_var( $_SERVER['REMOTE_ADDR'], FILTER_VALIDATE_IP, FILTER_FLAG_IPV4 ); + } + if(defined('IN_PHPBB')) + { + global $request; + $request->disable_super_globals(); + } + return $the_ip; +} + +function cleantalk_is_JSON($string) +{ + return ((is_string($string) && (is_object(json_decode($string)) || is_array(json_decode($string))))) ? true : false; +} diff --git a/CleanTalk/ControllerPublic/CleanTalkForum.php b/CleanTalk/ControllerPublic/CleanTalkForum.php new file mode 100644 index 0000000..679470c --- /dev/null +++ b/CleanTalk/ControllerPublic/CleanTalkForum.php @@ -0,0 +1,16 @@ +get('cleantalk', 'enabled_comm')) { + XenForo_Application::getSession()->set('ct_submit_comment_time', time()); + $field_name = CleanTalk_Base_CleanTalk::getCheckjsName(); + $ct_check = CleanTalk_Base_CleanTalk::getCheckjsValue(); + setcookie($field_name, $ct_check, 0, '/'); + } + return parent::actionCreateThread(); + } + +} diff --git a/CleanTalk/ControllerPublic/CleanTalkMisc.php b/CleanTalk/ControllerPublic/CleanTalkMisc.php new file mode 100644 index 0000000..157ada2 --- /dev/null +++ b/CleanTalk/ControllerPublic/CleanTalkMisc.php @@ -0,0 +1,219 @@ +get('cleantalk', 'enabled_comm')){ + + if ($options->contactUrl['type'] == 'custom') + return $this->responseRedirect( + XenForo_ControllerResponse_Redirect::RESOURCE_CANONICAL, + $options->contactUrl['custom'] + ); + else if (!$options->contactUrl['type']) + return $this->responseRedirect( + XenForo_ControllerResponse_Redirect::RESOURCE_CANONICAL, + XenForo_Link::buildPublicLink('index') + ); + + if ($this->_request->isPost()){ + + if (!XenForo_Captcha_Abstract::validateDefault($this->_input)) + return $this->responseCaptchaFailed(); + + $user = XenForo_Visitor::getInstance()->toArray(); + + if (!$user['user_id']){ + + $user['email'] = $this->_input->filterSingle('email', XenForo_Input::STRING); + + if (!XenForo_Helper_Email::isEmailValid($user['email'])) + return $this->responseError(new XenForo_Phrase('please_enter_valid_email')); + + } + + $input = $this->_input->filter(array( + 'subject' => XenForo_Input::STRING, + 'message' => XenForo_Input::STRING + )); + + if (!$user['username'] || !$input['subject'] || !$input['message']) + return $this->responseError(new XenForo_Phrase('please_complete_required_fields')); + + $this->assertNotFlooding('contact'); + + // CleanTalk Part + + + require_once 'CleanTalk/Base/cleantalk.class.php'; + + $options = XenForo_Application::getOptions(); + + $ct_authkey = $options->get('cleantalk', 'apikey'); + + $dataRegistryModel = $this->getModelFromCache('XenForo_Model_DataRegistry'); + $ct_ws = $dataRegistryModel->get('cleantalk_ws'); + if (!$ct_ws) { + $ct_ws = array( + 'work_url' => 'http://moderate.cleantalk.ru', + 'server_url' => 'http://moderate.cleantalk.ru', + 'server_ttl' => 0, + 'server_changed' => 0 + ); + } + + $field_name = CleanTalk_Base_CleanTalk::getCheckjsName(); + + if (!isset($_COOKIE[$field_name])) + $checkjs = NULL; + elseif (in_array($_COOKIE[$field_name], CleanTalk_Base_CleanTalk::getCheckJSArray())) + $checkjs = 1; + else + $checkjs = 0; + + $js_timezone = (isset($_COOKIE['ct_timezone']) ? $_COOKIE['ct_timezone'] : ''); + $first_key_timestamp = (isset($_COOKIE['ct_fkp_timestamp']) ? $_COOKIE['ct_fkp_timestamp'] : ''); + $pointer_data = (isset($_COOKIE['ct_pointer_data']) ? json_decode($_COOKIE['ct_pointer_data']) : ''); + $page_set_timestamp = (isset($_COOKIE['ct_ps_timestamp']) ? $_COOKIE['ct_ps_timestamp'] : 0); + + $refferrer = (!empty($_SERVER['HTTP_REFERER']) ? $_SERVER['HTTP_REFERER'] : null); + $user_agent = (!empty($_SERVER['HTTP_USER_AGENT']) ? $_SERVER['HTTP_USER_AGENT'] : null); + + $ct = new Cleantalk(); + $ct->work_url = $ct_ws['work_url']; + $ct->server_url = $ct_ws['server_url']; + $ct->server_ttl = $ct_ws['server_ttl']; + $ct->server_changed = $ct_ws['server_changed']; + + $options = XenForo_Application::getOptions(); + $ct_options=array( + 'enabled_reg' => $options->get('cleantalk', 'enabled_reg'), + 'enabled_comm' => $options->get('cleantalk', 'enabled_comm'), + 'apikey' => $options->get('cleantalk', 'apikey') + ); + + $sender_info = json_encode( + array( + 'cms_lang' => 'en', + 'REFFERRER' => $refferrer, + 'post_url' => $refferrer, + 'USER_AGENT' => $user_agent, + 'ct_options' => json_encode($ct_options), + 'js_timezone' => $js_timezone, + 'mouse_cursor_positions' => $pointer_data, + 'key_press_timestamp' => $first_key_timestamp, + 'page_set_timestamp' => $page_set_timestamp + ) + ); + + $ct_request = new CleantalkRequest(); + $ct_request->auth_key = $ct_authkey; + $ct_request->agent = 'xenforo-22'; + $ct_request->response_lang = 'en'; + $ct_request->js_on = $checkjs; + $ct_request->sender_info = $sender_info; + $ct_request->sender_email = $user['email']; + $ct_request->sender_nickname = $user['username']; + $ct_request->sender_ip = $ct->ct_session_ip($_SERVER['REMOTE_ADDR']); + + $ct_submit_time = NULL; + + $stored_time = XenForo_Application::getSession()->get('ct_submit_contact_time'); + if (!empty($stored_time)) + $ct_submit_time = time() - $stored_time; + + $timelabels_key = 'e_comm'; + + $ct_request->submit_time = $ct_submit_time; + $ct_request->message = $message = json_encode(array_merge( + array( + 'subject' => $input['subject']), + array( + 'message' => $input['message']) + )); + + // Additional info. + $post_info = ''; + $a_post_info['comment_type'] = 'comment'; + + // JSON format. + $post_info = json_encode($a_post_info); + + if ($post_info === FALSE) + $post_info = ''; + + $ct_request->post_info = $post_info; + + $ct_result = $ct->isAllowMessage($ct_request); + + $ret_val = array(); + $ret_val['ct_request_id'] = $ct_result->id; + + if ($ct->server_change) { + $dataRegistryModel->set('cleantalk_ws', array( + 'work_url' => $ct->work_url, + 'server_url' => $ct->server_url, + 'server_ttl' => $ct->server_ttl, + 'server_changed' => time() + )); + } + + + // First check errstr flag. + if (!empty($ct_result->errstr) || (!empty($ct_result->inactive) && $ct_result->inactive == 1)){ + // Cleantalk error so we go default way (no action at all). + // Just inform admin. + + if (!empty($ct_result->errstr)) + $ct_result->comment = $this->_filterResponse($ct_result->errstr); + + $send_flag = FALSE; + + $ct_time = $dataRegistryModel->get('cleantalk_' . $timelabels_key); + + if (!$ct_time) + $send_flag = TRUE; + elseif(time() - 900 > $ct_time[0])// 15 minutes. + $send_flag = TRUE; + + if ($send_flag) { + $dataRegistryModel->set('cleantalk_' . $timelabels_key, array(time())); + + $mail = XenForo_Mail::create('cleantalk_error', array( + 'plainText' => 1, + 'htmlText' => nl2br($ct_result->comment) + ) + ); + + $mail->send($options->get('contactEmailAddress')); + } + return parent::actionContact(); + } + + if ($ct_result->allow == 1) + return parent::actionContact(); + else + return $this->responseError(new XenForo_Phrase($ct_result->comment)); + + }else{ + XenForo_Application::getSession()->set('ct_submit_contact_time', time()); + return parent::actionContact(); + } + } + return parent::actionContact(); + } + + protected function _filterResponse($ct_response) { + + if (preg_match('//u', $ct_response)) + $err_str = preg_replace('/\*\*\*/iu', '', $ct_response); + else + $err_str = preg_replace('/\*\*\*/i', '', $ct_response); + + return $err_str; + } + +} diff --git a/CleanTalk/ControllerPublic/CleanTalkPost.php b/CleanTalk/ControllerPublic/CleanTalkPost.php new file mode 100644 index 0000000..992a98d --- /dev/null +++ b/CleanTalk/ControllerPublic/CleanTalkPost.php @@ -0,0 +1,16 @@ +get('cleantalk', 'enabled_comm')) { + XenForo_Application::getSession()->set('ct_submit_comment_time', time()); + $field_name = CleanTalk_Base_CleanTalk::getCheckjsName(); + $ct_check = CleanTalk_Base_CleanTalk::getCheckjsValue(); + setcookie($field_name, $ct_check, 0, '/'); + } + return parent::actionEdit(); + } + +} diff --git a/CleanTalk/ControllerPublic/CleanTalkRegister.php b/CleanTalk/ControllerPublic/CleanTalkRegister.php new file mode 100644 index 0000000..94dfb2f --- /dev/null +++ b/CleanTalk/ControllerPublic/CleanTalkRegister.php @@ -0,0 +1,16 @@ +get('cleantalk', 'enabled_reg')) { + XenForo_Application::getSession()->set('ct_submit_register_time', time()); + $field_name = CleanTalk_Base_CleanTalk::getCheckjsName(); + $ct_check = CleanTalk_Base_CleanTalk::getCheckjsValue(); + setcookie($field_name, $ct_check, 0, '/'); + } + return parent::_getRegisterFormResponse($fields, $errors); + } + +} diff --git a/CleanTalk/ControllerPublic/CleanTalkThread.php b/CleanTalk/ControllerPublic/CleanTalkThread.php new file mode 100644 index 0000000..c359517 --- /dev/null +++ b/CleanTalk/ControllerPublic/CleanTalkThread.php @@ -0,0 +1,16 @@ +get('cleantalk', 'enabled_comm')) { + XenForo_Application::getSession()->set('ct_submit_comment_time', time()); + $field_name = CleanTalk_Base_CleanTalk::getCheckjsName(); + $ct_check = CleanTalk_Base_CleanTalk::getCheckjsValue(); + setcookie($field_name, $ct_check, 0, '/'); + } + return parent::actionReply(); + } + +} diff --git a/CleanTalk/Listener/LoadClassController.php b/CleanTalk/Listener/LoadClassController.php new file mode 100644 index 0000000..295e242 --- /dev/null +++ b/CleanTalk/Listener/LoadClassController.php @@ -0,0 +1,34 @@ +_resultDetails)) + $this->_resultDetails = array(); + + $decisions[] = $this->_checkNewUser($user, $request); + + return $decisions; + } + + protected function _allowMessage($content, array $extraParams = array(), Zend_Controller_Request_Http $request) { + + $decisions = parent::_allowMessage($content, $extraParams, $request); + + if (!is_array($decisions)) + $decisions = array(self::RESULT_ALLOWED); + + if (!is_array($this->_resultDetails)) + $this->_resultDetails = array(); + + $decisions[] = $this->_checkMessage($content, $extraParams, $request); + + return $decisions; + } + + protected function _checkNewUser(array $user, Zend_Controller_Request_Http $request) { + + $decision = self::RESULT_ALLOWED; + + $options = XenForo_Application::getOptions(); + if ($options->get('cleantalk', 'enabled_reg')) { + + if(!is_array($this->_resultDetails)) + $this->_resultDetails = array(); + + $spam_check = array(); + $spam_check['type'] = 'register'; + $spam_check['sender_email'] = $user['email']; + $spam_check['sender_nickname'] = $user['username']; + $spam_check['timezone'] = $user['timezone']; + + $field_name = CleanTalk_Base_CleanTalk::getCheckjsName(); + + if (!isset($_COOKIE[$field_name])) + $checkjs = NULL; + elseif (in_array($_COOKIE[$field_name], CleanTalk_Base_CleanTalk::getCheckJSArray())) + $checkjs = 1; + else + $checkjs = 0; + + $spam_result = $this->_checkSpam($spam_check, $options); + if (isset($spam_result) + && is_array($spam_result) + && $spam_result['errno'] == 0 + && $spam_result['allow'] != 1 || + ($spam_result['errno'] !=0 && $checkjs != 1) + ) { + $decision = self::RESULT_DENIED; + $this->_resultDetails[] = array( + 'phrase' => 'cleantalk_response', + 'data' => array( + 'response' => $spam_result['ct_result_comment'] + ) + ); + } + + } + return $decision; + } + + protected function _checkMessage($content, array $extraParams = array(), Zend_Controller_Request_Http $request) { + $decision = self::RESULT_ALLOWED; + + $options = XenForo_Application::getOptions(); + if ($options->get('cleantalk', 'enabled_comm')) { + if(!is_array($this->_resultDetails)) + $this->_resultDetails = array(); + + $visitor = XenForo_Visitor::getInstance(); + + $spam_check = array(); + $spam_check['type'] = 'comment'; + $spam_check['sender_email'] = $visitor['email']; + $spam_check['sender_nickname'] = $visitor['username']; + $spam_check['message_body'] = $content; + + // $spam_check['sender_email'] = $user['email']; + // $spam_check['sender_nickname'] = $user['username']; + // $spam_check['timezone'] = $user['timezone']; + + $field_name = CleanTalk_Base_CleanTalk::getCheckjsName(); + + if (!isset($_COOKIE[$field_name])) + $checkjs = NULL; + elseif (in_array($_COOKIE[$field_name], CleanTalk_Base_CleanTalk::getCheckJSArray())) + $checkjs = 1; + else + $checkjs = 0; + + $spam_result = $this->_checkSpam($spam_check, $options); + if (isset($spam_result) + && is_array($spam_result) + && $spam_result['errno'] == 0 + && $spam_result['allow'] != 1 || + ($spam_result['errno'] !=0 && $checkjs != 1) + ) { + $decision = self::RESULT_DENIED; + $this->_resultDetails[] = array( + 'phrase' => 'cleantalk_response', + 'data' => array( + 'response' => $spam_result['ct_result_comment'] + ) + ); + } + + } + return $decision; + } + + protected function _checkSpam($spam_check, $options) { + + require_once 'CleanTalk/Base/cleantalk.class.php'; + + $ct_authkey = $options->get('cleantalk', 'apikey'); + + $dataRegistryModel = $this->getModelFromCache('XenForo_Model_DataRegistry'); + $ct_ws = $dataRegistryModel->get('cleantalk_ws'); + if (!$ct_ws) { + $ct_ws = array( + 'work_url' => 'http://moderate.cleantalk.ru', + 'server_url' => 'http://moderate.cleantalk.ru', + 'server_ttl' => 0, + 'server_changed' => 0 + ); + } + + $field_name = CleanTalk_Base_CleanTalk::getCheckjsName(); + + if (!isset($_COOKIE[$field_name])) + $checkjs = NULL; + elseif (in_array($_COOKIE[$field_name], CleanTalk_Base_CleanTalk::getCheckJSArray())) + $checkjs = 1; + else + $checkjs = 0; + + $js_timezone = (isset($_COOKIE['ct_timezone']) ? $_COOKIE['ct_timezone'] : ''); + $first_key_timestamp = (isset($_COOKIE['ct_fkp_timestamp']) ? $_COOKIE['ct_fkp_timestamp'] : ''); + $pointer_data = (isset($_COOKIE['ct_pointer_data']) ? json_decode($_COOKIE['ct_pointer_data']) : ''); + $page_set_timestamp = (isset($_COOKIE['ct_ps_timestamp']) ? $_COOKIE['ct_ps_timestamp'] : 0); + + $user_agent = ($_SERVER['HTTP_USER_AGENT'] ? $_SERVER['HTTP_USER_AGENT'] : null); + $refferrer = ($_SERVER['HTTP_REFERER'] ? $_SERVER['HTTP_REFERER'] : null); + + $ct = new Cleantalk(); + $ct->work_url = $ct_ws['work_url']; + $ct->server_url = $ct_ws['server_url']; + $ct->server_ttl = $ct_ws['server_ttl']; + $ct->server_changed = $ct_ws['server_changed']; + + $options = XenForo_Application::getOptions(); + $ct_options=array( + 'enabled_reg' => $options->get('cleantalk', 'enabled_reg'), + 'enabled_comm' => $options->get('cleantalk', 'enabled_comm'), + 'apikey' => $options->get('cleantalk', 'apikey') + ); + + $sender_info = json_encode( + array( + 'cms_lang' => 'en', + 'REFFERRER' => $refferrer, + 'post_url' => $refferrer, + 'USER_AGENT' => $user_agent, + 'ct_options' => json_encode($ct_options), + 'js_timezone' => $js_timezone, + 'mouse_cursor_positions' => $pointer_data, + 'key_press_timestamp' => $first_key_timestamp, + 'page_set_timestamp' => $page_set_timestamp + ) + ); + + $ct_request = new CleantalkRequest(); + $ct_request->auth_key = $ct_authkey; + $ct_request->agent = 'xenforo-24'; + $ct_request->response_lang = 'en'; + $ct_request->js_on = $checkjs; + $ct_request->sender_info = $sender_info; + $ct_request->sender_email = $spam_check['sender_email']; + $ct_request->sender_nickname = $spam_check['sender_nickname']; + $ct_request->sender_ip = $ct->ct_session_ip($_SERVER['REMOTE_ADDR']); + + $ct_submit_time = NULL; + // session_start(); + switch ($spam_check['type']) { + case 'comment': + $stored_time = XenForo_Application::getSession()->get('ct_submit_comment_time'); + // $stored_time = XenForo_Application::getSimpleCacheData('ct_submit_comment_time'); + + if (isset($stored_time)) + $ct_submit_time = time() - $stored_time; + + $timelabels_key = 'e_comm'; + + $ct_request->submit_time = $ct_submit_time; + $ct_request->message = $spam_check['message_body']; + + // $example = ''; + // $a_example = array(); + // $a_example['title'] = $spam_check['example_title']; + // $a_example['body'] = $spam_check['example_body']; + // $a_example['comments'] = $spam_check['example_comments']; + + // Additional info. + $post_info = ''; + $a_post_info['comment_type'] = 'comment'; + + // JSON format. + // $example = json_encode($a_example); + $post_info = json_encode($a_post_info); + + // Plain text format. + // if ($example === FALSE) { + // $example = ''; + // $example .= $a_example['title'] . " \n\n"; + // $example .= $a_example['body'] . " \n\n"; + // $example .= $a_example['comments']; + // } + + if ($post_info === FALSE) + $post_info = ''; + + // Example text + last N comments in json or plain text format. + // $ct_request->example = $example; + $ct_request->post_info = $post_info; + + $ct_result = $ct->isAllowMessage($ct_request); + break; + + case 'register': + $stored_time = XenForo_Application::getSession()->get('ct_submit_register_time'); + + if (isset($stored_time)) + $ct_submit_time = time() - $stored_time; + + $timelabels_key = 'e_reg'; + $ct_request->submit_time = $ct_submit_time; + $ct_request->tz = $spam_check['timezone']; + + $ct_result = $ct->isAllowUser($ct_request); + break; + + } + + $ret_val = array(); + $ret_val['ct_request_id'] = $ct_result->id; + + if ($ct->server_change) { + $dataRegistryModel->set('cleantalk_ws', array( + 'work_url' => $ct->work_url, + 'server_url' => $ct->server_url, + 'server_ttl' => $ct->server_ttl, + 'server_changed' => time() + )); + } + + + // First check errstr flag. + if (!empty($ct_result->errstr) || (!empty($ct_result->inactive) && $ct_result->inactive == 1)){ + // Cleantalk error so we go default way (no action at all). + $ret_val['errno'] = 1; + // Just inform admin. + //$err_title = $_SERVER['SERVER_NAME'] . ' - CleanTalk hook error'; + if (!empty($ct_result->errstr)) + $ret_val['errstr'] = $this->_filterResponse($ct_result->errstr); + else + $ret_val['errstr'] = $this->_filterResponse($ct_result->comment); + + $send_flag = FALSE; + + $ct_time = $dataRegistryModel->get('cleantalk_' . $timelabels_key); + + if (!$ct_time) + $send_flag = TRUE; + elseif(time() - 900 > $ct_time[0])// 15 minutes. + $send_flag = TRUE; + + if ($send_flag) { + $dataRegistryModel->set('cleantalk_' . $timelabels_key, array(time())); + + $mail = XenForo_Mail::create('cleantalk_error', array( + 'plainText' => $ret_val['errstr'], + 'htmlText' => nl2br($ret_val['errstr']) + ) + ); + + $mail->send($options->get('contactEmailAddress')); + } + return $ret_val; + } + + $ret_val['errno'] = 0; + if ($ct_result->allow == 1) { + // Not spammer. + $ret_val['allow'] = 1; + // Store request_id in globals to store it in DB later. + // _cleantalk_ct_result('set', $ct_result->id); + // Don't store 'ct_result_comment', means good comment. + }else{ + // Spammer. + $ret_val['allow'] = 0; + $ret_val['ct_result_comment'] = $this->_filterResponse($ct_result->comment); + + // Check stop_queue flag. + if ($spam_check['type'] == 'comment' && $ct_result->stop_queue == 0) { + // Spammer and stop_queue == 0 - to manual approvement. + $ret_val['stop_queue'] = 0; + + // Store request_id and comment in static to store them in DB later. + // Store 'ct_result_comment' - means bad comment. + // _cleantalk_ct_result('set', $ct_result->id, $ret_val['ct_result_comment']); + }else{ + // New user or Spammer and stop_queue == 1 - display form error message. + $ret_val['stop_queue'] = 1; + } + } + + return $ret_val; + + } + + protected function _filterResponse($ct_response) { + + if (preg_match('//u', $ct_response)) + $err_str = preg_replace('/\*\*\*/iu', '', $ct_response); + else + $err_str = preg_replace('/\*\*\*/i', '', $ct_response); + + // return filter_xss($err_str, array('a')); + return $err_str; + } + +} diff --git a/README.md b/README.md new file mode 100644 index 0000000..6826def --- /dev/null +++ b/README.md @@ -0,0 +1,6 @@ +xenforo-antispam +================ +Version 2.4 +================ + +XenForo anti-spam addon. diff --git a/README.txt b/README.txt new file mode 100644 index 0000000..eff873b --- /dev/null +++ b/README.txt @@ -0,0 +1,52 @@ +-- SUMMARY -- + +Antispam add-on by CleanTalk to protect XenForo sites from spam bots registration. + +Key features. +* No needs in CAPTCHA, etc. +* Invisible protection from spam bots registration. + +What CleanTalk is. + CleanTalk is a SaaS spam protection service for Web-sites. + CleanTalk uses protection methods which are invisible for site visitors. + Using CleanTalk eliminates needs in CAPTCHA, questions and answers, and other + methods of protection, complicating the exchange of information on the site. + +How it works. + Registration requests are sent to the CleanTalk cloud, data is + tested with several methods on the cloud, then the site receives a response + decision to approve or deny the registration. + + +-- INSTALLATION -- + +1. Unpack zip-archive. +2. Upload "CleanTalk" folder to /library/ directory. +3. Install "addon-CleanTalk.xml". +4. Get access key on https://cleantalk.org. +5. Put your access key into CleanTalk add-on settings at + Options -> Spam Management -> Antispam by CleanTalk -> Access key + + +-- TESTING -- + +* Try to register account with "stop_email@example.com" as email address. + + +-- NOTE -- + +* You can disable CAPTCHA and other filters on registration page. +* You can see details in Spam Trigger Log. + + +-- COMPATIBILITY -- + +Tested with XenForo 1.3.3. + + +-- CONTACT -- + +Feel free to contact us at https://cleantalk.org/contacts + +Current maintainers: +* Alexey Znaev - znaev@cleantalk.org diff --git a/addon-CleanTalk.xml b/addon-CleanTalk.xml new file mode 100644 index 0000000..f34b403 --- /dev/null +++ b/addon-CleanTalk.xml @@ -0,0 +1,108 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + here to get access key.]]> + + + + + + + + + + + + Use this feature carefully, it can't be rolled back! +May cause high load of the webserver.]]> + + + + + + + + + + + +]]> + + + + +