# HG changeset patch # User Dan # Date 1232936467 18000 # Node ID 2c20563245b2ff4a06814adb4b885062f3ed5971 # Parent dcf5381ce8ba271e5488ab57a1a4413163148baf# Parent 28d9fbcd4f0d3e1acda807f41c7b215e6f7c653b Merging Nighthawk (anti-spam work) and Scribus (AJAX work + debugging + CLI installer) branches diff -r 28d9fbcd4f0d -r 2c20563245b2 includes/clientside/static/comments.js --- a/includes/clientside/static/comments.js Sun Jan 25 20:35:32 2009 -0500 +++ b/includes/clientside/static/comments.js Sun Jan 25 21:21:07 2009 -0500 @@ -54,7 +54,8 @@ materializeComment(response); break; case 'error': - new MessageBox(MB_OK|MB_ICONSTOP, ( response.title ? response.title : 'Error fetching comment data' ), response.error); + load_component(['messagebox', 'fadefilter', 'flyin']); + new MessageBox(MB_OK|MB_ICONSTOP, ( response.title ? response.title : $lang.get('comment_ajax_err_generic_title') ), response.error); break; default: alert(ajax.responseText); @@ -180,8 +181,10 @@ tplvars.DATA = this_comment.comment_data; tplvars.SIGNATURE = this_comment.signature; - if ( this_comment.approved != '1' ) + if ( this_comment.approved == '0' ) tplvars.SUBJECT += ' ' + $lang.get('comment_msg_note_unapp') + ''; + else if ( this_comment.approved == '2' ) + tplvars.SUBJECT += ' ' + $lang.get('comment_msg_note_spam') + ''; // Name tplvars.NAME = this_comment.name; diff -r 28d9fbcd4f0d -r 2c20563245b2 includes/comment.php --- a/includes/comment.php Sun Jan 25 20:35:32 2009 -0500 +++ b/includes/comment.php Sun Jan 25 21:21:07 2009 -0500 @@ -123,7 +123,7 @@ $count_total++; ( $row['approved'] == 1 ) ? $count_appr++ : $count_unappr++; - if ( !$this->perms->get_permissions('mod_comments') && $row['approved'] == 0 ) + if ( !$this->perms->get_permissions('mod_comments') && $row['approved'] != COMMENT_APPROVED ) continue; // Localize the rank @@ -142,7 +142,7 @@
-Post from foe hidden. Display post
+' . $lang->get('comment_msg_foe_comment_hidden') . ' ' . $lang->get('comment_btn_display_foe_comment') . '
'; $row['comment_data'] = $wrapper; } @@ -193,7 +193,7 @@ break; case 'edit': $cid = (string)$data['id']; - if ( !preg_match('#^([0-9]+)$#i', $cid) || intval($cid) < 1 ) + if ( !ctype_digit($cid) || intval($cid) < 1 ) { echo '{"mode":"error","error":"HACKING ATTEMPT"}'; return false; @@ -228,7 +228,7 @@ break; case 'delete': $cid = (string)$data['id']; - if ( !preg_match('#^([0-9]+)$#i', $cid) || intval($cid) < 1 ) + if ( !ctype_digit($cid) || intval($cid) < 1 ) { echo '{"mode":"error","error":"HACKING ATTEMPT"}'; return false; @@ -266,17 +266,28 @@ // Guest authorization if ( getConfig('comments_need_login') == '2' && !$session->user_logged_in ) - $errors[] = 'You need to log in before posting comments.'; + $errors[] = $lang->get('comment_err_need_login'); // CAPTCHA code if ( getConfig('comments_need_login') == '1' && !$session->user_logged_in ) { $real_code = $session->get_captcha($data['captcha_id']); - if ( strtolower($real_code) != strtolower($data['captcha_code']) ) - $errors[] = 'The confirmation code you entered was incorrect.'; + if ( strtolower($real_code) !== strtolower($data['captcha_code']) ) + $errors[] = $lang->get('comment_err_captcha_wrong'); $session->kill_captcha(); } + // Spam check + $spam_policy = getConfig('comment_spam_policy', 'moderate'); + $sc_name = ( $session->user_logged_in ) ? $session->username : $data['name']; + $sc_mail = ( $session->user_logged_in ) ? $session->email : false; + $sc_url = ( $session->user_logged_in ) ? $session->user_extra['user_homepage'] : false; + $spamcheck = $spam_policy === 'accept' ? true : spamalyze($data['text'], $sc_name, $sc_mail, $sc_url); + if ( !$spamcheck && $spam_policy === 'reject' ) + { + $errors[] = $lang->get('comment_err_spamcheck_failed_rejected'); + } + if ( count($errors) > 0 ) { $ret = Array( @@ -295,7 +306,9 @@ $src = $text; $sql_text = $db->escape($text); $text = RenderMan::render($text); - $appr = ( getConfig('approve_comments') == '1' ) ? '0' : '1'; + $appr = ( getConfig('approve_comments') == '1' ) ? COMMENT_UNAPPROVED : COMMENT_APPROVED; + if ( $appr === COMMENT_APPROVED && $spam_policy === 'moderate' && !$spamcheck ) + $appr = COMMENT_SPAM; $time = time(); $date = enano_date('F d, Y h:i a', $time); $ip = $_SERVER['REMOTE_ADDR']; @@ -358,7 +371,7 @@ } $cid = (string)$data['id']; - if ( !preg_match('#^([0-9]+)$#i', $cid) || intval($cid) < 1 ) + if ( !ctype_digit($cid) || intval($cid) < 1 ) { echo '{"mode":"error","error":"HACKING ATTEMPT"}'; return false; diff -r 28d9fbcd4f0d -r 2c20563245b2 includes/constants.php --- a/includes/constants.php Sun Jan 25 20:35:32 2009 -0500 +++ b/includes/constants.php Sun Jan 25 21:21:07 2009 -0500 @@ -67,6 +67,11 @@ define('PAGE_GRP_NORMAL', 3); define('PAGE_GRP_REGEX', 4); +// Comment types +define('COMMENT_APPROVED', 1); +define('COMMENT_UNAPPROVED', 0); +define('COMMENT_SPAM', 2); + // Session key types // Short keys last for getConfig('session_short_time', '720'); in minutes and auto-renew. // Long keys last for getConfig('session_remember_time', '30'); in days and do NOT auto-renew. diff -r 28d9fbcd4f0d -r 2c20563245b2 includes/functions.php --- a/includes/functions.php Sun Jan 25 20:35:32 2009 -0500 +++ b/includes/functions.php Sun Jan 25 21:21:07 2009 -0500 @@ -1971,6 +1971,11 @@ // < // The rule is so specific because everything else will have been filtered by now $html = preg_replace('/<(script|iframe)(.+?)src=([^>]*)!', '</\\1>', $html); // Restore stripped comments $i = 0; @@ -2159,6 +2164,46 @@ } /** + * Portal function allowing spam-filtering plugins. + * Hooking guide: + * - Attach to spam_check + * - Return either true or false - true if the message is spam-free, false if it fails your test + * @example +
+ $plugins->attachHook('spam_check', 'return my_spam_check($string);');
+ function my_spam_check($string)
+ {
+ if ( stristr($string, 'viagra') )
+ return false;
+
+ return true;
+ }
+
+ * @param string String to check for spam
+ * @param string Author name
+ * @param string Author e-mail
+ * @param string Author website
+ * @param string Author IP
+ * @return bool
+ */
+
+function spamalyze($string, $name = false, $email = false, $url = false, $ip = false)
+{
+ global $db, $session, $paths, $template, $plugins; // Common objects
+ if ( !$ip )
+ $ip =& $_SERVER['REMOTE_ADDR'];
+
+ $code = $plugins->setHook('spam_check');
+ foreach ( $code as $cmd )
+ {
+ $result = eval($cmd);
+ if ( !$result )
+ return false;
+ }
+ return true;
+}
+
+/**
* Paginates (breaks into multiple pages) a MySQL result resource, which is treated as unbuffered.
* @param resource The MySQL result resource. This should preferably be an unbuffered query.
* @param string A template, with variables being named after the column name
diff -r 28d9fbcd4f0d -r 2c20563245b2 includes/pageprocess.php
--- a/includes/pageprocess.php Sun Jan 25 20:35:32 2009 -0500
+++ b/includes/pageprocess.php Sun Jan 25 21:21:07 2009 -0500
@@ -198,6 +198,11 @@
return false;
}
}
+ if ( $this->revision_id > 0 && !$this->perms->get_permissions('history_view') )
+ {
+ $this->err_access_denied();
+ return false;
+ }
// Is there a custom function registered for handling this namespace?
// DEPRECATED (even though it only saw its way into one alpha release.)
@@ -443,6 +448,13 @@
}
}
+ // Spam check
+ if ( !spamalyze($text) )
+ {
+ $this->raise_error($lang->get('editor_err_spamcheck_failed'));
+ return false;
+ }
+
//
// Protection validated; update page content
//
diff -r 28d9fbcd4f0d -r 2c20563245b2 includes/pageutils.php
--- a/includes/pageutils.php Sun Jan 25 20:35:32 2009 -0500
+++ b/includes/pageutils.php Sun Jan 25 21:21:07 2009 -0500
@@ -694,7 +694,7 @@
$i++;
$strings = Array();
$bool = Array();
- if ( $session->get_permissions('mod_comments') || $row['approved'] )
+ if ( $session->get_permissions('mod_comments') || $row['approved'] == COMMENT_APPROVED )
{
$list .= $i . ' : { \'comment\' : unescape(\''.rawurlencode($row['comment_data']).'\'), \'name\' : unescape(\''.rawurlencode($row['name']).'\'), \'subject\' : unescape(\''.rawurlencode($row['subject']).'\'), }, ';
diff -r 28d9fbcd4f0d -r 2c20563245b2 includes/plugins.php
--- a/includes/plugins.php Sun Jan 25 20:35:32 2009 -0500
+++ b/includes/plugins.php Sun Jan 25 21:21:07 2009 -0500
@@ -121,8 +121,9 @@
* @param array Deprecated.
*/
- function setHook($name, $opts = Array()) {
- if(isset($this->hook_list[$name]) && is_array($this->hook_list[$name]))
+ function setHook($name, $opts = Array())
+ {
+ if ( !empty($this->hook_list[$name]) && is_array($this->hook_list[$name]) )
{
return array(implode("\n", $this->hook_list[$name]));
}
@@ -149,8 +150,9 @@
*/
- function attachHook($name, $code) {
- if(!isset($this->hook_list[$name]))
+ function attachHook($name, $code)
+ {
+ if ( !isset($this->hook_list[$name]) )
{
$this->hook_list[$name] = Array();
}
diff -r 28d9fbcd4f0d -r 2c20563245b2 includes/sessions.php
--- a/includes/sessions.php Sun Jan 25 20:35:32 2009 -0500
+++ b/includes/sessions.php Sun Jan 25 21:21:07 2009 -0500
@@ -3716,7 +3716,7 @@
// Fetch private key
$dh_public = $_POST['dh_public_key'];
- if ( !preg_match('/^[0-9]+$/', $dh_public) )
+ if ( !ctype_digit($dh_public) )
{
throw new Exception('ERR_DH_KEY_NOT_INTEGER');
}
@@ -3888,7 +3888,7 @@
$dh_hash = $req['dh_secret_hash'];
// Check the key
- if ( !preg_match('/^[0-9]+$/', $dh_public) || !preg_match('/^[0-9]+$/', $req['dh_client_key']) )
+ if ( !ctype_digit($dh_public) || !ctype_digit($req['dh_client_key']) )
{
return array(
'mode' => 'error',
diff -r 28d9fbcd4f0d -r 2c20563245b2 includes/template.php
--- a/includes/template.php Sun Jan 25 20:35:32 2009 -0500
+++ b/includes/template.php Sun Jan 25 21:21:07 2009 -0500
@@ -611,36 +611,30 @@
{
$db->_die();
}
- $nc = $db->numrows();
- $nu = 0;
- $na = 0;
+ $num_comments = $db->numrows();
+ $approval_counts = array(COMMENT_UNAPPROVED => 0, COMMENT_APPROVED => 0, COMMENT_SPAM => 0);
while ( $r = $db->fetchrow() )
{
- if ( !$r['approved'] )
- {
- $nu++;
- }
- else
- {
- $na++;
- }
+ $approval_counts[$r['approved']]++;
}
$db->free_result();
- $n = ( $session->check_acl_scope('mod_comments', $local_namespace) && $perms->get_permissions('mod_comments') ) ? (string)$nc : (string)$na;
- if ( $session->check_acl_scope('mod_comments', $local_namespace) && $perms->get_permissions('mod_comments') && $nu > 0 )
+ // $n = ( $session->check_acl_scope('mod_comments', $local_namespace) && $perms->get_permissions('mod_comments') ) ? (string)$num_comments : (string)$na;
+ if ( $session->check_acl_scope('mod_comments', $local_namespace) && $perms->get_permissions('mod_comments') && ( $approval_counts[COMMENT_UNAPPROVED] + $approval_counts[COMMENT_SPAM] ) > 0 )
{
$subst = array(
- 'num_comments' => $nc,
- 'num_unapp' => $nu
+ 'num_comments' => $num_comments,
+ 'num_app' => $approval_counts[COMMENT_APPROVED],
+ 'num_unapp' => $approval_counts[COMMENT_UNAPPROVED],
+ 'num_spam' => $approval_counts[COMMENT_SPAM]
);
$btn_text = $lang->get('onpage_btn_discussion_unapp', $subst);
}
else
{
$subst = array(
- 'num_comments' => $nc
+ 'num_comments' => $num_comments
);
$btn_text = $lang->get('onpage_btn_discussion', $subst);
}
diff -r 28d9fbcd4f0d -r 2c20563245b2 index.php
--- a/index.php Sun Jan 25 20:35:32 2009 -0500
+++ b/index.php Sun Jan 25 21:21:07 2009 -0500
@@ -281,7 +281,7 @@
break;
case 'rollback':
$id = (isset($_GET['id'])) ? $_GET['id'] : false;
- if(!$id || !preg_match('#^([0-9]+)$#', $id)) die_friendly('Invalid action ID', 'The URL parameter "id" is not an integer. Exiting to prevent nasties like SQL injection, etc.
'); + if(!$id || !ctype_digit($id)) die_friendly('Invalid action ID', 'The URL parameter "id" is not an integer. Exiting to prevent nasties like SQL injection, etc.
'); $id = intval($id); diff -r 28d9fbcd4f0d -r 2c20563245b2 language/english/admin.json --- a/language/english/admin.json Sun Jan 25 20:35:32 2009 -0500 +++ b/language/english/admin.json Sun Jan 25 21:21:07 2009 -0500 @@ -279,6 +279,11 @@ field_comment_allow_guests_yes: 'Yes', field_comment_allow_guests_captcha: 'Require visual confirmation', field_comment_allow_guests_no: 'No (require login)', + field_comment_spam_policy: 'Spam policy:', + field_comment_spam_policy_hint: 'This requres a spam filtering plugin to be installed.', + field_comment_spam_policy_moderate: 'Moderate comments (default)', + field_comment_spam_policy_reject: 'Reject post', + field_comment_spam_policy_accept: 'Ignore and accept posts', // Section: disable site heading_disablesite: 'Disable all site access', diff -r 28d9fbcd4f0d -r 2c20563245b2 language/english/core.json --- a/language/english/core.json Sun Jan 25 20:35:32 2009 -0500 +++ b/language/english/core.json Sun Jan 25 21:21:07 2009 -0500 @@ -211,12 +211,21 @@ msg_count_unapp_one: 'However, there is 1 additional comment awaiting approval.', msg_count_unapp_plural: 'However, there are %num_unapp% additional comments awaiting approval.', + msg_foe_comment_hidden: 'Post from foe hidden.', + btn_display_foe_comment: 'Display post', + msg_note_unapp: '(Unapproved)', + msg_note_spam: '(Spam)', msg_ip_address: 'IP address:', msg_delete_confirm: 'Do you really want to delete this comment?', + err_captcha_wrong: 'The confirmation code you entered was incorrect.', + err_spamcheck_failed_rejected: 'Your comment was rejected because it appears to be spam.', + err_spamcheck_failed_flagged: 'Your comment was posted, but it appears to be spam and has been flagged as such for a moderator to review.', + ajax_err_generic_title: 'Error fetching comment data', + postform_title: 'Got something to say?', postform_blurb: 'If you have comments or suggestions on this article, you can shout it out here.', postform_blurb_unapp: 'Before your post will be visible to the public, a moderator will have to approve it.', @@ -250,7 +259,7 @@ lbl_page_external: 'external page', btn_discussion: 'discussion (%num_comments%)', - btn_discussion_unapp: 'discussion (%num_comments% total, %num_unapp% unapp.)', + btn_discussion_unapp: 'discussion (%num_comments%) [!]', btn_edit: 'edit this page', btn_viewsource: 'view source', btn_history: 'history', @@ -332,6 +341,7 @@ err_no_permission: 'You do not have permission to edit this page.', err_page_protected: 'This page is protected, and you do not have permission to edit protected pages.', err_captcha_wrong: 'The confirmation code you entered is incorrect.', + err_spamcheck_failed: 'Your edit was rejected because it looks like spam.', msg_editor_heading: 'Editing page', msg_saved: 'Your changes to this page have been saved.', diff -r 28d9fbcd4f0d -r 2c20563245b2 plugins/PrivateMessages.php --- a/plugins/PrivateMessages.php Sun Jan 25 20:35:32 2009 -0500 +++ b/plugins/PrivateMessages.php Sun Jan 25 21:21:07 2009 -0500 @@ -60,7 +60,7 @@ break; case 'View': $id = $argv[1]; - if ( !preg_match('#^([0-9]+)$#', $id) ) + if ( !ctype_digit($id) ) { die_friendly('Message error', 'Invalid message ID
'); } @@ -106,7 +106,7 @@ break; case 'Move': $id = $argv[1]; - if ( !preg_match('#^([0-9]+)$#', $id) ) + if ( !ctype_digit($id) ) { die_friendly('Message error', 'Invalid message ID
'); } @@ -136,7 +136,7 @@ break; case 'Delete': $id = $argv[1]; - if ( !preg_match('#^([0-9]+)$#', $id) ) + if ( !ctype_digit($id) ) { die_friendly('Message error', 'Invalid message ID
'); } @@ -365,7 +365,7 @@ break; case 'Edit': $id = $argv[1]; - if ( !preg_match('#^([0-9]+)$#', $id) ) + if ( !ctype_digit($id) ) { die_friendly('Message error', 'Invalid message ID
'); } diff -r 28d9fbcd4f0d -r 2c20563245b2 plugins/SpecialAdmin.php --- a/plugins/SpecialAdmin.php Sun Jan 25 20:35:32 2009 -0500 +++ b/plugins/SpecialAdmin.php Sun Jan 25 21:21:07 2009 -0500 @@ -304,6 +304,10 @@ if(isset($_POST['enable-comments'])) setConfig('enable_comments', '1'); else setConfig('enable_comments', '0'); setConfig('comments_need_login', $_POST['comments_need_login']); + if ( in_array($_POST['comment_spam_policy'], array('moderate', 'reject', 'accept')) ) + { + setConfig('comment_spam_policy', $_POST['comment_spam_policy']); + } // Powered by link if ( isset($_POST['enano_powered_link']) ) setConfig('powered_btn', '1'); @@ -350,10 +354,10 @@ setConfig('register_tou', RenderMan::preprocess_text($_POST['register_tou'], true, false)); // Account lockout policy - if ( preg_match('/^[0-9]+$/', $_POST['lockout_threshold']) ) + if ( ctype_digit($_POST['lockout_threshold']) ) setConfig('lockout_threshold', $_POST['lockout_threshold']); - if ( preg_match('/^[0-9]+$/', $_POST['lockout_duration']) ) + if ( ctype_digit($_POST['lockout_duration']) ) setConfig('lockout_duration', $_POST['lockout_duration']); if ( in_array($_POST['lockout_policy'], array('disable', 'captcha', 'lockout')) ) @@ -604,6 +608,27 @@ + +