Plugin Directory

Changeset 3056338

Timestamp:
03/21/2024 08:16:28 PM (5 months ago)
Author:
cfinke
Message:

Akismet: Refactor pre_check_pingback.

Previously, this function was hamstrung by a deficiency in WordPress core (https://core.trac.wordpress.org/ticket/52524), where the xmlrpc_action action call did not pass in any context around the action other than the method name.

This meant that for multicall XML-RPC calls, we had to keep track on our own of which call was being referenced, making the pre_check_pingback function more complex than it should have needed to be.

That deficiency was corrected in WordPress 5.7, and because our minimum supported version is now 5.8, we can take advantage of that change.

Location:
akismet/trunk
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • akismet/trunk/akismet.php

    r3055719 r3056338  
    77Plugin URI: https://akismet.com/
    88Description: Used by millions, Akismet is quite possibly the best way in the world to <strong>protect your blog from spam</strong>. Akismet Anti-spam 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.
    9 Version: 5.3.2
     9Version: 5.3.
    1010Requires at least: 5.8
    1111Requires PHP: 5.6.20
     
    4040}
    4141
    42 define( 'AKISMET_VERSION', '5.3.2' );
     42define( 'AKISMET_VERSION', '5.3.' );
    4343define( 'AKISMET__MINIMUM_WP_VERSION', '5.8' );
    4444define( 'AKISMET__PLUGIN_DIR', plugin_dir_path( __FILE__ ) );
  • akismet/trunk/class.akismet.php

    r3036615 r3056338  
    5454
    5555        // Run this early in the pingback call, before doing a remote fetch of the source uri
    56         add_action( 'xmlrpc_call', array( 'Akismet', 'pre_check_pingback' ) );
     56        add_action( 'xmlrpc_call', array( 'Akismet', 'pre_check_pingback' ) );
    5757
    5858        // Jetpack compatibility
     
    16801680    }
    16811681
    1682     public static function pre_check_pingback( $method ) {
    1683         $pingback_args = array();
    1684         if ( $method !== 'pingback.ping' )
     1682    /**
     1683     * Check pingbacks for spam before they're saved to the DB.
     1684     *
     1685     * @param string $method The XML-RPC method that was called.
     1686     * @param array $args This and the $server arg are marked as optional since plugins might still be
     1687     *                    calling do_action( 'xmlrpc_action', [...] ) without the arguments that were added in WP 5.7.
     1688     * @param wp_xmlrpc_server $server
     1689     */
     1690    public static function pre_check_pingback( $method, $args = array(), $server = null ) {
     1691        if ( $method !== 'pingback.ping' ) {
    16851692            return;
    1686 
    1687         // 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.
    1688         // This ticket should hopefully fix that: https://core.trac.wordpress.org/ticket/52524
    1689         // Until that happens, when it's a system.multicall, pre_check_pingback will be called once for every internal pingback call.
    1690         // Keep track of how many times this function has been called so we know which call to reference in the XML.
    1691         static $call_count = 0;
    1692 
    1693         $call_count++;
    1694 
    1695         global $wp_xmlrpc_server;
    1696 
    1697         if ( !is_object( $wp_xmlrpc_server ) )
    1698             return false;
    1699 
    1700         $is_multicall = false;
    1701         $multicall_count = 0;
    1702 
    1703         if ( 'system.multicall' === $wp_xmlrpc_server->message->methodName ) {
    1704             $is_multicall = true;
    1705 
    1706             if ( 0 === $call_count ) {
    1707                 // Only pass along the number of entries in the multicall the first time we see it.
    1708                 $multicall_count = is_countable( $wp_xmlrpc_server->message->params ) ? count( $wp_xmlrpc_server->message->params ) : 0;
    1709             }
    1710 
    1711             /*
    1712              * $wp_xmlrpc_server->message looks like this:
    1713              *
    1714                 (
    1715                     [message] =>
    1716                     [messageType] => methodCall
    1717                     [faultCode] =>
    1718                     [faultString] =>
    1719                     [methodName] => system.multicall
    1720                     [params] => Array
    1721                         (
    1722                             [0] => Array
    1723                                 (
    1724                                     [methodName] => pingback.ping
    1725                                     [params] => Array
    1726                                         (
    1727                                             [0] => http://www.example.net/?p=1 // Site that created the pingback.
    1728                                             [1] => https://www.example.com/?p=1 // Post being pingback'd on this site.
    1729                                         )
    1730                                 )
    1731                             [1] => Array
    1732                                 (
    1733                                     [methodName] => pingback.ping
    1734                                     [params] => Array
    1735                                         (
    1736                                             [0] => http://www.example.net/?p=1 // Site that created the pingback.
    1737                                             [1] => https://www.example.com/?p=2 // Post being pingback'd on this site.
    1738                                         )
    1739                                 )
    1740                         )
    1741                 )
    1742              */
    1743 
    1744             // Use the params from the nth pingback.ping call in the multicall.
    1745             $pingback_calls_found = 0;
    1746 
    1747             foreach ( $wp_xmlrpc_server->message->params as $xmlrpc_action ) {
    1748                 if ( 'pingback.ping' === $xmlrpc_action['methodName'] ) {
    1749                     $pingback_calls_found++;
    1750                 }
    1751 
    1752                 if ( $call_count === $pingback_calls_found ) {
    1753                     $pingback_args = $xmlrpc_action['params'];
    1754                     break;
    1755                 }
    1756             }
    1757         } else {
    1758             /*
    1759              * $wp_xmlrpc_server->message looks like this:
    1760              *
    1761                 (
    1762                     [message] =>
    1763                     [messageType] => methodCall
    1764                     [faultCode] =>
    1765                     [faultString] =>
    1766                     [methodName] => pingback.ping
    1767                     [params] => Array
    1768                         (
    1769                             [0] => http://www.example.net/?p=1 // Site that created the pingback.
    1770                             [1] => https://www.example.com/?p=2 // Post being pingback'd on this site.
    1771                         )
    1772                 )
    1773              */
    1774             $pingback_args = $wp_xmlrpc_server->message->params;
    1775         }
    1776 
    1777         if ( ! empty( $pingback_args[1] ) ) {
    1778             $post_id = url_to_postid( $pingback_args[1] );
     1693        }
     1694
     1695        /*
     1696         * $args looks like this:
     1697         *
     1698         * Array
     1699         * (
     1700         *     [0] => http://www.example.net/?p=1 // Site that created the pingback.
     1701         *     [1] => https://www.example.com/?p=2 // Post being pingback'd on this site.
     1702         * )
     1703         */
     1704
     1705        if ( ! is_null( $server ) && ! empty( $args[1] ) ) {
     1706            $is_multicall = false;
     1707            $multicall_count = 0;
     1708
     1709            if ( 'system.multicall' === $server->message->methodName ) {
     1710                $is_multicall = true;
     1711                $multicall_count = is_countable( $server->message->params ) ? count( $server->message->params ) : 0;
     1712            }
     1713
     1714            $post_id = url_to_postid( $args[1] );
    17791715
    17801716            // If pingbacks aren't open on this post, we'll still check whether this request is part of a potential DDOS,
     
    17821718            // since the user has already done their part by disabling pingbacks.
    17831719            $pingbacks_closed = false;
    1784            
     1720
    17851721            $post = get_post( $post_id );
    1786            
     1722
    17871723            if ( ! $post || ! pings_open( $post ) ) {
    17881724                $pingbacks_closed = true;
    17891725            }
    17901726
    1791             // 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.
    1792 
    17931727            $comment = array(
    1794                 'comment_author_url' => $pingback_args[0],
     1728                'comment_author_url' => $args[0],
    17951729                'comment_post_ID' => $post_id,
    17961730                'comment_author' => '',
     
    17991733                'comment_type' => 'pingback',
    18001734                'akismet_pre_check' => '1',
    1801                 'comment_pingback_target' => $pingback_args[1],
     1735                'comment_pingback_target' => $args[1],
    18021736                'pingbacks_closed' => $pingbacks_closed ? '1' : '0',
    18031737                'is_multicall' => $is_multicall,
     
    18091743            if ( isset( $comment['akismet_result'] ) && 'true' == $comment['akismet_result'] ) {
    18101744                // Sad: tightly coupled with the IXR classes. Unfortunately the action provides no context and no way to return anything.
    1811                 $wp_xmlrpc_server->error( new IXR_Error( 0, 'Invalid discovery target' ) );
     1745                $server->error( new IXR_Error( 0, 'Invalid discovery target' ) );
    18121746
    18131747                // Also note that if this was part of a multicall, a spam result will prevent the subsequent calls from being executed.
Note: See TracChangeset for help on using the changeset viewer.