Skip to content

Commit

Permalink
Fix theme checking and object access, add documentation
Browse files Browse the repository at this point in the history
  • Loading branch information
kyletaylored committed Apr 29, 2021
1 parent 60a84ef commit 3fa0f2f
Show file tree
Hide file tree
Showing 4 changed files with 51 additions and 36 deletions.
38 changes: 21 additions & 17 deletions CHECKS.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,33 +2,33 @@

All the checks in this extension should be explained in detail here. This file should be organized by command and type checker

There are currently two broad types of checkers.
* [\Pantheon\Checker](php/pantheon/checker.php): These checks simply examine a piece of data and register and alert if the data exists. For instance, does the ```wp-content/object-cache.php``` exist? If so some object caching is enabled.
There are currently two broad types of checkers.
* [\Pantheon\Checker](php/pantheon/checker.php): These checks simply examine a piece of data and register and alert if the data exists. For instance, does the ```wp-content/object-cache.php``` exist? If so some object caching is enabled.
* [\Pantheon\Filesearcher](php/pantheon/filesearcher.php): These checks are functionally the same as the above except that before being run the class uses [\Symfony\Component\Finder\Finder](http://symfony.com/doc/current/components/finder.html) to load a list of files to be checked and then runs the specified check on each file. The logic is slightly different here to allow the Finder operation to *only* run once even when multiple "Filesearcher" children are running


The Checker oject has two key methods
The Checker oject has two key methods
* ```register( Check $check )```: receives an instance of a check to run.
* ```execute()```: executes all registered checks
The checks themselves are all extensions of the [\Patheon\Checkimplementation](php/pantheon/Checkimplemtation.php) class, each containing the following methods:

The checks themselves are all extensions of the [\Patheon\Checkimplementation](php/pantheon/Checkimplemtation.php) class, each containing the following methods:
* ```init()```
* ```run()```
* ```message()```;

The Checker object holds a collection of Check objects which it iterates and invokes each of these methods. In the case of the Filesearcher object, the ```init()``` method generates the file list ( if not already present ) and the ```run()``` method is passed a $file parameter.

The message method recieves a [\Pantheon\Messsenger](php/pantheon/messenger.php) and updates the various Check object properties for output. The output of each check is simply the formatted representation of the object properties.
The message method receives a [\Pantheon\Messsenger](php/pantheon/messenger.php) and updates the various Check object properties for output. The output of each check is simply the formatted representation of the object properties.

**Check Obect Properties:**
**Check Object Properties:**
* ```$name```: machine name of the check for use at the index of the returned JSON ( if json is specified )
* ```$description```: textual description of what the check does
* ```$label```: display version of check name used on dashboard
* ```$score```: used to toggle display mechanisms in the dashboard
0: ok (green)
1: warning (orange)
2: error (red)
* ```$result```: rendered html returned for use on the dashboard ( @TODO this should eventual return raw output as well when dashboard is not the intended client )
* ```$result```: rendered html returned for use on the dashboard ( @TODO this should eventually return raw output as well when dashboard is not the intended client )
* ```$alerts```: an array of alerts to rendered for the ```$result```. Each alert should be an array: ``` array(
'code' => 2,
'class' => 'error',
Expand All @@ -47,34 +47,38 @@ This check looks for insecure code by running ````preg_match("#.*(eval|base64_de

**Check:** [\Pantheon\Check\Exploited](php/pantheon/checks/exploited.php) This check attempts to find actual exploits by running ```'.*eval\(.*base64_decode\(.*';```. The goal here is to find instance of ```eval``` operating on decoded base64, which is almost certainly a bad idea. This regex should be refined because now it technically could alert when it finds the two functions on the same page but not necessary in the right order, leading to a false positive.

## Regular Checkers
## Regular Checkers

### General
### General
**Check:** [\Pantheon\Checks\General](php/pantheon/checks/general.php)
This check does the following:
* Checks for WP_DEBUG=True, returns 'ok' if in dev, 'warning; in live
* Checks whether the debug-bar plugin is active, 'ok' in dev, 'warning' in live
* Counts active plugins. Alerts if more than 100 are active
* Checks database settings for ```home``` and ```siteurl``` and whether they match. If they do not it recommends fixing. You can do this with WP_CLI/Terminus using 'terminus wp search-replace 'domain1' 'domain2' --site=sitename --env=dev'
* Checks whether WP Super Cache and/or W3 Total Cache are found and alerts 'warning' if so.
*
*

### Database
**Database:** [\Pantheon\Checks\Database](php/pantheon/checks/database.php)
**Database:** [\Pantheon\Checks\Database](php/pantheon/checks/database.php)
This check runs the following db checks
* Runs this query ```SELECT TABLES.TABLE_NAME, TABLES.TABLE_SCHEMA, TABLES.TABLE_ROWS, TABLES.DATA_LENGTH, TABLES.ENGINE from information_schema.TABLES where TABLES.TABLE_SCHEMA = '%s'``` and checks that all tables as set to InnoDb storage engine, alerts 'error' if not and specifies a query that can be run to fix the issue.
* Also checks number of rows in the options table. If over 10,000 it alerts 'error' because this is an indication that expired transients are stacking up or that they are using a lugin that over uses the options table. A bloated options table can be a major cause of WP performance issues.
* Counts options that are set to 'autoload', alerts is more than 1,000 are found. This is relevant because WordPress runs ```SELECT * FROM wp_options WHERE autoload = 'yes'``` on every page load to prepopulate the runtime cache. In cases where the query takes to long or returns too much data this can slow down page load. The only benefit to the runtime cache comes when object caching is not in use, but it is strongly encourage that some kind of object cache is always in use.
* Also checks number of rows in the options table. If over 10,000 it alerts 'error' because this is an indication that expired transients are stacking up or that they are using a lugin that over uses the options table. A bloated options table can be a major cause of WP performance issues.
* Counts options that are set to 'autoload', alerts is more than 1,000 are found. This is relevant because WordPress runs ```SELECT * FROM wp_options WHERE autoload = 'yes'``` on every page load to prepopulate the runtime cache. In cases where the query takes to long or returns too much data this can slow down page load. The only benefit to the runtime cache comes when object caching is not in use, but it is strongly encourage that some kind of object cache is always in use.
* Looks for transients and expired transients. Some plugins will use transients regularly but not add a garbage collection cron task. Core WordPress has not garbage collection for the transient api. Over time this can cause transients to bloat the ```wp_options``` database as mentioned above.

### Cron
**Cron:** [\Pantheon\Checks\Cron](php/commands/checks/cron.php)
This check simple examines whether ```DISABLE_WP_CRON``` evaluates ```true``` to see if cron has been disabled. ( We should probably also curl the wp-cron.php?doing_wp_cron and ensure we get a 200 ). Some hosts disable the default WP_Cron functionality, substituting a system cron, because the HTTP base WP_Cron can sometimes have race conditions develop causing what might be referred to as "runaway cron", in which HTTP multiple requests trigger the cron a small amount of time causing a spike in PHP/MySQL resource consumption. This check also dumps the scheduled tasks into a table using ```get_option('cron')```.
This check simple examines whether ```DISABLE_WP_CRON``` evaluates ```true``` to see if cron has been disabled. ( We should probably also curl the wp-cron.php?doing_wp_cron and ensure we get a 200 ). Some hosts disable the default WP_Cron functionality, substituting a system cron, because the HTTP base WP_Cron can sometimes have race conditions develop causing what might be referred to as "runaway cron", in which HTTP multiple requests trigger the cron a small amount of time causing a spike in PHP/MySQL resource consumption. This check also dumps the scheduled tasks into a table using ```get_option('cron')```.

### object-cache
**objectcache** [\Pantheon\Checks\Cron](php/commands/checks/objectcache.php)
Checks is the ```wp-content/object-cache.php``` exists to detemine whether object caching is in use. Checks that the ```global $redis_server``` variable is not empty to determine whether redis is being used.
Checks is the ```wp-content/object-cache.php``` exists to determine whether object caching is in use. Checks that the ```global $redis_server``` variable is not empty to determine whether redis is being used.

### plugins
### Plugins
**plugins** [\Pantheon\Checks\Plugins](php/commands/checks/plugins.php)
Checks all plugins against the wpvulndb.com database we license. Alerts 'error' if a vulnerability is found and links to the wpvulndb.com page for more info. Also checks for available updates and alerts 'warning' if plugins needing an update are found.

### Themes
**themes** [\Pantheon\Checks\Themes](php/commands/checks/themes.php)
Checks all themes against the wpvulndb.com database we license. Alerts 'error' if a vulnerability is found and links to the wpvulndb.com page for more info. Also checks for available updates and alerts 'warning' if themes needing an update are found.
9 changes: 5 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,13 @@

# WP Launch Check

WP Launch Check is an extension for WP-CLI designed for Pantheon.io WordPress customers. While designed initially for the Pantheon dashboard it is intended to be fully usable outside of Pantheon.
WP Launch Check is an extension for WP-CLI designed for Pantheon.io WordPress customers. While designed initially for the Pantheon dashboard it is intended to be fully usable outside of Pantheon.

[![Build Status](https://travis-ci.org/pantheon-systems/wp_launch_check.svg?branch=master)](https://travis-ci.org/pantheon-systems/wp_launch_check)

To use WP Launch Check simply run the ```wp launchcheck <subcommand>``` command like you would any other WP-CLI command.

For more information about WP-CLI you can visit [their github page](https://github.com/wp-cli/wp-cli).
For more information about WP-CLI you can visit [their github page](https://github.com/wp-cli/wp-cli).

WP Launch Check should be considered in "BETA". Many of the checks have still not been tested in the wild. If you experience a problem please open an issue.

Expand All @@ -23,12 +23,13 @@ Once you've done so, you can install this package with `wp package install panth
Below is a summary of the available commands. *Full technical description of each check run by each command can be found in the [CHECKS.md](CHECKS.md)*

* **wp launchcheck cron** : Checks whether cron is enabled and what jobs are scheduled
* **wp launchcheck general**: General checks for data and best practice, i.e. are you running the debug-bar plugin or have WP_DEBUG defined? This will tell you.
* **wp launchcheck general**: General checks for data and best practice, i.e. are you running the debug-bar plugin or have WP_DEBUG defined? This will tell you.
* **wp launchcheck database**: Checks related to the databases.
* **wp launchcheck object_cache**: Checks whether object caching is enabled and if on Pantheon whether redis is enabled.
* **wp launchcheck sessions**: Checks for plugins refering to the php session_start() function or the superglobal ```$SESSION``` variable. In either case, if you are on a cloud/distributed platform you will need additional configuration achieve the expected functionality
* **wp launchcheck sessions**: Checks for plugins referring to the php session_start() function or the superglobal ```$SESSION``` variable. In either case, if you are on a cloud/distributed platform you will need additional configuration achieve the expected functionality
* **wp launchcheck secure**: Does some rudimentary security checks
* **wp launchcheck plugins**: Checks plugins for updates and known vulnerabilities
* **wp launchcheck themes**: Checks themes for updates and known vulnerabilities



Expand Down
6 changes: 2 additions & 4 deletions php/commands/launchcheck.php
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<?php
/**
* Implements example command.
* Audit WordPress configuration.
* @version 0.1.4
*/
class LaunchCheck {
Expand Down Expand Up @@ -186,7 +186,6 @@ public function secure($args, $assoc_args) {
public function plugins($args, $assoc_args) {
$checker = new \Pantheon\Checker();
$checker->register( new \Pantheon\Checks\Plugins( isset($assoc_args['all'])) );
$format = isset($assoc_args['format']) ? $assoc_args['format'] : 'raw';
$checker->execute();
$format = isset($assoc_args['format']) ? $assoc_args['format'] : 'raw';
\Pantheon\Messenger::emit($format);
Expand All @@ -211,8 +210,7 @@ public function plugins($args, $assoc_args) {
*/
public function themes($args, $assoc_args) {
$checker = new \Pantheon\Checker();
$checker->register( new \Pantheon\Checks\Themes( isset($assoc_args['all'])) );
$format = isset($assoc_args['format']) ? $assoc_args['format'] : 'raw';
$checker->register( new \Pantheon\Checks\Themes( isset($assoc_args['all']) ) );
$checker->execute();
$format = isset($assoc_args['format']) ? $assoc_args['format'] : 'raw';
\Pantheon\Messenger::emit($format);
Expand Down
34 changes: 23 additions & 11 deletions php/pantheon/checks/themes.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
class Themes extends Checkimplementation {
public $name = 'themes';
public $check_all_themes;
public $alerts = array();

public function __construct($check_all_themes) {
$this->check_all_themes = $check_all_themes;
Expand All @@ -25,7 +26,6 @@ public function init() {
$this->score = 0;
$this->result = '';
$this->label = 'Themes';
$this->alerts = array();
self::$instance = $this;
return $this;
}
Expand All @@ -34,6 +34,7 @@ public function run() {
if (!function_exists('wp_get_themes')) {
require_once \WP_CLI::get_config('path') . '/wp-includes/theme.php';
}
$current_theme = wp_get_theme();
$all_themes = Utils::sanitize_data( wp_get_themes() );
$update = Utils::sanitize_data( get_theme_updates() );
$report = array();
Expand All @@ -43,13 +44,23 @@ public function run() {
$slug = substr($theme_path, 0, stripos($theme_path,'/'));
}

$vulnerable = $this->is_vulnerable($slug, $data['Version']);
// Check if we only want to scan the active theme.
if (!$this->check_all_themes) {
// If theme list index doesn't match current theme, skip.
if ($current_theme->stylesheet !== $slug) {
continue;
}
}

$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[$theme_path]->update->new_version;
$available = $update[$slug]->update["new_version"];
}
if ( false === $vulnerable ) {
$vulnerable = "None";
Expand All @@ -59,7 +70,7 @@ public function run() {

$report[$slug] = array(
'slug' => $slug,
'installed' => (string) $data['Version'],
'installed' => (string) $version,
'available' => (string) $available,
'needs_update' => (string) $needs_update,
'vulnerable' => $vulnerable,
Expand Down Expand Up @@ -121,12 +132,13 @@ protected function getThemeVulnerability($theme_slug )
}

/**
* Checks a theme by slug and version for vulnerabilities
* @param $theme_slug string (required) string representing the theme slug
* @param $current_version string (required) string representing the theme version
*
* @return array containing the vulnerability or false
*/
* Checks a theme by slug and version for vulnerabilities
* @param $theme_slug string (required) string representing the theme slug
* @param $current_version string (required) string representing the theme version
*
* @return array containing the vulnerability or false
* @throws \Exception
*/
public function is_vulnerable($theme_slug, $current_version) {

// Fetch the theme data if we don't have it already
Expand All @@ -140,7 +152,7 @@ public function is_vulnerable($theme_slug, $current_version) {
}

// No issues if the theme has no vulnerabilities
if ( ! isset( $theme_results['vulnerabilities'] ) || empty( $theme_results['vulnerabilities'] ) ) {
if ( empty( $theme_results['vulnerabilities'] ) ) {
return false;
}

Expand Down

0 comments on commit 3fa0f2f

Please sign in to comment.