From d6d1dfaa04642908ab488292ffd21fac36460c56 Mon Sep 17 00:00:00 2001 From: "Anthony G. Basile" Date: Tue, 1 Jan 2019 22:26:55 -0500 Subject: Update akismet 4.1 Signed-off-by: Anthony G. Basile --- plugins/akismet/akismet.php | 4 +- plugins/akismet/class.akismet-admin.php | 63 +++++++++++++++++++- plugins/akismet/class.akismet-cli.php | 94 +++++++++++++++++++++++++++++ plugins/akismet/class.akismet-rest-api.php | 95 ++++++++++++++++++++++++++++++ plugins/akismet/class.akismet.php | 1 - plugins/akismet/readme.txt | 11 +++- 6 files changed, 262 insertions(+), 6 deletions(-) diff --git a/plugins/akismet/akismet.php b/plugins/akismet/akismet.php index d4f21350..800dd724 100644 --- a/plugins/akismet/akismet.php +++ b/plugins/akismet/akismet.php @@ -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 protect your blog from spam. 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.0.8 +Version: 4.1 Author: Automattic Author URI: https://automattic.com/wordpress-plugins/ License: GPLv2 or later @@ -37,7 +37,7 @@ if ( !function_exists( 'add_action' ) ) { exit; } -define( 'AKISMET_VERSION', '4.0.8' ); +define( 'AKISMET_VERSION', '4.1' ); define( 'AKISMET__MINIMUM_WP_VERSION', '4.0' ); define( 'AKISMET__PLUGIN_DIR', plugin_dir_path( __FILE__ ) ); define( 'AKISMET_DELETE_LIMIT', 100000 ); diff --git a/plugins/akismet/class.akismet-admin.php b/plugins/akismet/class.akismet-admin.php index 1e806173..07a4d193 100644 --- a/plugins/akismet/class.akismet-admin.php +++ b/plugins/akismet/class.akismet-admin.php @@ -74,6 +74,9 @@ class Akismet_Admin { add_filter( 'akismet_comment_form_privacy_notice_url_display', array( 'Akismet_Admin', 'jetpack_comment_form_privacy_notice_url' ) ); add_filter( 'akismet_comment_form_privacy_notice_url_hide', array( 'Akismet_Admin', 'jetpack_comment_form_privacy_notice_url' ) ); } + + // priority=1 because we need ours to run before core's comment anonymizer runs, and that's registered at priority=10 + add_filter( 'wp_privacy_personal_data_erasers', array( 'Akismet_Admin', 'register_personal_data_eraser' ), 1 ); } public static function admin_init() { @@ -1049,7 +1052,7 @@ class Akismet_Admin { $message .= ' '; if ( $spam_count === 0 ) { - $message .= __( 'No comments were caught as spam.' ); + $message .= __( 'No comments were caught as spam.', 'akismet' ); } else { $message .= sprintf( _n( '%s comment was caught as spam.', '%s comments were caught as spam.', $spam_count, 'akismet' ), number_format( $spam_count ) ); @@ -1180,4 +1183,62 @@ class Akismet_Admin { public static function jetpack_comment_form_privacy_notice_url( $url ) { return str_replace( 'options-general.php', 'admin.php', $url ); } + + public static function register_personal_data_eraser( $erasers ) { + $erasers['akismet'] = array( + 'eraser_friendly_name' => __( 'Akismet', 'akismet' ), + 'callback' => array( 'Akismet_Admin', 'erase_personal_data' ), + ); + + return $erasers; + } + + /** + * When a user requests that their personal data be removed, Akismet has a duty to discard + * any personal data we store outside of the comment itself. Right now, that is limited + * to the copy of the comment we store in the akismet_as_submitted commentmeta. + * + * FWIW, this information would be automatically deleted after 15 days. + * + * @param $email_address string The email address of the user who has requested erasure. + * @param $page int This function can (and will) be called multiple times to prevent timeouts, + * so this argument is used for pagination. + * @return array + * @see https://developer.wordpress.org/plugins/privacy/adding-the-personal-data-eraser-to-your-plugin/ + */ + public static function erase_personal_data( $email_address, $page = 1 ) { + $items_removed = false; + + $number = 50; + $page = (int) $page; + + $comments = get_comments( + array( + 'author_email' => $email_address, + 'number' => $number, + 'paged' => $page, + 'order_by' => 'comment_ID', + 'order' => 'ASC', + ) + ); + + foreach ( (array) $comments as $comment ) { + $comment_as_submitted = get_comment_meta( $comment->comment_ID, 'akismet_as_submitted', true ); + + if ( $comment_as_submitted ) { + delete_comment_meta( $comment->comment_ID, 'akismet_as_submitted' ); + $items_removed = true; + } + } + + // Tell core if we have more comments to work on still + $done = count( $comments ) < $number; + + return array( + 'items_removed' => $items_removed, + 'items_retained' => false, // always false in this example + 'messages' => array(), // no messages in this example + 'done' => $done, + ); + } } diff --git a/plugins/akismet/class.akismet-cli.php b/plugins/akismet/class.akismet-cli.php index b0b48367..9cbe7a92 100644 --- a/plugins/akismet/class.akismet-cli.php +++ b/plugins/akismet/class.akismet-cli.php @@ -88,4 +88,98 @@ class Akismet_CLI extends WP_CLI_Command { WP_CLI::line( sprintf( _n( "%d comment could not be checked.", "%d comments could not be checked.", $total_counts['error'], 'akismet' ), number_format( $total_counts['error'] ) ) ); } } + + /** + * Fetches stats from the Akismet API. + * + * ## OPTIONS + * + * [] + * : The time period for which to retrieve stats. + * --- + * default: all + * options: + * - days + * - months + * - all + * --- + * + * [--format=] + * : Allows overriding the output of the command when listing connections. + * --- + * default: table + * options: + * - table + * - json + * - csv + * - yaml + * - count + * --- + * + * [--summary] + * : When set, will display a summary of the stats. + * + * ## EXAMPLES + * + * wp akismet stats + * wp akismet stats all + * wp akismet stats days + * wp akismet stats months + * wp akismet stats all --summary + */ + public function stats( $args, $assoc_args ) { + $api_key = Akismet::get_api_key(); + + if ( empty( $api_key ) ) { + WP_CLI::error( __( 'API key must be set to fetch stats.', 'akismet' ) ); + } + + switch ( $args[0] ) { + case 'days': + $interval = '60-days'; + break; + case 'months': + $interval = '6-months'; + break; + default: + $interval = 'all'; + break; + } + + $response = Akismet::http_post( + Akismet::build_query( array( + 'blog' => get_option( 'home' ), + 'key' => $api_key, + 'from' => $interval, + ) ), + 'get-stats' + ); + + if ( empty( $response[1] ) ) { + WP_CLI::error( __( 'Currently unable to fetch stats. Please try again.', 'akismet' ) ); + } + + $response_body = json_decode( $response[1], true ); + + if ( is_null( $response_body ) ) { + WP_CLI::error( __( 'Stats response could not be decoded.', 'akismet' ) ); + } + + if ( isset( $assoc_args['summary'] ) ) { + $keys = array( + 'spam', + 'ham', + 'missed_spam', + 'false_positives', + 'accuracy', + 'time_saved', + ); + + WP_CLI\Utils\format_items( $assoc_args['format'], array( $response_body ), $keys ); + } + else { + $stats = $response_body['breakdown']; + WP_CLI\Utils\format_items( $assoc_args['format'], $stats, array_keys( end( $stats ) ) ); + } + } } \ No newline at end of file diff --git a/plugins/akismet/class.akismet-rest-api.php b/plugins/akismet/class.akismet-rest-api.php index f97b710d..bf71998b 100644 --- a/plugins/akismet/class.akismet-rest-api.php +++ b/plugins/akismet/class.akismet-rest-api.php @@ -87,6 +87,48 @@ class Akismet_REST_API { 'callback' => array( 'Akismet_REST_API', 'get_stats' ), ) ) ); + + register_rest_route( 'akismet/v1', '/alert', array( + array( + 'methods' => WP_REST_Server::READABLE, + 'permission_callback' => array( 'Akismet_REST_API', 'remote_call_permission_callback' ), + 'callback' => array( 'Akismet_REST_API', 'get_alert' ), + 'args' => array( + 'key' => array( + 'required' => false, + 'type' => 'string', + 'sanitize_callback' => array( 'Akismet_REST_API', 'sanitize_key' ), + 'description' => __( 'A 12-character Akismet API key. Available at akismet.com/get/', 'akismet' ), + ), + ), + ), + array( + 'methods' => WP_REST_Server::EDITABLE, + 'permission_callback' => array( 'Akismet_REST_API', 'remote_call_permission_callback' ), + 'callback' => array( 'Akismet_REST_API', 'set_alert' ), + 'args' => array( + 'key' => array( + 'required' => false, + 'type' => 'string', + 'sanitize_callback' => array( 'Akismet_REST_API', 'sanitize_key' ), + 'description' => __( 'A 12-character Akismet API key. Available at akismet.com/get/', 'akismet' ), + ), + ), + ), + array( + 'methods' => WP_REST_Server::DELETABLE, + 'permission_callback' => array( 'Akismet_REST_API', 'remote_call_permission_callback' ), + 'callback' => array( 'Akismet_REST_API', 'delete_alert' ), + 'args' => array( + 'key' => array( + 'required' => false, + 'type' => 'string', + 'sanitize_callback' => array( 'Akismet_REST_API', 'sanitize_key' ), + 'description' => __( 'A 12-character Akismet API key. Available at akismet.com/get/', 'akismet' ), + ), + ), + ) + ) ); } /** @@ -231,6 +273,50 @@ class Akismet_REST_API { return rest_ensure_response( $stat_totals ); } + /** + * Get the current alert code and message. Alert codes are used to notify the site owner + * if there's a problem, like a connection issue between their site and the Akismet API, + * invalid requests being sent, etc. + * + * @param WP_REST_Request $request + * @return WP_Error|WP_REST_Response + */ + public static function get_alert( $request ) { + return rest_ensure_response( array( + 'code' => get_option( 'akismet_alert_code' ), + 'message' => get_option( 'akismet_alert_msg' ), + ) ); + } + + /** + * Update the current alert code and message by triggering a call to the Akismet server. + * + * @param WP_REST_Request $request + * @return WP_Error|WP_REST_Response + */ + public static function set_alert( $request ) { + delete_option( 'akismet_alert_code' ); + delete_option( 'akismet_alert_msg' ); + + // Make a request so the most recent alert code and message are retrieved. + Akismet::verify_key( Akismet::get_api_key() ); + + return self::get_alert( $request ); + } + + /** + * Clear the current alert code and message. + * + * @param WP_REST_Request $request + * @return WP_Error|WP_REST_Response + */ + public static function delete_alert( $request ) { + delete_option( 'akismet_alert_code' ); + delete_option( 'akismet_alert_msg' ); + + return self::get_alert( $request ); + } + private static function key_is_valid( $key ) { $response = Akismet::http_post( Akismet::build_query( @@ -253,6 +339,15 @@ class Akismet_REST_API { return current_user_can( 'manage_options' ); } + /** + * For calls that Akismet.com makes to the site to clear outdated alert codes, use the API key for authorization. + */ + public static function remote_call_permission_callback( $request ) { + $local_key = Akismet::get_api_key(); + + return $local_key && ( strtolower( $request->get_param( 'key' ) ) === strtolower( $local_key ) ); + } + public static function sanitize_interval( $interval, $request, $param ) { $interval = trim( $interval ); diff --git a/plugins/akismet/class.akismet.php b/plugins/akismet/class.akismet.php index 3a1307f4..9b70d9ec 100644 --- a/plugins/akismet/class.akismet.php +++ b/plugins/akismet/class.akismet.php @@ -762,7 +762,6 @@ class Akismet { || strtotime( $comment->comment_date_gmt ) < strtotime( "-15 days" ) // Comment is too old. || $comment->comment_approved !== "0" // Comment is no longer in the Pending queue ) { - echo "Deleting"; delete_comment_meta( $comment_id, 'akismet_error' ); delete_comment_meta( $comment_id, 'akismet_delayed_moderation_email' ); continue; diff --git a/plugins/akismet/readme.txt b/plugins/akismet/readme.txt index 4853f6fa..9473fb95 100644 --- a/plugins/akismet/readme.txt +++ b/plugins/akismet/readme.txt @@ -2,8 +2,8 @@ Contributors: matt, ryan, andy, mdawaffe, tellyworth, josephscott, lessbloat, eoigal, cfinke, automattic, jgs, procifer, stephdau Tags: akismet, comments, spam, antispam, anti-spam, anti spam, comment moderation, comment spam, contact form spam, spam comments Requires at least: 4.0 -Tested up to: 4.9.6 -Stable tag: 4.0.8 +Tested up to: 5.0 +Stable tag: 4.1 License: GPLv2 or later Akismet checks your comments and contact form submissions against our global database of spam to protect you and your site from malicious content. @@ -30,6 +30,13 @@ Upload the Akismet plugin to your blog, Activate it, then enter your [Akismet.co == Changelog == += 4.1 = +*Release Date - 12 November 2018* + +* Added a WP-CLI method for retrieving stats. +* Hooked into the new "Personal Data Eraser" functionality from WordPress 4.9.6. +* Added functionality to clear outdated alerts from Akismet.com. + = 4.0.8 = *Release Date - 19 June 2018* -- cgit v1.2.3-18-g5258