Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions plugins/akismet/akismet.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
Plugin Name: Akismet Anti-Spam
Plugin URI: https://akismet.com/
Description: Used by millions, Akismet is quite possibly the best way in the world to <strong>protect your blog from spam</strong>. It keeps your site protected even while you sleep. To get started: activate the Akismet plugin and then go to your Akismet Settings page to set up your API key.
Version: 4.1.8
Version: 4.1.9
Author: Automattic
Author URI: https://automattic.com/wordpress-plugins/
License: GPLv2 or later
Expand Down Expand Up @@ -37,7 +37,7 @@
exit;
}

define( 'AKISMET_VERSION', '4.1.8' );
define( 'AKISMET_VERSION', '4.1.9' );
define( 'AKISMET__MINIMUM_WP_VERSION', '4.0' );
define( 'AKISMET__PLUGIN_DIR', plugin_dir_path( __FILE__ ) );
define( 'AKISMET_DELETE_LIMIT', 100000 );
Expand Down
130 changes: 115 additions & 15 deletions plugins/akismet/class.akismet.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,14 @@ class Akismet {
private static $prevent_moderation_email_for_these_comments = array();
private static $last_comment_result = null;
private static $comment_as_submitted_allowed_keys = array( 'blog' => '', 'blog_charset' => '', 'blog_lang' => '', 'blog_ua' => '', 'comment_agent' => '', 'comment_author' => '', 'comment_author_IP' => '', 'comment_author_email' => '', 'comment_author_url' => '', 'comment_content' => '', 'comment_date_gmt' => '', 'comment_tags' => '', 'comment_type' => '', 'guid' => '', 'is_test' => '', 'permalink' => '', 'reporter' => '', 'site_domain' => '', 'submit_referer' => '', 'submit_uri' => '', 'user_ID' => '', 'user_agent' => '', 'user_id' => '', 'user_ip' => '' );
private static $is_rest_api_call = false;

/**
* Is the comment check happening in the context of an API call? Of if false, then it's during the POST that happens after filling out a comment form.
*
* @var type bool
*/
private static $is_api_call = false;

public static function init() {
if ( ! self::$initiated ) {
self::init_hooks();
Expand Down Expand Up @@ -131,7 +137,7 @@ public static function added_option( $option_name, $value ) {
}

public static function rest_auto_check_comment( $commentdata ) {
self::$is_rest_api_call = true;
self::$is_api_call = true;

return self::auto_check_comment( $commentdata );
}
Expand Down Expand Up @@ -240,7 +246,7 @@ public static function auto_check_comment( $commentdata ) {
update_option( 'akismet_spam_count', get_option( 'akismet_spam_count' ) + $incr );
}

if ( self::$is_rest_api_call ) {
if ( self::$is_api_call ) {
return new WP_Error( 'akismet_rest_comment_discarded', __( 'Comment discarded.', 'akismet' ) );
}
else {
Expand All @@ -250,7 +256,7 @@ public static function auto_check_comment( $commentdata ) {
die();
}
}
else if ( self::$is_rest_api_call ) {
else if ( self::$is_api_call ) {
// The way the REST API structures its calls, we can set the comment_approved value right away.
$commentdata['comment_approved'] = 'spam';
}
Expand Down Expand Up @@ -1420,16 +1426,100 @@ public static function pre_check_pingback( $method ) {
if ( $method !== 'pingback.ping' )
return;

// A lot of this code is tightly coupled with the IXR class because the xmlrpc_call action doesn't pass along any information besides the method name.
// This ticket should hopefully fix that: https://core.trac.wordpress.org/ticket/52524
// Until that happens, when it's a system.multicall, pre_check_pingback will be called once for every internal pingback call.
// Keep track of how many times this function has been called so we know which call to reference in the XML.
static $call_count = 0;

$call_count++;

global $wp_xmlrpc_server;

if ( !is_object( $wp_xmlrpc_server ) )
return false;

// Lame: tightly coupled with the IXR class.
$args = $wp_xmlrpc_server->message->params;

if ( !empty( $args[1] ) ) {
$post_id = url_to_postid( $args[1] );

self::$is_api_call = true;

$is_multicall = false;
$multicall_count = 0;

if ( 'system.multicall' === $wp_xmlrpc_server->message->methodName ) {
$is_multicall = true;

if ( 0 === $call_count ) {
// Only pass along the number of entries in the multicall the first time we see it.
$multicall_count = count( $wp_xmlrpc_server->message->params );
}

/*
* $wp_xmlrpc_server->message looks like this:
*
(
[message] =>
[messageType] => methodCall
[faultCode] =>
[faultString] =>
[methodName] => system.multicall
[params] => Array
(
[0] => Array
(
[methodName] => pingback.ping
[params] => Array
(
[0] => http://www.example.net/?p=1 // Site that created the pingback.
[1] => https://www.example.com/?p=1 // Post being pingback'd on this site.
)
)
[1] => Array
(
[methodName] => pingback.ping
[params] => Array
(
[0] => http://www.example.net/?p=1 // Site that created the pingback.
[1] => https://www.example.com/?p=2 // Post being pingback'd on this site.
)
)
)
)
*/

// Use the params from the nth pingback.ping call in the multicall.
$pingback_calls_found = 0;

foreach ( $wp_xmlrpc_server->message->params as $xmlrpc_action ) {
if ( 'pingback.ping' === $xmlrpc_action['methodName'] ) {
$pingback_calls_found++;
}

if ( $call_count === $pingback_calls_found ) {
$pingback_args = $xmlrpc_action['params'];
break;
}
}
} else {
/*
* $wp_xmlrpc_server->message looks like this:
*
(
[message] =>
[messageType] => methodCall
[faultCode] =>
[faultString] =>
[methodName] => pingback.ping
[params] => Array
(
[0] => http://www.example.net/?p=1 // Site that created the pingback.
[1] => https://www.example.com/?p=2 // Post being pingback'd on this site.
)
)
*/
$pingback_args = $wp_xmlrpc_server->message->params;
}

if ( ! empty( $pingback_args[1] ) ) {
$post_id = url_to_postid( $pingback_args[1] );

// If pingbacks aren't open on this post, we'll still check whether this request is part of a potential DDOS,
// but indicate to the server that pingbacks are indeed closed so we don't include this request in the user's stats,
Expand All @@ -1442,23 +1532,33 @@ public static function pre_check_pingback( $method ) {
$pingbacks_closed = true;
}

// Note: If is_multicall is true and multicall_count=0, then we know this is at least the 2nd pingback we've processed in this multicall.

$comment = array(
'comment_author_url' => $args[0],
'comment_author_url' => $pingback_args[0],
'comment_post_ID' => $post_id,
'comment_author' => '',
'comment_author_email' => '',
'comment_content' => '',
'comment_type' => 'pingback',
'akismet_pre_check' => '1',
'comment_pingback_target' => $args[1],
'comment_pingback_target' => $pingback_args[1],
'pingbacks_closed' => $pingbacks_closed ? '1' : '0',
'is_multicall' => $is_multicall,
'multicall_count' => $multicall_count,
);

$comment = Akismet::auto_check_comment( $comment );

if ( isset( $comment['akismet_result'] ) && 'true' == $comment['akismet_result'] ) {
// Lame: tightly coupled with the IXR classes. Unfortunately the action provides no context and no way to return anything.
if (
is_wp_error( $comment ) // This triggered a 'discard' directive.
|| ( isset( $comment['akismet_result'] ) && 'true' == $comment['akismet_result'] ) // It was just a normal spam response.
) {
// Sad: tightly coupled with the IXR classes. Unfortunately the action provides no context and no way to return anything.
$wp_xmlrpc_server->error( new IXR_Error( 0, 'Invalid discovery target' ) );

// Also note that if this was part of a multicall, a spam result will prevent the subsequent calls from being executed.
// This is probably fine, but it raises the bar for what should be acceptable as a false positive.
}
}
}
Expand Down
9 changes: 7 additions & 2 deletions plugins/akismet/readme.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@
Contributors: matt, ryan, andy, mdawaffe, tellyworth, josephscott, lessbloat, eoigal, cfinke, automattic, jgs, procifer, stephdau
Tags: comments, spam, antispam, anti-spam, contact form, anti spam, comment moderation, comment spam, contact form spam, spam comments
Requires at least: 4.6
Tested up to: 5.6
Stable tag: 4.1.8
Tested up to: 5.7
Stable tag: 4.1.9
License: GPLv2 or later

The best anti-spam protection to block spam comments and spam in a contact form. The most trusted antispam solution for WordPress and WooCommerce.
Expand All @@ -30,6 +30,11 @@ Upload the Akismet plugin to your blog, activate it, and then enter your Akismet

== Changelog ==

= 4.1.9 =
*Release Date - 2 March 2021*

* Improved handling of pingbacks in XML-RPC multicalls

= 4.1.8 =
*Release Date - 6 January 2021*

Expand Down