add a linebreak and fix some whitespaces

This commit is contained in:
Ian 2015-09-03 11:43:49 +02:00
parent bec25c8f5f
commit d6166ffaa7
5 changed files with 218 additions and 207 deletions

View file

@ -1,3 +1,9 @@
Version 1.2.9
* add a linebreak
Version 1.2.8
* Size honepot form field in case it is actually shown
Version 1.2.7
* Made it work more nice with the contactform plugin

View file

@ -7,22 +7,22 @@
var url = typeof loadData.url != 'undefined' ? loadData.url : null;
var answer = typeof loadData.answer != 'undefined' ? loadData.answer : null;
var scrambleKey = typeof loadData.scrambleKey != 'undefined' ? loadData.scrambleKey : null;
this.attachToLoadEvent = function() {
var handlerCalled = false;
var eventHandler = function() {
// Since we use multiple handlers, only run this function once
if (handlerCalled) return;
handlerCalled = true;
that.initCaptcha();
// We don't need any additional load events anymore
if (document.addEventListener) {
document.removeEventListener('load', eventHandler, true);
}
}
if (document.addEventListener) {
// Use DOMContentLoaded for modern browsers, load for older ones
document.addEventListener('DOMContentLoaded', eventHandler, true);
@ -39,35 +39,35 @@
}
}
}
this.initCaptcha = function() {
if (null === inputCaptcha) {
return;
}
if ('default' == method && null !== answer) {
fillCaptcha(answer, scrambleKey)
} else if ('json' == method && null !== url) {
fetchJsonData();
}
}
this.hideBeeElement = function() {
var elementClass = divCaptcha.className;
if (null === elementClass.match(/\bspambeehidden\b/)) {
divCaptcha.className = elementClass + ' spambeehidden';
}
}
function fillCaptcha(answer, scrambleKey) {
if (typeof scrambleKey != 'undefined' && null !== scrambleKey) {
answer = xorDescramble(decodeUtf8(unescape(answer)), scrambleKey);
}
inputCaptcha.value = answer;
that.hideBeeElement();
}
function fetchJsonData() {
if (window.XMLHttpRequest) { // Mozilla, Safari, Opera, IE7
var httpRequest = new XMLHttpRequest();
@ -81,35 +81,35 @@
httpRequest.setRequestHeader('content-Type', 'application/x-www-form-urlencoded; charset=utf-8');
httpRequest.send();
}
function fetchJsonDataReady(httpRequest) {
if (null !== httpRequest && 4 == httpRequest.readyState && 200 == httpRequest.status) {
var response = httpRequest.responseText;
var jsonResponse = typeof JSON != 'undefined' ? JSON.parse(response) : eval('(' + response + ')');
var answer = jsonResponse.answer;
var scrambleKey = typeof jsonResponse.scrambleKey != 'undefined' ? jsonResponse.scrambleKey : null;
if (typeof answer != 'string' || 'ERROR' != answer.toUpperCase()) {
fillCaptcha(answer, scrambleKey);
}
}
}
function decodeUtf8(string) {
return decodeURIComponent(escape(string));
}
function xorDescramble(string, key) {
var decoded = '';
for (i = 0; i < string.length; ++i) {
decoded += String.fromCharCode(string.charCodeAt(i) ^ key);
}
return decoded;
}
}
var spamBeeObj = new SpamBeeCaptcha(spamBeeData);
spamBeeObj.attachToLoadEvent();
})();

View file

@ -1,6 +1,5 @@
<?php
if (IN_serendipity !== true) {
die ("Don't hack!");
}
@ -24,7 +23,7 @@ require_once dirname(__FILE__) . '/json/json.php4.include.php';
/**
* Serendipity plug-in for providing spam protection via a
* Honey Pot field and a hidden Captcha.
*
*
* @author Grischa Brockhaus
* @author Janek Bevendorff
*/
@ -35,62 +34,62 @@ class serendipity_event_spamblock_bee extends serendipity_event
* @var string
*/
var $title = PLUGIN_EVENT_SPAMBLOCK_BEE_TITLE;
/**
* Whether to use a Honey Pot
* @var boolean
*/
var $useHoneyPot = true;
/**
* Whether the Captcha is enabled and what to do when validation failed
* @var string
*/
var $hiddenCaptchaHandle = null;
/**
* Method for retrieving the correct answer of the hidden Captcha.
* Either 'default', 'json' or 'smarty'.
* @var string
*/
var $answerRetrievalMethod = null;
/**
* Correct answer for the Captcha. If RegExp matching is on, it'll
* also contain an index 'pattern'
* @var array
*/
var $captchaAnswer = array('answer' => null);
/**
* Type of question asked in the Captcha. This is either 'math' or 'custom'
* @var string
*/
var $captchaQuestionType = null;
/**
* Whether to use RegExp matching for the hidden Captcha
* @var boolean
*/
var $useRegularExpressions = false;
/**
* Constructor. Initialize class variables from configuration
* @return void
*/
function serendipity_event_spamblock_bee($instance) {
$this->instance = $instance;
$this->answerRetrievalMethod = $this->get_config('answer_retrieval_method', 'default');
$this->captchaQuestionType = $this->get_config('question_type', 'math');
$this->useHoneyPot = $this->get_config('do_honeypot', true);
$this->hiddenCaptchaHandle = $this->get_config('do_hiddencaptcha', PLUGIN_EVENT_SPAMBLOCK_SWTCH_MODERATE);
$this->useRegularExpressions = $this->get_config('use_regexp', false);
}
/**
* Declare Serendipity backend properties.
*
*
* @param serendipity_property_bag $propbag
*/
function introspect(&$propbag)
@ -106,28 +105,29 @@ class serendipity_event_spamblock_bee extends serendipity_event
'smarty' => '2.6.7',
'php' => '4.1.0'
));
$propbag->add('version', PLUGIN_SPAMBLOCK_BEE_VERSION); // setup via version.inc.php
$propbag->add('event_hooks', array(
'frontend_comment' => true,
'frontend_comment' => true,
'frontend_saveComment' => true,
'frontend_footer' => true,
'css' => true,
'external_plugin' => true,
'frontend_footer' => true,
'css' => true,
'external_plugin' => true
));
$propbag->add('groups', array('ANTISPAM'));
$configuration = array('header_desc','do_honeypot', 'do_hiddencaptcha' );
if (!class_exists('serendipity_event_spamblock')) { // Only do that, if spamblock is not installed.
$configuration =array_merge($configuration, array('entrytitle', 'samebody', 'required_fields'));
// Only do that, if spamblock is not installed
if (!class_exists('serendipity_event_spamblock')) {
$configuration = array_merge($configuration, array('entrytitle', 'samebody', 'required_fields'));
}
$configuration =array_merge($configuration, array('spamlogtype', 'spamlogfile', 'plugin_path'));
$configuration =array_merge($configuration, array(
$configuration = array_merge($configuration, array('spamlogtype', 'spamlogfile', 'plugin_path'));
$configuration = array_merge($configuration, array(
'advanced_cc_desc', 'answer_retrieval_method', 'question_type',
'questions', 'answers', 'use_regexp'
));
$propbag->add('configuration', $configuration );
$propbag->add('config_groups', array(
PLUGIN_EVENT_SPAMBLOCK_BEE_CONFIG_SECTION_LOGGING => array(
@ -140,19 +140,19 @@ class serendipity_event_spamblock_bee extends serendipity_event
)
);
}
/**
* Set plug-in title.
*
*
* @param string $title
*/
function generate_content(&$title) {
$title = PLUGIN_EVENT_SPAMBLOCK_BEE_TITLE;
}
/**
* Generate backend configuration fields
*
*
* @param string $name field name
* @param serendipity_property_bag $propbag properties
* @return bool
@ -160,27 +160,27 @@ class serendipity_event_spamblock_bee extends serendipity_event
function introspect_config_item($name, &$propbag)
{
global $serendipity;
$rejectType = array(
PLUGIN_EVENT_SPAMBLOCK_SWTCH_OFF => PLUGIN_EVENT_SPAMBLOCK_BEE_RESULT_OFF,
PLUGIN_EVENT_SPAMBLOCK_SWTCH_OFF => PLUGIN_EVENT_SPAMBLOCK_BEE_RESULT_OFF,
PLUGIN_EVENT_SPAMBLOCK_SWTCH_MODERATE => PLUGIN_EVENT_SPAMBLOCK_BEE_RESULT_MODERATE,
PLUGIN_EVENT_SPAMBLOCK_SWTCH_REJECT => PLUGIN_EVENT_SPAMBLOCK_BEE_RESULT_REJECT,
PLUGIN_EVENT_SPAMBLOCK_SWTCH_REJECT => PLUGIN_EVENT_SPAMBLOCK_BEE_RESULT_REJECT,
);
$retrievalMethod = array(
'default' => PLUGIN_EVENT_SPAMBLOCK_BEE_CONFIG_ADV_RM_DEFAULT,
'json' => PLUGIN_EVENT_SPAMBLOCK_BEE_CONFIG_ADV_RM_JSON,
'smarty' => PLUGIN_EVENT_SPAMBLOCK_BEE_CONFIG_ADV_RM_SMARTY,
'smarty_enc' => PLUGIN_EVENT_SPAMBLOCK_BEE_CONFIG_ADV_RM_SMARTY_ENC
);
$questionType = array(
'math' => PLUGIN_EVENT_SPAMBLOCK_BEE_CONFIG_ADV_QT_MATH,
'custom' => PLUGIN_EVENT_SPAMBLOCK_BEE_CONFIG_ADV_QT_CUSTOM
);
switch($name) {
case 'header_desc':
case 'header_desc':
$propbag->add('type', 'content');
$propbag->add('default', PLUGIN_EVENT_SPAMBLOCK_BEE_EXTRA_DESC .
'<img src="' . $serendipity['baseURL'] . 'index.php?/plugin/spamblockbee.png" alt="" title="' . PLUGIN_EVENT_SPAMBLOCK_BEE_TITLE . '" style="float:right">' );
@ -192,7 +192,7 @@ class serendipity_event_spamblock_bee extends serendipity_event
$propbag->add('description', PLUGIN_EVENT_SPAMBLOCK_BEE_CONFIG_SPAM_HONEYPOT_DESC);
$propbag->add('default', true);
break;
case 'do_hiddencaptcha':
$propbag->add('type', 'select');
$propbag->add('name', PLUGIN_EVENT_SPAMBLOCK_BEE_CONFIG_SPAM_HCAPTCHA);
@ -207,7 +207,7 @@ class serendipity_event_spamblock_bee extends serendipity_event
$propbag->add('description', PLUGIN_EVENT_SPAMBLOCK_BEE_REQUIRED_FIELDS_DESC);
$propbag->add('default', '');
break;
case 'entrytitle':
$propbag->add('type', 'select');
$propbag->add('name', PLUGIN_EVENT_SPAMBLOCK_BEE_FILTER_TITLE);
@ -215,7 +215,7 @@ class serendipity_event_spamblock_bee extends serendipity_event
$propbag->add('select_values', $rejectType);
$propbag->add('default', PLUGIN_EVENT_SPAMBLOCK_SWTCH_REJECT);
break;
case 'samebody':
$propbag->add('type', 'select');
$propbag->add('name', PLUGIN_EVENT_SPAMBLOCK_BEE_FILTER_SAMEBODY);
@ -223,7 +223,7 @@ class serendipity_event_spamblock_bee extends serendipity_event
$propbag->add('select_values', $rejectType);
$propbag->add('default', PLUGIN_EVENT_SPAMBLOCK_SWTCH_REJECT);
break;
case 'spamlogtype':
$logtypevalues = array (
'none' => PLUGIN_EVENT_SPAMBLOCK_BEE_CONFIG_SPAM_LOGTYPE_NONE,
@ -236,7 +236,7 @@ class serendipity_event_spamblock_bee extends serendipity_event
$propbag->add('select_values', $logtypevalues);
$propbag->add('default', 'none');
break;
case 'spamlogfile':
$propbag->add('type', 'string');
$propbag->add('name', PLUGIN_EVENT_SPAMBLOCK_BEE_CONFIG_SPAM_LOGFILE);
@ -250,12 +250,12 @@ class serendipity_event_spamblock_bee extends serendipity_event
$propbag->add('description', PLUGIN_EVENT_SPAMBLOCK_BEE_PATH_DESC);
$propbag->add('default', $serendipity['serendipityHTTPPath'] . 'plugins/serendipity_event_spamblock_bee/');
break;
case 'advanced_cc_desc':
$propbag->add('type', 'content');
$propbag->add('default', PLUGIN_EVENT_SPAMBLOCK_BEE_CONFIG_ADV_DESC);
break;
case 'answer_retrieval_method':
$propbag->add('type', 'select');
$propbag->add('name', PLUGIN_EVENT_SPAMBLOCK_BEE_CONFIG_ADV_ANSWER_RETRIEVAL);
@ -263,7 +263,7 @@ class serendipity_event_spamblock_bee extends serendipity_event
$propbag->add('select_values', $retrievalMethod);
$propbag->add('default', 'default');
break;
case 'question_type':
$propbag->add('type', 'select');
$propbag->add('name', PLUGIN_EVENT_SPAMBLOCK_BEE_CONFIG_ADV_QUESTION_TYPE);
@ -271,7 +271,7 @@ class serendipity_event_spamblock_bee extends serendipity_event
$propbag->add('select_values', $questionType);
$propbag->add('default', 'math');
break;
case 'questions':
$propbag->add('type', 'text');
$propbag->add('rows', 8);
@ -279,7 +279,7 @@ class serendipity_event_spamblock_bee extends serendipity_event
$propbag->add('description', PLUGIN_EVENT_SPAMBLOCK_BEE_CONFIG_ADV_QUESTIONS_DESC);
$propbag->add('default', PLUGIN_EVENT_SPAMBLOCK_BEE_CONFIG_ADV_DEFAULT_QUESTIONS);
break;
case 'answers':
$propbag->add('type', 'text');
$propbag->add('rows', 8);
@ -287,23 +287,23 @@ class serendipity_event_spamblock_bee extends serendipity_event
$propbag->add('description', PLUGIN_EVENT_SPAMBLOCK_BEE_CONFIG_ADV_ANSWERS_DESC);
$propbag->add('default', PLUGIN_EVENT_SPAMBLOCK_BEE_CONFIG_ADV_DEFAULT_ANSWERS);
break;
case 'use_regexp':
$propbag->add('type', 'boolean');
$propbag->add('name', PLUGIN_EVENT_SPAMBLOCK_BEE_CONFIG_ADV_USE_REGEXP);
$propbag->add('description', PLUGIN_EVENT_SPAMBLOCK_BEE_CONFIG_ADV_USE_REGEXP_DESC);
$propbag->add('default', false);
break;
default:
return false;
}
return true;
}
/**
* Hook for Serendipity events, initialize plug-in features
*
*
* @param string $event
* @param serendipity_property_bag $bag
* @param array $eventData
@ -312,7 +312,7 @@ class serendipity_event_spamblock_bee extends serendipity_event
*/
function event_hook($event, &$bag, &$eventData, $addData = null) {
global $serendipity;
$hooks = &$bag->get('event_hooks');
if (isset($hooks[$event])) {
switch($event) {
@ -327,7 +327,7 @@ class serendipity_event_spamblock_bee extends serendipity_event
break;
}
break;
case 'frontend_saveComment':
// Check only, if no one else denied it before
if (!is_array ( $eventData ) || serendipity_db_bool ( $eventData ['allow_comments'] )) {
@ -335,9 +335,11 @@ class serendipity_event_spamblock_bee extends serendipity_event
}
return true;
break;
case 'frontend_comment':
$this->printCommentEditExtras($eventData, $addData);
break;
case 'frontend_footer':
// Comment header code only if in single article mode or contactform
// If contact form is installed, display on any page not being the article list
@ -349,9 +351,11 @@ class serendipity_event_spamblock_bee extends serendipity_event
$this->printJsExtras();
}
break;
case 'css':
case 'css':
$this->printCss($eventData, $addData);
break;
default:
return false;
break;
@ -361,20 +365,20 @@ class serendipity_event_spamblock_bee extends serendipity_event
return false;
}
}
/**
* Check if Honey Pot or Captcha have been filled correctly (or if any
* other indications for spam can be found).
*
*
* @param array $eventData
* @param array $addData
* @return bool
*/
function checkComment(&$eventData, &$addData) {
global $serendipity;
if ("NORMAL" == $addData['type']) { // only supported for normal comments
// Check for Honey Pot:
$phone = $serendipity['POST']['phone'];
if ($this->useHoneyPot && (!empty($phone) || $phone == '0') ) {
@ -385,28 +389,28 @@ class serendipity_event_spamblock_bee extends serendipity_event
$eventData = array('allow_comments' => false);
return false;
}
// Check hidden Captcha
if (PLUGIN_EVENT_SPAMBLOCK_SWTCH_OFF != $this->hiddenCaptchaHandle) {
$answer = trim(strtolower($serendipity['POST']['beecaptcha']));
$correctAnswer = $this->getCaptchaAnswer();
$correctAnswer['answer'] = strtolower($correctAnswer['answer']);
$isCorrect = false;
// If provided answer is longer than 1000 characters and RegExp matching is on,
// reject comment for security reasons (minimize risk of ReDoS)
if ($this->useRegularExpressions && mb_strlen($answer) > 1000) {
$this->processComment($this->hiddenCaptchaHandle, $eventData, $addData, PLUGIN_EVENT_SPAMBLOCK_BEE_ERROR_HCAPTCHA, "BEE HiddenCaptcha [ Captcha input too long ]");
return false;
}
if ($this->captchaQuestionType == 'custom' && $this->useRegularExpressions) {
// Sanitize regular expression and remove answer part
$pattern = preg_replace('/^\s*\/(.*)\/\s*[imsxeADSUXJu]*\s*$/s', '$1', $correctAnswer['pattern']);
// Try to match pattern with given answer
$match = @preg_match('/' . $pattern . '/si', $answer);
// If pattern contains errors, fall back to basic string comparison
if ($match === false) {
$this->useRegularExpressions = false;
@ -414,17 +418,17 @@ class serendipity_event_spamblock_bee extends serendipity_event
$isCorrect = ($match === 1);
}
}
if ($this->captchaQuestionType != 'custom' || !$this->useRegularExpressions) {
$isCorrect = ($answer == $correctAnswer['answer']);
}
// Also allow numbers as words
if (!$isCorrect && $this->captchaQuestionType == 'math') {
$number = $this->generateNumberString($correctAnswer['answer']);
$isCorrect = ($answer == $number && $number != 'ERROR');
}
if (!$isCorrect) {
if (mb_strlen($answer) > 40) {
$answer = mb_substr($answer, 0, 40) . '..';
@ -435,7 +439,7 @@ class serendipity_event_spamblock_bee extends serendipity_event
}
// AntiSpam check, the general spamblock supports, too: Only if spamblock is not installed.
if (!class_exists('serendipity_event_spamblock')) {
// Check for required fields. Don't log but tell the user about the fields.
$required_fields = $this->get_config('required_fields', '');
if (!empty($required_fields)) {
@ -450,7 +454,7 @@ class serendipity_event_spamblock_bee extends serendipity_event
}
}
}
// AntiSpam check, the general spamblock supports, too: Only if spamblock is not installed.
if (!class_exists('serendipity_event_spamblock')) {
@ -461,7 +465,7 @@ class serendipity_event_spamblock_bee extends serendipity_event
$comment = str_replace($serendipity['blogTitle'], '', $addData['comment']);
$comment = str_replace($eventData['title'], '', $comment);
// Now blog- and entry title was stripped from comment.
// Remove special letters, that might have been between them:
// Remove special letters, that might have been between them:
$comment = trim(preg_replace('@[\s\-_:\(\)\|/]*@', '', $comment));
// Now that we stripped blog and entry title: Do we have an empty comment?
@ -470,33 +474,33 @@ class serendipity_event_spamblock_bee extends serendipity_event
return false;
}
}
// This check loads from DB, so do it last!
// Check if we already have a comment with the same body. (it's a reload normaly)
$spamHandle = $this->get_config('samebody', PLUGIN_EVENT_SPAMBLOCK_SWTCH_REJECT);
if (PLUGIN_EVENT_SPAMBLOCK_SWTCH_OFF!=$spamHandle) {
$query = "SELECT count(id) AS counter FROM {$serendipity['dbPrefix']}comments WHERE type = '" . $addData['type'] . "' AND body = '" . serendipity_db_escape_string($addData['comment']) . "'";
// This is a little different to the normal Spam Plugin:
// This is a little different to the normal Spam Plugin:
// We allow the same comment, if it is a trackback, but never on the same article
// (One article sending trackbacks to more than one local article)
if ($addData['type'] == 'PINGBACK' || $addData['type'] == 'TRACKBACK') {
$query .= ' AND entry_id=' . $eventData['id'];
$query .= ' AND entry_id=' . $eventData['id'];
}
$row = serendipity_db_query($query, true);
if (is_array($row) && $row['counter'] > 0) {
$this->processComment($spamHandle, $eventData, $addData, PLUGIN_EVENT_SPAMBLOCK_BEE_ERROR_BODY, "BEE Body already saved");
return false;
}
}
}
return true;
}
/**
* Reject or moderate a comment. Convenience function.
*
*
* @param string $spamHandle
* @param array $eventData
* @param array $addData
@ -512,10 +516,10 @@ class serendipity_event_spamblock_bee extends serendipity_event
$this->reject($eventData, $addData, $remoteResponse, $logResponse);
}
}
/**
* Reject a comment with optional log entry.
*
*
* @param array $eventData
* @param array $addData
* @param string $remoteResponse
@ -523,17 +527,17 @@ class serendipity_event_spamblock_bee extends serendipity_event
*/
function reject(&$eventData, &$addData, $remoteResponse, $logResponse = NULL) {
global $serendipity;
if (!empty($logResponse)) {
$this->spamlog($eventData['id'], 'REJECTED', $logResponse, $addData);
}
$eventData = array('allow_comments' => false);
$serendipity['csuccess'] = 'false';
$serendipity['csuccess'] = 'false';
$serendipity['messagestack']['comments'][] = $remoteResponse;
$this->log(print_r($serendipity['messagestack'], true));
}
/**
* Moderate a comment with optional log entry
* @param array $eventData
@ -544,7 +548,7 @@ class serendipity_event_spamblock_bee extends serendipity_event
*/
function moderate(&$eventData, &$addData, $remoteResponse, $logResponse = NULL) {
global $serendipity;
if (!empty($logResponse)) {
$this->spamlog($eventData['id'], 'MODERATE', $logResponse, $addData);
}
@ -555,38 +559,38 @@ class serendipity_event_spamblock_bee extends serendipity_event
$this->log(print_r($serendipity['messagestack'], true));
}
/**
* Produce JSON string with the correct for fetching via Ajax.
*
*
* @return string The generated JSON string
*/
function produceCaptchaAnswerJson() {
$answer = $this->getCaptchaAnswer();
$scrambleKey = rand();
if (!isset($answer['answer'])) {
$answer = array('answer' => 'ERROR');
} else {
$answer['answer'] = rawurlencode($this->xorScramble($answer['answer'], $scrambleKey));
$answer['scrambleKey'] = $scrambleKey;
}
return json_encode($answer);
}
/**
* Write the Honey Pot and Captcha field to the output buffer.
*
*
* @param array $eventData
* @param array $addData
*/
function printCommentEditExtras(&$eventData, &$addData) {
global $serendipity;
// Don't put extras on admin menu. They are not working there: ...or other backend forms like guestbook
if ((isset($eventData['GET']['action']) && $eventData['GET']['action']=='admin') || (int)$serendipity['serendipityUserlevel'] >= (int)USERLEVEL_ADMIN) return;
// Honeypot
if (serendipity_db_bool($this->useHoneyPot)) {
echo '<div id="serendipity_comment_phone" class="serendipity_commentDirection comment_phone_input">' . "\n";
@ -598,12 +602,12 @@ class serendipity_event_spamblock_bee extends serendipity_event
// Captcha
if (PLUGIN_EVENT_SPAMBLOCK_SWTCH_OFF != $this->hiddenCaptchaHandle) {
$question = $this->generateCaptchaQuestion();
echo '<div id="serendipity_comment_beecaptcha" class="form_field">' . "\n";
echo ' <label for="bee_captcha">'. $question. '</label>' . "\n";
echo ' <input class="" type="text" id="bee_captcha" name="serendipity[beecaptcha]" size="10" value="" placeholder=""/>' . "\n";
echo "</div>\n";
if ($this->answerRetrievalMethod == 'smarty' || $this->answerRetrievalMethod == 'smarty_enc') {
$answer = $this->getCaptchaAnswer();
if ($this->answerRetrievalMethod == 'smarty_enc') {
@ -611,12 +615,12 @@ class serendipity_event_spamblock_bee extends serendipity_event
$answer['answer'] = $this->xorScramble($answer['answer'], $scrambleKey);
$serendipity['smarty']->assign('beeCaptchaScrambleKey', $scrambleKey);
}
$serendipity['smarty']->assign('beeCaptchaAnswer', $answer['answer']);
}
}
}
/**
* If retrieval method != 'smarty' and the hidden Captcha is turned on,
* print the needed JavaScript for filling out and hiding the Captcha to the buffer.
@ -625,16 +629,16 @@ class serendipity_event_spamblock_bee extends serendipity_event
if ($this->answerRetrievalMethod == 'smarty' || $this->answerRetrievalMethod == 'smarty_enc') {
return;
}
global $serendipity;
if (PLUGIN_EVENT_SPAMBLOCK_SWTCH_OFF != $this->hiddenCaptchaHandle) {
$path = $this->path = $this->get_config('plugin_path', $serendipity['serendipityHTTPPath'] . 'plugins/serendipity_event_spamblock_bee/');
$answer = $this->getCaptchaAnswer();
$answer = $answer['answer'];
$jsProperties = array('method' => $this->answerRetrievalMethod);
if ($this->answerRetrievalMethod == 'json') {
$jsProperties['url'] = $serendipity['baseURL'] . 'index.php/plugin/spamblockbeecaptcha';
echo '<script>var spamBeeData = ' . json_encode($jsProperties) . ';</script>' . "\n";
@ -645,53 +649,53 @@ class serendipity_event_spamblock_bee extends serendipity_event
$jsProperties['answer'] = is_numeric($answer) ? $answer : trim($answer);
}
unset($jsProperties['pattern']);
if ($this->answerRetrievalMethod == 'default') {
// Do some weird obfuscation stuff to the JS code
$spamBeeVar = $this->generateUniqueVarName(array());
// Shuffle array but preserve keys
$jsPropertiesKeys = array_keys($jsProperties);
shuffle($jsPropertiesKeys);
$jsProperties = array_merge(array_flip($jsPropertiesKeys) , $jsProperties);
echo '<script>var spamBeeData = function() { var ' . $spamBeeVar . ' = {};';
$jsVars = array();
$existingKeys = array($spamBeeVar);
foreach($jsProperties as $property => $value) {
$varName = $this->generateUniqueVarName($existingKeys);
$jsVars[$varName] = $property;
$existingKeys[] = $varName;
// URL encode all characters to make values appear almost equal
$encVal = '';
$valLength = mb_strlen($value);
for ($i = 0; $i < $valLength; ++$i) {
$encVal .= '%' . bin2hex(mb_substr($value, $i, 1));
}
echo 'var ' . $varName . " = unescape('" . $encVal . "');";
}
foreach ($jsVars as $var => $value) {
echo $spamBeeVar . "['" . $value . "'] = " . $var . ';';
}
echo 'return ' . $spamBeeVar . '; }();';
echo "</script>\n";
}
echo '<script src="' . $path . 'serendipity_event_spamblock_bee.js"></script>';
echo '<script src="' . $path . 'serendipity_event_spamblock_bee.js"></script>' . "\n";
}
}
/**
* Generate a unique random variable name. Used for generating obfuscated
* JS code. To make sure, the name is really unique, pass an array of all
* variable names already existing to this function.
* Returns an empty string if no unique variable name could be generated.
*
*
* @param array $existingVarNames
* @param int $length
* @return string
@ -699,11 +703,11 @@ class serendipity_event_spamblock_bee extends serendipity_event
function generateUniqueVarName($existingVarNames, $length = 5) {
$varName = '';
$pool = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz_';
$attempts = 0;
for ($i = 0; $i < $length; ++$i) {
$varName .= $pool[rand(0, strlen($pool) - 1)];
// If variable name has been generated, but is not unique, start over again
if ($i == ($length - 1) && in_array($varName, $existingVarNames)) {
// If we already have 10 attempts, give up and return empty string (should not happen)
@ -714,14 +718,14 @@ class serendipity_event_spamblock_bee extends serendipity_event
++$attempts;
}
}
return $varName;
}
/**
* If retrieval method != 'json' and the hidden Captcha is enabled, print
* the needed CSS for hiding it to the output buffer.
*
*
* @param array $eventData
* @param array $addData
*/
@ -729,7 +733,7 @@ class serendipity_event_spamblock_bee extends serendipity_event
if ($this->answerRetrievalMethod == 'smarty' || $this->answerRetrievalMethod == 'smarty_enc') {
return;
}
global $serendipity;
// Hide and reveal classes by @yellowled used be the RSS chooser:
@ -745,9 +749,9 @@ class serendipity_event_spamblock_bee extends serendipity_event
position: absolute;
width: 1px;
}
<?php
<?php
}
if (!(strpos($eventData, '.comment_phone_input'))) {
?>
.comment_phone_input {
@ -758,7 +762,7 @@ class serendipity_event_spamblock_bee extends serendipity_event
<?php
}
}
function hashString( $what ) {
$installation_secret = $this->get_config('installation_secret');
if (empty($installation_secret)) {
@ -767,10 +771,10 @@ class serendipity_event_spamblock_bee extends serendipity_event
}
return md5($installation_secret . ':' . $what);
}
/**
* Generate the question for the Captcha and save the answer to the session.
*
*
* @return string the question
*/
function generateCaptchaQuestion() {
@ -785,22 +789,22 @@ class serendipity_event_spamblock_bee extends serendipity_event
return $question['question'];
}
}
if ($this->captchaQuestionType == 'math') {
$captchaData = $this->generateCaptchaMathProblem();
$this->setCaptchaAnswer($captchaData['answer']);
$method = PLUGIN_EVENT_SPAMBLOCK_BEE_CAPTCHA_PLUS;
if ($captchaData['operator'] == '-') {
$method = PLUGIN_EVENT_SPAMBLOCK_BEE_CAPTCHA_MINUS;
}
return PLUGIN_EVENT_SPAMBLOCK_BEE_CAPTCHA_QUEST . ' ' .
$this->generateNumberString($captchaData['n1']) . " " .
$method . " " . $this->generateNumberString($captchaData['n2']) . '?';
$method . " " . $this->generateNumberString($captchaData['n2']) . '?';
}
}
/**
* Get correct answer for current Captcha question.
* This method returns an array with one or two indices:
@ -809,37 +813,37 @@ class serendipity_event_spamblock_bee extends serendipity_event
* 'pattern' => the pattern for matching the answer (only present
* when regExp matching is turned on)
* )
*
*
* @return array
*/
function getCaptchaAnswer() {
if (!isset($this->captchaAnswer['answer']) && isset($_SESSION['spamblockbee']['captcha'])) {
$this->captchaAnswer = $_SESSION['spamblockbee']['captcha'];
}
// If for some reason RegExp matching is on, but no pattern is present,
// turn off RegExp matching
if ($this->useRegularExpressions && !isset($this->captchaAnswer['pattern'])) {
$this->useRegularExpressions = false;
}
return $this->captchaAnswer;
}
/**
* Save the answer for the Captcha question.
* Call this method when you have changed the question.
* If RegExp matching is turned on, pass a string in the format /pattern/:answer.
*
*
* @param string $answer
*/
function setCaptchaAnswer($answer) {
$answer = array('answer' => $answer);
// Split answer into array if RegExp matching is on
if ($this->captchaQuestionType == 'custom' && $this->useRegularExpressions) {
$delimiterIndex = strrpos($answer['answer'], ':');
if ($delimiterIndex !== false) {
$answer = array(
'pattern' => substr($answer['answer'], 0, $delimiterIndex),
@ -850,20 +854,20 @@ class serendipity_event_spamblock_bee extends serendipity_event
$this->useRegularExpressions = false;
}
}
$this->captchaAnswer = $answer;
$_SESSION['spamblockbee']['captcha'] = $this->captchaAnswer;
}
/**
* Generate a simple arithmetic problem for use in the Captcha.
* Returns an array containing the operator, the operands and the result.
*
*
* @return array
*/
function generateCaptchaMathProblem() {
$result = array();
$number1 = rand(0,9);
$number2 = rand(0,9);
if (($number1 + $number2) > 10 ) {
@ -878,7 +882,7 @@ class serendipity_event_spamblock_bee extends serendipity_event
$result['n2'] = $number1;
$result['n1'] = $number2;
$result['answer'] = $number2 - $number1;
}
}
} else {
// Add them
$result['operator'] = '+';
@ -886,13 +890,13 @@ class serendipity_event_spamblock_bee extends serendipity_event
$result['n2'] = $number2;
$result['answer'] = $number1 + $number2;
}
return $result;
}
/**
* Turn numbers between 0 and 10 into words.
*
*
* @param int $number
* @return string
*/
@ -913,7 +917,7 @@ class serendipity_event_spamblock_bee extends serendipity_event
default: return "ERROR";
}
}
/**
* Select a random question from the list of custom questions.
* Returns an array with to indices:
@ -921,7 +925,7 @@ class serendipity_event_spamblock_bee extends serendipity_event
* 'question' => the selected question
* 'answer' => the answer for that question
* )
*
*
* @return array
*/
function selectRandomCustomCaptchaQuestion() {
@ -930,31 +934,31 @@ class serendipity_event_spamblock_bee extends serendipity_event
if (empty($questions) || empty($answers)) {
return null;
}
$questions = preg_split('/(?:\r?\n|\r)/', $questions);
$answers = preg_split('/(?:\r?\n|\r)/', $answers);
// ignore questions without answer
if (count($questions) > count($answers)) {
array_splice($questions, count($answers));
}
// if no questions left
if (!count($questions)) {
return null;
}
$questionIndex = rand(0, count($questions) - 1);
return array(
'question' => trim($questions[$questionIndex]),
'answer' => trim($answers[$questionIndex])
);
}
/**
* Scramble a UTF-8 string with a simple XOR cipher in order
* to perform string obfuscation.
*
*
* @param string $string
* @param int $key
* @return string
@ -962,45 +966,45 @@ class serendipity_event_spamblock_bee extends serendipity_event
function xorScramble($string, $key) {
$scrambled = '';
$length = mb_strlen($string, 'UTF-8');
for ($i = 0; $i < $length; ++$i) {
$chr = mb_substr($string, $i, 1, 'UTF-8');
$ord = $this->ordUtf8($chr);
$scrambled .= $this->chrUtf8($ord ^ $key);
}
return $scrambled;
}
/**
* Multi-byte safe UTF-8 version of chr()
* Thanks to http://pastebin.com/fmiSnNin
*
*
* @param int $ord
* @return string
*/
function chrUtf8($ord)
function chrUtf8($ord)
{
return mb_convert_encoding(pack('n', $ord) , 'UTF-8', 'UTF-16BE');
}
/**
* Multi-byte safe UTF-8 version of ord().
* Thanks to http://pastebin.com/fmiSnNin
* Returns -1 on error.
*
*
* @param string $chr
* @return int
*/
function ordUtf8($chr)
function ordUtf8($chr)
{
// Return value of ord() if only single-byte
if (strlen($chr) == 1) {
return ord($chr);
}
$codePoint = ord($chr[0]);
if ($codePoint <= 0x7f) {
return $codePoint;
} else if ($codePoint < 0xc2) {
@ -1015,7 +1019,7 @@ class serendipity_event_spamblock_bee extends serendipity_event
return -1;
}
}
/**
* Log spam to file
* @param string $message
@ -1027,7 +1031,7 @@ class serendipity_event_spamblock_bee extends serendipity_event
fflush($fp);
fclose($fp);
}
/**
* Log spam to database
* @param string $id
@ -1037,10 +1041,10 @@ class serendipity_event_spamblock_bee extends serendipity_event
*/
function spamlog($id, $switch, $reason, $addData) {
global $serendipity;
$method = $this->get_config('spamlogtype', 'none');
$logfile = $this->get_config('spamlogfile', $serendipity['serendipityPath'] . 'spamblock.log');
switch($method) {
case 'file':
if (empty($logfile)) {
@ -1098,5 +1102,5 @@ class serendipity_event_spamblock_bee extends serendipity_event
serendipity_db_schema_import($q);
break;
}
}
}
}

View file

@ -1,4 +1,5 @@
<?php
// Probe for a language include with constants. Still include defines later on, if some constants were missing
$probelang = dirname(__FILE__) . '/' . $serendipity['charset'] . 'lang_' . $serendipity['lang'] . '.inc.php';
if (file_exists($probelang)) {
@ -9,9 +10,8 @@ include dirname(__FILE__) . '/version.inc.php';
class serendipity_plugin_spamblock_bee extends serendipity_plugin {
var $title = PLUGIN_SPAMBLOCK_BEE_TITLE;
var $cache_file = null;
var $cache_file = null;
function introspect(&$propbag) {
$this->title = $this->get_config('title', $this->title);
@ -26,14 +26,14 @@ class serendipity_plugin_spamblock_bee extends serendipity_plugin {
));
$propbag->add('version', PLUGIN_SPAMBLOCK_BEE_VERSION); // setup via version.inc.php
$propbag->add('groups', array('STATISTICS'));
$configuration = array('title', 'db_search_pattern', 'days', 'loggedin_only', 'cachemin');
$propbag->add('configuration', $configuration );
}
function introspect_config_item($name, &$propbag) {
global $serendipity;
@ -49,13 +49,13 @@ class serendipity_plugin_spamblock_bee extends serendipity_plugin {
$propbag->add('name', PLUGIN_SPAMBLOCK_BEE_DAYS);
$propbag->add('description', PLUGIN_SPAMBLOCK_BEE_DAYS_DESC);
$propbag->add('default','1,7,30');
break;
break;
case 'db_search_pattern':
$propbag->add('type', 'text');
$propbag->add('name', PLUGIN_SPAMBLOCK_BEE_DBSEARCHES);
$propbag->add('description', PLUGIN_SPAMBLOCK_BEE_DBSEARCHES_DESC);
$propbag->add('rows', 4);
$propbag->add('default',
$propbag->add('default',
'Honeypot:BEE Honeypot%
HiddenCaptcha:BEE HiddenCaptcha%
Bayes:%Bayes%'
@ -65,8 +65,8 @@ Bayes:%Bayes%'
$propbag->add('type', 'string');
$propbag->add('name', PLUGIN_SPAMBLOCK_BEE_CACHEMINS);
$propbag->add('description', PLUGIN_SPAMBLOCK_BEE_CACHEMINS_DESC);
$propbag->add('default','10'); // 10min
break;
$propbag->add('default', '10'); // 10min
break;
case 'loggedin_only':
$propbag->add('type', 'boolean');
$propbag->add('name', PLUGIN_SPAMBLOCK_BEE_LOGGEDIN);
@ -78,47 +78,47 @@ Bayes:%Bayes%'
}
return TRUE;
}
function generate_content(&$title) {
global $serendipity;
if (serendipity_db_bool($this->get_config('loggedin_only', TRUE))) {
// show content if logged on only
if ($_SESSION['serendipityAuthedUser'] != true) return;
}
$title = $this->get_config('title', $this->title);
$statsCached = $this->loadCachedStats();
$stats = array();
if (!empty($statsCached)) {
$stats = $statsCached;
}
$days = explode(',', $this->get_config('days'));
$searches = preg_split('/(?:\r?\n|\r)/', $this->get_config('db_search_pattern'));
$todayAtMidnight = mktime(0,0,0, date("n"), date("j"), date("Y"));
$timestampDay = 60 * 60 * 24;
$statsString = '';
foreach ($days as $day) {
if (!isset($stats[$day])) {
$stats[$day] = array();
}
$timestamp = $todayAtMidnight - ($timestampDay * (trim($day) -1));
if ($day==1) {
$statsString .= '<b>' . PLUGIN_SPAMBLOCK_BEE_TODAY . '</b> <br>';
} else {
$statsString .= '<b>' . sprintf(PLUGIN_SPAMBLOCK_BEE_LAST_X_DAYS, $day) . '</b><br>';
}
foreach ($searches as $search) {
$singleSearch = explode(':', $search, 2);
$singleSearch[0] = trim($singleSearch[0]);
$singleSearch[1] = trim($singleSearch[1]);
if (empty($statsCached)) {
$sql = "SELECT COUNT(*) as total FROM {$serendipity['dbPrefix']}spamblocklog WHERE reason like '%s' and timestamp>%d;";
$singleSql = sprintf($sql, serendipity_db_escape_string($singleSearch[1]), $timestamp);
@ -129,21 +129,21 @@ Bayes:%Bayes%'
$stats[$day][$singleSearch[1]] = 0;
}
}
$searchResult = isset($stats[$day][$singleSearch[1]]) ? $stats[$day][$singleSearch[1]] : 0;
if ($searchResult) {
$statsString .= "{$singleSearch[0]}: {$searchResult}<br>";
}
}
}
if (empty($statsCached)) {
$this->cacheStats($stats);
}
echo $statsString;
}
function loadCachedStats() {
$cacheFile = $this->getCacheFilename();
$cachesecs = $this->get_config('cachemin', '10') * 60;
@ -159,6 +159,7 @@ Bayes:%Bayes%'
}
return array();
}
function cacheStats($stats) {
$stats = serialize($stats);
$cacheFile = $this->getCacheFilename();
@ -166,7 +167,7 @@ Bayes:%Bayes%'
fputs($fh, $stats, strlen($stats));
fclose($fh);
}
/**
* Returns the cache file name
*/
@ -177,12 +178,12 @@ Bayes:%Bayes%'
}
return $this->cache_file;
}
function cleanup() {
$cacheFile = $this->getCacheFilename();
if (file_exists($cacheFile)) {
unlink($cacheFile);
}
}
}
}

View file

@ -1,2 +1,2 @@
<?php
@define('PLUGIN_SPAMBLOCK_BEE_VERSION', '1.2.8');
@define('PLUGIN_SPAMBLOCK_BEE_VERSION', '1.2.9');