Skip to content
Merged
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
2 changes: 1 addition & 1 deletion features/checksum-plugin.feature
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@ Feature: Validate checksums for WordPress plugins
duplicate-post
wptouch
"""
And a wp-content/mu-plugins/hide-qm-plugin.php file:
And a wp-content/mu-plugins/hide-dp-plugin.php file:
"""
<?php
/**
Expand Down
57 changes: 17 additions & 40 deletions src/Checksum_Core_Command.php
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
<?php

use WP_CLI\Utils;
use WP_CLI\WpOrgApi;

/**
* Verifies core file integrity by comparing to published checksums.
Expand Down Expand Up @@ -30,6 +31,9 @@ class Checksum_Core_Command extends Checksum_Base_Command {
* [--locale=<locale>]
* : Verify checksums against a specific locale of WordPress.
*
* [--insecure]
* : Retry downloads without certificate validation if TLS handshake fails. Note: This makes the request vulnerable to a MITM attack.
*
* ## EXAMPLES
*
* # Verify checksums
Expand All @@ -54,30 +58,34 @@ class Checksum_Core_Command extends Checksum_Base_Command {
* @when before_wp_load
*/
public function __invoke( $args, $assoc_args ) {
$wp_version = '';
$wp_local_package = '';
$wp_version = '';
$locale = '';

if ( ! empty( $assoc_args['version'] ) ) {
$wp_version = $assoc_args['version'];
}

if ( ! empty( $assoc_args['locale'] ) ) {
$wp_local_package = $assoc_args['locale'];
$locale = $assoc_args['locale'];
}

if ( empty( $wp_version ) ) {
$details = self::get_wp_details();
$wp_version = $details['wp_version'];

if ( empty( $wp_local_package ) ) {
$wp_local_package = $details['wp_local_package'];
if ( empty( $locale ) ) {
$locale = $details['wp_local_package'];
}
}

$checksums = self::get_core_checksums(
$wp_version,
! empty( $wp_local_package ) ? $wp_local_package : 'en_US'
);
$insecure = (bool) Utils\get_flag_value( $assoc_args, 'insecure', false );
$wp_org_api = new WpOrgApi( [ 'insecure' => $insecure ] );

try {
$checksums = $wp_org_api->get_core_checksums( $wp_version, empty( $locale ) ? 'en_US' : $locale );
} catch ( Exception $exception ) {
WP_CLI::error( $exception );
}

if ( ! is_array( $checksums ) ) {
WP_CLI::error( "Couldn't get checksums from WordPress.org." );
Expand Down Expand Up @@ -192,35 +200,4 @@ private static function find_var( $var_name, $code ) {

return trim( $value, "'" );
}

/**
* Security copy of the core function with Requests - Gets the checksums for the given version of WordPress.
*
* @param string $version Version string to query.
* @param string $locale Locale to query.
* @return bool|array False on failure. An array of checksums on success.
*/
private static function get_core_checksums( $version, $locale ) {
$query = http_build_query( compact( 'version', 'locale' ), null, '&' );
$url = "https://api.wordpress.org/core/checksums/1.0/?{$query}";

$options = [ 'timeout' => 30 ];

$headers = [ 'Accept' => 'application/json' ];
$response = Utils\http_request( 'GET', $url, null, $headers, $options );

if ( ! $response->success || 200 !== (int) $response->status_code ) {
return false;
}

$body = trim( $response->body );
$body = json_decode( $body, true );

if ( ! is_array( $body ) || ! isset( $body['checksums'] ) || ! is_array( $body['checksums'] ) ) {
return false;
}

return $body['checksums'];
}

}
65 changes: 16 additions & 49 deletions src/Checksum_Plugin_Command.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
use WP_CLI\Fetchers;
use WP_CLI\Formatter;
use WP_CLI\Utils;
use WP_CLI\WpOrgApi;

/**
* Verifies plugin file integrity by comparing to published checksums.
Expand Down Expand Up @@ -59,6 +60,9 @@ class Checksum_Plugin_Command extends Checksum_Base_Command {
* - count
* ---
*
* [--insecure]
* : Retry downloads without certificate validation if TLS handshake fails. Note: This makes the request vulnerable to a MITM attack.
*
* ## EXAMPLES
*
* # Verify the checksums of all installed plugins
Expand All @@ -71,10 +75,11 @@ class Checksum_Plugin_Command extends Checksum_Base_Command {
*/
public function __invoke( $args, $assoc_args ) {

$fetcher = new Fetchers\UnfilteredPlugin();
$all = Utils\get_flag_value( $assoc_args, 'all', false );
$strict = Utils\get_flag_value( $assoc_args, 'strict', false );
$plugins = $fetcher->get_many( $all ? $this->get_all_plugin_names() : $args );
$fetcher = new Fetchers\UnfilteredPlugin();
$all = (bool) Utils\get_flag_value( $assoc_args, 'all', false );
$strict = (bool) Utils\get_flag_value( $assoc_args, 'strict', false );
$insecure = (bool) Utils\get_flag_value( $assoc_args, 'insecure', false );
$plugins = $fetcher->get_many( $all ? $this->get_all_plugin_names() : $args );

if ( empty( $plugins ) && ! $all ) {
WP_CLI::error( 'You need to specify either one or more plugin slugs to check or use the --all flag to check all plugins.' );
Expand All @@ -91,7 +96,13 @@ public function __invoke( $args, $assoc_args ) {
continue;
}

$checksums = $this->get_plugin_checksums( $plugin->name, $version );
$wp_org_api = new WpOrgApi( [ 'insecure' => $insecure ] );

try {
$checksums = $wp_org_api->get_plugin_checksums( $plugin->name, $version );
} catch ( Exception $exception ) {
$checksums = false;
}

if ( false === $checksums ) {
WP_CLI::warning( "Could not retrieve the checksums for version {$version} of plugin {$plugin->name}, skipping." );
Expand Down Expand Up @@ -180,50 +191,6 @@ private function get_plugin_version( $path ) {
return $this->plugins_data[ $path ]['Version'];
}

/**
* Gets the checksums for the given version of plugin.
*
* @param string $version Version string to query.
* @param string $plugin plugin string to query.
*
* @return bool|array False on failure. An array of checksums on success.
*/
private function get_plugin_checksums( $plugin, $version ) {
$url = str_replace(
array(
'{slug}',
'{version}',
),
array(
$plugin,
$version,
),
$this->url_template
);

$options = array(
'timeout' => 30,
);

$headers = array(
'Accept' => 'application/json',
);
$response = Utils\http_request( 'GET', $url, null, $headers, $options );

if ( ! $response->success || 200 !== $response->status_code ) {
return false;
}

$body = trim( $response->body );
$body = json_decode( $body, true );

if ( ! is_array( $body ) || ! isset( $body['files'] ) || ! is_array( $body['files'] ) ) {
return false;
}

return $body['files'];
}

/**
* Gets the names of all installed plugins.
*
Expand Down