From d002386d9592d43531e9331e7a69318dd3dafe63 Mon Sep 17 00:00:00 2001 From: Nilambar Sharma Date: Thu, 26 Sep 2024 15:54:58 +0545 Subject: [PATCH 1/3] Check restricted plugin header fields --- .../Plugin_Header_Fields_Check.php | 35 +++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/includes/Checker/Checks/Plugin_Repo/Plugin_Header_Fields_Check.php b/includes/Checker/Checks/Plugin_Repo/Plugin_Header_Fields_Check.php index 4c6ef2c1f..33705de67 100644 --- a/includes/Checker/Checks/Plugin_Repo/Plugin_Header_Fields_Check.php +++ b/includes/Checker/Checks/Plugin_Repo/Plugin_Header_Fields_Check.php @@ -229,6 +229,41 @@ public function run( Check_Result $result ) { } } + $restricted_headers = array( + 'BitbucketPluginURI' => 'Bitbucket Plugin URI', + 'GistPluginURI' => 'Gist Plugin URI', + 'GiteaPluginURI' => 'Gitea Plugin URI', + 'GitHubPluginURI' => 'GitHub Plugin URI', + 'GitLabPluginURI' => 'GitLab Plugin URI', + ); + + $plugin_data = get_file_data( $plugin_main_file, $restricted_headers, 'plugin' ); + + $found_headers = array(); + + foreach ( $restricted_headers as $restricted_key => $restricted_label ) { + if ( array_key_exists( $restricted_key, $plugin_data ) && ! empty( $plugin_data[ $restricted_key ] ) ) { + $found_headers[ $restricted_key ] = $restricted_label; + } + } + + if ( ! empty( $found_headers ) ) { + $this->add_result_error_for_file( + $result, + sprintf( + /* translators: %s: header fields */ + __( 'Restricted plugin header field(s) found: %s', 'plugin-check' ), + "'" . implode( "', '", array_values( $found_headers ) ) . "'" + ), + 'plugin_header_restricted_fields', + $plugin_main_file, + 0, + 0, + '', + 7 + ); + } + if ( ! $result->plugin()->is_single_file_plugin() ) { if ( ! empty( $plugin_header['TextDomain'] ) ) { $plugin_slug = $result->plugin()->slug(); From 07f788f6a156330a16be7b968d713fb89ae9655d Mon Sep 17 00:00:00 2001 From: Nilambar Sharma Date: Thu, 26 Sep 2024 16:04:23 +0545 Subject: [PATCH 2/3] Add test for restricted plugin header fields --- .../plugins/test-plugin-header-fields-with-errors/load.php | 1 + .../tests/Checker/Checks/Plugin_Header_Fields_Check_Tests.php | 3 +++ 2 files changed, 4 insertions(+) diff --git a/tests/phpunit/testdata/plugins/test-plugin-header-fields-with-errors/load.php b/tests/phpunit/testdata/plugins/test-plugin-header-fields-with-errors/load.php index e505d32f6..efa5a69a0 100644 --- a/tests/phpunit/testdata/plugins/test-plugin-header-fields-with-errors/load.php +++ b/tests/phpunit/testdata/plugins/test-plugin-header-fields-with-errors/load.php @@ -12,6 +12,7 @@ * License URI: https://www.gnu.org/licenses/old-licenses/gpl-2.0.html * Text Domain: test-mismathed-textdomain-here * Domain Path: /nonexistent-folder + * GitHub Plugin URI: johndoe/package * Requires Plugins: Example Plugin, OtherPlugin * * @package test-plugin-header-fields-with-errors diff --git a/tests/phpunit/tests/Checker/Checks/Plugin_Header_Fields_Check_Tests.php b/tests/phpunit/tests/Checker/Checks/Plugin_Header_Fields_Check_Tests.php index d56ad15f8..14cc0e163 100644 --- a/tests/phpunit/tests/Checker/Checks/Plugin_Header_Fields_Check_Tests.php +++ b/tests/phpunit/tests/Checker/Checks/Plugin_Header_Fields_Check_Tests.php @@ -18,10 +18,13 @@ public function test_run_with_errors() { $check->run( $check_result ); + $errors = $check_result->get_errors(); $warnings = $check_result->get_warnings(); + $this->assertNotEmpty( $errors ); $this->assertNotEmpty( $warnings ); + $this->assertCount( 1, wp_list_filter( $errors['load.php'][0][0], array( 'code' => 'plugin_header_restricted_fields' ) ) ); $this->assertCount( 1, wp_list_filter( $warnings['load.php'][0][0], array( 'code' => 'plugin_header_invalid_plugin_uri_domain' ) ) ); $this->assertCount( 1, wp_list_filter( $warnings['load.php'][0][0], array( 'code' => 'plugin_header_invalid_plugin_description' ) ) ); $this->assertCount( 1, wp_list_filter( $warnings['load.php'][0][0], array( 'code' => 'plugin_header_invalid_author_uri' ) ) ); From 4ccecc626ce263e8612afcddaaf3b1a9563790df Mon Sep 17 00:00:00 2001 From: Nilambar Sharma Date: Thu, 26 Sep 2024 16:32:35 +0545 Subject: [PATCH 3/3] Add private method for custom get_plugin_data() output --- .../Plugin_Header_Fields_Check.php | 53 +++++++++++++------ 1 file changed, 36 insertions(+), 17 deletions(-) diff --git a/includes/Checker/Checks/Plugin_Repo/Plugin_Header_Fields_Check.php b/includes/Checker/Checks/Plugin_Repo/Plugin_Header_Fields_Check.php index 33705de67..e2fe1add3 100644 --- a/includes/Checker/Checks/Plugin_Repo/Plugin_Header_Fields_Check.php +++ b/includes/Checker/Checks/Plugin_Repo/Plugin_Header_Fields_Check.php @@ -51,12 +51,7 @@ public function get_categories() { * @SuppressWarnings(PHPMD.NPathComplexity) */ public function run( Check_Result $result ) { - if ( ! function_exists( 'get_plugin_data' ) ) { - require_once ABSPATH . 'wp-admin/includes/plugin.php'; - } - $plugin_main_file = $result->plugin()->main_file(); - $plugin_header = get_plugin_data( $plugin_main_file ); $labels = array( 'Name' => 'Plugin Name', @@ -74,6 +69,16 @@ public function run( Check_Result $result ) { 'RequiresPlugins' => 'Requires Plugins', ); + $restricted_labels = array( + 'BitbucketPluginURI' => 'Bitbucket Plugin URI', + 'GistPluginURI' => 'Gist Plugin URI', + 'GiteaPluginURI' => 'Gitea Plugin URI', + 'GitHubPluginURI' => 'GitHub Plugin URI', + 'GitLabPluginURI' => 'GitLab Plugin URI', + ); + + $plugin_header = $this->get_plugin_data( $plugin_main_file, array_merge( $labels, $restricted_labels ) ); + if ( ! empty( $plugin_header['Name'] ) ) { if ( in_array( $plugin_header['Name'], array( 'Plugin Name', 'My Basics Plugin' ), true ) ) { $this->add_result_warning_for_file( @@ -229,20 +234,10 @@ public function run( Check_Result $result ) { } } - $restricted_headers = array( - 'BitbucketPluginURI' => 'Bitbucket Plugin URI', - 'GistPluginURI' => 'Gist Plugin URI', - 'GiteaPluginURI' => 'Gitea Plugin URI', - 'GitHubPluginURI' => 'GitHub Plugin URI', - 'GitLabPluginURI' => 'GitLab Plugin URI', - ); - - $plugin_data = get_file_data( $plugin_main_file, $restricted_headers, 'plugin' ); - $found_headers = array(); - foreach ( $restricted_headers as $restricted_key => $restricted_label ) { - if ( array_key_exists( $restricted_key, $plugin_data ) && ! empty( $plugin_data[ $restricted_key ] ) ) { + foreach ( $restricted_labels as $restricted_key => $restricted_label ) { + if ( array_key_exists( $restricted_key, $plugin_header ) && ! empty( $plugin_header[ $restricted_key ] ) ) { $found_headers[ $restricted_key ] = $restricted_label; } } @@ -343,6 +338,30 @@ private function is_valid_url( $url ) { return filter_var( $url, FILTER_VALIDATE_URL ) === $url && str_starts_with( $url, 'http' ); } + /** + * Parses the plugin contents to retrieve plugin's metadata. + * + * @since 1.2.0 + * + * @param string $plugin_file Absolute path to the main plugin file. + * @param array $default_headers List of headers, in the format `array( 'HeaderKey' => 'Header Name' )`. + * @return string[] Array of file header values keyed by header name. + */ + private function get_plugin_data( $plugin_file, $default_headers ) { + $plugin_data = get_file_data( $plugin_file, $default_headers, 'plugin' ); + + // If no text domain is defined fall back to the plugin slug. + if ( ! $plugin_data['TextDomain'] ) { + $plugin_slug = dirname( plugin_basename( $plugin_file ) ); + + if ( '.' !== $plugin_slug && ! str_contains( $plugin_slug, '/' ) ) { + $plugin_data['TextDomain'] = $plugin_slug; + } + } + + return $plugin_data; + } + /** * Gets the description for the check. *