Skip to content

Commit

Permalink
Merge branch 'release-0.14'
Browse files Browse the repository at this point in the history
  • Loading branch information
chesio committed Dec 2, 2019
2 parents 94c4551 + c24a184 commit d449a70
Show file tree
Hide file tree
Showing 64 changed files with 677 additions and 550 deletions.
13 changes: 8 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ Helps keeping WordPress websites secure.

## Requirements

* [PHP](https://secure.php.net/) 7.1 or newer
* [WordPress](https://wordpress.org/) 4.9 or newer
* [PHP](https://secure.php.net/) 7.2 or newer
* [WordPress](https://wordpress.org/) 5.1 or newer

## Limitations

Expand All @@ -31,15 +31,17 @@ Basic checks cover common security practices. They do not require any informatio
1. Is backend editing of plugin and theme PHP files disabled?
1. Are directory listings disabled?
1. Is execution of PHP files from uploads directory forbidden?
1. Is display of PHP errors off by default? This check is only run in production environment, ie. when `WP_ENV === 'production'`.
1. Is display of PHP errors off by default? This check is only run in live environment (by default when `WP_ENV === 'production'` or `WP_ENV === 'staging'`, but this can be [customized via a filter](#customization)).
1. Is error log file not publicly available? This check is only run if both `WP_DEBUG` and `WP_DEBUG_LOG` constants are set to true.
1. Are there no common usernames like admin or administrator on the system?
1. Are user passwords hashed with some non-default hashing algorithm?
1. Are user passwords hashed with [more secure hashing algorithm](https://roots.io/improving-wordpress-password-security/) than MD5 used by [WordPress by default](https://core.trac.wordpress.org/ticket/21022)?
1. Is PHP version still supported?

#### Advanced checks

Advanced checks require data from external servers (in the moment from WordPress.org only). Because of this, they leak some information about your website. In the moment, **list of installed plugins** (but only those with _readme.txt_ file) is shared with WordPress.org. Also, because of the external HTTP request, the checks take more time to execute.
Advanced checks require data from external sources, therefore they leak some information about your website and take more time to execute.

In the moment, list of installed plugins (but only those with _readme.txt_ file) is shared with WordPress.org.

##### WordPress core integrity check

Expand Down Expand Up @@ -121,6 +123,7 @@ Logs are stored in database and can be viewed on backend. Logs are automatically
Some of the modules listed above come with settings panel. Further customization can be done with filters provided by plugin:

* `bc-security/filter:is-admin` - filters boolean value that determines whether current user is considered an admin user. This check determines whether admin login notification should be sent for particular user. By default, any user with `manage_options` capability is considered an admin (or `manage_network` on multisite).
* `bc-security/filter:is-live` - filters boolean value that determines whether your website is running in a live environment.
* `bc-security/filter:plugin-changelog-url` - filters changelog URL of given plugin. Might come handy in case of plugins not hosted in Plugins Directory.
* `bc-security/filter:obvious-usernames` - filters array of common usernames that are being checked via [checklist check](#basic-checks). By default, the array consists of _admin_ and _administrator_ values.
* `bc-security/filter:plugins-to-check-for-integrity` - filters array of plugins that should have their integrity checked. By default, the array consists of all installed plugins that have _readme.txt_ file. Note that plugins under version control are automatically omitted.
Expand Down
12 changes: 6 additions & 6 deletions bc-security.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,23 +3,23 @@
* Plugin Name: BC Security
* Plugin URI: https://github.com/chesio/bc-security
* Description: Helps keeping WordPress websites secure.
* Version: 0.13.1
* Version: 0.14.0
* Author: Česlav Przywara <[email protected]>
* Author URI: https://www.chesio.com
* Requires PHP: 7.1
* Requires WP: 4.9
* Tested up to: 5.2
* Requires PHP: 7.2
* Requires WP: 5.1
* Tested up to: 5.3
* Text Domain: bc-security
* GitHub Plugin URI: https://github.com/chesio/bc-security
*/

if (version_compare(PHP_VERSION, '7.1', '<')) {
if (version_compare(PHP_VERSION, '7.2', '<')) {
// Warn user that his/her PHP version is too low for this plugin to function.
add_action('admin_notices', function () {
echo '<div class="notice notice-error"><p>';
echo esc_html(
sprintf(
__('BC Security plugin requires PHP 7.1 to function properly, but you have version %s installed. The plugin has been auto-deactivated.', 'bc-security'),
__('BC Security plugin requires PHP 7.2 to function properly, but you have version %s installed. The plugin has been auto-deactivated.', 'bc-security'),
PHP_VERSION
)
);
Expand Down
8 changes: 4 additions & 4 deletions classes/BlueChip/Security/Admin.php
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ public function makeAdminMenu()
}

// First registered page acts as main page:
$main_page = reset($this->pages);
$main_page = \reset($this->pages);

// Add (main) menu page
add_menu_page(
Expand Down Expand Up @@ -119,7 +119,7 @@ public function makeAdminMenu()
public function filterActionLinks(array $links): array
{
if (current_user_can(self::CAPABILITY) && isset($this->pages['bc-security-setup'])) {
$links[] = sprintf(
$links[] = \sprintf(
'<a href="%s">%s</a>',
$this->pages['bc-security-setup']->getUrl(),
esc_html($this->pages['bc-security-setup']->getMenuTitle())
Expand All @@ -138,8 +138,8 @@ public function filterActionLinks(array $links): array
private function renderCounter(Core\Admin\AbstractPage $page): string
{
// Counter is optional.
return method_exists($page, 'getCount') && !empty($count = $page->getCount())
? sprintf(' <span class="awaiting-mod"><span>%d</span></span>', number_format_i18n($count))
return \method_exists($page, 'getCount') && !empty($count = $page->getCount())
? \sprintf(' <span class="awaiting-mod"><span>%d</span></span>', number_format_i18n($count))
: ''
;
}
Expand Down
2 changes: 1 addition & 1 deletion classes/BlueChip/Security/Core/Admin/CountablePage.php
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,6 @@ public function getCount(): int
*/
private function getCounterUserMetaKey(): string
{
return implode('/', [$this->getSlug(), 'last-visit']);
return \implode('/', [$this->getSlug(), 'last-visit']);
}
}
2 changes: 1 addition & 1 deletion classes/BlueChip/Security/Core/Admin/ListingPage.php
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ private function setPerPageOption(string $option_name)
$this->per_page_option_name = $option_name;

add_filter('set-screen-option', function ($status, $option, $value) use ($option_name) {
return ($option === $option_name) ? intval($value) : $status;
return ($option === $option_name) ? \intval($value) : $status;
}, 10, 3);
}

Expand Down
4 changes: 2 additions & 2 deletions classes/BlueChip/Security/Core/Admin/PageWithAssets.php
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ protected function enqueueJsAssets(array $assets)
$handle,
$this->assets_manager->getScriptFileUrl($filename),
['jquery'],
filemtime($this->assets_manager->getScriptFilePath($filename)),
\filemtime($this->assets_manager->getScriptFilePath($filename)),
true
);
}
Expand All @@ -54,7 +54,7 @@ protected function enqueueCssAssets(array $assets)
$handle,
$this->assets_manager->getStyleFileUrl($filename),
[],
filemtime($this->assets_manager->getStyleFilePath($filename))
\filemtime($this->assets_manager->getStyleFilePath($filename))
);
}
}, 10, 0);
Expand Down
20 changes: 10 additions & 10 deletions classes/BlueChip/Security/Core/Admin/SettingsPage.php
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ protected function useSettings(\BlueChip\Security\Core\Settings $settings)
// Remember the settings.
$this->settings = $settings;
$this->option_name = $settings->getOptionName();
$this->option_group = md5($this->option_name);
$this->option_group = \md5($this->option_name);
}


Expand Down Expand Up @@ -102,10 +102,10 @@ public function setSettingsPage(string $page)
protected function getFieldBaseProperties(string $key, $value = null): array
{
return [
'label_for' => sprintf('%s-%s', $this->option_name, $key), // "label_for" is WP reserved name
'label_for' => \sprintf('%s-%s', $this->option_name, $key), // "label_for" is WP reserved name
'key' => $key,
'name' => sprintf('%s[%s]', $this->option_name, $key),
'value' => is_null($value) ? $this->settings[$key] : $value,
'name' => \sprintf('%s[%s]', $this->option_name, $key),
'value' => null === $value ? $this->settings[$key] : $value,
];
}

Expand All @@ -123,7 +123,7 @@ protected function getFieldBaseProperties(string $key, $value = null): array
*/
public function addSettingsSection(string $section, string $title, ?callable $callback = null)
{
if (!is_string($this->recent_page)) {
if (!\is_string($this->recent_page)) {
_doing_it_wrong(__METHOD__, 'No recent page set yet!', '0.1.0');
return;
}
Expand All @@ -147,12 +147,12 @@ public function addSettingsSection(string $section, string $title, ?callable $ca
*/
public function addSettingsField(string $key, string $title, callable $callback, array $args = [])
{
if (!is_string($this->recent_page)) {
if (!\is_string($this->recent_page)) {
_doing_it_wrong(__METHOD__, 'No recent page set yet!', '0.1.0');
return;
}

if (!is_string($this->recent_section)) {
if (!\is_string($this->recent_section)) {
_doing_it_wrong(__METHOD__, 'No recent section added yet!', '0.1.0');
return;
}
Expand All @@ -163,7 +163,7 @@ public function addSettingsField(string $key, string $title, callable $callback,
$callback,
$this->recent_page, // $page
$this->recent_section, // $section
array_merge($args, $this->getFieldBaseProperties($key)) // $args
\array_merge($args, $this->getFieldBaseProperties($key)) // $args
);
}

Expand All @@ -184,7 +184,7 @@ public function printSettingsFields()
*/
public function printSettingsSections()
{
if (!is_string($this->recent_page)) {
if (!\is_string($this->recent_page)) {
_doing_it_wrong(__METHOD__, 'No recent page set!', '0.1.0');
return;
}
Expand All @@ -198,7 +198,7 @@ public function printSettingsSections()
*/
protected function printSettingsForm()
{
echo '<form method="post" action="' . admin_url('options.php') .'">';
echo '<form method="post" action="' . admin_url('options.php') . '">';

// Output nonce, action and other hidden fields...
$this->printSettingsFields();
Expand Down
8 changes: 4 additions & 4 deletions classes/BlueChip/Security/Core/AssetsManager.php
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ public function __construct(string $plugin_filename)
*/
public function getScriptFilePath(string $filename): string
{
return implode('', [plugin_dir_path($this->plugin_filename), self::JS_ASSETS_DIRECTORY_PATH, $filename]);
return \implode('', [plugin_dir_path($this->plugin_filename), self::JS_ASSETS_DIRECTORY_PATH, $filename]);
}


Expand All @@ -48,7 +48,7 @@ public function getScriptFilePath(string $filename): string
*/
public function getScriptFileUrl(string $filename): string
{
return implode('', [plugin_dir_url($this->plugin_filename), self::JS_ASSETS_DIRECTORY_PATH, $filename]);
return \implode('', [plugin_dir_url($this->plugin_filename), self::JS_ASSETS_DIRECTORY_PATH, $filename]);
}


Expand All @@ -58,7 +58,7 @@ public function getScriptFileUrl(string $filename): string
*/
public function getStyleFilePath(string $filename): string
{
return implode('', [plugin_dir_path($this->plugin_filename), self::CSS_ASSETS_DIRECTORY_PATH, $filename]);
return \implode('', [plugin_dir_path($this->plugin_filename), self::CSS_ASSETS_DIRECTORY_PATH, $filename]);
}


Expand All @@ -68,6 +68,6 @@ public function getStyleFilePath(string $filename): string
*/
public function getStyleFileUrl(string $filename): string
{
return implode('', [plugin_dir_url($this->plugin_filename), self::CSS_ASSETS_DIRECTORY_PATH, $filename]);
return \implode('', [plugin_dir_url($this->plugin_filename), self::CSS_ASSETS_DIRECTORY_PATH, $filename]);
}
}
20 changes: 10 additions & 10 deletions classes/BlueChip/Security/Core/ListTable.php
Original file line number Diff line number Diff line change
Expand Up @@ -51,18 +51,18 @@ public function __construct(string $url, string $per_page_option_name, array $ar
'ajax' => false,
];

parent::__construct(array_merge($default_args, $args));
parent::__construct(\array_merge($default_args, $args));

$this->url = $url;
$this->items_per_page = $this->get_items_per_page($per_page_option_name);

$order_by = filter_input(INPUT_GET, 'orderby', FILTER_SANITIZE_STRING);
if (in_array($order_by, $this->get_sortable_columns(), true)) {
$order_by = \filter_input(INPUT_GET, 'orderby', FILTER_SANITIZE_STRING);
if (\in_array($order_by, $this->get_sortable_columns(), true)) {
$this->order_by = $order_by;
$this->url = add_query_arg('orderby', $order_by, $this->url);
}

$order = filter_input(INPUT_GET, 'order', FILTER_SANITIZE_STRING);
$order = \filter_input(INPUT_GET, 'order', FILTER_SANITIZE_STRING);
if ($order === 'asc' || $order === 'desc') {
$this->order = $order;
$this->url = add_query_arg('order', $order, $this->url);
Expand All @@ -80,8 +80,8 @@ public function __construct(string $url, string $per_page_option_name, array $ar
protected function displayNotice(string $action, string $single, string $plural)
{
// Have any items been affected by given action?
$result = filter_input(INPUT_GET, $action, FILTER_VALIDATE_INT);
if (is_int($result) && ($result > 0)) {
$result = \filter_input(INPUT_GET, $action, FILTER_VALIDATE_INT);
if (\is_int($result) && ($result > 0)) {
AdminNotices::add(
_n($single, $plural, $result, 'bc-security'),
AdminNotices::SUCCESS
Expand All @@ -105,14 +105,14 @@ protected function displayNotice(string $action, string $single, string $plural)
*/
protected function renderRowAction(string $action, int $id, string $class, string $label): string
{
return sprintf(
return \sprintf(
'<span class="' . $class . '"><a href="%s">%s</a></span>',
wp_nonce_url(
add_query_arg(
['action' => $action, 'id' => $id],
$this->url
),
sprintf('%s:%s', $action, $id),
\sprintf('%s:%s', $action, $id),
self::NONCE_NAME
),
esc_html($label)
Expand All @@ -128,7 +128,7 @@ protected function renderRowAction(string $action, int $id, string $class, strin
*/
public function column_cb($item) // phpcs:ignore
{
return sprintf('<input type="checkbox" name="ids[]" value="%d" />', $item['id']);
return \sprintf('<input type="checkbox" name="ids[]" value="%d" />', $item['id']);
}


Expand All @@ -141,7 +141,7 @@ public function column_cb($item) // phpcs:ignore
*/
public function column_default($item, $column_name) // phpcs:ignore
{
return isset($item[$column_name]) ? $item[$column_name] : '';
return $item[$column_name] ?? '';
}


Expand Down
26 changes: 13 additions & 13 deletions classes/BlueChip/Security/Core/Settings.php
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ public function __get(string $name)
if (isset($this->data[$name])) {
return $this->data[$name];
} else {
_doing_it_wrong(__METHOD__, sprintf('Unknown settings key "%s"', $name), '0.1.0');
_doing_it_wrong(__METHOD__, \sprintf('Unknown settings key "%s"', $name), '0.1.0');
return null;
}
}
Expand All @@ -75,7 +75,7 @@ public function __set(string $name, $value)
if (isset($this->data[$name])) {
$this->update($name, $value);
} else {
_doing_it_wrong(__METHOD__, sprintf('Unknown settings key "%s"', $name), '0.1.0');
_doing_it_wrong(__METHOD__, \sprintf('Unknown settings key "%s"', $name), '0.1.0');
}
}

Expand Down Expand Up @@ -223,14 +223,14 @@ public function persist(): bool
public function sanitize(array $settings, array $defaults = []): array
{
// If no default values are provided, use data from internal cache as default values.
$values = empty($defaults) ? $this->data : $defaults;
$values = ($defaults === []) ? $this->data : $defaults;

foreach ($values as $key => $default_value) {
if (isset($settings[$key])) {
// New value is provided, sanitize it either...
$values[$key] = isset(static::SANITIZERS[$key])
// ...using provided callback...
? call_user_func(static::SANITIZERS[$key], $settings[$key])
? \call_user_func(static::SANITIZERS[$key], $settings[$key])
// ...or by type.
: self::sanitizeByType($settings[$key], $default_value)
;
Expand All @@ -250,13 +250,13 @@ public function sanitize(array $settings, array $defaults = []): array
*/
protected static function sanitizeByType($value, $default)
{
if (is_bool($default)) {
return boolval($value);
} elseif (is_float($default)) {
return floatval($value);
} elseif (is_int($default)) {
return intval($value);
} elseif (is_array($default) && is_string($value)) {
if (\is_bool($default)) {
return \boolval($value);
} elseif (\is_float($default)) {
return \floatval($value);
} elseif (\is_int($default)) {
return \intval($value);
} elseif (\is_array($default) && \is_string($value)) {
return self::parseList($value);
} else {
return $value;
Expand All @@ -272,7 +272,7 @@ protected static function sanitizeByType($value, $default)
*/
protected static function parseList($list): array
{
return is_array($list) ? $list : array_filter(array_map('trim', explode(PHP_EOL, $list)));
return \is_array($list) ? $list : \array_filter(\array_map('trim', \explode(PHP_EOL, $list)));
}


Expand All @@ -292,7 +292,7 @@ protected function update(string $name, $value): bool

$data = $this->data;

if (is_null($value)) {
if (null === $value) {
// Null value unsets (resets) setting to default state
unset($data[$name]);
} else {
Expand Down
Loading

0 comments on commit d449a70

Please sign in to comment.