Skip to content

Commit

Permalink
Merge pull request #144 from pantheon-systems/cmsp-261-remove-wpscan
Browse files Browse the repository at this point in the history
[CMSP-261] Remove vulnerability column for plugins and themes
  • Loading branch information
jazzsequence authored May 25, 2023
2 parents 2293f49 + 15426ba commit e4cfb97
Show file tree
Hide file tree
Showing 4 changed files with 137 additions and 72 deletions.
4 changes: 2 additions & 2 deletions features/theme.feature
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ Feature: Test WordPress for themes with known security issues
When I run `wp launchcheck all --all`
Then STDOUT should contain:
"""
Found 1 themes needing updates and 0 known vulnerabilities
Found one theme needing updates
"""
And STDOUT should contain:
"""
Expand All @@ -23,5 +23,5 @@ Feature: Test WordPress for themes with known security issues
When I run `wp launchcheck all --all`
Then STDOUT should contain:
"""
Found 0 themes needing updates and 0 known vulnerabilities
Found 0 themes needing updates
"""
36 changes: 36 additions & 0 deletions php/pantheon/checks/namespace.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
<?php
/**
* WP Launch Check common functions
*
* @package wp_launch_check
*/

namespace Pantheon\Checks\Common;

/**
* Get a WordPress vulnerability API token if one is defined and we're in the right environment.
* Copied from wp_launch_check/php/pantheon/checks/plugins.php
* Uses the WPSCAN_API_TOKEN constant if defined.
*
* @return string
* @todo Replace this with a Patchstack API token.
*/
function get_wp_vuln_api_token() {
if ( defined( 'WPSCAN_API_TOKEN' ) ) {
// Don't use WPSCAN if PANTHEON_WPSCAN_ENVIRONMENTS have not been specified.
if( ! defined( 'PANTHEON_WPSCAN_ENVIRONMENTS' ) ) {
return '';
}

$environments = ( ! is_array( PANTHEON_WPSCAN_ENVIRONMENTS ) ) ? explode( ',', PANTHEON_WPSCAN_ENVIRONMENTS ) : PANTHEON_WPSCAN_ENVIRONMENTS;

// Only run WPSCAN on the specified environments unless it's been configured to run on all (*).
if ( in_array( getenv( 'PANTHEON_ENVIRONMENT' ), $environments, true ) || in_array( '*', $environments, true ) ) {
return WPSCAN_API_TOKEN;
}
}

// TODO: Replace this PANTHEON_WPVULNDB_API_TOKEN with a new Patchstack API token.
// return getenv( 'PANTHEON_WPVULNDB_API_TOKEN' );
return '';
}
98 changes: 51 additions & 47 deletions php/pantheon/checks/plugins.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ class Plugins extends Checkimplementation {
public $check_all_plugins;

public function __construct($check_all_plugins) {
require_once __DIR__ . '/namespace.php';

$this->check_all_plugins = $check_all_plugins;
}

Expand All @@ -37,47 +39,56 @@ public function run() {
$all_plugins = Utils::sanitize_data( get_plugins() );
$update = Utils::sanitize_data( get_plugin_updates() );
$report = array();
$should_check_vulnerabilities = Common\get_wp_vuln_api_token();
$vulnerable = false;

foreach( $all_plugins as $plugin_path => $data ) {
$slug = $plugin_path;
if (stripos($plugin_path,'/')) {
$slug = substr($plugin_path, 0, stripos($plugin_path,'/'));
}

$vulnerable = $this->is_vulnerable($slug, $data['Version']);

$needs_update = 0;
$available = '-';
if (isset($update[$plugin_path])) {
$needs_update = 1;
$available = $update[$plugin_path]->update->new_version;
}
if ( false === $vulnerable ) {
$vulnerable = "None";
} else {
$vulnerable = sprintf('<a href="https://wpscan.com/plugins/%s" target="_blank" >more info</a>', $slug );
}

$report[$slug] = array(
$report[ $slug ] = array(
'slug' => $slug,
'installed' => (string) $data['Version'],
'available' => (string) $available,
'needs_update' => (string) $needs_update,
'vulnerable' => $vulnerable,
);

// If we're checking for vulnerabilities, do stuff.
if ( $should_check_vulnerabilities ) {
$vulnerable = $this->is_vulnerable($slug, $data['Version']);

if ( $vulnerable ) {
// Todo: Replace this URL with a Patchstack URL
$vulnerable = sprintf('<a href="https://wpscan.com/plugins/%s" target="_blank" >more info</a>', $slug );
} else {
$vulnerable = "None";
}

$report[ $slug ]['vulnerable'] = $vulnerable;
}
}
$this->alerts = $report;
}

/**
* Checks the plugin slug against the vulnerability db
* @param $plugin_slug string (required) string representing the plugin slug
*
* @return array containing vulnerability info or false
* @todo Refactor to use Patchstack API.
*/
protected function getPluginVulnerability( $plugin_slug )
{
// Get the vulnerability API token from the platform
$wpvulndb_api_token = $this->getWpScanApiToken();
$wpvulndb_api_token = Common\get_wp_vuln_api_token();

// Fail silently if there is no API token.
if( false === $wpvulndb_api_token || empty( $wpvulndb_api_token ) ) {
Expand Down Expand Up @@ -120,32 +131,6 @@ protected function getPluginVulnerability( $plugin_slug )
return $result[$plugin_slug];
}


protected function getWpScanApiToken() {
if( !defined( 'PANTHEON_WPSCAN_ENVIRONMENTS' ) ) {
return false;
}

if ( ! is_array( PANTHEON_WPSCAN_ENVIRONMENTS ) ) {
$environments = explode( ',', PANTHEON_WPSCAN_ENVIRONMENTS );
} else {
$environments = PANTHEON_WPSCAN_ENVIRONMENTS;
}

if(
!in_array( getenv( 'PANTHEON_ENVIRONMENT' ), $environments )
&& !in_array( '*', $environments )
) {
return false;
}

if( defined( 'WPSCAN_API_TOKEN' ) ) {
return WPSCAN_API_TOKEN;
}

return getenv( 'PANTHEON_WPVULNDB_API_TOKEN' );
}

/**
* Checks a plugin by slug and version for vulnerabilities
* @param $plugin_slug string (required) string representing the plugin slug
Expand Down Expand Up @@ -192,46 +177,65 @@ public function is_vulnerable($plugin_slug, $current_version) {
}

public function message(Messenger $messenger) {
$plugin_message = __( 'You should update all out-of-date plugins' );
$vuln_message = __( 'Update plugins to fix vulnerabilities' );
$no_plugins_message = __( 'No plugins found' );
$should_check_vulnerabilities = Common\get_wp_vuln_api_token();

if (!empty($this->alerts)) {
$headers = array(
'slug'=>"Plugin",
'installed'=>"Current",
'available' => "Available",
'needs_update'=>"Needs Update",
'vulnerable'=>"Vulnerabilities"
'slug'=> __( 'Plugin' ),
'installed'=> __( 'Current' ),
'available' => __( 'Available' ),
'needs_update'=> __( 'Needs Update' ),
);

if ( $should_check_vulnerabilities ) {
$headers['vulnerable'] = __( ' Vulnerabilities' );
}

$rows = array();
$count_update = 0;
$count_vuln = 0;

foreach( $this->alerts as $alert ) {
$class = 'ok';
if ($alert['needs_update']) {
$class = 'warning';
$count_update++;
}
if ('None' != $alert['vulnerable']) {

if ( $should_check_vulnerabilities && 'None' !== $alert['vulnerable']) {
$class = 'error';
$count_vuln++;
}

$rows[] = array('class'=>$class, 'data' => $alert);
}

$updates_message = $count_update === 1 ? __( 'Found one plugin needing updates' ) : sprintf( _n( 'Found %d plugin needing updates', 'Found %d plugins needing updates', $count_update ), $count_update );
$result_message = ! $should_check_vulnerabilities ?
// Not checking vulnerabilities message.
$updates_message . ' ...':
// Checking vulnerabilities message.
$updates_message . ' ' .
( $count_vuln === 1 ? __( 'Also found one plugin with known vulnerabilities ...' ) : sprintf( _n( 'Also found %d plugin with known vulnerabilities ...', 'Also found %d plugins with known vulnerabilities ...', $count_vuln ), $count_vuln ) );
$rendered = PHP_EOL;
$rendered .= sprintf("Found %d plugins needing updates and %d known vulnerabilities ... \n".PHP_EOL, $count_update, $count_vuln);
$rendered .= "$result_message \n" . PHP_EOL;
$rendered .= View::make('table', array('headers'=>$headers,'rows'=>$rows));

$this->result .= $rendered;
if ($count_update > 0) {
$this->score = 1;
$this->action = "You should update all out-of-date plugins";
$this->action = $plugin_message;
}

if ($count_vuln > 0) {
$this->score = 2;
$this->action = "Update plugins to fix vulnerabilities";
$this->action = $vuln_message;
}
} else {
$this->result .= "No plugins found.";
$this->result .= $no_plugins_message;
}
$messenger->addMessage(get_object_vars($this));
}
Expand Down
71 changes: 48 additions & 23 deletions php/pantheon/checks/themes.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ class Themes extends Checkimplementation {
public $alerts = array();

public function __construct($check_all_themes) {
require_once __DIR__ . '/namespace.php';

$this->check_all_themes = $check_all_themes;
}

Expand All @@ -38,6 +40,9 @@ public function run() {
$all_themes = Utils::sanitize_data( wp_get_themes() );
$update = Utils::sanitize_data( get_theme_updates() );
$report = array();
$should_check_vulnerabilities = Common\get_wp_vuln_api_token();
$vulnerable = false;

foreach( $all_themes as $theme_path => $data ) {
$slug = $theme_path;
if (stripos($theme_path,'/')) {
Expand All @@ -54,27 +59,34 @@ public function run() {

$data = wp_get_theme($slug);
$version = $data->version;
$vulnerable = $this->is_vulnerable($slug, $version);

$needs_update = 0;
$available = '-';

if (isset($update[$theme_path])) {
$needs_update = 1;
$available = $update[$slug]->update["new_version"];
}
if ( false === $vulnerable ) {
$vulnerable = "None";
} else {
$vulnerable = sprintf('<a href="https://wpscan.com/themes/%s" target="_blank" >more info</a>', $slug );
}

$report[$slug] = array(
'slug' => $slug,
'installed' => (string) $version,
'available' => (string) $available,
'needs_update' => (string) $needs_update,
'vulnerable' => $vulnerable,
);

// If we're checking for vulnerabilities, do stuff.
if ( $should_check_vulnerabilities ) {
$vulnerable = $this->is_vulnerable($slug, $version);

if ( $vulnerable ) {
// Todo: Replace this link with one to Patchstack.
$vulnerable = sprintf('<a href="https://wpscan.com/themes/%s" target="_blank" >more info</a>', $slug );
} else {
$vulnerable = "None";
}

$report[ $slug ]['vulnerable'] = $vulnerable;
}
}
$this->alerts = $report;
}
Expand All @@ -85,11 +97,10 @@ public function run() {
*
* @return array containing vulnerability info or false
* @throws \Exception
* @todo Refactor this to use the Patchstack API
*/
protected function getThemeVulnerability($theme_slug )
{
// Get the vulnerability API token from the platform
$wpvulndb_api_token = getenv('PANTHEON_WPVULNDB_API_TOKEN');
protected function getThemeVulnerability($theme_slug ) {
$wpvulndb_api_token = Common\get_wp_vuln_api_token();

// Fail silently if there is no API token.
if( false === $wpvulndb_api_token || empty( $wpvulndb_api_token ) ) {
Expand Down Expand Up @@ -179,13 +190,20 @@ public function is_vulnerable($theme_slug, $current_version) {

public function message(Messenger $messenger) {
if (!empty($this->alerts)) {
$should_check_vulnerabilities = Common\get_wp_vuln_api_token();
$theme_message = __( 'You should update all out-of-date themes' );
$vuln_message = __( 'Update themes to fix vulnerabilities' );
$no_themes_message = __( 'No themes found' );
$headers = array(
'slug'=>"Theme",
'installed'=>"Current",
'available' => "Available",
'needs_update'=>"Needs Update",
'vulnerable'=>"Vulnerabilities"
'slug' => __( 'Theme' ),
'installed' => __( 'Current' ),
'available' => __( 'Available' ),
'needs_update' => __( 'Needs Update' ),
);
if ( $should_check_vulnerabilities ) {
$headers['vulnerable'] = __( 'Vulnerable' );
}

$rows = array();
$count_update = 0;
$count_vuln = 0;
Expand All @@ -195,29 +213,36 @@ public function message(Messenger $messenger) {
$class = 'warning';
$count_update++;
}
if ('None' != $alert['vulnerable']) {
if ( $should_check_vulnerabilities && 'None' !== $alert['vulnerable']) {
$class = 'error';
$count_vuln++;
}
$rows[] = array('class'=>$class, 'data' => $alert);
}

$updates_message = $count_update === 1 ? __( 'Found one theme needing updates' ) : sprintf( _n( 'Found %d theme needing updates', 'Found %d themes needing updates', $count_update ), $count_update );
$result_message = ! $should_check_vulnerabilities ?
// Not checking vulnerabilities message.
$updates_message . ' ...':
// Checking vulnerabilities message.
$updates_message . ' ' .
( $count_vuln === 1 ? __( 'Also found one theme with known vulnerabilities ...' ) : sprintf( _n( 'Also found %d theme with known vulnerabilities ...', 'Also found %d themes with known vulnerabilities ...', $count_vuln ), $count_vuln ) );
$rendered = PHP_EOL;
$rendered .= sprintf("Found %d themes needing updates and %d known vulnerabilities ... \n".PHP_EOL, $count_update, $count_vuln);
$rendered .= "$result_message \n" .PHP_EOL;
$rendered .= View::make('table', array('headers'=>$headers,'rows'=>$rows));

$this->result .= $rendered;
if ($count_update > 0) {
$this->score = 1;
$this->action = "You should update all out-of-date themes";
$this->action = $theme_message;
}

if ($count_vuln > 0) {
if ( $should_check_vulnerabilities && $count_vuln > 0 ) {
$this->score = 2;
$this->action = "Update themes to fix vulnerabilities";
$this->action = $vuln_message;
}
} else {
$this->result .= "No themes found.";
$this->result .= $no_themes_message;
}
$messenger->addMessage(get_object_vars($this));
}
Expand Down

0 comments on commit e4cfb97

Please sign in to comment.