Merge branch 'rhymix:master' into develop

This commit is contained in:
Lastorder 2024-11-22 09:24:12 +09:00 committed by GitHub
commit 6e84829da4
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
80 changed files with 656 additions and 440 deletions

View file

@ -17,11 +17,15 @@
<action name="procSpamfilterAdminInsertConfigCaptcha" type="controller" />
</actions>
<eventHandlers>
<eventHandler before="document.manage" class="controller" method="triggerManageDocument" />
<eventHandler before="document.insertDocument" class="controller" method="triggerInsertDocument" />
<eventHandler before="document.updateDocument" class="controller" method="triggerInsertDocument" />
<eventHandler before="document.manage" class="controller" method="triggerManageDocument" />
<eventHandler before="document.updateVotedCount" class="controller" method="triggerVote" />
<eventHandler before="document.declaredDocument" class="controller" method="triggerDeclare" />
<eventHandler before="comment.insertComment" class="controller" method="triggerInsertComment" />
<eventHandler before="comment.updateComment" class="controller" method="triggerInsertComment" />
<eventHandler before="comment.updateVotedCount" class="controller" method="triggerVote" />
<eventHandler before="comment.declaredComment" class="controller" method="triggerDeclare" />
<eventHandler before="communication.sendMessage" class="controller" method="triggerSendMessage" />
<eventHandler before="moduleObject.proc" class="controller" method="triggerCheckCaptcha" />
</eventHandlers>

View file

@ -14,10 +14,11 @@ $lang->word = 'Keyword';
$lang->hit = 'Hit';
$lang->latest_hit = 'Latest Hits';
$lang->custom_message = 'Error Message';
$lang->enable_description = 'Enter # as description';
$lang->about_custom_message = 'You can customize the error message that will be displayed if a spam keyword is found.<br>%s can be used as a placeholder for the keyword. If not used, the keyword will be hidden.';
$lang->about_interval = 'All articles attempted for posting within the assigned time will be blocked.';
$lang->about_denied_ip = 'Please enter one IP address (e.g. 127.0.0.1) or range (e.g. 127.0.0.0/24) per line. Comments may start with // or #.';
$lang->about_denied_word = 'Please enter one keyword (2 to 180 characters) per line. Comments may start with #.<br>Formats such as /spam(key|word)?/ will be treated as a regular expression, and must use the proper syntax.<br>Spam keywords are not case sensitive.';
$lang->about_denied_word = 'Please enter one keyword (2 to 180 characters) per line. Comments start with #. If you need to block a keyword that includes #, disable the checkbox above.<br>Formats such as /spam(key|word)?/ will be treated as a regular expression, and must use the proper syntax.<br>Spam keywords are not case sensitive.';
$lang->msg_alert_limited_by_config = 'Please do not post repeatedly within %d seconds. If you keep trying, your IP address will be blocked.';
$lang->msg_alert_limited_message_by_config = 'Please do not send messages repeatedly within %d seconds. If you keep trying, your IP address will be blocked.';
$lang->msg_alert_denied_word = 'The word "%s" is not allowed on this site.';
@ -27,7 +28,9 @@ $lang->cmd_spamfilter_except_member = 'Except Members';
$lang->cmd_spamfilter_filter_html = 'HTML';
$lang->cmd_spamfilter_is_regexp = 'REGEXP';
$lang->cmd_interval = 'Block Post/Comment Spam';
$lang->cmd_interval_help = 'Block IP addresses that post or comment too much in a short time. Blocked IP addresses will not be able to post, comment, or send messages.';
$lang->cmd_interval_help = 'Block IP addresses that post or comment too much in a short time.';
$lang->cmd_blocked_actions = 'Blocked actions';
$lang->cmd_blocked_actions_help = 'The actions above will be disabled from blocked IP addresses.';
$lang->cmd_check_trackback = 'Block Trackback Spam';
$lang->cmd_check_trackback_help = 'Block IP addresses that send multiple trackbacks to the same document.<br>This only works if the trackback module is installed.';
$lang->cmd_limits_interval = 'Block Interval';

View file

@ -14,10 +14,11 @@ $lang->word = '키워드';
$lang->hit = '히트';
$lang->latest_hit = '최근 히트';
$lang->custom_message = '차단 메시지 설정';
$lang->enable_description = '# 뒷부분은 설명으로 입력';
$lang->about_custom_message = '스팸 키워드 발견시 표시할 에러 메시지를 지정할 수 있습니다.<br>%s를 넣으면 그 자리에 해당 키워드를 표시하고, 그렇지 않으면 키워드를 숨깁니다.';
$lang->about_interval = '지정된 시간 내에 글을 등록하지 못하게 합니다.';
$lang->about_denied_ip = '한 줄에 하나씩 IP 주소 또는 대역을 입력하세요. &quot;//&quot; 또는 &quot;#&quot; 뒷부분은 설명으로 저장됩니다.<br>예: 127.0.0.1 // 설명, 127.0.0.1 #설명<br>IP 대역 표기법은 <a href="https://github.com/rhymix/rhymix-docs/blob/master/ko/misc/ipfilter.md" target="_blank">매뉴얼</a>을 참고하십시오.';
$lang->about_denied_word = '한 줄에 하나씩 스팸 키워드(2~180자)를 입력하세요. &quot;#&quot; 뒷부분은 설명으로 입력됩니다.<br>/스팸(키+|워드)?/ 와 같은 형태로 입력하면 정규식으로 간주하며, 올바른 정규식 문법을 사용해야 합니다.<br>대소문자는 구분하지 않습니다.';
$lang->about_denied_word = '한 줄에 하나씩 스팸 키워드(2~180자)를 입력하세요. &quot;#&quot; 뒷부분은 설명으로 입력됩니다. &quot;#&quot;을 포함하는 키워드를 차단하려면 위의 설정을 해제하세요.<br>/스팸(키+|워드)?/ 와 같은 형태로 입력하면 정규식으로 간주하며, 올바른 정규식 문법을 사용해야 합니다.<br>대소문자는 구분하지 않습니다.';
$lang->msg_alert_limited_by_config = '%d초 이내에 연속 글 작성은 금지됩니다. 계속 시도하면 IP가 차단될 수 있습니다.';
$lang->msg_alert_limited_message_by_config = '%d초 이내에 연속 쪽지 발송은 금지됩니다. 계속 시도하면 IP가 차단될 수 있습니다.';
$lang->msg_alert_denied_word = '"%s"은(는) 사용이 금지된 단어입니다.';
@ -26,8 +27,10 @@ $lang->msg_alert_trackback_denied = '한 글에는 하나의 트랙백만 허용
$lang->cmd_spamfilter_except_member = '회원 제외';
$lang->cmd_spamfilter_filter_html = 'HTML';
$lang->cmd_spamfilter_is_regexp = '정규식';
$lang->cmd_interval = '글, 댓글 스팸 차단';
$lang->cmd_interval_help = '지정한 시간 내에 다수의 글이나 댓글을 작성하면 스패머로 간주하고 글, 댓글 작성과 엮인글 발송, 쪽지 발송을 차단합니다.';
$lang->cmd_interval = '단시간 다수 작성 차단';
$lang->cmd_interval_help = '지정한 시간 내에 다수의 글이나 댓글을 작성하면 스패머로 간주하고 IP를 차단합니다.';
$lang->cmd_blocked_actions = '차단할 행동';
$lang->cmd_blocked_actions_help = '차단된 IP에서는 위의 행동들을 할 수 없게 됩니다.';
$lang->cmd_check_trackback = '트랙백 스팸 차단';
$lang->cmd_check_trackback_help = '하나의 글에 2회 이상 엮인글을 등록하면 스패머로 간주하고 엮인글을 차단합니다.<br>트랙백 모듈이 설치되어 있는 경우에만 적용됩니다.';
$lang->cmd_limits_interval = '글, 댓글 제한 시간';

View file

@ -20,7 +20,7 @@ class SpamfilterAdminController extends Spamfilter
$config = ModuleModel::getModuleConfig('spamfilter') ?: new stdClass;
// Get the default information
$args = Context::gets('limits', 'limits_interval', 'limits_count', 'ipv4_block_range', 'ipv6_block_range', 'except_ip', 'custom_message');
$args = Context::gets('limits', 'limits_interval', 'limits_count', 'blocked_actions', 'ipv4_block_range', 'ipv6_block_range', 'except_ip', 'custom_message');
// Set default values
if($args->limits != 'Y')
@ -38,6 +38,7 @@ class SpamfilterAdminController extends Spamfilter
$args->except_ip = array_map('trim', preg_split('/[\n,]/', trim($args->except_ip ?? ''), -1, \PREG_SPLIT_NO_EMPTY));
$args->limits_interval = intval($args->limits_interval);
$args->limits_count = intval($args->limits_count);
$args->blocked_actions = array_values($args->blocked_actions ?? []);
$args->custom_message = escape(utf8_trim($args->custom_message));
foreach ($args as $key => $val)
{
@ -177,9 +178,10 @@ class SpamfilterAdminController extends Spamfilter
{
//스팸 키워드 추가
$word_list = Context::get('word_list');
$enable_description = Context::get('enable_description') ?? 'N';
if($word_list)
{
$output = $this->insertWord($word_list);
$output = $this->insertWord($word_list, $enable_description);
if(!$output->toBool() && !$output->get('fail_list')) return $output;
if($output->get('fail_list')) $message_fail = '<em>'.sprintf(lang('msg_faillist'),$output->get('fail_list')).'</em>';
@ -258,7 +260,7 @@ class SpamfilterAdminController extends Spamfilter
* @brief Register the spam word
* The post, which contains the newly registered spam word, should be considered as a spam
*/
public function insertWord($word_list)
public function insertWord($word_list, $enable_description = 'Y')
{
if (!is_array($word_list))
{
@ -273,7 +275,7 @@ class SpamfilterAdminController extends Spamfilter
{
continue;
}
if (preg_match('/^(.+?)#(.+)$/', $word, $matches))
if ($enable_description === 'Y' && preg_match('/^(.+?)#(.+)$/', $word, $matches))
{
$word = trim($matches[1]);
$description = trim($matches[2]);

View file

@ -50,10 +50,17 @@ class SpamfilterController extends Spamfilter
if($grant->manager) return;
}
$oFilterModel = getModel('spamfilter');
// Check if the IP is prohibited
$output = $oFilterModel->isDeniedIP();
if(!$output->toBool()) return $output;
$output = SpamfilterModel::isDeniedIP();
if(!$output->toBool())
{
$config = SpamfilterModel::getConfig();
if (!isset($config->blocked_actions) || in_array('document', $config->blocked_actions))
{
return $output;
}
}
// Check if there is a ban on the word
$filter_targets = [$obj->title, $obj->content, $obj->tags ?? ''];
if(!$is_logged)
@ -71,7 +78,7 @@ class SpamfilterController extends Spamfilter
}
}
}
$output = $oFilterModel->isDeniedWord(implode("\n", $filter_targets));
$output = SpamfilterModel::isDeniedWord(implode("\n", $filter_targets));
if(!$output->toBool())
{
return $output;
@ -79,7 +86,7 @@ class SpamfilterController extends Spamfilter
// Check the specified time beside the modificaiton time
if($obj->document_srl == 0)
{
$output = $oFilterModel->checkLimited();
$output = SpamfilterModel::checkLimited();
if(!$output->toBool()) return $output;
}
// Save a log
@ -103,10 +110,17 @@ class SpamfilterController extends Spamfilter
if($grant->manager) return;
}
$oFilterModel = getModel('spamfilter');
// Check if the IP is prohibited
$output = $oFilterModel->isDeniedIP();
if(!$output->toBool()) return $output;
$output = SpamfilterModel::isDeniedIP();
if(!$output->toBool())
{
$config = SpamfilterModel::getConfig();
if (!isset($config->blocked_actions) || in_array('comment', $config->blocked_actions))
{
return $output;
}
}
// Check if there is a ban on the word
if($is_logged)
{
@ -116,12 +130,12 @@ class SpamfilterController extends Spamfilter
{
$text = $obj->content . ' ' . $obj->nick_name . ' ' . $obj->homepage;
}
$output = $oFilterModel->isDeniedWord($text);
$output = SpamfilterModel::isDeniedWord($text);
if(!$output->toBool()) return $output;
// If the specified time check is not modified
if(!$obj->__isupdate)
{
$output = $oFilterModel->checkLimited();
$output = SpamfilterModel::checkLimited();
if(!$output->toBool()) return $output;
}
unset($obj->__isupdate);
@ -182,31 +196,101 @@ class SpamfilterController extends Spamfilter
return $output;
}
/**
* Block voting from a spam IP.
*/
function triggerVote(&$obj)
{
if (!empty($_SESSION['avoid_log']))
{
return;
}
if ($this->user->isAdmin() || (Context::get('grant')->manager ?? false))
{
return;
}
$config = SpamfilterModel::getConfig();
if ($obj->point > 0 && isset($config->blocked_actions) && !in_array('vote_up', $config->blocked_actions))
{
return;
}
if ($obj->point < 0 && isset($config->blocked_actions) && !in_array('vote_down', $config->blocked_actions))
{
return;
}
$output = SpamfilterModel::isDeniedIP();
if (!$output->toBool())
{
return $output;
}
}
/**
* Block reporting from a spam IP.
*/
function triggerDeclare(&$obj)
{
if (!empty($_SESSION['avoid_log']))
{
return;
}
if ($this->user->isAdmin() || (Context::get('grant')->manager ?? false))
{
return;
}
$config = SpamfilterModel::getConfig();
if (isset($config->blocked_actions) && !in_array('declare', $config->blocked_actions))
{
return;
}
$output = SpamfilterModel::isDeniedIP();
if (!$output->toBool())
{
return $output;
}
}
/**
* @brief The routine process to check the time it takes to store a message, when writing it, and to ban IP/word
*/
function triggerSendMessage(&$obj)
{
if($_SESSION['avoid_log']) return;
if($this->user->isAdmin() || !empty($_SESSION['avoid_log']))
{
return;
}
if(isset($obj->use_spamfilter) && $obj->use_spamfilter === false)
{
return;
}
$logged_info = Context::get('logged_info');
if($logged_info->is_admin == 'Y') return;
$oFilterModel = getModel('spamfilter');
// Check if the IP is prohibited
$output = $oFilterModel->isDeniedIP();
if(!$output->toBool()) return $output;
$output = SpamfilterModel::isDeniedIP();
if(!$output->toBool())
{
$config = SpamfilterModel::getConfig();
if (!isset($config->blocked_actions) || in_array('message', $config->blocked_actions))
{
return $output;
}
}
// Check if there is a ban on the word
$text = $obj->title . ' ' . $obj->content;
$output = $oFilterModel->isDeniedWord($text);
$output = SpamfilterModel::isDeniedWord($text);
if(!$output->toBool()) return $output;
// Check the specified time
$output = $oFilterModel->checkLimited(TRUE);
$output = SpamfilterModel::checkLimited(TRUE);
if(!$output->toBool()) return $output;
// Save a log
$this->insertLog();
}

View file

@ -7,17 +7,10 @@
*/
class SpamfilterModel extends Spamfilter
{
/**
* @brief Initialization
*/
function init()
{
}
/**
* @brief Return the user setting values of the Spam filter module
*/
function getConfig()
public static function getConfig()
{
return ModuleModel::getModuleConfig('spamfilter') ?: new stdClass;
}
@ -25,7 +18,7 @@ class SpamfilterModel extends Spamfilter
/**
* @brief Return the list of registered IP addresses which were banned
*/
function getDeniedIPList($sort_index = 'regdate')
public static function getDeniedIPList($sort_index = 'regdate')
{
$args = new stdClass();
$args->sort_index = $sort_index;
@ -38,12 +31,12 @@ class SpamfilterModel extends Spamfilter
/**
* @brief Check if the ipaddress is in the list of banned IP addresses
*/
function isDeniedIP()
public static function isDeniedIP()
{
$ip_list = Rhymix\Framework\Cache::get('spamfilter:denied_ip_list');
if ($ip_list === null)
{
$ip_list = $this->getDeniedIPList();
$ip_list = self::getDeniedIPList();
Rhymix\Framework\Cache::set('spamfilter:denied_ip_list', $ip_list);
}
if (!count($ip_list))
@ -75,7 +68,7 @@ class SpamfilterModel extends Spamfilter
/**
* @brief Return the list of registered Words which were banned
*/
function getDeniedWordList($sort_index = 'hit')
public static function getDeniedWordList($sort_index = 'hit')
{
$args = new stdClass();
$args->sort_index = $sort_index;
@ -86,12 +79,12 @@ class SpamfilterModel extends Spamfilter
/**
* @brief Check if the text, received as a parameter, is banned or not
*/
function isDeniedWord($text)
public static function isDeniedWord($text)
{
$word_list = Rhymix\Framework\Cache::get('spamfilter:denied_word_list');
if ($word_list === null)
{
$word_list = $this->getDeniedWordList();
$word_list = self::getDeniedWordList();
Rhymix\Framework\Cache::set('spamfilter:denied_word_list', $word_list);
}
if (!count($word_list))
@ -128,7 +121,7 @@ class SpamfilterModel extends Spamfilter
$args->word = $word;
executeQuery('spamfilter.updateDeniedWordHit', $args);
$config = $this->getConfig();
$config = self::getConfig();
if($config->custom_message)
{
@ -161,9 +154,9 @@ class SpamfilterModel extends Spamfilter
/**
* @brief Check the specified time
*/
function checkLimited($isMessage = FALSE)
public static function checkLimited($isMessage = FALSE)
{
$config = $this->getConfig();
$config = self::getConfig();
if($config->limits != 'Y') return new BaseObject();
$limit_count = $config->limits_count ?: 3;
@ -177,7 +170,7 @@ class SpamfilterModel extends Spamfilter
}
}
$count = $this->getLogCount($interval);
$count = self::getLogCount($interval);
// Ban the IP address if the interval is exceeded
if($count>=$limit_count)
@ -272,7 +265,7 @@ class SpamfilterModel extends Spamfilter
/**
* @brief Check if the trackbacks have already been registered to a particular article
*/
function isInsertedTrackback($document_srl)
public static function isInsertedTrackback($document_srl)
{
$oTrackbackModel = getModel('trackback');
if (is_object($oTrackbackModel) && method_exists($oTrackbackModel, 'getTrackbackCountByIPAddress'))
@ -289,7 +282,7 @@ class SpamfilterModel extends Spamfilter
/**
* @brief Return the number of logs recorded within the interval for the specified IPaddress
*/
function getLogCount($time = 60, $ipaddress='')
public static function getLogCount($time = 60, $ipaddress='')
{
if(!$ipaddress) $ipaddress = \RX_CLIENT_IP;

View file

@ -27,6 +27,36 @@
<p class="x_help-block">{$lang->cmd_interval_help}</p>
</div>
</div>
<div class="x_control-group">
<label class="x_control-label">{$lang->cmd_blocked_actions}</label>
<div class="x_controls">
<label class="x_inline">
<input type="checkbox" name="blocked_actions[]" value="document" checked="checked"|cond="!$config->blocked_actions || in_array('document', $config->blocked_actions)" />
{$lang->document}
</label>
<label class="x_inline">
<input type="checkbox" name="blocked_actions[]" value="comment" checked="checked"|cond="!$config->blocked_actions || in_array('comment', $config->blocked_actions)" />
{$lang->comment}
</label>
<label class="x_inline">
<input type="checkbox" name="blocked_actions[]" value="vote_up" checked="checked"|cond="!$config->blocked_actions || in_array('vote_up', $config->blocked_actions)" />
{$lang->cmd_vote}
</label>
<label class="x_inline">
<input type="checkbox" name="blocked_actions[]" value="vote_down" checked="checked"|cond="!$config->blocked_actions || in_array('vote_down', $config->blocked_actions)" />
{$lang->cmd_vote_down}
</label>
<label class="x_inline">
<input type="checkbox" name="blocked_actions[]" value="declare" checked="checked"|cond="!$config->blocked_actions || in_array('declare', $config->blocked_actions)" />
{$lang->cmd_declare}
</label>
<label class="x_inline">
<input type="checkbox" name="blocked_actions[]" value="message" checked="checked"|cond="!$config->blocked_actions || in_array('message', $config->blocked_actions)" />
{$lang->member_message}
</label>
<p class="x_help-block">{$lang->cmd_blocked_actions_help}</p>
</div>
</div>
<div class="x_control-group">
<label class="x_control-label" for="custom_message">{$lang->custom_message}</label>
<div class="x_controls">

View file

@ -44,6 +44,7 @@
<input type="hidden" name="active" value="word" />
<input type="hidden" name="xe_validator_id" value="modules/spamfilter/tpl/1" />
<textarea name="word_list" title="{$lang->add_denied_word}" rows="4" cols="42" style="width:100%"></textarea>
<label><input type="checkbox" name="enable_description" value="Y" checked="checked" /> {$lang->enable_description}</label>
<p class="x_help-block">{$lang->about_denied_word}</p>
<span class="x_pull-right" style="margin-right:-14px">
<button type="submit" class="x_btn x_btn-primary">{$lang->add_denied_word}</button>