Skip to content

Commit

Permalink
Version 1.8.3. XSS vulnerability fixed. Other minor improvements.
Browse files Browse the repository at this point in the history
  • Loading branch information
doiftrue committed Oct 13, 2024
1 parent 2d15331 commit a99af72
Show file tree
Hide file tree
Showing 4 changed files with 76 additions and 77 deletions.
73 changes: 31 additions & 42 deletions Kama_Spamblock.php
Original file line number Diff line number Diff line change
Expand Up @@ -21,21 +21,16 @@ class Kama_Spamblock {
*/
private $process_comment_types = [ '', 'comment' ];

/**
* @param string $plug_file
*/
public function __construct( $plug_file ) {

$this->opt = new Kama_Spamblock_Options();
public function __construct( string $plug_file, Kama_Spamblock_Options $opt ) {
$this->opt = $opt;

$this->plug_file = $plug_file;
$this->plug_dir = dirname( $plug_file );
$this->plug_dir = dirname( $plug_file );

$this->process_comment_types = apply_filters( 'kama_spamblock__process_comment_types', $this->process_comment_types );
}

public function init_plugin() {

if( ! defined( 'DOING_AJAX' ) ){
load_plugin_textdomain( 'kama-spamblock', false, basename( $this->plug_dir ) . '/languages' );
}
Expand All @@ -56,22 +51,18 @@ private function init_front() {
}

if( ! wp_doing_ajax() && ! is_admin() ){
add_action( 'wp_footer', [ $this, 'main_js' ], 99 );
add_action( 'wp_footer', [ $this, 'main_js' ], 0 );
}

$this->nonce = self::make_nonce( date( 'jn' ) . $this->opt->unique_code );
$this->nonce = self::make_hash( date( 'jn' ) . $this->opt->unique_code );

add_filter( 'preprocess_comment', [ $this, 'block_spam' ], 0 );
}

/**
* Check and block comment if needed.
*
* @param array $commentdata
*
* @return array
*/
public function block_spam( $commentdata ) {
public function block_spam( array $commentdata ): array {

$this->block_pings_trackbacks( $commentdata );
$this->block_regular_comment( $commentdata );
Expand Down Expand Up @@ -101,21 +92,18 @@ private function block_regular_comment( $commentdata ) {
return;
}

$ksbn_code = isset( $_POST['ksbn_code'] ) ? trim( $_POST['ksbn_code'] ) : '';
$ksbn_code = trim( $_POST['ksbn_code'] ?? '' );

if( self::make_nonce( $ksbn_code ) !== $this->nonce ){
if( self::make_hash( $ksbn_code ) !== $this->nonce ){
/** @noinspection ForgottenDebugOutputInspection */
wp_die( $this->block_form() );
}
}

/**
* @param string $key
*
* @return string
* Creates hash from specified key if it's not hashed yet.
*/
private static function make_nonce( $key ) {
// maybe already md5
private static function make_hash( string $key ): string {
return preg_match( '/^[a-f0-9]{32}$/', $key ) ? $key : md5( $key );
}

Expand All @@ -126,64 +114,65 @@ public function main_js() {
global $post;

// note: is_singular() may work incorrectly
if( ! empty( $post ) && ( 'open' !== $post->comment_status ) && is_singular() ){
if( $post && ( 'open' !== $post->comment_status ) && is_singular() ){
return;
}
?>
<script id="kama_spamblock">
(function(){

const catch_submit = function( ev ){

let sbmt = ev.target.closest( '#<?= esc_html( $this->opt->sibmit_button_id ) ?>' );
window.addEventListener( 'DOMContentLoaded', function() {
document.addEventListener( 'mousedown', handleSubmit );
document.addEventListener( 'touchstart', handleSubmit );
document.addEventListener( 'keypress', handleSubmit );

function handleSubmit( ev ){
let sbmt = ev.target.closest( '#<?= esc_html( sanitize_html_class( $this->opt->sibmit_button_id ) ) ?>' );
if( ! sbmt ){
return;
}

let input = document.createElement( 'input' );
let date = new Date();

input.value = ''+ date.getUTCDate() + (date.getUTCMonth() + 1) + '<?= esc_html( $this->opt->unique_code ) ?>';
input.value = ''+ date.getUTCDate() + (date.getUTCMonth() + 1) + '<?= esc_html( Kama_Spamblock_Options::sanitize_uniue_code( $this->opt->unique_code ) ) ?>';
input.name = 'ksbn_code';
input.type = 'hidden';

sbmt.parentNode.insertBefore( input, sbmt );
}

document.addEventListener( 'mousedown', catch_submit );
document.addEventListener( 'keypress', catch_submit );
})()
} );
</script>
<?php
}

/**
* Output form when comment has been blocked.
*
* @return string
* Gets Form HTML for blocked comment.
*/
private function block_form() {
private function block_form(): string {
ob_start();
?>
<h1><?= __( 'Antispam block your comment!', 'kama-spamblock' ) ?></h1>

<form method="post" action="<?= site_url( '/wp-comments-post.php' ) ?>">
<form method="POST" action="<?= site_url( '/wp-comments-post.php' ) ?>">
<p>
<?= sprintf(
__( 'Copy %1$s to the field %2$s and press button', 'kama-spamblock' ),
'<code style="background:rgba(255,255,255,.2);">' . $this->nonce . '</code>',
'<code style="background:rgba(255,255,255,.2);">' . esc_html( $this->nonce ) . '</code>',
'<input type="text" name="ksbn_code" value="" style="width:150px; border:1px solid #ccc; border-radius:3px; padding:.3em;" />'
) ?>
</p>

<input type="submit" style="height:70px; width:100%; font-size:150%; cursor:pointer; border:none; color:#fff; background:#555;" value="<?= __( 'Send comment again', 'kama-spamblock' ) ?>" />

<?php
unset( $_POST['ksbn_code'] );

foreach( $_POST as $key => $val ){
echo sprintf( '<textarea style="display:none;" name="%s">%s</textarea>', $key, esc_textarea( stripslashes( $val ) ) );
if( $key === 'ksbn_code' ){
continue;
}

echo sprintf( '<textarea style="display:none;" name="%s">%s</textarea>',
esc_attr( $key ),
esc_textarea( stripslashes( $val ) )
);
}
?>
</form>
Expand Down
32 changes: 22 additions & 10 deletions Kama_Spamblock_Options.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,21 +12,29 @@ class Kama_Spamblock_Options {

public function __construct() {
$opt = array_merge( $this->default_options(), get_option( self::OPT_NAME, [] ) );
$this->check_empty_unique_code( $opt['unique_code'] );

$opt = apply_filters( 'kama_spamblock__options', $opt );
$opt = (object) $opt;

$this->unique_code = $opt->unique_code;
$this->sibmit_button_id = $opt->sibmit_button_id;
$this->unique_code = $opt['unique_code'];
$this->sibmit_button_id = $opt['sibmit_button_id'];
}

/**
* @return string[]
* @return void
*/
public function default_options(){
private function check_empty_unique_code( string $code ) {
if( ! $code ){
$opt = get_option( self::OPT_NAME, [] );
$opt['unique_code'] = wp_generate_password( 10, false );
update_option( self::OPT_NAME, $opt );
}
}

public function default_options(): array {
return [
'sibmit_button_id' => 'submit',
'unique_code' => 'uniq9065',
'unique_code' => '', // default value will be auto-generated
];
}

Expand All @@ -36,7 +44,7 @@ public function admin_options() {
add_settings_field(
self::OPT_NAME . '_field',
__( 'Kama Spamblock settings', 'kama-spamblock' ),
[ $this, 'options_field', ],
[ $this, 'options_fields', ],
'discussion',
'kama_spamblock'
);
Expand All @@ -51,7 +59,8 @@ public static function sanitize_opt( $opts ) {
$val = sanitize_html_class( $val );
}
elseif( 'unique_code' === $key ){
$val = preg_replace( '~[^A-Za-z0-9*%$#@!_-]~', '', $val );
$val = self::sanitize_uniue_code( $val );
$val || $val = wp_generate_password( 10, false );
}
else{
$val = sanitize_text_field( $val );
Expand All @@ -61,7 +70,11 @@ public static function sanitize_opt( $opts ) {
return $opts;
}

public function options_field() {
public static function sanitize_uniue_code( string $code ) {
return preg_replace( '~[^A-Za-z0-9*%$#@!_-]~', '', $code );
}

public function options_fields() {
?>
<p>
<input type="text" name="<?= self::OPT_NAME ?>[sibmit_button_id]" value="<?= esc_attr( $this->sibmit_button_id ) ?>" />
Expand All @@ -75,7 +88,6 @@ public function options_field() {
}

public static function settings_link( $links ) {

$links[] = sprintf( '<a href="%s">%s</a>', admin_url( '/options-discussion.php#wpfooter' ), __( 'Settings', 'kama-spamblock' ) );

return $links;
Expand Down
14 changes: 5 additions & 9 deletions kama-spamblock.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,29 +11,25 @@
* Author URI: https://wp-kama.ru
* Plugin URI: https://wp-kama.ru/95
*
* Requires PHP: 5.6
* Requires at least: 2.7
* Requires PHP: 7.0
* Requires at least: 5.7
*
* Version: 1.8.2
* Version: 1.8.3
*/

require_once __DIR__ . '/Kama_Spamblock.php';
require_once __DIR__ . '/Kama_Spamblock_Options.php';

add_action( 'init', 'kama_spamblock_init', 11 );


function kama_spamblock_init() {
return kama_spamblock()->init_plugin();
}

/**
* @return Kama_Spamblock
*/
function kama_spamblock() {
function kama_spamblock(): Kama_Spamblock {
static $inst;

$inst || $inst = new Kama_Spamblock( __FILE__ );
$inst || $inst = new Kama_Spamblock( __FILE__, new Kama_Spamblock_Options() );

return $inst;
}
34 changes: 18 additions & 16 deletions readme.txt
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
=== Plugin Name ===
Stable tag: trunk
Contributors: Tkama
Tested up to: 6.4.1
Tested up to: 6.6.2
License: GPLv2 or later
License URI: http://www.gnu.org/licenses/gpl-2.0.html
Tags: spam, spammer, autospam, spamblock, antispam, anti-spam, protect, comments, ping, trackback, bot, robot, human, captcha, invisible

A lightweight and discreet solution to prevent automatic spam when a spam comment is posted. Additionally, it conducts checks on pings and trackbacks to verify genuine backlinks.
Light and invisible method to block auto-spam when a spam comment is posted. Pings and trackbacks check for real backlinks.



Expand All @@ -20,9 +20,9 @@ Even if you are using an external comment system like Disqus, installing Kama Sp

== Screenshots ==

1. Plugin settings on standart WordPress <code>Settings > Discussion</code> page.
1. Plugin settings on standard WordPress <code>Settings > Discussion</code> page.

2. Spam alert, when spam comment detected or if user have javascript disabled in his browser. This alert allows send comment once again, when it was blocked in any nonstandard cases.
2. Spam alert, when spam comment is detected or if the user has JavaScript disabled in their browser. This alert allows sending the comment once again when it was blocked in any nonstandard cases.



Expand All @@ -34,9 +34,12 @@ No! The plugin is invisible to users. You should navigate to the 'Discussion' se




== Changelog ==

= 1.8.3 =
* FIX: XSS vulnerability fixed. Thanks to [Wordfence](https://www.wordfence.com/) for the report.
* IMP: Other minor improvements.

= 1.8.2 =
* Minor refactoring.

Expand All @@ -48,33 +51,32 @@ No! The plugin is invisible to users. You should navigate to the 'Discussion' se
* FIX: WordPress 5.5 support.

= 1.7.5 =
* FIX: bug with uniq code comparation
* minor code fixes

* FIX: bug with unique code comparison.
* Minor code fixes.

= 1.7.4 =
* CHG: change sanitize-options-on-save function - sanitize_key() to sanitize_html_class() - it's not so hard but hard enough...
* CHG: 'sanitize_setting' function call. Seems it hasn't have back-compat for wordpress versions less then 4.7
* CHG: changed sanitize-options-on-save function - sanitize_key() to sanitize_html_class() - it's not so hard but hard enough...
* CHG: 'sanitize_setting' function call. Seems it doesn't have back-compat for WordPress versions less than 4.7.

= 1.7.3 =
* FIX: options fix of 1.7.2
* FIX: options fix of 1.7.2.

= 1.7.2 =
* CHG: move translation to translation.wordpress.org
* CHG: moved translation to translation.wordpress.org.
* ADD: new 'unique code' option.
* IMP: some code improvements.

= 1.7.0 =
* BUG: Last UP bug fix...

= 1.6.0 =
* CHG: check logic is little change in order to correctly work with page cache plugins
* CHG: check logic is slightly changed in order to work correctly with page cache plugins.

= 1.5.2 =
* ADD: delete is_singular check for themes where this check work wrong. Now plugin JS showen in all pages
* ADD: deleted is_singular check for themes where this check works incorrectly. Now plugin JS is shown on all pages.

= 1.5.1 =
* ADD: js include from numbers of hooks. If there is no "wp_footer" hook in theme
* ADD: JS included from a number of hooks if there is no "wp_footer" hook in the theme.

= 1.5.0 =
* ADD: Russian localization
* ADD: Russian localization.

0 comments on commit a99af72

Please sign in to comment.