Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add plugin checksums verification #26

Merged
merged 49 commits into from
Dec 22, 2017
Merged

Add plugin checksums verification #26

merged 49 commits into from
Dec 22, 2017

Conversation

schlessera
Copy link
Member

Initial implementation of the plugin checksum verification.

The WordPress.org infrastructure now calculates MD5 and SHA-256 checksums for all plugin files and stores them in a publically accessible way. You can find a specification of the current endpoint to retrieve the checksums here.

The wp checksum plugin command goes through some or all of the plugins installed on a machine, downloads the checksums for each plugin, and then verifies the downloaded checksums against freshly generated ones.

  • The output on STDOUT will provide a list of checksum mismatches or added/removed files.
  • STDERR will contain warnings about skipped plugins.
  • The exit code will return 0 if all compared checksums were valid, and 1 otherwise.

Uses https://meta.trac.wordpress.org/ticket/3192

Resolves #15

schlessera and others added 30 commits November 22, 2017 20:39
Multiple checksums act as a whitelist, accepting any one of the available checksums as proof for the file's integrity.

Fixes #24
/**
* Recursively get the list of files for a given path.
*
* @param string $path Root parse to start the recursive traversal in.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

path* ?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in 454a227

Copy link
Contributor

@gitlost gitlost left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It'd be nice maybe to have a --report option or similar to give more feedback but that's for another day...

Scenario: Multiple checksums for a single file are supported
Given a WP install

When I run `wp plugin install wptouch --version=4.3.22`
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you add a comment here that wptouch has sha256 (and md5) checksums with multiple values per file as it's not immediately obvious what's being tested here...

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I thought the scenario name Multiple checksums for a single file are supported already gave that away...?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ha yeah it does, it just wasn't obvious to me why wptouch should test it... ignore at will!

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, I see. The choice of the plugin was based on the issue that reported the error: #24
I might add comments to link the tests to the relevant source issues then.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added in 464be76

$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.' );
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you add a test to provoke this error (and similarly for other errors/warnings - where feasible!)?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added in 9ef77d6


if ( empty( $this->errors ) ) {
WP_CLI::success(
count( $plugins ) > 1
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

At the moment if you do wp checksum plugin hello then you get a warning about checksums not being available and Success: Plugin verifies against checksums. at the end. It'd probably be better to use Utils\report_batch_operation_results() instead once (after the error report if any), and also have a skip count to give it.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm...
I just tried using report_batch_operation_results() instead, but in the above case, that then tells us the plugin was already verified, which is nonsense of course:
image 2017-12-22 at 2 05 15 pm

Copy link
Contributor

@gitlost gitlost Dec 22, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you keep a $skips count and then pass it it should work ok eg:

if ( ! empty( $this->errors ) ) {
	$formatter = new \WP_CLI\Formatter(
		$assoc_args,
		array( 'plugin_name', 'file', 'message' )
	);
	$formatter->display_items( $this->errors );
}

$total = count( $plugins );
$failures = count( $this->errors );
$successes = $total - $failures - $skips;
Utils\report_batch_operation_results( 'plugin', 'verify', $total, $successes, $failures, $skips );

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changed in 73efdd4

*/
private function get_all_plugin_names() {
$names = array();
foreach ( get_plugins() as $file => $details ) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm wondering if the all_plugins filter should be applied here or not??

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think that would introduce a security vulnerability, as a malicious plugin could just filter itself out of the integrity check.

* @return array<string> 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, ...)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think for future proofing it should check here that $path includes a directory and isn't just a bare file like hello.php.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, yes, thanks for catching the TODO, that does indeed still need an implementation.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So, I just checked, and the current code just works with bare files like hello.php as well. I don't think that we want to force the need for a folder for plugins.

However, must-use plugins are currently being ignored...

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But $folder = trailingslashit( dirname( $this->get_absolute_path( $path ) ) ); where $path === "hello.php" will just cause the plugins directory to be traversed. I was thinking of it doing something like:

if ( false === strpos( $path, '/' ) ) {
	return array( $this->get_absolute_path( $path ) );
}

However, must-use plugins are currently being ignored...

I was wondering if they're ever stored on wordpress.org/plugins, and would checksums ever be provided?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Re. single file. Yes, you are right. I did some deeper checking, and it only worked right now because the checksum could not be retrieved for hello.php (as the hello-dolly plugin is different on the repository).

Re. must-use plugins, I know that some people just move existing plugins into the must-use folder for client sites, to make sure they can't be disabled. This is usually done by adding something like the bedrock mu-plugins autoloader.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have fixed the single file issue (commits incoming). I suggest skipping the mu-checking for now and adding a separate issue for that, it might need more discussion.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Single-file support: 9251a68

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Issue re. mu-plugins: #27

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() );
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you reuse $pathname here (also technically more correct!)...

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I originally built it this way to have wp-content/plugins be the root and everything else related to that.
This means that you have the plugin's folder included in the file name for error messages, like akismet/akismet.php.
This serves two purposes:

  • Allow proper delineation between plugins in a folder, and single-file plugins that don't have their own folder.
  • Show whatever custom folder name the plugin happens to be installed in. Potentially, you can even have the same plugin installed in multiple versions, with differing checksum errors. Showing the folder helps you identify which one is being checked.

Can you elaborate why you think your suggestion is "technically more correct" ?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I just meant to do $filtered_files[] = $pathname rather than the str_replace() - it's a pet bugbear of mine when I see this str_replace() pattern used on paths when it should be the "correct" substr() - as used here for $pathanme - but totally ignorable...

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess I can replace the str_replace() with a substr() anyway...

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, nvm, I just noticed it myself... Doing the change now! :)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in 22bc73e

@gitlost gitlost merged commit 05e2f8e into master Dec 22, 2017
@gitlost gitlost deleted the plugin-checksums branch December 22, 2017 15:25
@gitlost
Copy link
Contributor

gitlost commented Dec 22, 2017

Good stuff. We have our first headline release feature!

@nateinaction
Copy link

Hey guys, really love this feature. I didn't see it explicitly mentioned in any of the changes for 1.5. Will this be included in WP CLI 1.5?

@gitlost
Copy link
Contributor

gitlost commented Jan 8, 2018

Absolutely!

@schlessera
Copy link
Member Author

@nateinaction Yes, it will be part of 1.5, coming soon!

@nateinaction
Copy link

Thanks again guys!

@gitlost
Copy link
Contributor

gitlost commented Jan 10, 2018

@schlessera was wondering should a release be made of checksum-command now/shortly so that people can try it in the nightly?

schlessera pushed a commit that referenced this pull request Dec 23, 2021
Add plugin checksums verification
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants