From f48fe77dea220797205fa46287980dcd424555df Mon Sep 17 00:00:00 2001 From: Alain Schlesser Date: Wed, 22 Nov 2017 20:39:59 +0100 Subject: [PATCH 01/47] Rename Checksum_Command into Core_Command. --- checksum-command.php | 2 +- src/{Checksum_Command.php => Core_Command.php} | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) rename src/{Checksum_Command.php => Core_Command.php} (99%) diff --git a/checksum-command.php b/checksum-command.php index 6ab66ca41..939a3170a 100644 --- a/checksum-command.php +++ b/checksum-command.php @@ -9,4 +9,4 @@ require_once $autoload; } -WP_CLI::add_command( 'checksum', 'Checksum_Command' ); +WP_CLI::add_command( 'checksum core', 'Core_Command' ); diff --git a/src/Checksum_Command.php b/src/Core_Command.php similarity index 99% rename from src/Checksum_Command.php rename to src/Core_Command.php index 347cc67a0..f7d010972 100644 --- a/src/Checksum_Command.php +++ b/src/Core_Command.php @@ -7,7 +7,7 @@ * * @package wp-cli */ -class Checksum_Command extends WP_CLI_Command { +class Core_Command extends WP_CLI_Command { private static function _read( $url ) { $headers = array('Accept' => 'application/json'); From cf5f83b5a8134b85f3cc2498e363bdddc9907a8d Mon Sep 17 00:00:00 2001 From: Alain Schlesser Date: Wed, 22 Nov 2017 20:42:29 +0100 Subject: [PATCH 02/47] Make Core command executable. --- src/Core_Command.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Core_Command.php b/src/Core_Command.php index f7d010972..14c57f7bd 100644 --- a/src/Core_Command.php +++ b/src/Core_Command.php @@ -77,7 +77,7 @@ private function get_download_offer( $locale ) { * * @when before_wp_load */ - public function core( $args, $assoc_args ) { + public function __invoke( $args, $assoc_args ) { global $wp_version, $wp_local_package; if ( ! empty( $assoc_args['version'] ) ) { From ce1ffd0327ddd2210e0fdb42be7bab36f26d8733 Mon Sep 17 00:00:00 2001 From: Alain Schlesser Date: Wed, 22 Nov 2017 20:44:36 +0100 Subject: [PATCH 03/47] Add checksum namespace. --- checksum-command.php | 3 +++ src/Checksum_Namespace.php | 10 ++++++++++ 2 files changed, 13 insertions(+) create mode 100644 src/Checksum_Namespace.php diff --git a/checksum-command.php b/checksum-command.php index 939a3170a..6501368bb 100644 --- a/checksum-command.php +++ b/checksum-command.php @@ -10,3 +10,6 @@ } WP_CLI::add_command( 'checksum core', 'Core_Command' ); +if ( class_exists( 'WP_CLI\Dispatcher\CommandNamespace' ) ) { + WP_CLI::add_command( 'checksum', 'Checksum_Namespace' ); +} diff --git a/src/Checksum_Namespace.php b/src/Checksum_Namespace.php new file mode 100644 index 000000000..ace1174ff --- /dev/null +++ b/src/Checksum_Namespace.php @@ -0,0 +1,10 @@ + Date: Wed, 22 Nov 2017 20:56:57 +0100 Subject: [PATCH 04/47] Add separate plugin command and provide base class. --- checksum-command.php | 3 ++- src/Checksum_Base_Command.php | 12 ++++++++++++ ..._Command.php => Checksum_Core_Command.php} | 5 ++--- src/Checksum_Namespace.php | 2 ++ src/Checksum_Plugin_Command.php | 19 +++++++++++++++++++ 5 files changed, 37 insertions(+), 4 deletions(-) create mode 100644 src/Checksum_Base_Command.php rename src/{Core_Command.php => Checksum_Core_Command.php} (98%) create mode 100644 src/Checksum_Plugin_Command.php diff --git a/checksum-command.php b/checksum-command.php index 6501368bb..3f6f78be1 100644 --- a/checksum-command.php +++ b/checksum-command.php @@ -9,7 +9,8 @@ require_once $autoload; } -WP_CLI::add_command( 'checksum core', 'Core_Command' ); +WP_CLI::add_command( 'checksum core', 'Checksum_Core_Command' ); +WP_CLI::add_command( 'checksum plugin', 'Checksum_Plugin_Command' ); if ( class_exists( 'WP_CLI\Dispatcher\CommandNamespace' ) ) { WP_CLI::add_command( 'checksum', 'Checksum_Namespace' ); } diff --git a/src/Checksum_Base_Command.php b/src/Checksum_Base_Command.php new file mode 100644 index 000000000..c20e71922 --- /dev/null +++ b/src/Checksum_Base_Command.php @@ -0,0 +1,12 @@ + 'application/json'); @@ -32,7 +32,6 @@ private function get_download_offer( $locale ) { return $offer; } - /** * Verify WordPress files against WordPress.org's checksums. * diff --git a/src/Checksum_Namespace.php b/src/Checksum_Namespace.php index ace1174ff..b692300f5 100644 --- a/src/Checksum_Namespace.php +++ b/src/Checksum_Namespace.php @@ -4,6 +4,8 @@ /** * Verifies file integrity by comparing to published checksums. + * + * @package wp-cli */ class Checksum_Namespace extends CommandNamespace { diff --git a/src/Checksum_Plugin_Command.php b/src/Checksum_Plugin_Command.php new file mode 100644 index 000000000..14663f68d --- /dev/null +++ b/src/Checksum_Plugin_Command.php @@ -0,0 +1,19 @@ + Date: Thu, 23 Nov 2017 01:26:58 +0530 Subject: [PATCH 05/47] created plugin function same as core --- src/Checksum_Command.php | 64 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 64 insertions(+) diff --git a/src/Checksum_Command.php b/src/Checksum_Command.php index 347cc67a0..cae2255bc 100644 --- a/src/Checksum_Command.php +++ b/src/Checksum_Command.php @@ -140,6 +140,70 @@ public function core( $args, $assoc_args ) { WP_CLI::error( "WordPress install doesn't verify against checksums." ); } } + + public function plugin( $args, $assoc_args ) { + global $wp_version, $wp_local_package; + + if ( ! empty( $assoc_args['version'] ) ) { + $wp_version = $assoc_args['version']; + } + + if ( ! empty( $assoc_args['locale'] ) ) { + $wp_local_package = $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']; + } + } + + $checksums = self::get_core_checksums( $wp_version, + ! empty( $wp_local_package ) ? $wp_local_package : 'en_US' ); + + if ( ! is_array( $checksums ) ) { + WP_CLI::error( "Couldn't get checksums from WordPress.org." ); + } + + $has_errors = false; + foreach ( $checksums as $file => $checksum ) { + // Skip files which get updated + if ( 'wp-content' == substr( $file, 0, 10 ) ) { + continue; + } + + if ( ! file_exists( ABSPATH . $file ) ) { + WP_CLI::warning( "File doesn't exist: {$file}" ); + $has_errors = true; + continue; + } + + $md5_file = md5_file( ABSPATH . $file ); + if ( $md5_file !== $checksum ) { + WP_CLI::warning( "File doesn't verify against checksum: {$file}" ); + $has_errors = true; + } + } + + $core_checksums_files = array_filter( array_keys( $checksums ), array( $this, 'only_core_files_filter' ) ); + $core_files = $this->get_wp_core_files(); + $additional_files = array_diff( $core_files, $core_checksums_files ); + + if ( ! empty( $additional_files ) ) { + foreach ( $additional_files as $additional_file ) { + WP_CLI::warning( "File should not exist: {$additional_file}" ); + } + } + + if ( ! $has_errors ) { + WP_CLI::success( "WordPress install verifies against checksums." ); + } else { + WP_CLI::error( "WordPress install doesn't verify against checksums." ); + } + } private function get_wp_core_files() { $core_files = array(); From 5f6f759038b3c7fdb6c173947c489b74a894c11d Mon Sep 17 00:00:00 2001 From: Alain Schlesser Date: Wed, 22 Nov 2017 21:00:21 +0100 Subject: [PATCH 06/47] Remove copied plugin method again. --- src/Checksum_Core_Command.php | 64 ----------------------------------- 1 file changed, 64 deletions(-) diff --git a/src/Checksum_Core_Command.php b/src/Checksum_Core_Command.php index afa0aa7e1..f533ad339 100644 --- a/src/Checksum_Core_Command.php +++ b/src/Checksum_Core_Command.php @@ -139,70 +139,6 @@ public function __invoke( $args, $assoc_args ) { WP_CLI::error( "WordPress install doesn't verify against checksums." ); } } - - public function plugin( $args, $assoc_args ) { - global $wp_version, $wp_local_package; - - if ( ! empty( $assoc_args['version'] ) ) { - $wp_version = $assoc_args['version']; - } - - if ( ! empty( $assoc_args['locale'] ) ) { - $wp_local_package = $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']; - } - } - - $checksums = self::get_core_checksums( $wp_version, - ! empty( $wp_local_package ) ? $wp_local_package : 'en_US' ); - - if ( ! is_array( $checksums ) ) { - WP_CLI::error( "Couldn't get checksums from WordPress.org." ); - } - - $has_errors = false; - foreach ( $checksums as $file => $checksum ) { - // Skip files which get updated - if ( 'wp-content' == substr( $file, 0, 10 ) ) { - continue; - } - - if ( ! file_exists( ABSPATH . $file ) ) { - WP_CLI::warning( "File doesn't exist: {$file}" ); - $has_errors = true; - continue; - } - - $md5_file = md5_file( ABSPATH . $file ); - if ( $md5_file !== $checksum ) { - WP_CLI::warning( "File doesn't verify against checksum: {$file}" ); - $has_errors = true; - } - } - - $core_checksums_files = array_filter( array_keys( $checksums ), array( $this, 'only_core_files_filter' ) ); - $core_files = $this->get_wp_core_files(); - $additional_files = array_diff( $core_files, $core_checksums_files ); - - if ( ! empty( $additional_files ) ) { - foreach ( $additional_files as $additional_file ) { - WP_CLI::warning( "File should not exist: {$additional_file}" ); - } - } - - if ( ! $has_errors ) { - WP_CLI::success( "WordPress install verifies against checksums." ); - } else { - WP_CLI::error( "WordPress install doesn't verify against checksums." ); - } - } private function get_wp_core_files() { $core_files = array(); From 8d1406bdcb660353053a1f65cfe88735134c1300 Mon Sep 17 00:00:00 2001 From: Alain Schlesser Date: Wed, 22 Nov 2017 21:18:09 +0100 Subject: [PATCH 07/47] Add basic feature tests. --- features/checksum-plugin.feature | 40 ++++++++++++++++++++++++++++++++ src/Checksum_Plugin_Command.php | 8 +++++++ 2 files changed, 48 insertions(+) create mode 100644 features/checksum-plugin.feature diff --git a/features/checksum-plugin.feature b/features/checksum-plugin.feature new file mode 100644 index 000000000..5bc38459e --- /dev/null +++ b/features/checksum-plugin.feature @@ -0,0 +1,40 @@ +Feature: Validate checksums for WordPress plugins + + Scenario: Verify plugin checksums + Given a WP install + + When I run `wp plugin install https://downloads.wordpress.org/plugins/test-plugin-3.test-tag.zip` + Then STDOUT should not be empty + And STDERR should be empty + + When I run `wp checksum plugin test-plugin-3` + Then STDOUT should be: + """ + Success: Plugin verifies against checksums. + """ + + Scenario: Modified plugin doesn't verify + Given a WP install + + When I run `wp plugin install https://downloads.wordpress.org/plugins/test-plugin-3.test-tag.zip` + Then STDOUT should not be empty + And STDERR should be empty + + Given "WordPress" replaced with "Wordpress" in the wp-content/plugins/test-plugin-3/README.md file + + When I run `wp checksum plugin test-plugin-3` + Then STDERR should be: + """ + Warning: File doesn't verify against checksum: README.md + Error: Plugin doesn't verify against checksums. + """ + + When I run `rm wp-content/plugins/test-plugin-3/README.md` + Then STDERR should be empty + + When I try `wp checksum plugin test-plugin-3` + Then STDERR should be: + """ + Warning: File doesn't exist: README.md + Error: Plugin doesn't verify against checksums. + """ diff --git a/src/Checksum_Plugin_Command.php b/src/Checksum_Plugin_Command.php index 14663f68d..dde6d0eb7 100644 --- a/src/Checksum_Plugin_Command.php +++ b/src/Checksum_Plugin_Command.php @@ -15,5 +15,13 @@ class Checksum_Plugin_Command extends Checksum_Base_Command { * @when before_wp_load */ public function __invoke( $args, $assoc_args ) { + + $has_errors = false; + + if ( ! $has_errors ) { + WP_CLI::success( 'Plugin verifies against checksums.' ); + } else { + WP_CLI::error( 'Plugin doesn\'t verify against checksums.' ); + } } } From 98acdebdf487af64db88e4c4c07e680ad2c1a262 Mon Sep 17 00:00:00 2001 From: Alain Schlesser Date: Wed, 22 Nov 2017 21:31:05 +0100 Subject: [PATCH 08/47] Provide basic plugin argument parsing. --- src/Checksum_Plugin_Command.php | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/src/Checksum_Plugin_Command.php b/src/Checksum_Plugin_Command.php index dde6d0eb7..9accc5e02 100644 --- a/src/Checksum_Plugin_Command.php +++ b/src/Checksum_Plugin_Command.php @@ -16,12 +16,28 @@ class Checksum_Plugin_Command extends Checksum_Base_Command { */ public function __invoke( $args, $assoc_args ) { + $fetcher = new \WP_CLI\Fetchers\Plugin(); + $plugins = $fetcher->get_many( $args ); + $has_errors = false; + // Iterate over plugins + // - fetch plugin's checksums from wordpress.org server + // - Iterate over plugin's files + // - Verify plugin file checksum against downloaded checksum + if ( ! $has_errors ) { - WP_CLI::success( 'Plugin verifies against checksums.' ); + WP_CLI::success( + count( $plugins ) > 1 + ? 'Plugins verify against checksums.' + : 'Plugin verifies against checksums.' + ); } else { - WP_CLI::error( 'Plugin doesn\'t verify against checksums.' ); + WP_CLI::error( + count( $plugins ) > 1 + ? 'One or more plugins don\'t verify against checksums.' + : 'Plugin doesn\'t verify against checksums.' + ); } } } From b13e467ef517374ad5f2673a35917f748e548750 Mon Sep 17 00:00:00 2001 From: Alain Schlesser Date: Wed, 22 Nov 2017 21:32:56 +0100 Subject: [PATCH 09/47] Provide "--all" paramter parsing. --- src/Checksum_Plugin_Command.php | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Checksum_Plugin_Command.php b/src/Checksum_Plugin_Command.php index 9accc5e02..38280089f 100644 --- a/src/Checksum_Plugin_Command.php +++ b/src/Checksum_Plugin_Command.php @@ -18,6 +18,7 @@ public function __invoke( $args, $assoc_args ) { $fetcher = new \WP_CLI\Fetchers\Plugin(); $plugins = $fetcher->get_many( $args ); + $all = \WP_CLI\Utils\get_flag_value( $assoc_args, 'all', false ); $has_errors = false; From 7a37c7e912f8e6450661ef5b42469e50b803e598 Mon Sep 17 00:00:00 2001 From: Alain Schlesser Date: Wed, 22 Nov 2017 21:33:39 +0100 Subject: [PATCH 10/47] Add arguments to synopsis. --- src/Checksum_Plugin_Command.php | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/Checksum_Plugin_Command.php b/src/Checksum_Plugin_Command.php index 38280089f..5bc911454 100644 --- a/src/Checksum_Plugin_Command.php +++ b/src/Checksum_Plugin_Command.php @@ -12,6 +12,14 @@ class Checksum_Plugin_Command extends Checksum_Base_Command { /** * Verify plugin files against WordPress.org's checksums. * + * ## OPTIONS + * + * [...] + * : One or more plugins to verify. + * + * [--all] + * : If set, all plugins will be verified. + * * @when before_wp_load */ public function __invoke( $args, $assoc_args ) { From 3321bc7b68dcdfa8d26154d5558d5e95aeff85d3 Mon Sep 17 00:00:00 2001 From: Alain Schlesser Date: Wed, 22 Nov 2017 21:43:27 +0100 Subject: [PATCH 11/47] Move _read method into base class (and make it protected). --- src/Checksum_Base_Command.php | 9 +++++++++ src/Checksum_Core_Command.php | 10 ---------- 2 files changed, 9 insertions(+), 10 deletions(-) diff --git a/src/Checksum_Base_Command.php b/src/Checksum_Base_Command.php index c20e71922..e1f1e7184 100644 --- a/src/Checksum_Base_Command.php +++ b/src/Checksum_Base_Command.php @@ -9,4 +9,13 @@ */ class Checksum_Base_Command extends WP_CLI_Command { + protected static function _read( $url ) { + $headers = array('Accept' => 'application/json'); + $response = Utils\http_request( 'GET', $url, null, $headers, array( 'timeout' => 30 ) ); + if ( 200 === $response->status_code ) { + return $response->body; + } else { + WP_CLI::error( "Couldn't fetch response from {$url} (HTTP code {$response->status_code})." ); + } + } } diff --git a/src/Checksum_Core_Command.php b/src/Checksum_Core_Command.php index f533ad339..b3585ac41 100644 --- a/src/Checksum_Core_Command.php +++ b/src/Checksum_Core_Command.php @@ -9,16 +9,6 @@ */ class Checksum_Core_Command extends Checksum_Base_Command { - private static function _read( $url ) { - $headers = array('Accept' => 'application/json'); - $response = Utils\http_request( 'GET', $url, null, $headers, array( 'timeout' => 30 ) ); - if ( 200 === $response->status_code ) { - return $response->body; - } else { - WP_CLI::error( "Couldn't fetch response from {$url} (HTTP code {$response->status_code})." ); - } - } - private function get_download_offer( $locale ) { $out = unserialize( self::_read( 'https://api.wordpress.org/core/version-check/1.6/?locale=' . $locale ) ); From 2e62bd130af7ba01fb88274c5be9da35777786a8 Mon Sep 17 00:00:00 2001 From: Alain Schlesser Date: Wed, 22 Nov 2017 22:00:43 +0100 Subject: [PATCH 12/47] Move recursive file retrieval into base class. --- src/Checksum_Base_Command.php | 58 ++++++++++++++++++++++++++++++++--- src/Checksum_Core_Command.php | 35 +++++++-------------- 2 files changed, 65 insertions(+), 28 deletions(-) diff --git a/src/Checksum_Base_Command.php b/src/Checksum_Base_Command.php index e1f1e7184..3a0c0eebd 100644 --- a/src/Checksum_Base_Command.php +++ b/src/Checksum_Base_Command.php @@ -9,13 +9,63 @@ */ class Checksum_Base_Command extends WP_CLI_Command { + /** + * Read a remote file and return its contents. + * + * @param string $url URL of the remote file to read. + * + * @return mixed + */ protected static function _read( $url ) { - $headers = array('Accept' => 'application/json'); - $response = Utils\http_request( 'GET', $url, null, $headers, array( 'timeout' => 30 ) ); + $headers = array( 'Accept' => 'application/json' ); + $response = Utils\http_request( 'GET', $url, null, $headers, + array( 'timeout' => 30 ) ); if ( 200 === $response->status_code ) { return $response->body; - } else { - WP_CLI::error( "Couldn't fetch response from {$url} (HTTP code {$response->status_code})." ); } + WP_CLI::error( "Couldn't fetch response from {$url} (HTTP code {$response->status_code})." ); + } + + /** + * Recursively get the list of files for a given path. + * + * @param string $path Root parse to start the recursive traversal in. + * + * @return array + */ + protected function get_files( $path ) { + $filtered_files = array(); + try { + $files = new RecursiveIteratorIterator( + new RecursiveDirectoryIterator( $path, + RecursiveDirectoryIterator::SKIP_DOTS ), + RecursiveIteratorIterator::CHILD_FIRST + ); + foreach ( $files as $file_info ) { + $pathname = substr( $file_info->getPathname(), + strlen( $path ) ); + if ( $file_info->isFile() && $this->filter_file( $pathname ) ) { + $filtered_files[] = str_replace( $path, '', + $file_info->getPathname() ); + } + } + } catch ( Exception $e ) { + WP_CLI::error( $e->getMessage() ); + } + + return $filtered_files; + } + + /** + * Whether to include the file in the verification or not. + * + * Can be overridden in subclasses. + * + * @param string $filepath Path to a file. + * + * @return bool + */ + protected function filter_file( $filepath ) { + return true; } } diff --git a/src/Checksum_Core_Command.php b/src/Checksum_Core_Command.php index b3585ac41..d65f75230 100644 --- a/src/Checksum_Core_Command.php +++ b/src/Checksum_Core_Command.php @@ -113,8 +113,8 @@ public function __invoke( $args, $assoc_args ) { } } - $core_checksums_files = array_filter( array_keys( $checksums ), array( $this, 'only_core_files_filter' ) ); - $core_files = $this->get_wp_core_files(); + $core_checksums_files = array_filter( array_keys( $checksums ), array( $this, 'filter_file' ) ); + $core_files = $this->get_files( ABSPATH ); $additional_files = array_diff( $core_files, $core_checksums_files ); if ( ! empty( $additional_files ) ) { @@ -130,28 +130,15 @@ public function __invoke( $args, $assoc_args ) { } } - private function get_wp_core_files() { - $core_files = array(); - try { - $files = new RecursiveIteratorIterator( - new RecursiveDirectoryIterator( ABSPATH, RecursiveDirectoryIterator::SKIP_DOTS ), - RecursiveIteratorIterator::CHILD_FIRST - ); - foreach ( $files as $file_info ) { - $pathname = substr( $file_info->getPathname(), strlen( ABSPATH ) ); - if ( $file_info->isFile() && ( 0 === strpos( $pathname, 'wp-admin/' ) || 0 === strpos( $pathname, 'wp-includes/' ) ) ) { - $core_files[] = str_replace( ABSPATH, '', $file_info->getPathname() ); - } - } - } catch( Exception $e ) { - WP_CLI::error( $e->getMessage() ); - } - - return $core_files; - } - - private function only_core_files_filter( $file ) { - return ( 0 === strpos( $file, 'wp-admin/' ) || 0 === strpos( $file, 'wp-includes/' ) ); + /** + * Whether to include the file in the verification or not. + * + * @param string $filepath Path to a file. + * + * @return bool + */ + protected function filter_file( $filepath ) { + return ( 0 === strpos( $filepath, 'wp-admin/' ) || 0 === strpos( $filepath, 'wp-includes/' ) ); } /** From 6ad5600e533874060ec729da07f36c7540a064c5 Mon Sep 17 00:00:00 2001 From: Alain Schlesser Date: Wed, 22 Nov 2017 22:02:09 +0100 Subject: [PATCH 13/47] Load WordPress to execute the command, as we need access to plugin data. --- src/Checksum_Plugin_Command.php | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/Checksum_Plugin_Command.php b/src/Checksum_Plugin_Command.php index 5bc911454..6c030973a 100644 --- a/src/Checksum_Plugin_Command.php +++ b/src/Checksum_Plugin_Command.php @@ -19,8 +19,6 @@ class Checksum_Plugin_Command extends Checksum_Base_Command { * * [--all] * : If set, all plugins will be verified. - * - * @when before_wp_load */ public function __invoke( $args, $assoc_args ) { From a3cec9c66b107d70b5fd636c056d79592f9332da Mon Sep 17 00:00:00 2001 From: Sagar Prajapati Date: Fri, 24 Nov 2017 18:52:43 +0530 Subject: [PATCH 14/47] added get_plugin_checksums function --- src/Checksum_Plugin_Command.php | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/src/Checksum_Plugin_Command.php b/src/Checksum_Plugin_Command.php index 6c030973a..e5f9d52c4 100644 --- a/src/Checksum_Plugin_Command.php +++ b/src/Checksum_Plugin_Command.php @@ -47,4 +47,35 @@ public function __invoke( $args, $assoc_args ) { ); } } + + /** + * 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 static function get_plugin_checksums( $plugin, $version ) { + $url = 'https://api.wordpress.org/plugin/checksums/1.0/?' . http_build_query( compact( 'plugin', 'version' ), null, '&' ); + + $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['checksums'] ) || ! is_array( $body['checksums'] ) ) + return false; + + return $body['checksums']; + } } From 3be5b279dd7636e58cf07e49eec93837c274ebaf Mon Sep 17 00:00:00 2001 From: Alain Schlesser Date: Tue, 28 Nov 2017 23:54:57 +0100 Subject: [PATCH 15/47] Use a URL template string to build the endpoint URL. --- src/Checksum_Plugin_Command.php | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/src/Checksum_Plugin_Command.php b/src/Checksum_Plugin_Command.php index e5f9d52c4..cf3ba0794 100644 --- a/src/Checksum_Plugin_Command.php +++ b/src/Checksum_Plugin_Command.php @@ -9,6 +9,13 @@ */ class Checksum_Plugin_Command extends Checksum_Base_Command { + /** + * URL template that points to the API endpoint to use. + * + * @var string + */ + private $url_template = 'https://downloads.wordpress.org/plugin-checksums/{slug}/{version}.json'; + /** * Verify plugin files against WordPress.org's checksums. * @@ -55,8 +62,18 @@ public function __invoke( $args, $assoc_args ) { * @param string $plugin plugin string to query. * @return bool|array False on failure. An array of checksums on success. */ - private static function get_plugin_checksums( $plugin, $version ) { - $url = 'https://api.wordpress.org/plugin/checksums/1.0/?' . http_build_query( compact( 'plugin', 'version' ), null, '&' ); + private function get_plugin_checksums( $plugin, $version ) { + $url = str_replace( + array( + '{slug}', + '{version}' + ), + array( + $plugin, + $version + ), + $this->url_template + ); $options = array( 'timeout' => 30 From aa4360e90115f34e3dafec38e39f755a78db74e6 Mon Sep 17 00:00:00 2001 From: Alain Schlesser Date: Tue, 28 Nov 2017 23:59:30 +0100 Subject: [PATCH 16/47] Always use braces for conditional code. --- src/Checksum_Plugin_Command.php | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/Checksum_Plugin_Command.php b/src/Checksum_Plugin_Command.php index cf3ba0794..d7f6ff4ea 100644 --- a/src/Checksum_Plugin_Command.php +++ b/src/Checksum_Plugin_Command.php @@ -84,14 +84,16 @@ private function get_plugin_checksums( $plugin, $version ) { ); $response = Utils\http_request( 'GET', $url, null, $headers, $options ); - if ( ! $response->success || 200 != $response->status_code ) + if ( ! $response->success || 200 != $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'] ) ) + if ( ! is_array( $body ) || ! isset( $body['checksums'] ) || ! is_array( $body['checksums'] ) ) { return false; + } return $body['checksums']; } From 13bfff367e2f6019dcb0e432da697c1286ccc61b Mon Sep 17 00:00:00 2001 From: Alain Schlesser Date: Wed, 29 Nov 2017 00:01:47 +0100 Subject: [PATCH 17/47] Adapt to latest JSON file structure. --- src/Checksum_Plugin_Command.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Checksum_Plugin_Command.php b/src/Checksum_Plugin_Command.php index d7f6ff4ea..9b750c6f1 100644 --- a/src/Checksum_Plugin_Command.php +++ b/src/Checksum_Plugin_Command.php @@ -91,10 +91,10 @@ private function get_plugin_checksums( $plugin, $version ) { $body = trim( $response->body ); $body = json_decode( $body, true ); - if ( ! is_array( $body ) || ! isset( $body['checksums'] ) || ! is_array( $body['checksums'] ) ) { + if ( ! is_array( $body ) || ! isset( $body['files'] ) || ! is_array( $body['files'] ) ) { return false; } - return $body['checksums']; + return $body['files']; } } From 498185094eae4427b831c94f3cafb7fe7b6286f1 Mon Sep 17 00:00:00 2001 From: Alain Schlesser Date: Wed, 29 Nov 2017 00:11:02 +0100 Subject: [PATCH 18/47] Iterate over plugins and fetch checksums. --- src/Checksum_Plugin_Command.php | 46 ++++++++++++++++++++++++--------- 1 file changed, 34 insertions(+), 12 deletions(-) diff --git a/src/Checksum_Plugin_Command.php b/src/Checksum_Plugin_Command.php index 9b750c6f1..8504e1eb3 100644 --- a/src/Checksum_Plugin_Command.php +++ b/src/Checksum_Plugin_Command.php @@ -31,14 +31,22 @@ public function __invoke( $args, $assoc_args ) { $fetcher = new \WP_CLI\Fetchers\Plugin(); $plugins = $fetcher->get_many( $args ); - $all = \WP_CLI\Utils\get_flag_value( $assoc_args, 'all', false ); + $all = \WP_CLI\Utils\get_flag_value( $assoc_args, 'all', false ); $has_errors = false; - // Iterate over plugins - // - fetch plugin's checksums from wordpress.org server - // - Iterate over plugin's files - // - Verify plugin file checksum against downloaded checksum + foreach ( $plugins as $plugin ) { + $version = $this->get_plugin_version( $plugin->name ); + + if ( false === $version ) { + continue; + } + + $checksums = $this->get_plugin_checksums( $plugin->name, $version ); + + // - Iterate over plugin's files + // - Verify plugin file checksum against downloaded checksum + } if ( ! $has_errors ) { WP_CLI::success( @@ -55,36 +63,50 @@ public function __invoke( $args, $assoc_args ) { } } + /** + * Get the currently installed version for a given plugin. + * + * @param string $plugin Plugin to get the version for. + * + * @return string|false Installed version of the plugin, or false if not + * found. + */ + private function get_plugin_version( $plugin ) { + // TODO: Fetch the currently installed version of the given plugin. + return '1.5.2'; + } + /** * Gets the checksums for the given version of plugin. * * @param string $version Version string to query. - * @param string $plugin plugin 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}' + '{version}', ), array( $plugin, - $version + $version, ), $this->url_template ); $options = array( - 'timeout' => 30 + 'timeout' => 30, ); - $headers = array( - 'Accept' => 'application/json' + $headers = array( + 'Accept' => 'application/json', ); $response = Utils\http_request( 'GET', $url, null, $headers, $options ); - if ( ! $response->success || 200 != $response->status_code ) { + if ( ! $response->success || 200 !== $response->status_code ) { return false; } From b8df360391896cd28d1e60de741137eb8b545f86 Mon Sep 17 00:00:00 2001 From: Alain Schlesser Date: Wed, 29 Nov 2017 00:16:51 +0100 Subject: [PATCH 19/47] Fetch actual version string from plugin data. --- src/Checksum_Plugin_Command.php | 24 +++++++++++++++++++----- 1 file changed, 19 insertions(+), 5 deletions(-) diff --git a/src/Checksum_Plugin_Command.php b/src/Checksum_Plugin_Command.php index 8504e1eb3..3948a5ddf 100644 --- a/src/Checksum_Plugin_Command.php +++ b/src/Checksum_Plugin_Command.php @@ -16,6 +16,13 @@ class Checksum_Plugin_Command extends Checksum_Base_Command { */ private $url_template = 'https://downloads.wordpress.org/plugin-checksums/{slug}/{version}.json'; + /** + * Cached plugin data for all installed plugins. + * + * @var array|null + */ + private $plugins_data; + /** * Verify plugin files against WordPress.org's checksums. * @@ -36,7 +43,7 @@ public function __invoke( $args, $assoc_args ) { $has_errors = false; foreach ( $plugins as $plugin ) { - $version = $this->get_plugin_version( $plugin->name ); + $version = $this->get_plugin_version( $plugin->file ); if ( false === $version ) { continue; @@ -66,14 +73,21 @@ public function __invoke( $args, $assoc_args ) { /** * Get the currently installed version for a given plugin. * - * @param string $plugin Plugin to get the version for. + * @param string $path Relative path to plugin file to get the version for. * * @return string|false Installed version of the plugin, or false if not * found. */ - private function get_plugin_version( $plugin ) { - // TODO: Fetch the currently installed version of the given plugin. - return '1.5.2'; + private function get_plugin_version( $path ) { + if ( ! isset( $this->plugins_data ) ) { + $this->plugins_data = get_plugins(); + } + + if ( ! array_key_exists( $path, $this->plugins_data ) ) { + return false; + } + + return $this->plugins_data[ $path ]['Version']; } /** From 49c06c6b43657e672e8a83ef5e6fd669a6e3577e Mon Sep 17 00:00:00 2001 From: Alain Schlesser Date: Wed, 29 Nov 2017 00:29:52 +0100 Subject: [PATCH 20/47] Scaffold the remaining logic. --- src/Checksum_Plugin_Command.php | 41 +++++++++++++++++++++++++++++---- 1 file changed, 37 insertions(+), 4 deletions(-) diff --git a/src/Checksum_Plugin_Command.php b/src/Checksum_Plugin_Command.php index 3948a5ddf..3248d6707 100644 --- a/src/Checksum_Plugin_Command.php +++ b/src/Checksum_Plugin_Command.php @@ -40,7 +40,7 @@ public function __invoke( $args, $assoc_args ) { $plugins = $fetcher->get_many( $args ); $all = \WP_CLI\Utils\get_flag_value( $assoc_args, 'all', false ); - $has_errors = false; + $errors = array(); foreach ( $plugins as $plugin ) { $version = $this->get_plugin_version( $plugin->file ); @@ -51,11 +51,17 @@ public function __invoke( $args, $assoc_args ) { $checksums = $this->get_plugin_checksums( $plugin->name, $version ); - // - Iterate over plugin's files - // - Verify plugin file checksum against downloaded checksum + $files = $this->get_plugin_files( $plugin->file ); + + foreach ( $files as $file ) { + $result = $this->check_file( $file, $checksums ); + if ( true !== $result ) { + $errors[ $plugin ][ $file ] = $result; + } + } } - if ( ! $has_errors ) { + if ( empty( $errors ) ) { WP_CLI::success( count( $plugins ) > 1 ? 'Plugins verify against checksums.' @@ -133,4 +139,31 @@ private function get_plugin_checksums( $plugin, $version ) { return $body['files']; } + + /** + * Get the list of files that are part of the given plugin. + * + * @param string $path Relative path to the main plugin file. + * + * @return array Array of files with their relative paths. + */ + private function get_plugin_files( $path ) { + // TODO: Fetch and return the lift of plugin files. + return array(); + } + + /** + * Check the integrity of a single plugin file by comparing it to the + * officially provided checksum. + * + * @param string $path Relative path to the plugin file to check the + * integrity of. + * @param array $checksums Array of provided checksums to compare against. + * + * @return true|string + */ + private function check_file( $path, $checksums ) { + // TODO: Compute the checksum and compare it to the provided one. + return true; + } } From 4f8fda58a0c04a0f3c05af45ec8f53f245ac1f65 Mon Sep 17 00:00:00 2001 From: Alain Schlesser Date: Wed, 29 Nov 2017 00:38:47 +0100 Subject: [PATCH 21/47] Make sure either one or more plugins or the --all flag are provided. --- src/Checksum_Plugin_Command.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/Checksum_Plugin_Command.php b/src/Checksum_Plugin_Command.php index 3248d6707..e4217228f 100644 --- a/src/Checksum_Plugin_Command.php +++ b/src/Checksum_Plugin_Command.php @@ -40,6 +40,10 @@ public function __invoke( $args, $assoc_args ) { $plugins = $fetcher->get_many( $args ); $all = \WP_CLI\Utils\get_flag_value( $assoc_args, 'all', false ); + 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.' ); + } + $errors = array(); foreach ( $plugins as $plugin ) { From 04dce502dc88bcaf99ab5526a92e3aea9ab3b929 Mon Sep 17 00:00:00 2001 From: Alain Schlesser Date: Wed, 29 Nov 2017 00:40:04 +0100 Subject: [PATCH 22/47] Print a warning if a plugin is being skipped because the version could not be retrieved. --- src/Checksum_Plugin_Command.php | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Checksum_Plugin_Command.php b/src/Checksum_Plugin_Command.php index e4217228f..eadea7bb7 100644 --- a/src/Checksum_Plugin_Command.php +++ b/src/Checksum_Plugin_Command.php @@ -50,6 +50,7 @@ public function __invoke( $args, $assoc_args ) { $version = $this->get_plugin_version( $plugin->file ); if ( false === $version ) { + WP_CLI::warning( "Could not retrieve the version for plugin {$plugin->name}, skipping." ); continue; } From 39df3ef1249bc1af055410c6496cb6f80e86ddd8 Mon Sep 17 00:00:00 2001 From: Alain Schlesser Date: Wed, 29 Nov 2017 00:41:44 +0100 Subject: [PATCH 23/47] Print a warning if the checksums for a given plugin could not be retrieved. --- src/Checksum_Plugin_Command.php | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/Checksum_Plugin_Command.php b/src/Checksum_Plugin_Command.php index eadea7bb7..95bf92a04 100644 --- a/src/Checksum_Plugin_Command.php +++ b/src/Checksum_Plugin_Command.php @@ -56,6 +56,11 @@ public function __invoke( $args, $assoc_args ) { $checksums = $this->get_plugin_checksums( $plugin->name, $version ); + if ( false === $checksums ) { + WP_CLI::warning( "Could not retrieve the checksums for plugin {$plugin->name}, skipping." ); + continue; + } + $files = $this->get_plugin_files( $plugin->file ); foreach ( $files as $file ) { From 43d00c2644ebdaf767444c721b2cb341ccf92295 Mon Sep 17 00:00:00 2001 From: Alain Schlesser Date: Wed, 29 Nov 2017 00:58:45 +0100 Subject: [PATCH 24/47] Display found errors in several different formats. --- src/Checksum_Plugin_Command.php | 33 ++++++++++++++++++++++++++++++--- 1 file changed, 30 insertions(+), 3 deletions(-) diff --git a/src/Checksum_Plugin_Command.php b/src/Checksum_Plugin_Command.php index 95bf92a04..5d2744944 100644 --- a/src/Checksum_Plugin_Command.php +++ b/src/Checksum_Plugin_Command.php @@ -33,6 +33,18 @@ class Checksum_Plugin_Command extends Checksum_Base_Command { * * [--all] * : If set, all plugins will be verified. + * + * [--format=] + * : Render output in a specific format. + * --- + * default: table + * options: + * - table + * - json + * - csv + * - yaml + * - count + * --- */ public function __invoke( $args, $assoc_args ) { @@ -63,10 +75,22 @@ public function __invoke( $args, $assoc_args ) { $files = $this->get_plugin_files( $plugin->file ); + foreach ( $checksums as $file => $checksum_array ) { + if ( ! array_key_exists( $file, $files ) ) { + $error['plugin_name'] = $plugin->name; + $error['file'] = $file; + $error['message'] = 'File is missing'; + $errors[] = $error; + } + } + foreach ( $files as $file ) { - $result = $this->check_file( $file, $checksums ); + $result = $this->check_file_checksum( $file, $checksums ); if ( true !== $result ) { - $errors[ $plugin ][ $file ] = $result; + $error['plugin_name'] = $plugin->name; + $error['file'] = $file; + $error['message'] = $result; + $errors[] = $error; } } } @@ -78,6 +102,9 @@ public function __invoke( $args, $assoc_args ) { : 'Plugin verifies against checksums.' ); } else { + $formatter = new \WP_CLI\Formatter( $assoc_args, array( 'plugin_name', 'file', 'message' ) ); + $formatter->display_items( $errors ); + WP_CLI::error( count( $plugins ) > 1 ? 'One or more plugins don\'t verify against checksums.' @@ -172,7 +199,7 @@ private function get_plugin_files( $path ) { * * @return true|string */ - private function check_file( $path, $checksums ) { + private function check_file_checksum( $path, $checksums ) { // TODO: Compute the checksum and compare it to the provided one. return true; } From ea9c177162283269f1fc77009fbc87f9a42573f9 Mon Sep 17 00:00:00 2001 From: Alain Schlesser Date: Wed, 29 Nov 2017 03:29:11 +0100 Subject: [PATCH 25/47] Add beginnings of the checksum check. --- src/Checksum_Plugin_Command.php | 118 +++++++++++++++++++++++++++----- 1 file changed, 101 insertions(+), 17 deletions(-) diff --git a/src/Checksum_Plugin_Command.php b/src/Checksum_Plugin_Command.php index 5d2744944..f5ea0854a 100644 --- a/src/Checksum_Plugin_Command.php +++ b/src/Checksum_Plugin_Command.php @@ -23,6 +23,13 @@ class Checksum_Plugin_Command extends Checksum_Base_Command { */ private $plugins_data; + /** + * Array of detected errors. + * + * @var array + */ + private $errors = array(); + /** * Verify plugin files against WordPress.org's checksums. * @@ -56,8 +63,6 @@ public function __invoke( $args, $assoc_args ) { WP_CLI::error( 'You need to specify either one or more plugin slugs to check or use the --all flag to check all plugins.' ); } - $errors = array(); - foreach ( $plugins as $plugin ) { $version = $this->get_plugin_version( $plugin->file ); @@ -77,33 +82,35 @@ public function __invoke( $args, $assoc_args ) { foreach ( $checksums as $file => $checksum_array ) { if ( ! array_key_exists( $file, $files ) ) { - $error['plugin_name'] = $plugin->name; - $error['file'] = $file; - $error['message'] = 'File is missing'; - $errors[] = $error; + $this->add_error( $plugin->name, $file, 'File is missing' ); } } foreach ( $files as $file ) { - $result = $this->check_file_checksum( $file, $checksums ); + if ( ! array_key_exists( $file, $checksums ) ) { + $this->add_error( $plugin->name, $file, 'File was added' ); + continue; + } + + $result = $this->check_file_checksum( $file, $checksums[ $file ] ); if ( true !== $result ) { - $error['plugin_name'] = $plugin->name; - $error['file'] = $file; - $error['message'] = $result; - $errors[] = $error; + $this->add_error( $plugin->name, $file, $result ); } } } - if ( empty( $errors ) ) { + if ( empty( $this->errors ) ) { WP_CLI::success( count( $plugins ) > 1 ? 'Plugins verify against checksums.' : 'Plugin verifies against checksums.' ); } else { - $formatter = new \WP_CLI\Formatter( $assoc_args, array( 'plugin_name', 'file', 'message' ) ); - $formatter->display_items( $errors ); + $formatter = new \WP_CLI\Formatter( + $assoc_args, + array( 'plugin_name', 'file', 'message' ) + ); + $formatter->display_items( $this->errors ); WP_CLI::error( count( $plugins ) > 1 @@ -113,6 +120,20 @@ public function __invoke( $args, $assoc_args ) { } } + /** + * Add a new error to the array of detected errors. + * + * @param string $plugin_name Name of the plugin that had the error. + * @param string $file Relative path to the file that had the error. + * @param string $message Message explaining the error. + */ + private function add_error( $plugin_name, $file, $message ) { + $error['plugin_name'] = $plugin_name; + $error['file'] = $file; + $error['message'] = $message; + $this->errors[] = $error; + } + /** * Get the currently installed version for a given plugin. * @@ -185,8 +206,8 @@ private function get_plugin_checksums( $plugin, $version ) { * @return array Array of files with their relative paths. */ private function get_plugin_files( $path ) { - // TODO: Fetch and return the lift of plugin files. - return array(); + // TODO: Fetch and return the list of plugin files. + return $this->get_files( $this->get_absolute_path( $path ) ); } /** @@ -200,7 +221,70 @@ private function get_plugin_files( $path ) { * @return true|string */ private function check_file_checksum( $path, $checksums ) { - // TODO: Compute the checksum and compare it to the provided one. + if ( empty( $checksums ) ) { + return 'File was added'; + } + + if ( $this->supports_sha256() + && array_key_exists( 'sha256', $checksums ) ) { + $sha256 = $this->get_sha256( $this->get_absolute_path( $path ) ); + + return $checksums['sha256'] === $sha256; + } + + if ( ! array_key_exists( 'md5', $checksums ) ) { + return 'No matching checksum algorithm found'; + } + + $md5 = $this->get_md5( $this->get_absolute_path( $path ) ); + + return $checksums['md5'] === $md5; + } + + /** + * Check whether the current environment supports 256-bit SHA-2. + * + * @return bool + */ + private function supports_sha256() { + // TODO: Check whether the current environment supports SHA-256. return true; } + + /** + * Get the 256-bit SHA-2 of a given file. + * + * @param string $filepath Absolute path to the file to calculate the SHA-2 + * for. + * + * @return string + */ + private function get_sha256( $filepath ) { + // TODO: Calculate the 256-bit SHA-2 for the given file. + return ''; + } + + /** + * Get the MD% of a given file. + * + * @param string $filepath Absolute path to the file to calculate the MD5 + * for. + * + * @return string + */ + private function get_md5( $filepath ) { + // TODO: Calculate the MD5 for the given file. + return ''; + } + + /** + * Get the absolute path to a relative plugin file. + * + * @param string $path Relative path to get the absolute path for. + * + * @return string + */ + private function get_absolute_path( $path ) { + return WP_PLUGIN_DIR . '/' . plugin_dir_path( $path ); + } } From e615c1bb585bf22c1967218ba049add20c1b0171 Mon Sep 17 00:00:00 2001 From: Alain Schlesser Date: Wed, 29 Nov 2017 18:51:58 +0100 Subject: [PATCH 26/47] Iterate over checksum values, not keys. --- src/Checksum_Plugin_Command.php | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/Checksum_Plugin_Command.php b/src/Checksum_Plugin_Command.php index f5ea0854a..8f0a16aa1 100644 --- a/src/Checksum_Plugin_Command.php +++ b/src/Checksum_Plugin_Command.php @@ -81,7 +81,7 @@ public function __invoke( $args, $assoc_args ) { $files = $this->get_plugin_files( $plugin->file ); foreach ( $checksums as $file => $checksum_array ) { - if ( ! array_key_exists( $file, $files ) ) { + if ( ! in_array( $file, $files, true ) ) { $this->add_error( $plugin->name, $file, 'File is missing' ); } } @@ -94,7 +94,7 @@ public function __invoke( $args, $assoc_args ) { $result = $this->check_file_checksum( $file, $checksums[ $file ] ); if ( true !== $result ) { - $this->add_error( $plugin->name, $file, $result ); + $this->add_error( $plugin->name, $file, is_string( $result ) ? $result : 'Checksum does not match' ); } } } @@ -221,10 +221,6 @@ private function get_plugin_files( $path ) { * @return true|string */ private function check_file_checksum( $path, $checksums ) { - if ( empty( $checksums ) ) { - return 'File was added'; - } - if ( $this->supports_sha256() && array_key_exists( 'sha256', $checksums ) ) { $sha256 = $this->get_sha256( $this->get_absolute_path( $path ) ); From f3703daa02bdca8e942bcffc0b331febd5ad4151 Mon Sep 17 00:00:00 2001 From: Alain Schlesser Date: Wed, 29 Nov 2017 19:33:28 +0100 Subject: [PATCH 27/47] Fix the path and file names handling. --- src/Checksum_Base_Command.php | 6 ++---- src/Checksum_Plugin_Command.php | 7 ++++--- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/src/Checksum_Base_Command.php b/src/Checksum_Base_Command.php index 3a0c0eebd..cfd86927a 100644 --- a/src/Checksum_Base_Command.php +++ b/src/Checksum_Base_Command.php @@ -42,11 +42,9 @@ protected function get_files( $path ) { RecursiveIteratorIterator::CHILD_FIRST ); foreach ( $files as $file_info ) { - $pathname = substr( $file_info->getPathname(), - strlen( $path ) ); + $pathname = substr( $file_info->getPathname(), strlen( $path ) ); if ( $file_info->isFile() && $this->filter_file( $pathname ) ) { - $filtered_files[] = str_replace( $path, '', - $file_info->getPathname() ); + $filtered_files[] = str_replace( $path, '', $file_info->getPathname() ); } } } catch ( Exception $e ) { diff --git a/src/Checksum_Plugin_Command.php b/src/Checksum_Plugin_Command.php index 8f0a16aa1..511e97e5e 100644 --- a/src/Checksum_Plugin_Command.php +++ b/src/Checksum_Plugin_Command.php @@ -206,8 +206,9 @@ private function get_plugin_checksums( $plugin, $version ) { * @return array Array of files with their relative paths. */ private function get_plugin_files( $path ) { - // TODO: Fetch and return the list of plugin files. - return $this->get_files( $this->get_absolute_path( $path ) ); + // TODO: Make sure this works for all types of plugins (single files, must-use, ...) + $folder = trailingslashit( dirname( $this->get_absolute_path( $path ) ) ); + return $this->get_files( $folder ); } /** @@ -281,6 +282,6 @@ private function get_md5( $filepath ) { * @return string */ private function get_absolute_path( $path ) { - return WP_PLUGIN_DIR . '/' . plugin_dir_path( $path ); + return WP_PLUGIN_DIR . '/' . $path; } } From 5c70e9964bd9af597f4c63458942b523fb866345 Mon Sep 17 00:00:00 2001 From: Alain Schlesser Date: Wed, 29 Nov 2017 19:38:38 +0100 Subject: [PATCH 28/47] Add MD5 calculation. --- src/Checksum_Plugin_Command.php | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/Checksum_Plugin_Command.php b/src/Checksum_Plugin_Command.php index 511e97e5e..702b58529 100644 --- a/src/Checksum_Plugin_Command.php +++ b/src/Checksum_Plugin_Command.php @@ -92,7 +92,7 @@ public function __invoke( $args, $assoc_args ) { continue; } - $result = $this->check_file_checksum( $file, $checksums[ $file ] ); + $result = $this->check_file_checksum( dirname( $plugin->file ) . '/' . $file, $checksums[ $file ] ); if ( true !== $result ) { $this->add_error( $plugin->name, $file, is_string( $result ) ? $result : 'Checksum does not match' ); } @@ -245,7 +245,7 @@ private function check_file_checksum( $path, $checksums ) { */ private function supports_sha256() { // TODO: Check whether the current environment supports SHA-256. - return true; + return false; } /** @@ -270,8 +270,7 @@ private function get_sha256( $filepath ) { * @return string */ private function get_md5( $filepath ) { - // TODO: Calculate the MD5 for the given file. - return ''; + return md5_file( $filepath ); } /** From 0bfa0c4fb054f1963c4e275afbfb6ed5d1e42d30 Mon Sep 17 00:00:00 2001 From: Alain Schlesser Date: Wed, 29 Nov 2017 19:43:04 +0100 Subject: [PATCH 29/47] Add SHA-256 algorithm. --- src/Checksum_Plugin_Command.php | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/Checksum_Plugin_Command.php b/src/Checksum_Plugin_Command.php index 702b58529..c1fe1e161 100644 --- a/src/Checksum_Plugin_Command.php +++ b/src/Checksum_Plugin_Command.php @@ -245,7 +245,7 @@ private function check_file_checksum( $path, $checksums ) { */ private function supports_sha256() { // TODO: Check whether the current environment supports SHA-256. - return false; + return true; } /** @@ -257,12 +257,11 @@ private function supports_sha256() { * @return string */ private function get_sha256( $filepath ) { - // TODO: Calculate the 256-bit SHA-2 for the given file. - return ''; + return hash_file( 'sha256', $filepath ); } /** - * Get the MD% of a given file. + * Get the MD5 of a given file. * * @param string $filepath Absolute path to the file to calculate the MD5 * for. @@ -270,7 +269,7 @@ private function get_sha256( $filepath ) { * @return string */ private function get_md5( $filepath ) { - return md5_file( $filepath ); + return hash_file( 'md5', $filepath ); } /** From 51f6338f7bb55b5dde9465884a9e371f8c88c11e Mon Sep 17 00:00:00 2001 From: Alain Schlesser Date: Wed, 29 Nov 2017 19:44:39 +0100 Subject: [PATCH 30/47] Add note to supports_sha256 method. --- src/Checksum_Plugin_Command.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/Checksum_Plugin_Command.php b/src/Checksum_Plugin_Command.php index c1fe1e161..bbd374568 100644 --- a/src/Checksum_Plugin_Command.php +++ b/src/Checksum_Plugin_Command.php @@ -241,10 +241,12 @@ private function check_file_checksum( $path, $checksums ) { /** * Check whether the current environment supports 256-bit SHA-2. * + * Should be supported for PHP 5+, but we might find edge cases depending on + * host. + * * @return bool */ private function supports_sha256() { - // TODO: Check whether the current environment supports SHA-256. return true; } From 6619b1e034d698419cfcd63231139ec53995f8b3 Mon Sep 17 00:00:00 2001 From: Alain Schlesser Date: Wed, 29 Nov 2017 21:45:38 +0100 Subject: [PATCH 31/47] Add handling for the --all paramter. --- src/Checksum_Plugin_Command.php | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/src/Checksum_Plugin_Command.php b/src/Checksum_Plugin_Command.php index bbd374568..11c905d78 100644 --- a/src/Checksum_Plugin_Command.php +++ b/src/Checksum_Plugin_Command.php @@ -56,8 +56,8 @@ class Checksum_Plugin_Command extends Checksum_Base_Command { public function __invoke( $args, $assoc_args ) { $fetcher = new \WP_CLI\Fetchers\Plugin(); - $plugins = $fetcher->get_many( $args ); $all = \WP_CLI\Utils\get_flag_value( $assoc_args, 'all', 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.' ); @@ -74,7 +74,7 @@ public function __invoke( $args, $assoc_args ) { $checksums = $this->get_plugin_checksums( $plugin->name, $version ); if ( false === $checksums ) { - WP_CLI::warning( "Could not retrieve the checksums for plugin {$plugin->name}, skipping." ); + WP_CLI::warning( "Could not retrieve the checksums for version {$version} of plugin {$plugin->name}, skipping." ); continue; } @@ -198,6 +198,20 @@ private function get_plugin_checksums( $plugin, $version ) { return $body['files']; } + /** + * Get the names of all installed plugins. + * + * @return array Names of all installed plugins. + */ + private function get_all_plugin_names() { + $names = array(); + foreach ( get_plugins() as $file => $details ) { + $names[] = Utils\get_plugin_name( $file ); + } + + return $names; + } + /** * Get the list of files that are part of the given plugin. * From 58734e9092c85eca4987b9cc8c17a1066b65a88b Mon Sep 17 00:00:00 2001 From: Alain Schlesser Date: Sat, 9 Dec 2017 19:08:19 +0100 Subject: [PATCH 32/47] Adapt README file. --- README.md | 36 +++++++++++++++++++++++++++++++++ composer.json | 3 ++- src/Checksum_Plugin_Command.php | 2 +- 3 files changed, 39 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 8a3d2af28..8198d484c 100644 --- a/README.md +++ b/README.md @@ -9,6 +9,12 @@ Quick links: [Using](#using) | [Installing](#installing) | [Contributing](#contr ## Using +This package implements the following commands: + +### wp checksum core + +Verifies WordPress files against WordPress.org's checksums. + ~~~ wp checksum core [--version=] [--locale=] ~~~ @@ -52,6 +58,36 @@ site. Warning: File doesn't verify against checksum: wp-config-sample.php Error: WordPress installation doesn't verify against checksums. + + +### wp checksum plugin + +Verifies plugin files against WordPress.org's checksums. + +~~~ +wp checksum plugin [...] [--all] [--format=] +~~~ + +**OPTIONS** + + [...] + One or more plugins to verify. + + [--all] + If set, all plugins will be verified. + + [--format=] + Render output in a specific format. + --- + default: table + options: + - table + - json + - csv + - yaml + - count + --- + ## Installing This package is included with WP-CLI itself, no additional installation necessary. diff --git a/composer.json b/composer.json index cdad47a57..d7a356ce4 100644 --- a/composer.json +++ b/composer.json @@ -33,7 +33,8 @@ }, "bundled": true, "commands": [ - "checksum core" + "checksum core", + "checksum plugin" ] } } diff --git a/src/Checksum_Plugin_Command.php b/src/Checksum_Plugin_Command.php index 11c905d78..7bea03dbc 100644 --- a/src/Checksum_Plugin_Command.php +++ b/src/Checksum_Plugin_Command.php @@ -31,7 +31,7 @@ class Checksum_Plugin_Command extends Checksum_Base_Command { private $errors = array(); /** - * Verify plugin files against WordPress.org's checksums. + * Verifies plugin files against WordPress.org's checksums. * * ## OPTIONS * From 3aa47eb8728f4348c53814837c00d3ef93d30fe1 Mon Sep 17 00:00:00 2001 From: Alain Schlesser Date: Thu, 14 Dec 2017 04:18:26 +0100 Subject: [PATCH 33/47] Fix feature tests and have them use the "Duplicate Post" plugin. --- features/checksum-plugin.feature | 41 +++++++++++++++++++++++--------- 1 file changed, 30 insertions(+), 11 deletions(-) diff --git a/features/checksum-plugin.feature b/features/checksum-plugin.feature index 5bc38459e..f8d94f6b3 100644 --- a/features/checksum-plugin.feature +++ b/features/checksum-plugin.feature @@ -3,11 +3,11 @@ Feature: Validate checksums for WordPress plugins Scenario: Verify plugin checksums Given a WP install - When I run `wp plugin install https://downloads.wordpress.org/plugins/test-plugin-3.test-tag.zip` + When I run `wp plugin install duplicate-post --version=3.2.1` Then STDOUT should not be empty And STDERR should be empty - When I run `wp checksum plugin test-plugin-3` + When I run `wp checksum plugin duplicate-post` Then STDOUT should be: """ Success: Plugin verifies against checksums. @@ -16,25 +16,44 @@ Feature: Validate checksums for WordPress plugins Scenario: Modified plugin doesn't verify Given a WP install - When I run `wp plugin install https://downloads.wordpress.org/plugins/test-plugin-3.test-tag.zip` + When I run `wp plugin install duplicate-post --version=3.2.1` Then STDOUT should not be empty And STDERR should be empty - Given "WordPress" replaced with "Wordpress" in the wp-content/plugins/test-plugin-3/README.md file + Given "Duplicate Post" replaced with "Different Name" in the wp-content/plugins/duplicate-post/duplicate-post.php file - When I run `wp checksum plugin test-plugin-3` - Then STDERR should be: + When I try `wp checksum plugin duplicate-post --format=json` + Then STDOUT should contain: + """ + "plugin_name":"duplicate-post","file":"duplicate-post.php","message":"Checksum does not match" + """ + And STDERR should be: + """ + Error: Plugin doesn't verify against checksums. + """ + + When I run `rm wp-content/plugins/duplicate-post/duplicate-post.css` + Then STDERR should be empty + + When I try `wp checksum plugin duplicate-post --format=json` + Then STDOUT should contain: + """ + "plugin_name":"duplicate-post","file":"duplicate-post.css","message":"File is missing" + """ + And STDERR should be: """ - Warning: File doesn't verify against checksum: README.md Error: Plugin doesn't verify against checksums. """ - When I run `rm wp-content/plugins/test-plugin-3/README.md` + When I run `touch wp-content/plugins/duplicate-post/additional-file.php` Then STDERR should be empty - When I try `wp checksum plugin test-plugin-3` - Then STDERR should be: + When I try `wp checksum plugin duplicate-post --format=json` + Then STDOUT should contain: + """ + "plugin_name":"duplicate-post","file":"additional-file.php","message":"File was added" + """ + And STDERR should be: """ - Warning: File doesn't exist: README.md Error: Plugin doesn't verify against checksums. """ From 33d5bdba8d9ce668f2192eff2dcac5d050ec78ee Mon Sep 17 00:00:00 2001 From: Alain Schlesser Date: Thu, 14 Dec 2017 04:19:07 +0100 Subject: [PATCH 34/47] Add test to cover soft changes against readme.txt. --- features/checksum-plugin.feature | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/features/checksum-plugin.feature b/features/checksum-plugin.feature index f8d94f6b3..5470b05c5 100644 --- a/features/checksum-plugin.feature +++ b/features/checksum-plugin.feature @@ -57,3 +57,24 @@ Feature: Validate checksums for WordPress plugins """ Error: Plugin doesn't verify against checksums. """ + + Scenario: Soft changes are only reported in strict mode + Given a WP install + + When I run `wp plugin install duplicate-post --version=3.2.1` + Then STDOUT should not be empty + And STDERR should be empty + + When I run `wp checksum plugin duplicate-post` + Then STDOUT should be: + """ + Success: Plugin verifies against checksums. + """ + And STDERR should be empty + + When I try `wp checksum plugin duplicate-post --strict` + Then STDOUT should not be empty + And STDERR should contain: + """ + Error: Plugin doesn't verify against checksums. + """ From b4f07856db9fb644bb997e7751f161e03e3cd89e Mon Sep 17 00:00:00 2001 From: Alain Schlesser Date: Thu, 14 Dec 2017 04:19:28 +0100 Subject: [PATCH 35/47] Implement soft changes and --strict parameter. See #22 --- src/Checksum_Plugin_Command.php | 35 +++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/src/Checksum_Plugin_Command.php b/src/Checksum_Plugin_Command.php index 7bea03dbc..67a90d7bc 100644 --- a/src/Checksum_Plugin_Command.php +++ b/src/Checksum_Plugin_Command.php @@ -41,6 +41,10 @@ class Checksum_Plugin_Command extends Checksum_Base_Command { * [--all] * : If set, all plugins will be verified. * + * [--strict] + * : If set, even "soft changes" like readme.txt changes will trigger + * checksum errors. + * * [--format=] * : Render output in a specific format. * --- @@ -57,6 +61,7 @@ public function __invoke( $args, $assoc_args ) { $fetcher = new \WP_CLI\Fetchers\Plugin(); $all = \WP_CLI\Utils\get_flag_value( $assoc_args, 'all', false ); + $strict = \WP_CLI\Utils\get_flag_value( $assoc_args, 'strict', false ); $plugins = $fetcher->get_many( $all ? $this->get_all_plugin_names() : $args ); if ( empty( $plugins ) && ! $all ) { @@ -92,6 +97,10 @@ public function __invoke( $args, $assoc_args ) { continue; } + if ( ! $strict && $this->is_soft_change_file( $file ) ) { + continue; + } + $result = $this->check_file_checksum( dirname( $plugin->file ) . '/' . $file, $checksums[ $file ] ); if ( true !== $result ) { $this->add_error( $plugin->name, $file, is_string( $result ) ? $result : 'Checksum does not match' ); @@ -298,4 +307,30 @@ private function get_md5( $filepath ) { private function get_absolute_path( $path ) { return WP_PLUGIN_DIR . '/' . $path; } + + /** + * Return a list of files that only trigger checksum errors in strict mode. + * + * @return array Array of file names. + */ + private function get_soft_change_files() { + static $files = array( + 'readme.txt', + ); + + return $files; + } + + /** + * Check whether a given file will only trigger checksum errors in strict + * mode. + * + * @param string $file File to check. + * + * @return bool Whether the file only triggers checksum errors in strict + * mode. + */ + private function is_soft_change_file( $file ) { + return in_array( $file, $this->get_soft_change_files(), true ); + } } From f277f9c4b44ab530dba38b011120d450b8e189a5 Mon Sep 17 00:00:00 2001 From: Alain Schlesser Date: Thu, 14 Dec 2017 04:21:15 +0100 Subject: [PATCH 36/47] Add --strict flag documentation. --- README.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 8198d484c..c44db5772 100644 --- a/README.md +++ b/README.md @@ -65,7 +65,7 @@ site. Verifies plugin files against WordPress.org's checksums. ~~~ -wp checksum plugin [...] [--all] [--format=] +wp checksum plugin [...] [--all] [--strict] [--format=] ~~~ **OPTIONS** @@ -76,6 +76,10 @@ wp checksum plugin [...] [--all] [--format=] [--all] If set, all plugins will be verified. + [--strict] + If set, even "soft changes" like readme.txt changes will trigger + checksum errors. + [--format=] Render output in a specific format. --- From e3ad28afdf0d3989bdec0f5378320a2ebba13dcc Mon Sep 17 00:00:00 2001 From: Alain Schlesser Date: Thu, 21 Dec 2017 15:37:22 +0100 Subject: [PATCH 37/47] Add support for multiple checksums for a single file. Multiple checksums act as a whitelist, accepting any one of the available checksums as proof for the file's integrity. Fixes #24 --- features/checksum-plugin.feature | 16 ++++++++++++++++ src/Checksum_Plugin_Command.php | 4 ++-- 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/features/checksum-plugin.feature b/features/checksum-plugin.feature index 5470b05c5..4e74bb995 100644 --- a/features/checksum-plugin.feature +++ b/features/checksum-plugin.feature @@ -65,6 +65,8 @@ Feature: Validate checksums for WordPress plugins Then STDOUT should not be empty And STDERR should be empty + Given "Duplicate Post" replaced with "Different Name" in the wp-content/plugins/duplicate-post/README.txt file + When I run `wp checksum plugin duplicate-post` Then STDOUT should be: """ @@ -78,3 +80,17 @@ Feature: Validate checksums for WordPress plugins """ Error: Plugin doesn't verify against checksums. """ + + Scenario: Multiple checksums for a single file are supported + Given a WP install + + When I run `wp plugin install wptouch --version=4.3.22` + Then STDOUT should not be empty + And STDERR should be empty + + When I run `wp checksum plugin wptouch` + Then STDOUT should be: + """ + Success: Plugin verifies against checksums. + """ + And STDERR should be empty diff --git a/src/Checksum_Plugin_Command.php b/src/Checksum_Plugin_Command.php index 67a90d7bc..65edaa9e8 100644 --- a/src/Checksum_Plugin_Command.php +++ b/src/Checksum_Plugin_Command.php @@ -249,7 +249,7 @@ private function check_file_checksum( $path, $checksums ) { && array_key_exists( 'sha256', $checksums ) ) { $sha256 = $this->get_sha256( $this->get_absolute_path( $path ) ); - return $checksums['sha256'] === $sha256; + return in_array( $sha256, (array) $checksums['sha256'], true ); } if ( ! array_key_exists( 'md5', $checksums ) ) { @@ -258,7 +258,7 @@ private function check_file_checksum( $path, $checksums ) { $md5 = $this->get_md5( $this->get_absolute_path( $path ) ); - return $checksums['md5'] === $md5; + return in_array( $md5, (array) $checksums['md5'], true ); } /** From 5c30552c8301e27ee76b0f4c68b7ff6f7883fc6a Mon Sep 17 00:00:00 2001 From: Alain Schlesser Date: Thu, 21 Dec 2017 16:08:06 +0100 Subject: [PATCH 38/47] Fix case mismatch in multiple checksum test. --- features/checksum-plugin.feature | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/features/checksum-plugin.feature b/features/checksum-plugin.feature index 4e74bb995..70f38ad6c 100644 --- a/features/checksum-plugin.feature +++ b/features/checksum-plugin.feature @@ -65,7 +65,7 @@ Feature: Validate checksums for WordPress plugins Then STDOUT should not be empty And STDERR should be empty - Given "Duplicate Post" replaced with "Different Name" in the wp-content/plugins/duplicate-post/README.txt file + Given "Duplicate Post" replaced with "Different Name" in the wp-content/plugins/duplicate-post/readme.txt file When I run `wp checksum plugin duplicate-post` Then STDOUT should be: From 454a227117c4f60a38092bc809ecafcfb53c2b06 Mon Sep 17 00:00:00 2001 From: Alain Schlesser Date: Thu, 21 Dec 2017 21:53:32 +0100 Subject: [PATCH 39/47] Fix typo: parse -> path --- src/Checksum_Base_Command.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Checksum_Base_Command.php b/src/Checksum_Base_Command.php index cfd86927a..a296bd23c 100644 --- a/src/Checksum_Base_Command.php +++ b/src/Checksum_Base_Command.php @@ -29,7 +29,7 @@ protected static function _read( $url ) { /** * Recursively get the list of files for a given path. * - * @param string $path Root parse to start the recursive traversal in. + * @param string $path Root path to start the recursive traversal in. * * @return array */ From 464be76fed2761ede0363edf371ccafe77c5381d Mon Sep 17 00:00:00 2001 From: Alain Schlesser Date: Fri, 22 Dec 2017 13:47:35 +0100 Subject: [PATCH 40/47] Add a reference to why wptouch plugin is being used in tests. --- features/checksum-plugin.feature | 2 ++ 1 file changed, 2 insertions(+) diff --git a/features/checksum-plugin.feature b/features/checksum-plugin.feature index 70f38ad6c..949021db8 100644 --- a/features/checksum-plugin.feature +++ b/features/checksum-plugin.feature @@ -81,6 +81,8 @@ Feature: Validate checksums for WordPress plugins Error: Plugin doesn't verify against checksums. """ + # WPTouch 4.3.22 contains multiple checksums for some of its files. + # See https://github.com/wp-cli/checksum-command/issues/24 Scenario: Multiple checksums for a single file are supported Given a WP install From 22bc73e1d36e1a1b1f99783baee7a5898b59b75c Mon Sep 17 00:00:00 2001 From: Alain Schlesser Date: Fri, 22 Dec 2017 13:51:06 +0100 Subject: [PATCH 41/47] Replace redundant str_replace() with direct variable reference. --- src/Checksum_Base_Command.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Checksum_Base_Command.php b/src/Checksum_Base_Command.php index a296bd23c..3c341b110 100644 --- a/src/Checksum_Base_Command.php +++ b/src/Checksum_Base_Command.php @@ -44,7 +44,7 @@ protected function get_files( $path ) { foreach ( $files as $file_info ) { $pathname = substr( $file_info->getPathname(), strlen( $path ) ); if ( $file_info->isFile() && $this->filter_file( $pathname ) ) { - $filtered_files[] = str_replace( $path, '', $file_info->getPathname() ); + $filtered_files[] = $pathname; } } } catch ( Exception $e ) { From 9ef77d6cbcb4f751ae630c3674d4838b91857359 Mon Sep 17 00:00:00 2001 From: Alain Schlesser Date: Fri, 22 Dec 2017 13:56:19 +0100 Subject: [PATCH 42/47] Add test for parameter logic check. --- features/checksum-plugin.feature | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/features/checksum-plugin.feature b/features/checksum-plugin.feature index 949021db8..9a51f417d 100644 --- a/features/checksum-plugin.feature +++ b/features/checksum-plugin.feature @@ -96,3 +96,13 @@ Feature: Validate checksums for WordPress plugins Success: Plugin verifies against checksums. """ And STDERR should be empty + + Scenario: Throws an error if provided with neither plugin names nor the --all flag + Given a WP install + + When I try `wp checksum plugin` + Then STDERR should contain: + """ + You need to specify either one or more plugin slugs to check or use the --all flag to check all plugins. + """ + And STDOUT should be empty From 9251a68833b5428908157c0d204148b30ab6a63e Mon Sep 17 00:00:00 2001 From: Alain Schlesser Date: Fri, 22 Dec 2017 15:05:59 +0100 Subject: [PATCH 43/47] Fix buggy behavior for single-file plugins. --- src/Checksum_Plugin_Command.php | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/Checksum_Plugin_Command.php b/src/Checksum_Plugin_Command.php index 65edaa9e8..0c5f43877 100644 --- a/src/Checksum_Plugin_Command.php +++ b/src/Checksum_Plugin_Command.php @@ -229,8 +229,15 @@ private function get_all_plugin_names() { * @return array Array of files with their relative paths. */ private function get_plugin_files( $path ) { - // TODO: Make sure this works for all types of plugins (single files, must-use, ...) - $folder = trailingslashit( dirname( $this->get_absolute_path( $path ) ) ); + $absolute_path = $this->get_absolute_path( $path ); + + // Return single file plugins immediately, to avoid iterating over the + // entire plugins folder. + if ( is_file( $absolute_path ) ) { + return (array) $absolute_path; + } + + $folder = trailingslashit( dirname( $absolute_path ) ); return $this->get_files( $folder ); } From 73efdd43fd3f4f60b396f51d6eeaba3aa382bb55 Mon Sep 17 00:00:00 2001 From: Alain Schlesser Date: Fri, 22 Dec 2017 15:20:02 +0100 Subject: [PATCH 44/47] Use `report_batch_operation_results()` to report on verified plugins. --- src/Checksum_Plugin_Command.php | 31 ++++++++++++++++++------------- 1 file changed, 18 insertions(+), 13 deletions(-) diff --git a/src/Checksum_Plugin_Command.php b/src/Checksum_Plugin_Command.php index 0c5f43877..896a2b29c 100644 --- a/src/Checksum_Plugin_Command.php +++ b/src/Checksum_Plugin_Command.php @@ -68,11 +68,14 @@ public function __invoke( $args, $assoc_args ) { WP_CLI::error( 'You need to specify either one or more plugin slugs to check or use the --all flag to check all plugins.' ); } + $skips = 0; + foreach ( $plugins as $plugin ) { $version = $this->get_plugin_version( $plugin->file ); if ( false === $version ) { WP_CLI::warning( "Could not retrieve the version for plugin {$plugin->name}, skipping." ); + $skips++; continue; } @@ -80,6 +83,7 @@ public function __invoke( $args, $assoc_args ) { if ( false === $checksums ) { WP_CLI::warning( "Could not retrieve the checksums for version {$version} of plugin {$plugin->name}, skipping." ); + $skips++; continue; } @@ -108,25 +112,26 @@ public function __invoke( $args, $assoc_args ) { } } - if ( empty( $this->errors ) ) { - WP_CLI::success( - count( $plugins ) > 1 - ? 'Plugins verify against checksums.' - : 'Plugin verifies against checksums.' - ); - } else { + if ( ! empty( $this->errors ) ) { $formatter = new \WP_CLI\Formatter( $assoc_args, array( 'plugin_name', 'file', 'message' ) ); $formatter->display_items( $this->errors ); - - WP_CLI::error( - count( $plugins ) > 1 - ? 'One or more plugins don\'t verify against checksums.' - : 'Plugin doesn\'t verify against checksums.' - ); } + + $total = count( $plugins ); + $failures = count( $this->errors ); + $successes = $total - $failures - $skips; + + \WP_CLI\Utils\report_batch_operation_results( + 'plugin', + 'verify', + $total, + $successes, + $failures, + $skips + ); } /** From 9326466e7c967fde30531ffa03ce2f4238c9f474 Mon Sep 17 00:00:00 2001 From: Alain Schlesser Date: Fri, 22 Dec 2017 15:32:03 +0100 Subject: [PATCH 45/47] Second try at fixing single-file plugin support. --- src/Checksum_Plugin_Command.php | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/Checksum_Plugin_Command.php b/src/Checksum_Plugin_Command.php index 896a2b29c..7d7d365bc 100644 --- a/src/Checksum_Plugin_Command.php +++ b/src/Checksum_Plugin_Command.php @@ -234,16 +234,15 @@ private function get_all_plugin_names() { * @return array Array of files with their relative paths. */ private function get_plugin_files( $path ) { - $absolute_path = $this->get_absolute_path( $path ); + $folder = dirname( $this->get_absolute_path( $path ) ); // Return single file plugins immediately, to avoid iterating over the // entire plugins folder. - if ( is_file( $absolute_path ) ) { - return (array) $absolute_path; + if ( WP_PLUGIN_DIR === $folder ) { + return (array) $path; } - $folder = trailingslashit( dirname( $absolute_path ) ); - return $this->get_files( $folder ); + return $this->get_files( trailingslashit( $folder ) ); } /** From cd77f6e24aa1fa8215b48dc11298f063220c4aae Mon Sep 17 00:00:00 2001 From: Alain Schlesser Date: Fri, 22 Dec 2017 15:32:28 +0100 Subject: [PATCH 46/47] Adapt tests to reporting change. --- features/checksum-plugin.feature | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/features/checksum-plugin.feature b/features/checksum-plugin.feature index 9a51f417d..9908191ac 100644 --- a/features/checksum-plugin.feature +++ b/features/checksum-plugin.feature @@ -10,7 +10,7 @@ Feature: Validate checksums for WordPress plugins When I run `wp checksum plugin duplicate-post` Then STDOUT should be: """ - Success: Plugin verifies against checksums. + Success: Verified 1 of 1 plugins. """ Scenario: Modified plugin doesn't verify @@ -29,7 +29,7 @@ Feature: Validate checksums for WordPress plugins """ And STDERR should be: """ - Error: Plugin doesn't verify against checksums. + Error: No plugins verified (1 failed). """ When I run `rm wp-content/plugins/duplicate-post/duplicate-post.css` @@ -42,7 +42,7 @@ Feature: Validate checksums for WordPress plugins """ And STDERR should be: """ - Error: Plugin doesn't verify against checksums. + Error: No plugins verified (1 failed). """ When I run `touch wp-content/plugins/duplicate-post/additional-file.php` @@ -55,7 +55,7 @@ Feature: Validate checksums for WordPress plugins """ And STDERR should be: """ - Error: Plugin doesn't verify against checksums. + Error: No plugins verified (1 failed). """ Scenario: Soft changes are only reported in strict mode @@ -70,7 +70,7 @@ Feature: Validate checksums for WordPress plugins When I run `wp checksum plugin duplicate-post` Then STDOUT should be: """ - Success: Plugin verifies against checksums. + Success: Verified 1 of 1 plugins. """ And STDERR should be empty @@ -78,7 +78,7 @@ Feature: Validate checksums for WordPress plugins Then STDOUT should not be empty And STDERR should contain: """ - Error: Plugin doesn't verify against checksums. + Error: No plugins verified (1 failed). """ # WPTouch 4.3.22 contains multiple checksums for some of its files. @@ -93,7 +93,7 @@ Feature: Validate checksums for WordPress plugins When I run `wp checksum plugin wptouch` Then STDOUT should be: """ - Success: Plugin verifies against checksums. + Success: Verified 1 of 1 plugins. """ And STDERR should be empty From 1d8a74adcd791193c7ef5313ad068eb6d4a97474 Mon Sep 17 00:00:00 2001 From: Alain Schlesser Date: Fri, 22 Dec 2017 15:36:15 +0100 Subject: [PATCH 47/47] Fix failures count (number of unique plugins, not total failures). --- src/Checksum_Plugin_Command.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Checksum_Plugin_Command.php b/src/Checksum_Plugin_Command.php index 7d7d365bc..4419f8e20 100644 --- a/src/Checksum_Plugin_Command.php +++ b/src/Checksum_Plugin_Command.php @@ -121,7 +121,7 @@ public function __invoke( $args, $assoc_args ) { } $total = count( $plugins ); - $failures = count( $this->errors ); + $failures = count( array_unique( array_column( $this->errors, 'plugin_name' ) ) ); $successes = $total - $failures - $skips; \WP_CLI\Utils\report_batch_operation_results(