From 7be3dc5e75c1f8ff512d3e7b8da49fd400858c7c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C4=8Ceslav=20Przywara?= Date: Fri, 20 Sep 2019 22:32:24 +0200 Subject: [PATCH 01/19] Update README.md Add some links related to password hashing --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 3b5f227..b55a5b0 100644 --- a/README.md +++ b/README.md @@ -34,7 +34,7 @@ Basic checks cover common security practices. They do not require any informatio 1. Is display of PHP errors off by default? This check is only run in production environment, ie. when `WP_ENV === 'production'`. 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 From 50deb071bcd015fd75c2ebb130d744f1247081e4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C4=8Ceslav=20Przywara?= Date: Tue, 24 Sep 2019 10:50:57 +0200 Subject: [PATCH 02/19] Pass \WP_User instance as second argument to `bc-security/filter:is-admin` Fixes #84. --- classes/BlueChip/Security/Helpers/Is.php | 3 ++- tests/unit/src/Cases/Helpers/IsTest.php | 11 ++++++----- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/classes/BlueChip/Security/Helpers/Is.php b/classes/BlueChip/Security/Helpers/Is.php index 7345d63..ad4423f 100644 --- a/classes/BlueChip/Security/Helpers/Is.php +++ b/classes/BlueChip/Security/Helpers/Is.php @@ -20,7 +20,8 @@ public static function admin(\WP_User $user): bool { return apply_filters( Hooks::IS_ADMIN, - is_multisite() ? user_can($user, 'manage_network') : user_can($user, 'manage_options') + is_multisite() ? user_can($user, 'manage_network') : user_can($user, 'manage_options'), + $user ); } diff --git a/tests/unit/src/Cases/Helpers/IsTest.php b/tests/unit/src/Cases/Helpers/IsTest.php index 3acb1b2..4657174 100644 --- a/tests/unit/src/Cases/Helpers/IsTest.php +++ b/tests/unit/src/Cases/Helpers/IsTest.php @@ -26,7 +26,8 @@ public function testIsAdminHookFires() /** - * Ensure that `bc-security/filter:is-admin` filters return value of Is::admin(). + * Ensure that `bc-security/filter:is-admin` filters return value of Is::admin() and + * passes \WP_User instance as its second argument. */ public function testIsAdminFilter() { @@ -35,19 +36,19 @@ public function testIsAdminFilter() // User can't. Functions\when('user_can')->justReturn(false); // In: false; Out: false; - Filters\expectApplied(Hooks::IS_ADMIN)->once()->with(false)->andReturn(false); + Filters\expectApplied(Hooks::IS_ADMIN)->once()->with(false, $user)->andReturn(false); $this->assertFalse(Is::admin($user)); // In: false; Out: true; - Filters\expectApplied(Hooks::IS_ADMIN)->once()->with(false)->andReturn(true); + Filters\expectApplied(Hooks::IS_ADMIN)->once()->with(false, $user)->andReturn(true); $this->assertTrue(Is::admin($user)); // User can. Functions\when('user_can')->justReturn(true); // In: true; Out: false; - Filters\expectApplied(Hooks::IS_ADMIN)->once()->with(true)->andReturn(false); + Filters\expectApplied(Hooks::IS_ADMIN)->once()->with(true, $user)->andReturn(false); $this->assertFalse(Is::admin($user)); // In: true; Out: true; - Filters\expectApplied(Hooks::IS_ADMIN)->once()->with(true)->andReturn(true); + Filters\expectApplied(Hooks::IS_ADMIN)->once()->with(true, $user)->andReturn(true); $this->assertTrue(Is::admin($user)); } } From 2725b58b1937de35e8706e9b650a0ccaef2b0050 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C4=8Ceslav=20Przywara?= Date: Tue, 24 Sep 2019 19:18:01 +0200 Subject: [PATCH 03/19] Require WordPress 5.1 at least --- README.md | 2 +- bc-security.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index b55a5b0..91ea3be 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ Helps keeping WordPress websites secure. ## Requirements * [PHP](https://secure.php.net/) 7.1 or newer -* [WordPress](https://wordpress.org/) 4.9 or newer +* [WordPress](https://wordpress.org/) 5.1 or newer ## Limitations diff --git a/bc-security.php b/bc-security.php index 21e7903..b16f8cb 100644 --- a/bc-security.php +++ b/bc-security.php @@ -7,7 +7,7 @@ * Author: Česlav Przywara * Author URI: https://www.chesio.com * Requires PHP: 7.1 - * Requires WP: 4.9 + * Requires WP: 5.1 * Tested up to: 5.2 * Text Domain: bc-security * GitHub Plugin URI: https://github.com/chesio/bc-security From 787489fa4a563ab66f7b98a3954d1e8d97b58537 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C4=8Ceslav=20Przywara?= Date: Tue, 24 Sep 2019 19:34:30 +0200 Subject: [PATCH 04/19] Add return value type hints and improve comments --- classes/BlueChip/Security/Modules/Cron/Manager.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/classes/BlueChip/Security/Modules/Cron/Manager.php b/classes/BlueChip/Security/Modules/Cron/Manager.php index ccbfb12..81a749c 100644 --- a/classes/BlueChip/Security/Modules/Cron/Manager.php +++ b/classes/BlueChip/Security/Modules/Cron/Manager.php @@ -72,9 +72,9 @@ public function getJob(string $hook): Job * Activate cron job: schedule the job and mark it as permanently active, if scheduling succeeds. * * @param string $hook - * @return bool True, if cron job has been activated or was already active, false otherwise. + * @return bool True if cron job has been activated or was active already, false otherwise. */ - public function activateJob(string $hook) + public function activateJob(string $hook): bool { if ($this->getJob($hook)->schedule()) { $this->settings[$hook] = true; @@ -88,9 +88,9 @@ public function activateJob(string $hook) * Deactivate cron job: unschedule the job and mark it as permanently inactive, if unscheduling succeeds. * * @param string $hook - * @return bool True, if cron job has been deactivated or was not active already, false otherwise. + * @return bool True if cron job has been deactivated or was inactive already, false otherwise. */ - public function deactivateJob(string $hook) + public function deactivateJob(string $hook): bool { if ($this->getJob($hook)->unschedule()) { $this->settings[$hook] = false; From bbe1af70ecac37f6fd2b4d3c4315ba6eeebc2549 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C4=8Ceslav=20Przywara?= Date: Tue, 24 Sep 2019 19:37:21 +0200 Subject: [PATCH 05/19] Update plugin use of WordPress Cron API Fixes #67. --- classes/BlueChip/Security/Modules/Cron/Job.php | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/classes/BlueChip/Security/Modules/Cron/Job.php b/classes/BlueChip/Security/Modules/Cron/Job.php index d742f60..df92156 100644 --- a/classes/BlueChip/Security/Modules/Cron/Job.php +++ b/classes/BlueChip/Security/Modules/Cron/Job.php @@ -53,7 +53,7 @@ public function __construct(string $hook, $time, string $recurrence) /** * Schedule this cron job, if not scheduled yet. * - * @return bool True, if cron job has been activated or was already active, false otherwise. + * @return bool True if cron job has been activated or was already active, false otherwise. */ public function schedule(): bool { @@ -65,24 +65,25 @@ public function schedule(): bool // Compute Unix timestamp (UTC) for when to run the cron job based on $time value. $timestamp = is_int($this->time) ? $this->time : self::getTimestamp($this->time); - return wp_schedule_event($timestamp, $this->recurrence, $this->hook) !== false; + return wp_schedule_event($timestamp, $this->recurrence, $this->hook); } /** * Unschedule this cron job. * - * @return bool True (always). + * @return bool True in case of success, false on error. */ public function unschedule(): bool { - wp_clear_scheduled_hook($this->hook); - return true; + return wp_clear_scheduled_hook($this->hook) !== false; } /** - * @return bool True, if cron job is currently scheduled. + * Check whether cron job is currently scheduled. + * + * @return bool True if cron job is currently scheduled, false otherwise. */ public function isScheduled(): bool { From f409b8bde3ce44ea2c6591179e6a9ed1d890cf8a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C4=8Ceslav=20Przywara?= Date: Tue, 24 Sep 2019 20:16:55 +0200 Subject: [PATCH 06/19] Add leading \ to all calls to native PHP functions --- classes/BlueChip/Security/Admin.php | 8 ++-- .../Security/Core/Admin/CountablePage.php | 2 +- .../Security/Core/Admin/ListingPage.php | 2 +- .../Security/Core/Admin/PageWithAssets.php | 4 +- .../Security/Core/Admin/SettingsPage.php | 18 +++---- .../BlueChip/Security/Core/AssetsManager.php | 8 ++-- classes/BlueChip/Security/Core/ListTable.php | 18 +++---- classes/BlueChip/Security/Core/Settings.php | 24 +++++----- .../Security/Helpers/AdminNotices.php | 6 +-- .../BlueChip/Security/Helpers/AjaxHelper.php | 4 +- .../BlueChip/Security/Helpers/FormHelper.php | 28 +++++------ .../Security/Helpers/HaveIBeenPwned.php | 10 ++-- classes/BlueChip/Security/Helpers/Is.php | 6 +-- classes/BlueChip/Security/Helpers/Plugin.php | 16 +++---- .../BlueChip/Security/Helpers/Transients.php | 6 +-- .../Security/Modules/Checklist/AdminPage.php | 14 +++--- .../Modules/Checklist/CheckResult.php | 6 +-- .../Checklist/Checks/CoreIntegrity.php | 18 +++---- .../Checks/DirectoryListingDisabled.php | 4 +- .../Checks/DisplayOfPhpErrorsIsOff.php | 10 ++-- .../Checks/ErrorLogNotPubliclyAccessible.php | 8 ++-- .../NoAccessToPhpFilesInUploadsDirectory.php | 18 +++---- .../Checklist/Checks/NoMd5HashedPasswords.php | 6 +-- .../Checks/NoObviousUsernamesCheck.php | 8 ++-- .../Checks/NoPluginsRemovedFromDirectory.php | 10 ++-- .../Checks/PhpFilesEditationDisabled.php | 4 +- .../Checklist/Checks/PhpVersionSupported.php | 22 ++++----- .../Checklist/Checks/PluginsIntegrity.php | 16 +++---- .../Security/Modules/Checklist/Helper.php | 24 +++++----- .../Security/Modules/Checklist/Manager.php | 12 ++--- .../BlueChip/Security/Modules/Cron/Job.php | 12 ++--- .../Security/Modules/Hardening/AdminPage.php | 16 +++---- .../Security/Modules/Hardening/Core.php | 20 ++++---- .../Modules/IpBlacklist/AdminPage.php | 24 +++++----- .../Security/Modules/IpBlacklist/Bouncer.php | 2 +- .../Modules/IpBlacklist/ListTable.php | 26 +++++----- .../Security/Modules/IpBlacklist/Manager.php | 48 +++++++++---------- .../BlueChip/Security/Modules/Log/Event.php | 2 +- .../Security/Modules/Log/EventsManager.php | 2 +- .../Security/Modules/Log/ListTable.php | 24 +++++----- .../BlueChip/Security/Modules/Log/Logger.php | 36 +++++++------- .../Security/Modules/Login/AdminPage.php | 2 +- .../Security/Modules/Login/Bookkeeper.php | 12 ++--- .../Security/Modules/Login/Gatekeeper.php | 4 +- .../Security/Modules/Login/Settings.php | 2 +- .../Modules/Notifications/AdminPage.php | 2 +- .../Modules/Notifications/Mailman.php | 10 ++-- .../Modules/Notifications/Settings.php | 2 +- .../Modules/Notifications/Watchman.php | 40 ++++++++-------- .../Services/ReverseDnsLookup/Resolver.php | 4 +- .../Security/Modules/Tools/AdminPage.php | 22 ++++----- classes/BlueChip/Security/Setup/AdminPage.php | 6 +-- classes/BlueChip/Security/Setup/Core.php | 2 +- classes/BlueChip/Security/Setup/IpAddress.php | 8 ++-- classes/BlueChip/Security/Setup/Settings.php | 2 +- 55 files changed, 335 insertions(+), 335 deletions(-) diff --git a/classes/BlueChip/Security/Admin.php b/classes/BlueChip/Security/Admin.php index d1730bf..442440e 100644 --- a/classes/BlueChip/Security/Admin.php +++ b/classes/BlueChip/Security/Admin.php @@ -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( @@ -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( '%s', $this->pages['bc-security-setup']->getUrl(), esc_html($this->pages['bc-security-setup']->getMenuTitle()) @@ -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(' %d', number_format_i18n($count)) + return \method_exists($page, 'getCount') && !empty($count = $page->getCount()) + ? \sprintf(' %d', number_format_i18n($count)) : '' ; } diff --git a/classes/BlueChip/Security/Core/Admin/CountablePage.php b/classes/BlueChip/Security/Core/Admin/CountablePage.php index dd8722c..ac9ebe7 100644 --- a/classes/BlueChip/Security/Core/Admin/CountablePage.php +++ b/classes/BlueChip/Security/Core/Admin/CountablePage.php @@ -58,6 +58,6 @@ public function getCount(): int */ private function getCounterUserMetaKey(): string { - return implode('/', [$this->getSlug(), 'last-visit']); + return \implode('/', [$this->getSlug(), 'last-visit']); } } diff --git a/classes/BlueChip/Security/Core/Admin/ListingPage.php b/classes/BlueChip/Security/Core/Admin/ListingPage.php index 8352e8b..d9a1280 100644 --- a/classes/BlueChip/Security/Core/Admin/ListingPage.php +++ b/classes/BlueChip/Security/Core/Admin/ListingPage.php @@ -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); } diff --git a/classes/BlueChip/Security/Core/Admin/PageWithAssets.php b/classes/BlueChip/Security/Core/Admin/PageWithAssets.php index 48110bf..1608345 100644 --- a/classes/BlueChip/Security/Core/Admin/PageWithAssets.php +++ b/classes/BlueChip/Security/Core/Admin/PageWithAssets.php @@ -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 ); } @@ -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); diff --git a/classes/BlueChip/Security/Core/Admin/SettingsPage.php b/classes/BlueChip/Security/Core/Admin/SettingsPage.php index 16b3d2a..218475f 100644 --- a/classes/BlueChip/Security/Core/Admin/SettingsPage.php +++ b/classes/BlueChip/Security/Core/Admin/SettingsPage.php @@ -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); } @@ -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' => \is_null($value) ? $this->settings[$key] : $value, ]; } @@ -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; } @@ -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; } @@ -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 ); } @@ -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; } diff --git a/classes/BlueChip/Security/Core/AssetsManager.php b/classes/BlueChip/Security/Core/AssetsManager.php index b9cd6bb..8601647 100644 --- a/classes/BlueChip/Security/Core/AssetsManager.php +++ b/classes/BlueChip/Security/Core/AssetsManager.php @@ -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]); } @@ -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]); } @@ -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]); } @@ -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]); } } diff --git a/classes/BlueChip/Security/Core/ListTable.php b/classes/BlueChip/Security/Core/ListTable.php index 3831735..8362325 100644 --- a/classes/BlueChip/Security/Core/ListTable.php +++ b/classes/BlueChip/Security/Core/ListTable.php @@ -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); @@ -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 @@ -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( '%s', 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) @@ -128,7 +128,7 @@ protected function renderRowAction(string $action, int $id, string $class, strin */ public function column_cb($item) // phpcs:ignore { - return sprintf('', $item['id']); + return \sprintf('', $item['id']); } diff --git a/classes/BlueChip/Security/Core/Settings.php b/classes/BlueChip/Security/Core/Settings.php index a6895b5..9d93bab 100644 --- a/classes/BlueChip/Security/Core/Settings.php +++ b/classes/BlueChip/Security/Core/Settings.php @@ -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; } } @@ -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'); } } @@ -230,7 +230,7 @@ public function sanitize(array $settings, array $defaults = []): array // 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) ; @@ -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; @@ -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))); } @@ -292,7 +292,7 @@ protected function update(string $name, $value): bool $data = $this->data; - if (is_null($value)) { + if (\is_null($value)) { // Null value unsets (resets) setting to default state unset($data[$name]); } else { diff --git a/classes/BlueChip/Security/Helpers/AdminNotices.php b/classes/BlueChip/Security/Helpers/AdminNotices.php index ca3e207..b4ef0e7 100644 --- a/classes/BlueChip/Security/Helpers/AdminNotices.php +++ b/classes/BlueChip/Security/Helpers/AdminNotices.php @@ -27,11 +27,11 @@ abstract class AdminNotices */ public static function add($message, string $type = self::INFO, bool $is_dismissible = true, bool $escape_html = true) { - $classes = implode(' ', array_filter(['notice', $type, $is_dismissible ? 'is-dismissible' : ''])); + $classes = \implode(' ', \array_filter(['notice', $type, $is_dismissible ? 'is-dismissible' : ''])); add_action('admin_notices', function () use ($message, $classes, $escape_html) { echo '
'; - $messages = is_array($message) ? $message : [$message]; - array_walk($messages, function ($msg) use ($escape_html) { + $messages = \is_array($message) ? $message : [$message]; + \array_walk($messages, function ($msg) use ($escape_html) { echo '

' . ($escape_html ? esc_html($msg) : $msg) . '

'; }); echo '
'; diff --git a/classes/BlueChip/Security/Helpers/AjaxHelper.php b/classes/BlueChip/Security/Helpers/AjaxHelper.php index c497a10..7485c5a 100644 --- a/classes/BlueChip/Security/Helpers/AjaxHelper.php +++ b/classes/BlueChip/Security/Helpers/AjaxHelper.php @@ -28,7 +28,7 @@ public static function addHandler(string $action, callable $handler) // Check AJAX referer for given action - will die, if invalid. check_ajax_referer($action); - call_user_func($handler); + \call_user_func($handler); }, 10, 0); } @@ -54,7 +54,7 @@ public static function injectSetup(string $handle, string $object_name, string $ wp_localize_script( $handle, $object_name, - array_merge($data, $l10n) + \array_merge($data, $l10n) ); }, 10, 0); } diff --git a/classes/BlueChip/Security/Helpers/FormHelper.php b/classes/BlueChip/Security/Helpers/FormHelper.php index e670397..a8114fd 100644 --- a/classes/BlueChip/Security/Helpers/FormHelper.php +++ b/classes/BlueChip/Security/Helpers/FormHelper.php @@ -47,7 +47,7 @@ public static function printCheckbox(array $args) 'value' => 'true', 'id' => $args['label_for'], 'name' => $args['name'], - 'checked' => boolval($args['value']), + 'checked' => \boolval($args['value']), ]; if (!isset($args['plain'])) { @@ -146,11 +146,11 @@ public static function printTextArea(array $args) 'id' => $args['label_for'], 'name' => $args['name'], 'cols' => $args['cols'] ?? self::TEXTAREA_COLS_DEFAULT_VALUE, - 'rows' => $args['rows'] ?? max(min(count($args['value']), self::TEXTAREA_ROWS_MAXIMUM_VALUE), self::TEXTAREA_ROWS_MINIMUM_VALUE), + 'rows' => $args['rows'] ?? \max(\min(\count($args['value']), self::TEXTAREA_ROWS_MAXIMUM_VALUE), self::TEXTAREA_ROWS_MINIMUM_VALUE), ]; echo ''; self::printAppendix($args, false); @@ -168,28 +168,28 @@ public static function printTextArea(array $args) */ protected static function renderFieldProperties(array $properties): string { - $filtered = array_filter( + $filtered = \array_filter( $properties, // Remove any false-like values (empty strings and false booleans) except for integers and floats. function ($value) { - return is_int($value) - || is_float($value) - || (is_string($value) && $value !== '') - || (is_bool($value) && $value) + return \is_int($value) + || \is_float($value) + || (\is_string($value) && $value !== '') + || (\is_bool($value) && $value) ; } ); // Map keys and values together as key=value - $mapped = array_map( + $mapped = \array_map( function ($key, $value) { // Boolean values are replaced with key name: checked => true ---> checked="checked" - return sprintf('%s="%s"', $key, esc_attr(is_bool($value) ? $key : $value)); + return \sprintf('%s="%s"', $key, esc_attr(\is_bool($value) ? $key : $value)); }, - array_keys($filtered), - array_values($filtered) + \array_keys($filtered), + \array_values($filtered) ); // Join all properties into single string - return implode(' ', $mapped); + return \implode(' ', $mapped); } @@ -203,7 +203,7 @@ function ($key, $value) { protected static function printAppendix(array $args, bool $inline) { if (isset($args['description'])) { - echo sprintf( + echo \sprintf( '<%1$s class="description">%2$s', $inline ? 'span' : 'p', esc_html($args['description']) diff --git a/classes/BlueChip/Security/Helpers/HaveIBeenPwned.php b/classes/BlueChip/Security/Helpers/HaveIBeenPwned.php index 47147d0..731b86e 100644 --- a/classes/BlueChip/Security/Helpers/HaveIBeenPwned.php +++ b/classes/BlueChip/Security/Helpers/HaveIBeenPwned.php @@ -28,10 +28,10 @@ abstract class HaveIBeenPwned */ public static function hasPasswordBeenPwned(string $password): ?bool { - $sha1 = sha1($password); + $sha1 = \sha1($password); // Only first 5 characters of the hash are required. - $sha1_prefix = substr($sha1, 0, 5); + $sha1_prefix = \substr($sha1, 0, 5); $response = wp_remote_get(esc_url(self::PWNEDPASSWORDS_API_RANGE_SEARCH_URL . $sha1_prefix)); @@ -49,11 +49,11 @@ public static function hasPasswordBeenPwned(string $password): ?bool } // Every record has "hash_suffix:count" format. - $records = explode(PHP_EOL, $body); + $records = \explode(PHP_EOL, $body); foreach ($records as $record) { - [$sha1_suffix, $count] = explode(':', $record); + [$sha1_suffix, $count] = \explode(':', $record); - if ($sha1 === ($sha1_prefix . strtolower($sha1_suffix))) { + if ($sha1 === ($sha1_prefix . \strtolower($sha1_suffix))) { return true; // Your password been pwned, my friend! } } diff --git a/classes/BlueChip/Security/Helpers/Is.php b/classes/BlueChip/Security/Helpers/Is.php index ad4423f..be4ee9a 100644 --- a/classes/BlueChip/Security/Helpers/Is.php +++ b/classes/BlueChip/Security/Helpers/Is.php @@ -31,7 +31,7 @@ public static function admin(\WP_User $user): bool */ public static function cli(): bool { - return php_sapi_name() === 'cli'; + return \php_sapi_name() === 'cli'; } @@ -53,9 +53,9 @@ public static function request(string $type): bool case 'frontend': return (!is_admin() || wp_doing_ajax()) && !wp_doing_cron(); case 'wp-cli': - return defined('WP_CLI') && WP_CLI; + return \defined('WP_CLI') && WP_CLI; default: - _doing_it_wrong(__METHOD__, sprintf('Unknown request type: %s', $type), '0.1.0'); + _doing_it_wrong(__METHOD__, \sprintf('Unknown request type: %s', $type), '0.1.0'); return false; } } diff --git a/classes/BlueChip/Security/Helpers/Plugin.php b/classes/BlueChip/Security/Helpers/Plugin.php index 8806109..72b6afc 100644 --- a/classes/BlueChip/Security/Helpers/Plugin.php +++ b/classes/BlueChip/Security/Helpers/Plugin.php @@ -75,7 +75,7 @@ public static function getSlug(string $plugin_basename): string { // This is fine most of the time and WPCentral/WP-CLI-Security gets the slug the same way, // but it does not seem to be guaranteed that slug is always equal to directory name... - $slug = dirname($plugin_basename); + $slug = \dirname($plugin_basename); // For single-file plugins, return empty string. return $slug === '.' ? '' : $slug; } @@ -87,7 +87,7 @@ public static function getSlug(string $plugin_basename): string */ public static function hasReadmeTxt(string $plugin_basename): bool { - return is_file(self::getPluginDirPath($plugin_basename) . '/readme.txt'); + return \is_file(self::getPluginDirPath($plugin_basename) . '/readme.txt'); } @@ -98,7 +98,7 @@ public static function hasReadmeTxt(string $plugin_basename): bool public static function isVersionControlled(string $plugin_basename): bool { $plugin_dir = self::getPluginDirPath($plugin_basename); - return is_dir($plugin_dir . '/.git') || is_dir($plugin_dir . '/.svn'); + return \is_dir($plugin_dir . '/.git') || \is_dir($plugin_dir . '/.svn'); } @@ -111,14 +111,14 @@ public static function isVersionControlled(string $plugin_basename): bool public static function getPluginsInstalledFromWordPressOrg(): array { // We're using some wp-admin stuff here, so make sure it's available. - if (!function_exists('get_plugins')) { + if (!\function_exists('get_plugins')) { require_once ABSPATH . 'wp-admin/includes/plugin.php'; } // There seem to be no easy way to find out if plugin is hosted at WordPress.org repository or not, see: // https://core.trac.wordpress.org/ticket/32101 - return array_filter( + return \array_filter( get_plugins(), [self::class, 'hasReadmeTxt'], ARRAY_FILTER_USE_KEY @@ -148,7 +148,7 @@ public static function getPluginData(string $plugin_basename): array */ public static function getPluginDirPath(string $plugin_basename): string { - return wp_normalize_path(WP_PLUGIN_DIR . '/' . dirname($plugin_basename)); + return wp_normalize_path(WP_PLUGIN_DIR . '/' . \dirname($plugin_basename)); } @@ -161,9 +161,9 @@ public static function getPluginDirPath(string $plugin_basename): string */ public static function implodeList(array $plugins, string $linkTo = ''): string { - return implode( + return \implode( ', ', - array_map( + \array_map( function (array $plugin_data) use ($linkTo): string { $plugin_name = '' . esc_html($plugin_data['Name']) . ''; return $linkTo diff --git a/classes/BlueChip/Security/Helpers/Transients.php b/classes/BlueChip/Security/Helpers/Transients.php index 8829614..0db48a0 100644 --- a/classes/BlueChip/Security/Helpers/Transients.php +++ b/classes/BlueChip/Security/Helpers/Transients.php @@ -41,7 +41,7 @@ public static function flush(\wpdb $wpdb) // First, delete all transients from database... $wpdb->query( - sprintf( + \sprintf( "DELETE FROM {$table_name} WHERE (option_name LIKE '%s' OR option_name LIKE '%s')", '_site_transient_' . self::NAME_PREFIX . '%', '_site_transient_timeout_' . self::NAME_PREFIX . '%' @@ -75,7 +75,7 @@ public static function getForSite(string ...$key) public static function setForSite($value, ...$args): bool { // If the first from variable arguments is plain integer, take it as expiration value. - $expiration = is_int($args[0]) ? array_shift($args) : 0; + $expiration = \is_int($args[0]) ? \array_shift($args) : 0; return set_site_transient(self::name($args), $value, $expiration); } @@ -89,6 +89,6 @@ public static function setForSite($value, ...$args): bool */ private static function name(array $key): string { - return self::NAME_PREFIX . md5(implode(':', $key)); + return self::NAME_PREFIX . \md5(\implode(':', $key)); } } diff --git a/classes/BlueChip/Security/Modules/Checklist/AdminPage.php b/classes/BlueChip/Security/Modules/Checklist/AdminPage.php index 62b6d58..8b2d286 100644 --- a/classes/BlueChip/Security/Modules/Checklist/AdminPage.php +++ b/classes/BlueChip/Security/Modules/Checklist/AdminPage.php @@ -85,7 +85,7 @@ public function loadPage() */ public function getCount(): int { - return count($this->checklist_manager->getChecks(['meaningful' => true, 'monitored' => true, 'status' => false])); + return \count($this->checklist_manager->getChecks(['meaningful' => true, 'monitored' => true, 'status' => false])); } @@ -98,7 +98,7 @@ public function printContents() echo '

' . esc_html($this->page_title) . '

'; echo '

'; - echo sprintf( + echo \sprintf( /* translators: %s: tick icon */ esc_html__('The more %s you have, the better!'), '' @@ -125,10 +125,10 @@ public function printContents() echo ''; echo '

'; - echo sprintf( + echo \sprintf( /* translators: %s: link to hardening options */ esc_html__('You might also want to enable some other %s.', 'bc-security'), - sprintf( + \sprintf( '%s', Hardening\AdminPage::getPageUrl(), esc_html__('hardening options', 'bc-security') @@ -185,7 +185,7 @@ private function printChecklistMonitoringSection() echo '

'; echo esc_html__('You can let BC Security monitor the checklist automatically. Just select the checks you want to monitor:', 'bc-security'); echo ' '; - echo implode(' ', [ + echo \implode(' ', [ '', '', '', @@ -244,14 +244,14 @@ private function printCheckRow(Check $check, string $check_class) $check_id = $check::getId(); $result = $check->getResult(); $status = $result->getStatus(); - $status_class = is_bool($status) ? ($status ? 'bcs-check--ok' : 'bcs-check--ko') : ''; + $status_class = \is_bool($status) ? ($status ? 'bcs-check--ok' : 'bcs-check--ko') : ''; echo ''; // Background monitoring toggle. echo ''; if (isset($this->settings[$check_id])) { - FormHelper::printCheckbox($this->getFieldBaseProperties($check_id, intval($this->settings[$check_id]))); + FormHelper::printCheckbox($this->getFieldBaseProperties($check_id, \intval($this->settings[$check_id]))); } echo ''; // Name should be short and descriptive and without HTML tags. diff --git a/classes/BlueChip/Security/Modules/Checklist/CheckResult.php b/classes/BlueChip/Security/Modules/Checklist/CheckResult.php index 10117d1..3dc2418 100644 --- a/classes/BlueChip/Security/Modules/Checklist/CheckResult.php +++ b/classes/BlueChip/Security/Modules/Checklist/CheckResult.php @@ -22,7 +22,7 @@ class CheckResult public function __construct(?bool $status, $message) { $this->status = $status; - $this->message = is_array($message) ? $message : [$message]; + $this->message = \is_array($message) ? $message : [$message]; } @@ -40,7 +40,7 @@ public function getMessage(): array */ public function getMessageAsHtml(): string { - return implode('
', $this->message); + return \implode('
', $this->message); } @@ -49,7 +49,7 @@ public function getMessageAsHtml(): string */ public function getMessageAsPlainText(): string { - return strip_tags(implode(PHP_EOL, $this->message)); + return \strip_tags(\implode(PHP_EOL, $this->message)); } diff --git a/classes/BlueChip/Security/Modules/Checklist/Checks/CoreIntegrity.php b/classes/BlueChip/Security/Modules/Checklist/Checks/CoreIntegrity.php index 10fc644..bac17e1 100644 --- a/classes/BlueChip/Security/Modules/Checklist/Checks/CoreIntegrity.php +++ b/classes/BlueChip/Security/Modules/Checklist/Checks/CoreIntegrity.php @@ -25,7 +25,7 @@ public function __construct() { parent::__construct( __('WordPress core files are untouched', 'bc-security'), - sprintf( + \sprintf( /* translators: 1: link to Wikipedia article about md5sum, 2: link to checksums file at WordPress.org */ esc_html__('By comparing %1$s of local core files with %2$s it is possible to determine, if any of core files have been modified or if there are any unknown files in core directories.', 'bc-security'), '' . esc_html__('MD5 checksums', 'bc-security') . '', @@ -41,7 +41,7 @@ protected function runInternal(): Checklist\CheckResult // Get checksums via WordPress.org API. if (empty($checksums = self::getChecksums($url))) { - $message = sprintf( + $message = \sprintf( /* translators: 1: link to checksums file at WordPress.org */ esc_html__('Failed to get core file checksums from %1$s.', 'bc-security'), '' . esc_html($url) . '' @@ -59,13 +59,13 @@ protected function runInternal(): Checklist\CheckResult } else { $message_parts = []; if (!empty($modified_files)) { - $message_parts[] = sprintf( + $message_parts[] = \sprintf( esc_html__('The following WordPress core files have been modified: %s', 'bc-security'), Checklist\Helper::formatListOfFiles($modified_files) ); } if (!empty($unknown_files)) { - $message_parts[] = sprintf( + $message_parts[] = \sprintf( esc_html__('There are following unknown files present in WordPress core directory: %s', 'bc-security'), Checklist\Helper::formatListOfFiles($unknown_files) ); @@ -132,10 +132,10 @@ private static function findModifiedFiles($checksums): array $modified_files = Checklist\Helper::checkDirectoryForModifiedFiles(ABSPATH, $checksums, $ignored_files); // Ignore any modified files in wp-content directory. - return array_filter( + return \array_filter( $modified_files, function ($filename) { - return strpos($filename, 'wp-content/') !== 0; + return \strpos($filename, 'wp-content/') !== 0; } ); } @@ -164,8 +164,8 @@ private static function findUnknownFiles($checksums): array ] ); - return array_filter( - array_merge( + return \array_filter( + \array_merge( // Scan root WordPress directory. Checklist\Helper::scanDirectoryForUnknownFiles(ABSPATH, ABSPATH, $checksums, false), // Scan wp-admin directory recursively. @@ -174,7 +174,7 @@ private static function findUnknownFiles($checksums): array Checklist\Helper::scanDirectoryForUnknownFiles(ABSPATH . WPINC, ABSPATH, $checksums, true) ), function (string $filename) use ($ignored_files): bool { - return !in_array($filename, $ignored_files, true); + return !\in_array($filename, $ignored_files, true); } ); } diff --git a/classes/BlueChip/Security/Modules/Checklist/Checks/DirectoryListingDisabled.php b/classes/BlueChip/Security/Modules/Checklist/Checks/DirectoryListingDisabled.php index 3a34717..c3a13f6 100644 --- a/classes/BlueChip/Security/Modules/Checklist/Checks/DirectoryListingDisabled.php +++ b/classes/BlueChip/Security/Modules/Checklist/Checks/DirectoryListingDisabled.php @@ -13,7 +13,7 @@ public function __construct() { parent::__construct( __('Directory listing disabled', 'bc-security'), - sprintf( + \sprintf( /* translators: 1: link to documentation about DirectoryListings at apache.org */ esc_html__('A sensible security practice is to disable %1$s.', 'bc-security'), '' . esc_html__('directory listings', 'bc-security') . '' @@ -32,7 +32,7 @@ protected function runInternal(): Checklist\CheckResult $response = wp_remote_get($upload_paths['baseurl']); $response_body = wp_remote_retrieve_body($response); - return (stripos($response_body, 'Index of') === false) + return (\stripos($response_body, '<title>Index of') === false) ? new Checklist\CheckResult(true, esc_html__('It seems that directory listing is disabled.', 'bc-security')) : new Checklist\CheckResult(false, esc_html__('It seems that directory listing is not disabled!', 'bc-security')) ; diff --git a/classes/BlueChip/Security/Modules/Checklist/Checks/DisplayOfPhpErrorsIsOff.php b/classes/BlueChip/Security/Modules/Checklist/Checks/DisplayOfPhpErrorsIsOff.php index f29a8e1..35f4231 100644 --- a/classes/BlueChip/Security/Modules/Checklist/Checks/DisplayOfPhpErrorsIsOff.php +++ b/classes/BlueChip/Security/Modules/Checklist/Checks/DisplayOfPhpErrorsIsOff.php @@ -13,7 +13,7 @@ public function __construct() { parent::__construct( __('Display of PHP errors is off', 'bc-security'), - sprintf( + \sprintf( /* translators: 1: link to PHP manual documentation on display-errors php.ini setting, 2: link to WordPress Handbook article */ esc_html__('%1$s to the screen as part of the output on production systems. In WordPress environment, %2$s when directly loading certain files.', 'bc-security'), '<a href="' . esc_url(__('https://secure.php.net/manual/en/errorfunc.configuration.php#ini.display-errors', 'bc-security')) . '" rel="noreferrer">' . esc_html__('Errors should never be printed', 'bc-security') . '</a>', @@ -30,14 +30,14 @@ public function __construct() */ public function isMeaningful(): bool { - return defined('WP_ENV') && (WP_ENV === 'production'); + return \defined('WP_ENV') && (WP_ENV === 'production'); } protected function runInternal(): Checklist\CheckResult { // Craft temporary file name. - $name = sprintf('bc-security-checklist-test-error-display-%s.php', md5(rand())); + $name = \sprintf('bc-security-checklist-test-error-display-%s.php', \md5(\rand())); // The file is going to be created in wp-content directory. $path = WP_CONTENT_DIR . '/' . $name; @@ -49,7 +49,7 @@ protected function runInternal(): Checklist\CheckResult $status = new Checklist\CheckResult(null, esc_html__('BC Security has failed to determine whether display of errors is turned off by default.', 'bc-security')); // Write temporary file... - if (file_put_contents($path, $php_snippet) === false) { + if (\file_put_contents($path, $php_snippet) === false) { // ...bail on failure. return $status; } @@ -65,7 +65,7 @@ protected function runInternal(): Checklist\CheckResult } // Remove temporary PHP file. - unlink($path); + \unlink($path); // Report on status. return $status; diff --git a/classes/BlueChip/Security/Modules/Checklist/Checks/ErrorLogNotPubliclyAccessible.php b/classes/BlueChip/Security/Modules/Checklist/Checks/ErrorLogNotPubliclyAccessible.php index 76e2520..6188a06 100644 --- a/classes/BlueChip/Security/Modules/Checklist/Checks/ErrorLogNotPubliclyAccessible.php +++ b/classes/BlueChip/Security/Modules/Checklist/Checks/ErrorLogNotPubliclyAccessible.php @@ -13,7 +13,7 @@ public function __construct() { parent::__construct( __('Error log not publicly accessible', 'bc-security'), - sprintf( + \sprintf( /* translators: 1: link to Codex page on debugging, 2: WP_DEBUG constant, 3: WP_DEBUG_LOG constant, 4: debug.log file, 5: /wp-content path */ esc_html__('Both %2$s and %3$s constants are set to true, therefore %1$s to a %4$s log file inside the %5$s directory. This file can contain sensitive information and therefore should not be publicly accessible.', 'bc-security'), '<a href="' . esc_url(__('https://codex.wordpress.org/Debugging_in_WordPress', 'bc-security')) . '" rel="noreferrer">' . esc_html__('WordPress saves all errors', 'bc-security') . '</a>', @@ -39,9 +39,9 @@ public function isMeaningful(): bool protected function runInternal(): Checklist\CheckResult { - $is_wordpress_51 = version_compare(get_bloginfo('version'), '5.1', '>='); + $is_wordpress_51 = \version_compare(get_bloginfo('version'), '5.1', '>='); - if (!$is_wordpress_51 || in_array(strtolower((string) WP_DEBUG_LOG), ['true', '1'], true)) { + if (!$is_wordpress_51 || \in_array(\strtolower((string) WP_DEBUG_LOG), ['true', '1'], true)) { // `WP_DEBUG_LOG` is set truthy value (or we are on WordPress older than 5.1). // Path to debug.log and filename is hardcoded in `wp-includes/load.php`. $url = WP_CONTENT_URL . '/debug.log'; @@ -49,7 +49,7 @@ protected function runInternal(): Checklist\CheckResult // Report status. $status = Checklist\Helper::isAccessToUrlForbidden($url); - if (is_bool($status)) { + if (\is_bool($status)) { return $status ? new Checklist\CheckResult(true, esc_html__('It seems that error log is not publicly accessible.', 'bc-security')) : new Checklist\CheckResult(false, esc_html__('It seems that error log is publicly accessible!', 'bc-security')) diff --git a/classes/BlueChip/Security/Modules/Checklist/Checks/NoAccessToPhpFilesInUploadsDirectory.php b/classes/BlueChip/Security/Modules/Checklist/Checks/NoAccessToPhpFilesInUploadsDirectory.php index 3401b28..0bd01ed 100644 --- a/classes/BlueChip/Security/Modules/Checklist/Checks/NoAccessToPhpFilesInUploadsDirectory.php +++ b/classes/BlueChip/Security/Modules/Checklist/Checks/NoAccessToPhpFilesInUploadsDirectory.php @@ -13,7 +13,7 @@ public function __construct() { parent::__construct( __('No access to PHP files in uploads directory', 'bc-security'), - sprintf( + \sprintf( /* translators: 1: link to gist with .htaccess configuration that disables access to PHP files */ esc_html__('Vulnerable plugins may allow upload of arbitrary files into uploads directory. %1$s within uploads directory may help prevent successful exploitation of such vulnerabilities.', 'bc-security'), '<a href="https://gist.github.com/chesio/8f83224840eccc1e80a17fc29babadf2" rel="noreferrer">' . esc_html__('Disabling access to PHP files', 'bc-security') . '</a>' @@ -27,8 +27,8 @@ protected function runInternal(): Checklist\CheckResult $php_file_message = 'It is more secure to not allow PHP files to be accessed from within WordPress uploads directory.'; // Prepare temporary file name and contents. - $name = sprintf('bc-security-checklist-test-%s.txt', md5(rand())); // .txt extension to avoid upload file MIME check killing our test - $bits = sprintf('<?php echo "%s";', $php_file_message); + $name = \sprintf('bc-security-checklist-test-%s.txt', \md5(\rand())); // .txt extension to avoid upload file MIME check killing our test + $bits = \sprintf('<?php echo "%s";', $php_file_message); // Create temporary PHP file in uploads directory. $result = wp_upload_bits($name, null, $bits); @@ -38,22 +38,22 @@ protected function runInternal(): Checklist\CheckResult } // Change file extension to php. - $file = substr($result['file'], 0, -3) . 'php'; - if (!rename($result['file'], $file)) { - unlink($result['file']); + $file = \substr($result['file'], 0, -3) . 'php'; + if (!\rename($result['file'], $file)) { + \unlink($result['file']); return new Checklist\CheckResult(null, esc_html__('BC Security has failed to determine whether PHP files can be executed from uploads directory.', 'bc-security')); } - $url = substr($result['url'], 0, -3) . 'php'; + $url = \substr($result['url'], 0, -3) . 'php'; // Check, if access to PHP file is forbidden. $status = Checklist\Helper::isAccessToUrlForbidden($url, $php_file_message); // Remove temporary PHP file from uploads directory - unlink($file); + \unlink($file); // Report status - if (is_bool($status)) { + if (\is_bool($status)) { return $status ? new Checklist\CheckResult(true, esc_html__('It seems that PHP files cannot be executed from uploads directory.', 'bc-security')) : new Checklist\CheckResult(false, esc_html__('It seems that PHP files can be executed from uploads directory!', 'bc-security')) diff --git a/classes/BlueChip/Security/Modules/Checklist/Checks/NoMd5HashedPasswords.php b/classes/BlueChip/Security/Modules/Checklist/Checks/NoMd5HashedPasswords.php index 6e00155..4a084d1 100644 --- a/classes/BlueChip/Security/Modules/Checklist/Checks/NoMd5HashedPasswords.php +++ b/classes/BlueChip/Security/Modules/Checklist/Checks/NoMd5HashedPasswords.php @@ -28,7 +28,7 @@ public function __construct(\wpdb $wpdb) { parent::__construct( __('No default MD5 password hashes', 'bc-security'), - sprintf( + \sprintf( /* translators: 1: link to plugin with alternative implementation of password hashing scheme */ esc_html__('WordPress by default uses an MD5 based password hashing scheme that is too cheap and fast to generate cryptographically secure hashes. For modern PHP versions, there are %1$s available.', 'bc-security'), '<a href="https://github.com/roots/wp-password-bcrypt" rel="noreferrer">' . esc_html__('more secure alternatives', 'bc-security') . '</a>' @@ -42,7 +42,7 @@ public function __construct(\wpdb $wpdb) protected function runInternal(): Checklist\CheckResult { // Get all users with old hash prefix - $result = $this->wpdb->get_results(sprintf( + $result = $this->wpdb->get_results(\sprintf( "SELECT `user_login` FROM {$this->wpdb->users} WHERE `user_pass` LIKE '%s%%';", self::WP_OLD_HASH_PREFIX )); @@ -52,7 +52,7 @@ protected function runInternal(): Checklist\CheckResult } else { return empty($result) ? new Checklist\CheckResult(true, esc_html__('No users have password hashed with default MD5-based algorithm.', 'bc-security')) - : new Checklist\CheckResult(false, esc_html__('The following users have their password hashed with default MD5-based algorithm:', 'bc-security') . ' <em>' . implode(', ', wp_list_pluck($result, 'user_login')) . '</em>') + : new Checklist\CheckResult(false, esc_html__('The following users have their password hashed with default MD5-based algorithm:', 'bc-security') . ' <em>' . \implode(', ', wp_list_pluck($result, 'user_login')) . '</em>') ; } } diff --git a/classes/BlueChip/Security/Modules/Checklist/Checks/NoObviousUsernamesCheck.php b/classes/BlueChip/Security/Modules/Checklist/Checks/NoObviousUsernamesCheck.php index c214907..d9e51a6 100644 --- a/classes/BlueChip/Security/Modules/Checklist/Checks/NoObviousUsernamesCheck.php +++ b/classes/BlueChip/Security/Modules/Checklist/Checks/NoObviousUsernamesCheck.php @@ -13,7 +13,7 @@ public function __construct() { parent::__construct( __('No obvious usernames exist', 'bc-security'), - sprintf( + \sprintf( /* translators: 1: link to Codex page on WordPress hardening */ esc_html__('Usernames like "admin" and "administrator" are often used in brute force attacks and %1$s.', 'bc-security'), '<a href="' . esc_url(__('https://codex.wordpress.org/Hardening_WordPress#Security_through_obscurity', 'bc-security')) . '" rel="noreferrer">' . esc_html__('should be avoided', 'bc-security') . '</a>' @@ -27,13 +27,13 @@ protected function runInternal(): Checklist\CheckResult // Get (filtered) list of obvious usernames to test. $obvious = apply_filters(Checklist\Hooks::OBVIOUS_USERNAMES, ['admin', 'administrator']); // Check for existing usernames. - $existing = array_filter($obvious, function ($username) { + $existing = \array_filter($obvious, function ($username) { return get_user_by('login', $username); }); return empty($existing) - ? new Checklist\CheckResult(true, esc_html__('None of the following usernames exists on the system:', 'bc-security') . ' <em>' . implode(', ', $obvious) . '</em>') - : new Checklist\CheckResult(false, esc_html__('The following obvious usernames exists on the system:', 'bc-security') . ' <em>' . implode(', ', $existing) . '</em>') + ? new Checklist\CheckResult(true, esc_html__('None of the following usernames exists on the system:', 'bc-security') . ' <em>' . \implode(', ', $obvious) . '</em>') + : new Checklist\CheckResult(false, esc_html__('The following obvious usernames exists on the system:', 'bc-security') . ' <em>' . \implode(', ', $existing) . '</em>') ; } } diff --git a/classes/BlueChip/Security/Modules/Checklist/Checks/NoPluginsRemovedFromDirectory.php b/classes/BlueChip/Security/Modules/Checklist/Checks/NoPluginsRemovedFromDirectory.php index de1b6f6..f218607 100644 --- a/classes/BlueChip/Security/Modules/Checklist/Checks/NoPluginsRemovedFromDirectory.php +++ b/classes/BlueChip/Security/Modules/Checklist/Checks/NoPluginsRemovedFromDirectory.php @@ -26,7 +26,7 @@ public function __construct() { parent::__construct( __('No removed plugins installed', 'bc-security'), - sprintf( + \sprintf( /* translators: 1: link to Plugins Directory, 2: link to article on Wordfence blog */ esc_html__('Plugins can be removed from %1$s for several reasons (including but no limited to %2$s). Use of removed plugins is discouraged.', 'bc-security'), '<a href="' . esc_url(__('https://wordpress.org/plugins/', 'bc-security')) . '" rel="noreferrer">' . esc_html__('Plugins Directory', 'bc-security') . '</a>', @@ -52,7 +52,7 @@ protected function runInternal(): Checklist\CheckResult $list_of_unknown_plugins = Helpers\Plugin::implodeList($problematic_plugins['unknown_plugins'], 'DirectoryURL'); if (!empty($list_of_removed_plugins)) { - $message = sprintf( + $message = \sprintf( esc_html__('Following plugins seem to have been removed from Plugins Directory: %s', 'bc-security'), $list_of_removed_plugins ); @@ -60,7 +60,7 @@ protected function runInternal(): Checklist\CheckResult if (!empty($list_of_unknown_plugins)) { // Also report any plugins that could not be checked, just in case. $message .= '<br>'; - $message .= sprintf( + $message .= \sprintf( esc_html__('Furthermore, following plugins could not be checked: %s', 'bc-security'), $list_of_unknown_plugins ); @@ -69,7 +69,7 @@ protected function runInternal(): Checklist\CheckResult } if (!empty($list_of_unknown_plugins)) { - $message = sprintf( + $message = \sprintf( esc_html__('No removed plugins found, but following plugins could not be checked: %s', 'bc-security'), $list_of_unknown_plugins ); @@ -114,7 +114,7 @@ private function getProblematicPlugins(array $plugins): array // Check response body for presence of "Download" button and download URL prefix. // Note: full URL contains the most recent version number, thus check only the prefix. $plugin_download_url_prefix = self::PLUGINS_DOWNLOAD_URL . Helpers\Plugin::getSlug($plugin_basename); - if ((strpos($body, 'download-button') === false) || (strpos($body, $plugin_download_url_prefix) === false)) { + if ((\strpos($body, 'download-button') === false) || (\strpos($body, $plugin_download_url_prefix) === false)) { $removed_plugins[$plugin_basename] = $plugin_data; } } diff --git a/classes/BlueChip/Security/Modules/Checklist/Checks/PhpFilesEditationDisabled.php b/classes/BlueChip/Security/Modules/Checklist/Checks/PhpFilesEditationDisabled.php index 957f540..cb8f353 100644 --- a/classes/BlueChip/Security/Modules/Checklist/Checks/PhpFilesEditationDisabled.php +++ b/classes/BlueChip/Security/Modules/Checklist/Checks/PhpFilesEditationDisabled.php @@ -13,7 +13,7 @@ public function __construct() { parent::__construct( __('PHP files editation disabled', 'bc-security'), - sprintf( + \sprintf( /* translators: 1: link to Codex page on WordPress hardening */ esc_html__('It is generally recommended to %1$s.', 'bc-security'), '<a href="' . esc_url(__('https://codex.wordpress.org/Hardening_WordPress#Disable_File_Editing', 'bc-security')) . '" rel="noreferrer">' . esc_html__('disable editation of PHP files', 'bc-security') . '</a>' @@ -24,7 +24,7 @@ public function __construct() protected function runInternal(): Checklist\CheckResult { - return defined('DISALLOW_FILE_EDIT') && DISALLOW_FILE_EDIT + return \defined('DISALLOW_FILE_EDIT') && DISALLOW_FILE_EDIT ? new Checklist\CheckResult(true, esc_html__('Theme and plugin files cannot be edited from backend.', 'bc-security')) : new Checklist\CheckResult(false, esc_html__('Theme and plugin files can be edited from backend!', 'bc-security')) ; diff --git a/classes/BlueChip/Security/Modules/Checklist/Checks/PhpVersionSupported.php b/classes/BlueChip/Security/Modules/Checklist/Checks/PhpVersionSupported.php index 650a5ef..b0f521e 100644 --- a/classes/BlueChip/Security/Modules/Checklist/Checks/PhpVersionSupported.php +++ b/classes/BlueChip/Security/Modules/Checklist/Checks/PhpVersionSupported.php @@ -23,7 +23,7 @@ public function __construct() { parent::__construct( __('PHP version is supported', 'bc-security'), - sprintf( + \sprintf( /* translators: 1: link to official page on supported PHP versions */ esc_html__('Running an %1$s may pose a security risk.', 'bc-security'), '<a href="' . esc_url(__('https://secure.php.net/supported-versions.php', 'bc-security')) . '" rel="noreferrer">' . esc_html__('unsupported PHP version', 'bc-security') . '</a>' @@ -37,8 +37,8 @@ protected function runInternal(): Checklist\CheckResult // Get oldest supported version (as <major>.<minor>): $oldest_supported_version = self::getOldestSupportedPhpVersion(); - if (is_null($oldest_supported_version)) { - $message = sprintf( + if (\is_null($oldest_supported_version)) { + $message = \sprintf( esc_html__('List of supported PHP versions is out-dated. Consider updating the plugin. Btw. you are running PHP %1$s.', 'bc-security'), self::formatPhpVersion() ); @@ -46,26 +46,26 @@ protected function runInternal(): Checklist\CheckResult } // Get active PHP version as <major>.<minor> string: - $php_version = sprintf("%s.%s", PHP_MAJOR_VERSION, PHP_MINOR_VERSION); + $php_version = \sprintf("%s.%s", PHP_MAJOR_VERSION, PHP_MINOR_VERSION); - if (version_compare($php_version, $oldest_supported_version, '>=')) { + if (\version_compare($php_version, $oldest_supported_version, '>=')) { // PHP version is supported, but do we have end-of-life date? $eol_date = self::SUPPORTED_VERSIONS[$php_version] ?? null; // Format message accordingly. $message = $eol_date - ? sprintf( + ? \sprintf( esc_html__('You are running PHP %1$s, which is supported until %2$s.', 'bc-security'), self::formatPhpVersion(), - date_i18n(get_option('date_format'), strtotime($eol_date)) + date_i18n(get_option('date_format'), \strtotime($eol_date)) ) - : sprintf( + : \sprintf( esc_html__('You are running PHP %1$s, which is still supported.', 'bc-security'), self::formatPhpVersion() ) ; return new Checklist\CheckResult(true, $message); } else { - $message = sprintf( + $message = \sprintf( esc_html__('You are running PHP %1$s, which is no longer supported! Consider upgrading your PHP version.', 'bc-security'), self::formatPhpVersion() ); @@ -79,7 +79,7 @@ protected function runInternal(): Checklist\CheckResult */ private static function formatPhpVersion(): string { - return sprintf('<em title="%s">%s.%s</em>', PHP_VERSION, PHP_MAJOR_VERSION, PHP_MINOR_VERSION); + return \sprintf('<em title="%s">%s.%s</em>', PHP_VERSION, PHP_MAJOR_VERSION, PHP_MINOR_VERSION); } @@ -91,7 +91,7 @@ private static function getOldestSupportedPhpVersion(): ?string $now = current_time('timestamp'); foreach (self::SUPPORTED_VERSIONS as $version => $eol_date) { - if (strtotime($eol_date) >= $now) { + if (\strtotime($eol_date) >= $now) { return $version; } } diff --git a/classes/BlueChip/Security/Modules/Checklist/Checks/PluginsIntegrity.php b/classes/BlueChip/Security/Modules/Checklist/Checks/PluginsIntegrity.php index 76863db..5a7c429 100644 --- a/classes/BlueChip/Security/Modules/Checklist/Checks/PluginsIntegrity.php +++ b/classes/BlueChip/Security/Modules/Checklist/Checks/PluginsIntegrity.php @@ -21,7 +21,7 @@ public function __construct() { parent::__construct( __('Plugin files are untouched', 'bc-security'), - sprintf( + \sprintf( /* translators: 1: link to Wikipedia article about md5sum, 2: link to Plugins Directory at WordPress.org */ esc_html__('By comparing %1$s of local plugin files with checksums provided by WordPress.org it is possible to determine, if any of plugin files have been modified or if there are any unknown files in plugin directories. Note that this check works only with plugins installed from %2$s.', 'bc-security'), '<a href="' . esc_url(__('https://en.wikipedia.org/wiki/Md5sum', 'bc-security')) . '" rel="noreferrer">' . esc_html__('MD5 checksums', 'bc-security') . '</a>', @@ -40,7 +40,7 @@ protected function runInternal(): Checklist\CheckResult ); // Do not check plugins that are under version control. - $plugins = array_filter($plugins, function (string $plugin_basename): bool { + $plugins = \array_filter($plugins, function (string $plugin_basename): bool { return !Helpers\Plugin::isVersionControlled($plugin_basename); }, ARRAY_FILTER_USE_KEY); @@ -72,7 +72,7 @@ protected function runInternal(): Checklist\CheckResult // Trigger alert, if any suspicious files have been found. if (!empty($modified_files) || !empty($unknown_files)) { - $checksums_verification_failed[$plugin_basename] = array_merge( + $checksums_verification_failed[$plugin_basename] = \array_merge( $plugin_data, [ 'ModifiedFiles' => Checklist\Helper::formatListOfFiles($modified_files), @@ -90,19 +90,19 @@ protected function runInternal(): Checklist\CheckResult foreach ($checksums_verification_failed as $plugin_basename => $plugin_data) { $message_parts[] = ''; - $message_parts[] = sprintf('<strong>%s</strong> <code>%s</code>', esc_html($plugin_data['Name']), $plugin_basename); + $message_parts[] = \sprintf('<strong>%s</strong> <code>%s</code>', esc_html($plugin_data['Name']), $plugin_basename); if (!empty($plugin_data['ModifiedFiles'])) { - $message_parts[] = sprintf(esc_html__('Modified files: %s', 'bc-security'), $plugin_data['ModifiedFiles']); + $message_parts[] = \sprintf(esc_html__('Modified files: %s', 'bc-security'), $plugin_data['ModifiedFiles']); } if (!empty($plugin_data['UnknownFiles'])) { - $message_parts[] = sprintf(esc_html__('Unknown files: %s', 'bc-security'), $plugin_data['UnknownFiles']); + $message_parts[] = \sprintf(esc_html__('Unknown files: %s', 'bc-security'), $plugin_data['UnknownFiles']); } } if (!empty($checksums_retrieval_failed)) { // Also report any plugins that could not be checked, just in case. $message_parts[] = ''; - $message_parts[] = sprintf( + $message_parts[] = \sprintf( esc_html__('Furthermore, checksums for the following plugins could not be fetched: %s', 'bc-security'), Helpers\Plugin::implodeList($checksums_retrieval_failed, 'ChecksumsURL') ); @@ -111,7 +111,7 @@ protected function runInternal(): Checklist\CheckResult } if (!empty($checksums_retrieval_failed)) { - $message = sprintf( + $message = \sprintf( esc_html__('No modified plugins found, but checksums for the following plugins could not be fetched: %s', 'bc-security'), Helpers\Plugin::implodeList($checksums_retrieval_failed, 'ChecksumsURL') ); diff --git a/classes/BlueChip/Security/Modules/Checklist/Helper.php b/classes/BlueChip/Security/Modules/Checklist/Helper.php index 1b70294..74f84dd 100644 --- a/classes/BlueChip/Security/Modules/Checklist/Helper.php +++ b/classes/BlueChip/Security/Modules/Checklist/Helper.php @@ -24,10 +24,10 @@ public static function getJson(string $url) } // Read JSON. - $json = json_decode(wp_remote_retrieve_body($response)); + $json = \json_decode(wp_remote_retrieve_body($response)); // If decoding went fine, return JSON data. - return (json_last_error() === JSON_ERROR_NONE) ? $json : null; + return (\json_last_error() === JSON_ERROR_NONE) ? $json : null; } @@ -40,7 +40,7 @@ public static function formatLastRunTimestamp(Check $check): string if (empty($timestamp = $check->getTimeOfLastRun())) { return '--'; } else { - $format = sprintf('%s %s', get_option('date_format'), get_option('time_format')); + $format = \sprintf('%s %s', get_option('date_format'), get_option('time_format')); return date_i18n($format, $timestamp); } } @@ -52,7 +52,7 @@ public static function formatLastRunTimestamp(Check $check): string */ public static function formatListOfFiles(array $list): string { - return implode(', ', array_map( + return \implode(', ', \array_map( function (string $file): string { return '<em>' . esc_html($file) . '</em>'; }, @@ -78,12 +78,12 @@ function (string $file): string { public static function isAccessToUrlForbidden(string $url, ?string $body = null): ?bool { // Try to get provided URL. Use HEAD request for simplicity, if response body is of no interest. - $response = is_string($body) ? wp_remote_get($url) : wp_remote_head($url); + $response = \is_string($body) ? wp_remote_get($url) : wp_remote_head($url); switch (wp_remote_retrieve_response_code($response)) { case 200: // Status suggests that URL can be accessed, but check response body too, if given. - return is_string($body) ? ((wp_remote_retrieve_body($response) === $body) ? false : null) : false; + return \is_string($body) ? ((wp_remote_retrieve_body($response) === $body) ? false : null) : false; case 403: // Status suggests that access to URL is forbidden. return true; @@ -113,7 +113,7 @@ public static function checkDirectoryForModifiedFiles(string $path, $checksums, // Loop through all files in list. foreach ($checksums as $filename => $checksum) { // Skip any ignored files. - if (in_array($filename, $ignored_files, true)) { + if (\in_array($filename, $ignored_files, true)) { continue; } @@ -121,14 +121,14 @@ public static function checkDirectoryForModifiedFiles(string $path, $checksums, $pathname = $path . $filename; // Check, if file exists (skip non-existing files). - if (!file_exists($pathname)) { + if (!\file_exists($pathname)) { continue; } // Compare MD5 hashes. // Note that there can be multiple checksums provided for a single file (at least in plugin checksums). - $md5 = md5_file($pathname); - if (is_array($checksum) ? !in_array($md5, $checksum, true) : ($md5 !== $checksum)) { + $md5 = \md5_file($pathname); + if (\is_array($checksum) ? !\in_array($md5, $checksum, true) : ($md5 !== $checksum)) { $modified_files[] = $filename; } } @@ -156,7 +156,7 @@ public static function scanDirectoryForUnknownFiles(string $directory, string $p : new \DirectoryIterator($directory) ; - $directory_path_length = strlen($path); + $directory_path_length = \strlen($path); foreach ($it as $fileinfo) { // Skip directories as they don't have checksums. @@ -165,7 +165,7 @@ public static function scanDirectoryForUnknownFiles(string $directory, string $p } // Strip directory path from file's pathname. - $filename = substr($fileinfo->getPathname(), $directory_path_length); + $filename = \substr($fileinfo->getPathname(), $directory_path_length); // Check, whether it is a known file. if (!isset($checksums->$filename)) { diff --git a/classes/BlueChip/Security/Modules/Checklist/Manager.php b/classes/BlueChip/Security/Modules/Checklist/Manager.php index 77678af..4105350 100644 --- a/classes/BlueChip/Security/Modules/Checklist/Manager.php +++ b/classes/BlueChip/Security/Modules/Checklist/Manager.php @@ -116,14 +116,14 @@ public function getChecks(array $filters = []): array if (isset($filters['class'])) { $class = $filters['class']; - $checks = array_filter($checks, function (Check $check) use ($class): bool { + $checks = \array_filter($checks, function (Check $check) use ($class): bool { return $check instanceof $class; }); } if (isset($filters['meaningful'])) { $is_meaningful = $filters['meaningful']; - $checks = array_filter($checks, function (Check $check) use ($is_meaningful): bool { + $checks = \array_filter($checks, function (Check $check) use ($is_meaningful): bool { return $is_meaningful ? $check->isMeaningful() : !$check->isMeaningful(); }); } @@ -131,14 +131,14 @@ public function getChecks(array $filters = []): array if (isset($filters['monitored'])) { $monitored = $filters['monitored']; $settings = $this->settings; - $checks = array_filter($checks, function (string $check_id) use ($monitored, $settings): bool { + $checks = \array_filter($checks, function (string $check_id) use ($monitored, $settings): bool { return $monitored ? $settings[$check_id] : !$settings[$check_id]; }, ARRAY_FILTER_USE_KEY); } if (isset($filters['status'])) { $status = $filters['status']; - $checks = array_filter($checks, function (Check $check) use ($status): bool { + $checks = \array_filter($checks, function (Check $check) use ($status): bool { return $check->getResult()->getStatus() === $status; }); } @@ -216,7 +216,7 @@ public function runBasicChecks() */ public function runCheck() { - if (empty($check_id = filter_input(INPUT_POST, 'check_id', FILTER_SANITIZE_STRING))) { + if (empty($check_id = \filter_input(INPUT_POST, 'check_id', FILTER_SANITIZE_STRING))) { wp_send_json_error([ 'message' => __('No check ID provided!', 'bc-security'), ]); @@ -225,7 +225,7 @@ public function runCheck() $checks = $this->getChecks(); if (empty($check = $checks[$check_id])) { wp_send_json_error([ - 'message' => sprintf(__('Unknown check ID: %s', 'bc-security'), $check_id), + 'message' => \sprintf(__('Unknown check ID: %s', 'bc-security'), $check_id), ]); } diff --git a/classes/BlueChip/Security/Modules/Cron/Job.php b/classes/BlueChip/Security/Modules/Cron/Job.php index df92156..a2479dd 100644 --- a/classes/BlueChip/Security/Modules/Cron/Job.php +++ b/classes/BlueChip/Security/Modules/Cron/Job.php @@ -63,7 +63,7 @@ public function schedule(): bool } // Compute Unix timestamp (UTC) for when to run the cron job based on $time value. - $timestamp = is_int($this->time) ? $this->time : self::getTimestamp($this->time); + $timestamp = \is_int($this->time) ? $this->time : self::getTimestamp($this->time); return wp_schedule_event($timestamp, $this->recurrence, $this->hook); } @@ -87,7 +87,7 @@ public function unschedule(): bool */ public function isScheduled(): bool { - return is_int(wp_next_scheduled($this->hook)); + return \is_int(wp_next_scheduled($this->hook)); } @@ -105,10 +105,10 @@ public function isScheduled(): bool public static function getTimestamp(string $time_string): int { if ($time_string === self::RUN_AT_NIGHT || $time_string === self::RUN_RANDOMLY) { - $hour = mt_rand(0, ($time_string === self::RUN_AT_NIGHT) ? 5 : 23); - $minute = mt_rand(0, 59); - $second = mt_rand(0, 59); - $time = sprintf("%02d:%02d:%02d", $hour, $minute, $second); + $hour = \mt_rand(0, ($time_string === self::RUN_AT_NIGHT) ? 5 : 23); + $minute = \mt_rand(0, 59); + $second = \mt_rand(0, 59); + $time = \sprintf("%02d:%02d:%02d", $hour, $minute, $second); } else { // Assume $time_string denotes actual time like '01:02:03'. $time = $time_string; diff --git a/classes/BlueChip/Security/Modules/Hardening/AdminPage.php b/classes/BlueChip/Security/Modules/Hardening/AdminPage.php index 88d285e..28acfdc 100644 --- a/classes/BlueChip/Security/Modules/Hardening/AdminPage.php +++ b/classes/BlueChip/Security/Modules/Hardening/AdminPage.php @@ -67,7 +67,7 @@ public function initPage() 'disable-pingback', __('Disable pingbacks', 'bc-security'), function () { - echo '<p>' . sprintf( + echo '<p>' . \sprintf( /* translators: 1: Pingbacks label, 2: link to Sucuri Blog article on DDOSing via pingbacks */ esc_html__('%1$s can be %2$s. Although the "Allow link notifications from other blogs" setting can be used to disable them, it does not affect configuration of existing posts.', 'bc-security'), '<strong>' . esc_html__('Pingbacks', 'bc-security') . '</strong>', @@ -86,7 +86,7 @@ function () { 'disable-xml-rpc', __('Disable XML-RPC methods that require authentication', 'bc-security'), function () { - echo '<p>' . sprintf( + echo '<p>' . \sprintf( /* translators: 1: XML-RPC authentication label, 2: link to Sucuri Blog article on brute force amplification attacks */ esc_html__('Disabling methods that require %1$s helps to prevent %2$s.', 'bc-security'), '<strong>' . esc_html__('XML-RPC authentication', 'bc-security') . '</strong>', @@ -107,12 +107,12 @@ function () { function () { echo '<p>' . esc_html__('There are two ways for anonymous users to find out a list of usernames on your website:', 'bc-security') . '</p>'; echo '<ol>'; - echo '<li>' . sprintf( + echo '<li>' . \sprintf( /* translators: 1: link to wp/users REST API endpoint */ esc_html__('Through %1$s REST API endpoint', 'bc-security'), '<a href="https://developer.wordpress.org/rest-api/reference/users/#list-users" rel="noreferrer"><code>wp/users</code></a>' ) . '</li>'; - echo '<li>' . sprintf( + echo '<li>' . \sprintf( /* translators: 1: link to blog article explaining username enumeration attack */ esc_html__('Via %1$s technique', 'bc-security'), '<a href="https://hackertarget.com/wordpress-user-enumeration/" rel="noreferrer">' . esc_html__('username enumeration', 'bc-security') . '</a>' @@ -132,25 +132,25 @@ function () { 'pwned-passwords', __('Validate user passwords against Pwned Passwords database', 'bc-security'), function () { - echo '<p>' . sprintf( + echo '<p>' . \sprintf( /* translators: 1: link to Pwned Passwords homepage */ esc_html__('%1$s is a large database of passwords previously exposed in data breaches. This exposure makes them unsuitable for ongoing use as they are at much greater risk of being used to take over other accounts.', 'bc-security'), '<a href="' . HaveIBeenPwned::PWNEDPASSWORDS_HOME_URL . '" rel="noreferrer">Pwned Passwords</a>' ) . '</p>'; echo '<p>' . esc_html__('BC Security allows you to utilize this database in two ways:', 'bc-security'); echo '<ol>'; - echo '<li>' . sprintf( + echo '<li>' . \sprintf( /* translators: 1: password validation label */ esc_html__('When %1$s is enabled, passwords are checked against the Pwned Passwords database when new user is being created or existing user\'s password is being changed via profile update page or through password reset form. If there is a match, the operation is aborted with an error message asking for a different password.', 'bc-security'), '<strong>' . esc_html__('password validation', 'bc-security') . '</strong>' ). '</li>'; - echo '<li>' . sprintf( + echo '<li>' . \sprintf( /* translators: 1: password check label */ esc_html__('When %1$s is enabled, passwords are checked against the Pwned Passwords database when user logs in to the backend. If there is a match, a non-dismissible warning is displayed on all back-end pages encouraging the user to change its password.', 'bc-security'), '<strong>' . esc_html__('password check', 'bc-security') . '</strong>' ) . '</li>'; echo '</ol>'; - echo '<p>' . sprintf( + echo '<p>' . \sprintf( /* translators: 1: link to Pwned Passwords API documentation */ esc_html__('Important: Only the first 5 characters of SHA-1 hash of the actual password are ever shared with Pwned Passwords service. See %1$s for more details.', 'bc-security'), '<a href="https://haveibeenpwned.com/API/v2#PwnedPasswords" rel="noreferrer">' . esc_html__('Pwned Passwords API documentation', 'bc-security') . '</a>' diff --git a/classes/BlueChip/Security/Modules/Hardening/Core.php b/classes/BlueChip/Security/Modules/Hardening/Core.php index ab5cb9f..720f95d 100644 --- a/classes/BlueChip/Security/Modules/Hardening/Core.php +++ b/classes/BlueChip/Security/Modules/Hardening/Core.php @@ -135,11 +135,11 @@ public function filterJsonAPIAuthor($response, array $handler, \WP_REST_Request $url_base = (new class extends \WP_REST_Users_Controller { public function getUrlBase(): string { - return rtrim($this->namespace . '/' . $this->rest_base, '/'); + return \rtrim($this->namespace . '/' . $this->rest_base, '/'); } })->getUrlBase(); - if (preg_match('#' . preg_quote($url_base, '#') . '/*$#i', $route)) { + if (\preg_match('#' . \preg_quote($url_base, '#') . '/*$#i', $route)) { $this->rest_api_supressed = true; return rest_ensure_response(new \WP_Error( 'rest_user_cannot_view', @@ -149,8 +149,8 @@ public function getUrlBase(): string } $matches = []; - if (preg_match('#' . preg_quote($url_base, '#') . '/+(\d+)/*$#i', $route, $matches)) { - if (get_current_user_id() !== intval($matches[1])) { + if (\preg_match('#' . \preg_quote($url_base, '#') . '/+(\d+)/*$#i', $route, $matches)) { + if (get_current_user_id() !== \intval($matches[1])) { $this->rest_api_supressed = true; return rest_ensure_response(new \WP_Error( 'rest_user_invalid_id', @@ -208,7 +208,7 @@ public function filterAuthorQuery(array $query_vars): array */ protected static function smellsLikeAuthorScan(array $query_vars): bool { - return !empty($query_vars['author']) && (is_array($query_vars['author']) || is_numeric(preg_replace('/[^0-9]/', '', $query_vars['author']))); + return !empty($query_vars['author']) && (\is_array($query_vars['author']) || \is_numeric(\preg_replace('/[^0-9]/', '', $query_vars['author']))); } @@ -223,7 +223,7 @@ public function stopAuthorScan(\WP $wp) status_header(404); nocache_headers(); - if (!empty($template = get_404_template()) && file_exists($template)) { + if (!empty($template = get_404_template()) && \file_exists($template)) { include $template; } @@ -242,7 +242,7 @@ public function stopAuthorScan(\WP $wp) */ public function checkUserPassword(string $username, \WP_User $user) { - if (empty($password = filter_input(INPUT_POST, 'pwd'))) { + if (empty($password = \filter_input(INPUT_POST, 'pwd'))) { // Non-interactive sign on (probably). return; } @@ -280,7 +280,7 @@ public function displayPasswordPwnedNotice(\WP_Screen $screen) if (apply_filters(Hooks::SHOW_PWNED_PASSWORD_WARNING, true, $screen, $user)) { // Show the warning for current user on current screen. - $notice = sprintf( + $notice = \sprintf( /* translators: 1: link to Pwned Passwords homepage, 2: link to profile editation page */ esc_html__('Your password is present in a %1$s previously exposed in data breaches. Please, consider %2$s.', 'bc-security'), '<a href="' . HaveIBeenPwned::PWNEDPASSWORDS_HOME_URL . '" rel="noreferrer">' . esc_html__('large database of passwords', 'bc-security') . '</a>', @@ -330,7 +330,7 @@ public function validatePasswordReset(\WP_Error $errors, $user) return; } - if (empty($password = filter_input(INPUT_POST, 'pass1'))) { + if (empty($password = \filter_input(INPUT_POST, 'pass1'))) { // Do not check empty password. return; } @@ -348,7 +348,7 @@ public function validatePasswordReset(\WP_Error $errors, $user) protected static function checkIfPasswordHasBeenPwned(string $password, \WP_Error &$errors) { if (HaveIBeenPwned::hasPasswordBeenPwned($password)) { - $message = sprintf( + $message = \sprintf( /* translators: 1: Error label, 2: link to Pwned Passwords homepage */ esc_html__('%1$s: Provided password is present in a %2$s previously exposed in data breaches. Please, pick a different one.', 'bc-security'), '<strong>' . esc_html__('ERROR', 'bc-security') . '</strong>', diff --git a/classes/BlueChip/Security/Modules/IpBlacklist/AdminPage.php b/classes/BlueChip/Security/Modules/IpBlacklist/AdminPage.php index 1a367dc..59fc4fd 100644 --- a/classes/BlueChip/Security/Modules/IpBlacklist/AdminPage.php +++ b/classes/BlueChip/Security/Modules/IpBlacklist/AdminPage.php @@ -122,8 +122,8 @@ private function printBlacklistingForm() // Accept the following values as "pre-fill" // Note: the "add-" prefix is especially important for scope, because // there is "scope" GET argument used for list table views already. - $ip_address = filter_input(INPUT_GET, self::DEFAULT_IP_ADDRESS, FILTER_VALIDATE_IP); - $scope = filter_input(INPUT_GET, self::DEFAULT_SCOPE, FILTER_VALIDATE_INT); + $ip_address = \filter_input(INPUT_GET, self::DEFAULT_IP_ADDRESS, FILTER_VALIDATE_IP); + $scope = \filter_input(INPUT_GET, self::DEFAULT_SCOPE, FILTER_VALIDATE_INT); // Default lock duration is 1 month, unless different value is provided by filter. $duration = apply_filters(Hooks::DEFAULT_MANUAL_LOCK_DURATION, MONTH_IN_SECONDS); @@ -141,7 +141,7 @@ private function printBlacklistingForm() // Transform number of seconds into the biggest fitting time unit. // For example 172800 seconds are 2 days: $duration = 172800; => $duration_units = 2; $duration_unit_in_seconds => 86400; - list($duration_units, $duration_unit_in_seconds) = $this->transformSecondsIntoFittingUnit($duration, array_keys($units_in_seconds)); + list($duration_units, $duration_unit_in_seconds) = $this->transformSecondsIntoFittingUnit($duration, \array_keys($units_in_seconds)); // Simple styling echo '<style>form.bc-security { overflow: hidden; } span.bc-security { float: left; margin-right: 1.5em; margin-bottom: 0.5em; } span.bc-security label { display: block; margin-left: 0.25em; margin-bottom: 0.25em; } span.bc-security input, span.bc-security select { vertical-align: middle; } </style>'; @@ -239,7 +239,7 @@ private function initListTable() */ private function processActions() { - $nonce = filter_input(INPUT_POST, self::NONCE_NAME, FILTER_SANITIZE_STRING); + $nonce = \filter_input(INPUT_POST, self::NONCE_NAME, FILTER_SANITIZE_STRING); if (empty($nonce)) { // No nonce, no action. return; @@ -272,11 +272,11 @@ private function processActions() */ private function processBlacklistAction() { - $ip_address = filter_input(INPUT_POST, 'ip-address', FILTER_VALIDATE_IP); - $duration_length = filter_input(INPUT_POST, 'duration-length', FILTER_VALIDATE_INT); - $duration_unit = filter_input(INPUT_POST, 'duration-unit', FILTER_VALIDATE_INT); - $scope = filter_input(INPUT_POST, 'scope', FILTER_VALIDATE_INT); - $comment = filter_input(INPUT_POST, 'comment', FILTER_SANITIZE_STRING); + $ip_address = \filter_input(INPUT_POST, 'ip-address', FILTER_VALIDATE_IP); + $duration_length = \filter_input(INPUT_POST, 'duration-length', FILTER_VALIDATE_INT); + $duration_unit = \filter_input(INPUT_POST, 'duration-unit', FILTER_VALIDATE_INT); + $scope = \filter_input(INPUT_POST, 'scope', FILTER_VALIDATE_INT); + $comment = \filter_input(INPUT_POST, 'comment', FILTER_SANITIZE_STRING); // Check, if input is formally valid. if (empty($ip_address) || empty($duration_length) || empty($duration_unit) || empty($scope)) { @@ -286,13 +286,13 @@ private function processBlacklistAction() $duration = $duration_length * $duration_unit; // Check, if input is semantically valid. - if (($duration <= 0) || !in_array($scope, [LockScope::ADMIN, LockScope::COMMENTS, LockScope::WEBSITE], true)) { + if (($duration <= 0) || !\in_array($scope, [LockScope::ADMIN, LockScope::COMMENTS, LockScope::WEBSITE], true)) { return; } if ($this->bl_manager->lock($ip_address, $duration, $scope, BanReason::MANUALLY_BLACKLISTED, $comment)) { AdminNotices::add( - sprintf(__('IP address %s has been added to blacklist.', 'bc-security'), $ip_address), + \sprintf(__('IP address %s has been added to blacklist.', 'bc-security'), $ip_address), AdminNotices::SUCCESS ); } else { @@ -368,7 +368,7 @@ private function transformSecondsIntoFittingUnit(int $seconds, array $units_in_s { foreach ($units_in_seconds as $unit_in_seconds) { $units = $seconds / $unit_in_seconds; - if (is_int($units)) { + if (\is_int($units)) { return [$units, $unit_in_seconds]; } } diff --git a/classes/BlueChip/Security/Modules/IpBlacklist/Bouncer.php b/classes/BlueChip/Security/Modules/IpBlacklist/Bouncer.php index d4d7838..f61077c 100644 --- a/classes/BlueChip/Security/Modules/IpBlacklist/Bouncer.php +++ b/classes/BlueChip/Security/Modules/IpBlacklist/Bouncer.php @@ -71,7 +71,7 @@ public static function blockAccessTemporarily(string $ip_address = '') { $error_msg = empty($ip_address) ? esc_html__('Access from your device has been temporarily disabled for security reasons.', 'bc-security') - : sprintf(esc_html__('Access from your IP address %1$s has been temporarily disabled for security reasons.', 'bc-security'), sprintf('<em>%s</em>', $ip_address)) + : \sprintf(esc_html__('Access from your IP address %1$s has been temporarily disabled for security reasons.', 'bc-security'), \sprintf('<em>%s</em>', $ip_address)) ; // wp_die($error_msg, __('Service Temporarily Unavailable', 'bc-security'), 503); diff --git a/classes/BlueChip/Security/Modules/IpBlacklist/ListTable.php b/classes/BlueChip/Security/Modules/IpBlacklist/ListTable.php index d218475..b08e05a 100644 --- a/classes/BlueChip/Security/Modules/IpBlacklist/ListTable.php +++ b/classes/BlueChip/Security/Modules/IpBlacklist/ListTable.php @@ -68,7 +68,7 @@ public function __construct(string $url, string $per_page_option_name, Manager $ $this->bl_manager = $bl_manager; - $this->scope = filter_input(INPUT_GET, self::VIEW_SCOPE, FILTER_VALIDATE_INT, ['options' => ['default' => LockScope::ANY]]); + $this->scope = \filter_input(INPUT_GET, self::VIEW_SCOPE, FILTER_VALIDATE_INT, ['options' => ['default' => LockScope::ANY]]); if ($this->scope !== LockScope::ANY) { $this->url = add_query_arg(self::VIEW_SCOPE, $this->scope, $this->url); } @@ -174,28 +174,28 @@ public function get_sortable_columns() // phpcs:ignore protected function get_views() // phpcs:ignore { return [ - 'any' => sprintf( + 'any' => \sprintf( '<a href="%s" class="%s">%s</a> (%d)', remove_query_arg([self::VIEW_SCOPE], $this->url), $this->scope === LockScope::ANY ? 'current' : '', esc_html__('Any', 'bc-security'), $this->bl_manager->countAll() ), - 'admin' => sprintf( + 'admin' => \sprintf( '<a href="%s" class="%s">%s</a> (%d)', add_query_arg([self::VIEW_SCOPE => LockScope::ADMIN], $this->url), $this->scope === LockScope::ADMIN ? 'current' : '', esc_html__('Admin', 'bc-security'), $this->bl_manager->countAll(LockScope::ADMIN) ), - 'comments' => sprintf( + 'comments' => \sprintf( '<a href="%s" class="%s">%s</a> (%d)', add_query_arg([self::VIEW_SCOPE => LockScope::COMMENTS], $this->url), $this->scope === LockScope::COMMENTS ? 'current' : '', esc_html__('Comments', 'bc-security'), $this->bl_manager->countAll(LockScope::COMMENTS) ), - 'website' => sprintf( + 'website' => \sprintf( '<a href="%s" class="%s">%s</a> (%d)', add_query_arg([self::VIEW_SCOPE => LockScope::WEBSITE], $this->url), $this->scope === LockScope::WEBSITE ? 'current' : '', @@ -233,15 +233,15 @@ public function prepare_items() // phpcs:ignore public function processActions() { // Remove or unlock single record? - if (($action = filter_input(INPUT_GET, 'action'))) { + if (($action = \filter_input(INPUT_GET, 'action'))) { // Get ID of record to act upon. - $id = filter_input(INPUT_GET, 'id', FILTER_VALIDATE_INT); - if (!is_int($id)) { + $id = \filter_input(INPUT_GET, 'id', FILTER_VALIDATE_INT); + if (!\is_int($id)) { return; } - $nonce = filter_input(INPUT_GET, self::NONCE_NAME); - if (!wp_verify_nonce($nonce, sprintf('%s:%s', $action, $id))) { + $nonce = \filter_input(INPUT_GET, self::NONCE_NAME); + if (!wp_verify_nonce($nonce, \sprintf('%s:%s', $action, $id))) { // Nonce check failed return; } @@ -258,9 +258,9 @@ public function processActions() } // Bulk unlock? - if (($current_action = $this->current_action()) && isset($_POST['ids']) && is_array($_POST['ids'])) { + if (($current_action = $this->current_action()) && isset($_POST['ids']) && \is_array($_POST['ids'])) { // Sanitize: convert IDs to unsigned int and remove any zero values. - $ids = array_filter(array_map('absint', $_POST['ids'])); + $ids = \array_filter(\array_map('absint', $_POST['ids'])); if ($current_action === self::BULK_ACTION_REMOVE && ($removed = $this->bl_manager->removeMany($ids))) { // Records removed successfully, redirect to overview (and trigger admin notice) @@ -313,7 +313,7 @@ private function getRowActions(array $item): array ), ]; - if (strtotime($item['release_time']) > current_time('timestamp')) { + if (\strtotime($item['release_time']) > current_time('timestamp')) { // Only active locks can be unlocked $actions[self::ACTION_UNLOCK] = $this->renderRowAction( self::ACTION_UNLOCK, diff --git a/classes/BlueChip/Security/Modules/IpBlacklist/Manager.php b/classes/BlueChip/Security/Modules/IpBlacklist/Manager.php index b44b07c..4f95ecb 100644 --- a/classes/BlueChip/Security/Modules/IpBlacklist/Manager.php +++ b/classes/BlueChip/Security/Modules/IpBlacklist/Manager.php @@ -74,7 +74,7 @@ public function install() $charset_collate = $this->wpdb->get_charset_collate(); - dbDelta(implode(PHP_EOL, [ + dbDelta(\implode(PHP_EOL, [ "CREATE TABLE {$this->blacklist_table} (", "id int unsigned NOT NULL AUTO_INCREMENT,", "scope tinyint unsigned NOT NULL,", @@ -92,7 +92,7 @@ public function install() public function uninstall() { - $this->wpdb->query(sprintf('DROP TABLE IF EXISTS %s', $this->blacklist_table)); + $this->wpdb->query(\sprintf('DROP TABLE IF EXISTS %s', $this->blacklist_table)); } @@ -130,7 +130,7 @@ public function countAll(int $scope = LockScope::ANY): int $query .= $this->wpdb->prepare(" WHERE scope = %d", $scope); } - return intval($this->wpdb->get_var($query)); + return \intval($this->wpdb->get_var($query)); } @@ -146,10 +146,10 @@ public function countFrom(int $timestamp): int { $query = $this->wpdb->prepare( "SELECT COUNT(id) AS total FROM {$this->blacklist_table} WHERE ban_time > %s", - date(self::MYSQL_DATETIME_FORMAT, $timestamp) + \date(self::MYSQL_DATETIME_FORMAT, $timestamp) ); - return intval($this->wpdb->get_var($query)); + return \intval($this->wpdb->get_var($query)); } @@ -170,11 +170,11 @@ public function fetch(int $scope = LockScope::ANY, int $from = 0, int $limit = 2 // Apply scope if given if ($scope !== LockScope::ANY) { - $query .= sprintf(" WHERE scope = %d", $scope); + $query .= \sprintf(" WHERE scope = %d", $scope); } // Apply order by column, if column name is valid - if ($order_by && in_array($order_by, $this->columns, true)) { + if ($order_by && \in_array($order_by, $this->columns, true)) { $query .= " ORDER BY {$order_by}"; if ($order === 'asc') { $query .= ' ASC'; @@ -184,13 +184,13 @@ public function fetch(int $scope = LockScope::ANY, int $from = 0, int $limit = 2 } // Apply limits - $query .= sprintf(" LIMIT %d, %d", $from, $limit); + $query .= \sprintf(" LIMIT %d, %d", $from, $limit); // Execute query $results = $this->wpdb->get_results($query, ARRAY_A); // Return results - return is_array($results) ? $results : []; + return \is_array($results) ? $results : []; } @@ -211,7 +211,7 @@ public function fetchAll(int $scope = LockScope::ANY): array // Execute query $results = $this->wpdb->get_results($query); // Return results - return is_array($results) ? $results : []; + return \is_array($results) ? $results : []; } @@ -236,7 +236,7 @@ public function isLocked(string $ip_address, int $scope): bool // Execute query $release_time = $this->wpdb->get_var($query); // Evaluate release time - $result = is_string($release_time) && (current_time('timestamp') < strtotime($release_time)); + $result = \is_string($release_time) && (current_time('timestamp') < \strtotime($release_time)); // Allow the result to be filtered return apply_filters(Hooks::IS_IP_ADDRESS_LOCKED, $result, $ip_address, $scope); } @@ -257,8 +257,8 @@ public function lock(string $ip_address, int $duration, int $scope, int $reason, $now = current_time('timestamp'); $data = [ - 'ban_time' => date(self::MYSQL_DATETIME_FORMAT, $now), - 'release_time' => date(self::MYSQL_DATETIME_FORMAT, $now + $duration), + 'ban_time' => \date(self::MYSQL_DATETIME_FORMAT, $now), + 'release_time' => \date(self::MYSQL_DATETIME_FORMAT, $now + $duration), 'comment' => $comment, ]; @@ -278,7 +278,7 @@ public function lock(string $ip_address, int $duration, int $scope, int $reason, $result = $this->wpdb->update($this->blacklist_table, $data, $where, $format, $where_format); } else { // Insert: merge $data with $where, $format with $where_format. - $result = $this->wpdb->insert($this->blacklist_table, array_merge($data, $where), array_merge($format, $where_format)); + $result = $this->wpdb->insert($this->blacklist_table, \array_merge($data, $where), \array_merge($format, $where_format)); } return $result !== false; @@ -296,7 +296,7 @@ public function prune(): bool // Note: $wpdb->delete cannot be used as it does not support "<=" comparison) $query = $this->wpdb->prepare( "DELETE FROM {$this->blacklist_table} WHERE release_time <= %s", - date(self::MYSQL_DATETIME_FORMAT, current_time('timestamp')) + \date(self::MYSQL_DATETIME_FORMAT, current_time('timestamp')) ); // Execute query $result = $this->wpdb->query($query); @@ -332,10 +332,10 @@ public function removeMany(array $ids): int return 0; } // Prepare query. - $query = sprintf( + $query = \sprintf( "DELETE FROM {$this->blacklist_table} WHERE %s", - implode(' OR ', array_map(function ($id) { - return sprintf('id = %d', $id); + \implode(' OR ', \array_map(function ($id) { + return \sprintf('id = %d', $id); }, $ids)) ); // Execute query. @@ -358,7 +358,7 @@ public function unlock(int $id): bool // Execute query. $result = $this->wpdb->update( $this->blacklist_table, - ['release_time' => date(self::MYSQL_DATETIME_FORMAT, current_time('timestamp'))], + ['release_time' => \date(self::MYSQL_DATETIME_FORMAT, current_time('timestamp'))], ['id' => $id], ['%s'], ['%d'] @@ -382,11 +382,11 @@ public function unlockMany(array $ids): int return 0; } // Prepare query. - $query = sprintf( + $query = \sprintf( "UDPATE {$this->blacklist_table} SET release_time = '%s' WHERE %s", - date(self::MYSQL_DATETIME_FORMAT, current_time('timestamp')), - implode(' OR ', array_map(function ($id) { - return sprintf('id = %d', $id); + \date(self::MYSQL_DATETIME_FORMAT, current_time('timestamp')), + \implode(' OR ', \array_map(function ($id) { + return \sprintf('id = %d', $id); }, $ids)) ); // Execute query. @@ -417,6 +417,6 @@ protected function getId(string $ip_address, int $scope, int $reason): ?int // Execute query. $result = $this->wpdb->get_var($query); // Return result. - return is_null($result) ? $result : intval($result); + return \is_null($result) ? $result : \intval($result); } } diff --git a/classes/BlueChip/Security/Modules/Log/Event.php b/classes/BlueChip/Security/Modules/Log/Event.php index 88cb740..a33f8d4 100644 --- a/classes/BlueChip/Security/Modules/Log/Event.php +++ b/classes/BlueChip/Security/Modules/Log/Event.php @@ -97,7 +97,7 @@ public function explainContext(): array private static function getPropertyLabel(\ReflectionProperty $property): string { $matches = []; - if (preg_match("/__\('(.+)'\)/i", $property->getDocComment(), $matches)) { + if (\preg_match("/__\('(.+)'\)/i", $property->getDocComment(), $matches)) { return __($matches[1], 'bc-security'); } else { return ''; diff --git a/classes/BlueChip/Security/Modules/Log/EventsManager.php b/classes/BlueChip/Security/Modules/Log/EventsManager.php index 0fb5858..fa9fb9b 100644 --- a/classes/BlueChip/Security/Modules/Log/EventsManager.php +++ b/classes/BlueChip/Security/Modules/Log/EventsManager.php @@ -50,7 +50,7 @@ public static function getMapping(): array */ public static function getInstances(): array { - return array_map( + return \array_map( function (string $classname): Event { return new $classname(); }, diff --git a/classes/BlueChip/Security/Modules/Log/ListTable.php b/classes/BlueChip/Security/Modules/Log/ListTable.php index f5058f8..c4d3c0b 100644 --- a/classes/BlueChip/Security/Modules/Log/ListTable.php +++ b/classes/BlueChip/Security/Modules/Log/ListTable.php @@ -38,7 +38,7 @@ public function __construct(string $url, string $per_page_option_name, Logger $l $this->logger = $logger; // Display only events of particular type? - $event_id = filter_input(INPUT_GET, self::VIEW_EVENT, FILTER_SANITIZE_URL); + $event_id = \filter_input(INPUT_GET, self::VIEW_EVENT, FILTER_SANITIZE_URL); if ($event_id && !empty($event = EventsManager::create($event_id))) { $this->event = $event; $this->url = add_query_arg(self::VIEW_EVENT, $event_id, $this->url); @@ -67,11 +67,11 @@ public function column_date_and_time(array $item): string // phpcs:ignore */ public function column_default($item, $column_name) // phpcs:ignore { - if ($this->event && array_key_exists($column_name, $this->event->getContext())) { - $context = empty($item['context']) ? [] : unserialize($item['context']); + if ($this->event && \array_key_exists($column_name, $this->event->getContext())) { + $context = empty($item['context']) ? [] : \unserialize($item['context']); $value = $context[$column_name] ?? ''; // Value can be an array, in such case output array values separated by ",". - return is_array($value) ? implode(', ', $value) : $value; + return \is_array($value) ? \implode(', ', $value) : $value; } else { return isset($item[$column_name]) ? $item[$column_name] : ''; } @@ -118,7 +118,7 @@ public function column_ip_address(array $item): string // phpcs:ignore public function column_message(array $item): string // phpcs:ignore { $message = empty($item['message']) ? '' : $item['message']; - $context = empty($item['context']) ? [] : unserialize($item['context']); + $context = empty($item['context']) ? [] : \unserialize($item['context']); return self::formatMessage($message, $context); } @@ -170,13 +170,13 @@ public function get_sortable_columns() // phpcs:ignore */ protected function get_views() // phpcs:ignore { - $event_id = is_null($this->event) ? null : $this->event->getId(); + $event_id = \is_null($this->event) ? null : $this->event->getId(); $views = [ - 'all' => sprintf( + 'all' => \sprintf( '<a href="%s" class="%s">%s</a> (%d)', remove_query_arg([self::VIEW_EVENT], $this->url), - is_null($event_id) ? 'current' : '', + \is_null($event_id) ? 'current' : '', esc_html__('All', 'bc-security'), $this->logger->countAll() ), @@ -185,7 +185,7 @@ protected function get_views() // phpcs:ignore foreach (EventsManager::getInstances() as $eid => $event) { // Get human readable name for event type. - $views[$eid] = sprintf( + $views[$eid] = \sprintf( '<a href="%s" class="%s">%s</a> (%d)', add_query_arg([self::VIEW_EVENT => $eid], $this->url), $event_id === $eid ? 'current' : '', @@ -231,7 +231,7 @@ private function getRowActions(array $item): array } return [ - self::ACTION_BLACKLIST => sprintf( + self::ACTION_BLACKLIST => \sprintf( '<span class="delete"><a href="%s">%s</a></span>', add_query_arg( [ @@ -281,9 +281,9 @@ private static function formatMessage(string $message, array $context): string foreach ($context as $key => $value) { // Format array as comma separated list (indicate empty array with "-") // Convert all other values to string (and make the value stand out in bold in such case). - $formatted = is_array($value) ? (empty($value) ? '-' : implode(', ', $value)) : sprintf('<strong>%s</strong>', $value); + $formatted = \is_array($value) ? (empty($value) ? '-' : \implode(', ', $value)) : \sprintf('<strong>%s</strong>', $value); // Inject formatted values into message. - $message = str_replace("{{$key}}", $formatted, $message); + $message = \str_replace("{{$key}}", $formatted, $message); } return $message; diff --git a/classes/BlueChip/Security/Modules/Log/Logger.php b/classes/BlueChip/Security/Modules/Log/Logger.php index db5f50b..883595d 100644 --- a/classes/BlueChip/Security/Modules/Log/Logger.php +++ b/classes/BlueChip/Security/Modules/Log/Logger.php @@ -70,7 +70,7 @@ public function install() $charset_collate = $this->wpdb->get_charset_collate(); - dbDelta(implode(PHP_EOL, [ + dbDelta(\implode(PHP_EOL, [ "CREATE TABLE {$this->log_table} (", "id int unsigned NOT NULL AUTO_INCREMENT,", "date_and_time datetime NOT NULL,", @@ -89,7 +89,7 @@ public function install() public function uninstall() { - $this->wpdb->query(sprintf('DROP TABLE IF EXISTS %s', $this->log_table)); + $this->wpdb->query(\sprintf('DROP TABLE IF EXISTS %s', $this->log_table)); } @@ -137,12 +137,12 @@ public function log($level, $message, array $context = []) $insertion_status = $this->wpdb->insert( $this->log_table, [ - 'date_and_time' => date(self::MYSQL_DATETIME_FORMAT, current_time('timestamp')), + 'date_and_time' => \date(self::MYSQL_DATETIME_FORMAT, current_time('timestamp')), 'ip_address' => $ip_address, 'event' => $event, 'level' => $this->translateLogLevel($level), 'message' => $message, - 'context' => serialize($context), + 'context' => \serialize($context), ], [ '%s', @@ -161,7 +161,7 @@ public function log($level, $message, array $context = []) [Events\AuthBadCookie::ID, Events\LoginFailure::ID, Events\LoginLockout::ID, Events\LoginSuccessful::ID,] ); - if (in_array($event, $events_with_hostname_resolving, true)) { + if (\in_array($event, $events_with_hostname_resolving, true)) { // Schedule hostname resolution for inserted log record. $this->hostname_resolver->resolveHostnameInBackground( $ip_address, @@ -181,7 +181,7 @@ public function log($level, $message, array $context = []) public function logEvent(Event $event) { // Include event ID in context. - $this->log($event->getLogLevel(), $event->getMessage(), array_merge(['event' => $event->getId()], $event->getContext())); + $this->log($event->getLogLevel(), $event->getMessage(), \array_merge(['event' => $event->getId()], $event->getContext())); } @@ -211,7 +211,7 @@ public function translateLogLevel(string $level): ?int case Log\LogLevel::DEBUG: return 7; default: - _doing_it_wrong(__METHOD__, sprintf('Unknown log level: %s', $level), '0.2.0'); + _doing_it_wrong(__METHOD__, \sprintf('Unknown log level: %s', $level), '0.2.0'); return null; } } @@ -258,11 +258,11 @@ public function countAll(?string $event = null): int $query = "SELECT COUNT(id) AS total FROM {$this->log_table}"; // Event may be empty string as well, therefore do not use empty(). - if (is_string($event)) { + if (\is_string($event)) { $query .= $this->wpdb->prepare(' WHERE event = %s', $event); } - return intval($this->wpdb->get_var($query)); + return \intval($this->wpdb->get_var($query)); } @@ -278,10 +278,10 @@ public function countFrom(int $timestamp): int { $query = $this->wpdb->prepare( "SELECT COUNT(id) AS total FROM {$this->log_table} WHERE date_and_time > %s", - date(self::MYSQL_DATETIME_FORMAT, $timestamp) + \date(self::MYSQL_DATETIME_FORMAT, $timestamp) ); - return intval($this->wpdb->get_var($query)); + return \intval($this->wpdb->get_var($query)); } @@ -301,12 +301,12 @@ public function fetch(?string $event = null, int $from = 0, int $limit = 20, str $query = "SELECT * FROM {$this->log_table}"; // Event may be empty string as well, therefore do not use empty(). - if (is_string($event)) { + if (\is_string($event)) { $query .= $this->wpdb->prepare(" WHERE event = %s", $event); } // Apply order by column, if column name is valid. - if ($order_by && in_array($order_by, $this->columns, true)) { + if ($order_by && \in_array($order_by, $this->columns, true)) { $query .= " ORDER BY {$order_by}"; if ($order === 'asc') { $query .= ' ASC'; @@ -316,13 +316,13 @@ public function fetch(?string $event = null, int $from = 0, int $limit = 20, str } // Apply limits - $query .= sprintf(" LIMIT %d, %d", $from, $limit); + $query .= \sprintf(" LIMIT %d, %d", $from, $limit); // Execute query $results = $this->wpdb->get_results($query, ARRAY_A); // Return results - return is_array($results) ? $results : []; + return \is_array($results) ? $results : []; } @@ -337,7 +337,7 @@ public function getKnownIps(): array $this->wpdb->prepare("SELECT DISTINCT(ip_address) FROM {$this->log_table} WHERE event = %s", Events\LoginSuccessful::ID) ); - return is_array($result) ? wp_list_pluck($result, 'ip_address') : []; + return \is_array($result) ? wp_list_pluck($result, 'ip_address') : []; } @@ -364,7 +364,7 @@ public function pruneByAge(): bool // Note: $wpdb->delete cannot be used as it does not support "<=" comparison) $query = $this->wpdb->prepare( "DELETE FROM {$this->log_table} WHERE date_and_time <= %s", - date(self::MYSQL_DATETIME_FORMAT, current_time('timestamp') - $max_age) + \date(self::MYSQL_DATETIME_FORMAT, current_time('timestamp') - $max_age) ); // Execute query and return true/false status. return $this->wpdb->query($query) !== false; @@ -387,7 +387,7 @@ public function pruneBySize(): bool // Find the biggest ID from all records that should be pruned. $query_id = $this->wpdb->prepare("SELECT id FROM {$this->log_table} ORDER BY id DESC LIMIT %d, 1", $max_size); - if (empty($id = intval($this->wpdb->get_var($query_id)))) { + if (empty($id = \intval($this->wpdb->get_var($query_id)))) { return false; } diff --git a/classes/BlueChip/Security/Modules/Login/AdminPage.php b/classes/BlueChip/Security/Modules/Login/AdminPage.php index ea5f811..e750ef5 100644 --- a/classes/BlueChip/Security/Modules/Login/AdminPage.php +++ b/classes/BlueChip/Security/Modules/Login/AdminPage.php @@ -136,7 +136,7 @@ function () { 'generic-error-message', __('Display generic error message on failed login', 'bc-security'), function () { - echo '<p>' . sprintf( + echo '<p>' . \sprintf( /* translators: 1: link to Wikipedia page on Security through obscurity */ esc_html__('This is a %1$s approach, but it may make it harder for attackers to guess user credentials.', 'bc-security'), '<a href="' . esc_url(__('https://en.wikipedia.org/wiki/Security_through_obscurity', 'bc-security')) . '" rel="noreferrer">' . esc_html__('security through obscurity', 'bc-security') . '</a>' diff --git a/classes/BlueChip/Security/Modules/Login/Bookkeeper.php b/classes/BlueChip/Security/Modules/Login/Bookkeeper.php index fec3908..6bfe4eb 100644 --- a/classes/BlueChip/Security/Modules/Login/Bookkeeper.php +++ b/classes/BlueChip/Security/Modules/Login/Bookkeeper.php @@ -58,7 +58,7 @@ public function install() $charset_collate = $this->wpdb->get_charset_collate(); - dbDelta(implode(PHP_EOL, [ + dbDelta(\implode(PHP_EOL, [ "CREATE TABLE {$this->failed_logins_table} (", "id int unsigned NOT NULL AUTO_INCREMENT,", "ip_address char(128) NOT NULL,", @@ -74,7 +74,7 @@ public function install() public function uninstall() { - $this->wpdb->query(sprintf('DROP TABLE IF EXISTS %s', $this->failed_logins_table)); + $this->wpdb->query(\sprintf('DROP TABLE IF EXISTS %s', $this->failed_logins_table)); } @@ -93,7 +93,7 @@ public function recordFailedLoginAttempt(string $ip_address, string $username): // Insert new failed login attempt for given IP address. $data = [ 'ip_address' => $ip_address, - 'date_and_time' => date(self::MYSQL_DATETIME_FORMAT, $now), + 'date_and_time' => \date(self::MYSQL_DATETIME_FORMAT, $now), 'username' => $username, 'user_id' => ($user === false) ? null : $user->ID, ]; @@ -104,10 +104,10 @@ public function recordFailedLoginAttempt(string $ip_address, string $username): $query = $this->wpdb->prepare( "SELECT COUNT(*) AS retries_count FROM {$this->failed_logins_table} WHERE ip_address = %s AND date_and_time > %s", $ip_address, - date(self::MYSQL_DATETIME_FORMAT, $now - $this->settings->getResetTimeoutDuration()) + \date(self::MYSQL_DATETIME_FORMAT, $now - $this->settings->getResetTimeoutDuration()) ); - return intval($this->wpdb->get_var($query)); + return \intval($this->wpdb->get_var($query)); } @@ -124,7 +124,7 @@ public function prune() // Note: $wpdb->delete cannot be used as it does not support "<" comparison) $query = $this->wpdb->prepare( "DELETE FROM {$this->failed_logins_table} WHERE date_and_time <= %s", - date(self::MYSQL_DATETIME_FORMAT, $threshold) + \date(self::MYSQL_DATETIME_FORMAT, $threshold) ); // Execute query. return $this->wpdb->query($query); diff --git a/classes/BlueChip/Security/Modules/Login/Gatekeeper.php b/classes/BlueChip/Security/Modules/Login/Gatekeeper.php index 605c8e1..69dd441 100644 --- a/classes/BlueChip/Security/Modules/Login/Gatekeeper.php +++ b/classes/BlueChip/Security/Modules/Login/Gatekeeper.php @@ -94,7 +94,7 @@ public function init() */ public function filterIllegalUserLogins(array $usernames): array { - return array_merge($usernames, $this->settings->getUsernameBlacklist()); + return \array_merge($usernames, $this->settings->getUsernameBlacklist()); } @@ -170,7 +170,7 @@ public function lockIpIfUsernameOnBlacklist($user, string $username) // When a non-existing username (or email)... if (is_wp_error($user) && ($user->get_error_code() === 'invalid_username' || $user->get_error_code() === 'invalid_email')) { // ...is found on black list... - if (in_array($username, $this->settings->getUsernameBlacklist(), true)) { + if (\in_array($username, $this->settings->getUsernameBlacklist(), true)) { // ...lock IP out! $this->lockOut($username, $this->settings->getLongLockoutDuration(), IpBlacklist\BanReason::USERNAME_BLACKLIST); } diff --git a/classes/BlueChip/Security/Modules/Login/Settings.php b/classes/BlueChip/Security/Modules/Login/Settings.php index 09933c1..5d9de05 100644 --- a/classes/BlueChip/Security/Modules/Login/Settings.php +++ b/classes/BlueChip/Security/Modules/Login/Settings.php @@ -65,7 +65,7 @@ class Settings extends \BlueChip\Security\Core\Settings */ public static function sanitizeUsernameBlacklist($value): array { - return array_filter(self::parseList($value), '\validate_username'); + return \array_filter(self::parseList($value), '\validate_username'); } diff --git a/classes/BlueChip/Security/Modules/Notifications/AdminPage.php b/classes/BlueChip/Security/Modules/Notifications/AdminPage.php index c329948..0ad0467 100644 --- a/classes/BlueChip/Security/Modules/Notifications/AdminPage.php +++ b/classes/BlueChip/Security/Modules/Notifications/AdminPage.php @@ -123,7 +123,7 @@ function () { Settings::NOTIFY_SITE_ADMIN, __('Notify site admin', 'bc-security'), [FormHelper::class, 'printCheckbox'], - [ 'description' => sprintf(__('Currently: %s', 'bc-security'), get_option('admin_email')), ] + [ 'description' => \sprintf(__('Currently: %s', 'bc-security'), get_option('admin_email')), ] ); $this->addSettingsField( Settings::NOTIFICATION_RECIPIENTS, diff --git a/classes/BlueChip/Security/Modules/Notifications/Mailman.php b/classes/BlueChip/Security/Modules/Notifications/Mailman.php index 1e35982..be8a727 100644 --- a/classes/BlueChip/Security/Modules/Notifications/Mailman.php +++ b/classes/BlueChip/Security/Modules/Notifications/Mailman.php @@ -29,7 +29,7 @@ public static function send($to, string $subject, $message): bool return \wp_mail( $to, self::formatSubject($subject), - self::formatMessage(is_array($message) ? $message : [$message]) + self::formatMessage(\is_array($message) ? $message : [$message]) ); } @@ -43,7 +43,7 @@ public static function send($to, string $subject, $message): bool private static function formatMessage(array $message): string { $boilerplate_intro = [ - sprintf( + \sprintf( __('This email was sent from your website "%1$s" by BC Security plugin on %2$s at %3$s.'), get_option('blogname'), date_i18n('d.m.Y'), @@ -54,13 +54,13 @@ private static function formatMessage(array $message): string $boilerplate_outro = [ '', - sprintf( + \sprintf( __('To change your notification settings, visit: %s', 'bc-security'), AdminPage::getPageUrl() ), ]; - return implode(self::EOL, array_merge($boilerplate_intro, $message, $boilerplate_outro)); + return \implode(self::EOL, \array_merge($boilerplate_intro, $message, $boilerplate_outro)); } @@ -72,6 +72,6 @@ private static function formatMessage(array $message): string */ private static function formatSubject(string $subject): string { - return sprintf('[%s | %s] %s', get_option('blogname'), __('BC Security Alert', 'bc-security'), $subject); + return \sprintf('[%s | %s] %s', get_option('blogname'), __('BC Security Alert', 'bc-security'), $subject); } } diff --git a/classes/BlueChip/Security/Modules/Notifications/Settings.php b/classes/BlueChip/Security/Modules/Notifications/Settings.php index 4c7aaef..2ae7df4 100644 --- a/classes/BlueChip/Security/Modules/Notifications/Settings.php +++ b/classes/BlueChip/Security/Modules/Notifications/Settings.php @@ -68,6 +68,6 @@ class Settings extends \BlueChip\Security\Core\Settings */ public static function sanitizeNotificationRecipient($value): array { - return array_filter(self::parseList($value), '\is_email'); + return \array_filter(self::parseList($value), '\is_email'); } } diff --git a/classes/BlueChip/Security/Modules/Notifications/Watchman.php b/classes/BlueChip/Security/Modules/Notifications/Watchman.php index a5c2469..82d9886 100644 --- a/classes/BlueChip/Security/Modules/Notifications/Watchman.php +++ b/classes/BlueChip/Security/Modules/Notifications/Watchman.php @@ -51,7 +51,7 @@ public function __construct(Settings $settings, string $remote_address, Logger $ $this->recipients = $settings[Settings::NOTIFICATION_RECIPIENTS]; // If site admin should be notified to, include him as well. if ($settings[Settings::NOTIFY_SITE_ADMIN]) { - array_unshift($this->recipients, get_option('admin_email')); + \array_unshift($this->recipients, get_option('admin_email')); } } @@ -61,7 +61,7 @@ public function __construct(Settings $settings, string $remote_address, Logger $ */ public static function isMuted(): bool { - return defined('BC_SECURITY_MUTE_NOTIFICATIONS') && BC_SECURITY_MUTE_NOTIFICATIONS; + return \defined('BC_SECURITY_MUTE_NOTIFICATIONS') && BC_SECURITY_MUTE_NOTIFICATIONS; } @@ -73,7 +73,7 @@ public static function isMuted(): bool */ private static function formatRemoteAddress(string $remote_address): string { - $remote_hostname = gethostbyaddr($remote_address); + $remote_hostname = \gethostbyaddr($remote_address); if (empty($remote_hostname) || ($remote_hostname === $remote_address)) { return $remote_address; } else { @@ -136,7 +136,7 @@ public function deactivate() $user = wp_get_current_user(); if ($user->ID) { // Name the bastard that turned us off! - $message = sprintf( + $message = \sprintf( __('User "%s" had just deactivated BC Security plugin on your website!', 'bc-security'), $user->user_login ); @@ -162,7 +162,7 @@ public function deactivate() public function watchCoreUpdateAvailable($update_transient) { // Check, if update transient has the data we are interested in. - if (!isset($update_transient->updates) || !is_array($update_transient->updates) || empty($update_transient->updates)) { + if (!isset($update_transient->updates) || !\is_array($update_transient->updates) || empty($update_transient->updates)) { return; } @@ -182,7 +182,7 @@ public function watchCoreUpdateAvailable($update_transient) } $subject = __('WordPress update available', 'bc-security'); - $message = sprintf( + $message = \sprintf( __('WordPress has an update to version %s available.', 'bc-security'), $latest_version ); @@ -206,14 +206,14 @@ public function watchCoreUpdateAvailable($update_transient) public function watchPluginUpdatesAvailable($update_transient) { // Check, if update transient has the data we are interested in. - if (!isset($update_transient->response) || !is_array($update_transient->response)) { + if (!isset($update_transient->response) || !\is_array($update_transient->response)) { return; } // Filter out any updates for which notification has been sent already. - $plugin_updates = array_filter($update_transient->response, function ($plugin_update_data, $plugin_file) { + $plugin_updates = \array_filter($update_transient->response, function ($plugin_update_data, $plugin_file) { $notified_version = Transients::getForSite('update-notifications', 'plugin', $plugin_file); - return empty($notified_version) || version_compare($notified_version, $plugin_update_data->new_version, '<'); + return empty($notified_version) || \version_compare($notified_version, $plugin_update_data->new_version, '<'); }, ARRAY_FILTER_USE_BOTH); if (empty($plugin_updates)) { @@ -225,7 +225,7 @@ public function watchPluginUpdatesAvailable($update_transient) foreach ($plugin_updates as $plugin_file => $plugin_update_data) { $plugin_data = Plugin::getPluginData($plugin_file); - $plugin_message = sprintf( + $plugin_message = \sprintf( __('Plugin "%1$s" has an update to version %2$s available.', 'bc-security'), $plugin_data['Name'], $plugin_update_data->new_version @@ -233,7 +233,7 @@ public function watchPluginUpdatesAvailable($update_transient) if (!empty($plugin_changelog_url = Plugin::getChangelogUrl($plugin_file))) { // Append link to changelog, if available. - $plugin_message .= ' ' . sprintf( + $plugin_message .= ' ' . \sprintf( __('Changelog: %1$s', 'bc-security'), $plugin_changelog_url ); @@ -263,14 +263,14 @@ public function watchPluginUpdatesAvailable($update_transient) public function watchThemeUpdatesAvailable($update_transient) { // Check, if update transient has the data we are interested in. - if (!isset($update_transient->response) || !is_array($update_transient->response)) { + if (!isset($update_transient->response) || !\is_array($update_transient->response)) { return; } // Filter out any updates for which notification has been sent already. - $theme_updates = array_filter($update_transient->response, function ($theme_update_data, $theme_slug) { + $theme_updates = \array_filter($update_transient->response, function ($theme_update_data, $theme_slug) { $last_version = Transients::getForSite('update-notifications', 'theme', $theme_slug); - return empty($last_version) || version_compare($last_version, $theme_update_data['new_version'], '<'); + return empty($last_version) || \version_compare($last_version, $theme_update_data['new_version'], '<'); }, ARRAY_FILTER_USE_BOTH); if (empty($theme_updates)) { @@ -282,7 +282,7 @@ public function watchThemeUpdatesAvailable($update_transient) foreach ($theme_updates as $theme_slug => $theme_update_data) { $theme = wp_get_theme($theme_slug); - $message[] = sprintf( + $message[] = \sprintf( __('Theme "%1$s" has an update to version %2$s available.', 'bc-security'), $theme, $theme_update_data['new_version'] @@ -311,9 +311,9 @@ public function watchThemeUpdatesAvailable($update_transient) */ public function watchLockoutEvents(string $remote_address, string $username, int $duration) { - if (in_array($remote_address, $this->logger->getKnownIps(), true)) { + if (\in_array($remote_address, $this->logger->getKnownIps(), true)) { $subject = __('Known IP locked out', 'bc-security'); - $message = sprintf( + $message = \sprintf( __('A known IP address %1$s has been locked out for %2$d seconds after someone tried to log in with username "%3$s".', 'bc-security'), self::formatRemoteAddress($remote_address), $duration, @@ -335,7 +335,7 @@ public function watchWpLogin(string $username, \WP_User $user) { if (Is::admin($user)) { $subject = __('Admin user login', 'bc-security'); - $message = sprintf( + $message = \sprintf( __('User "%1$s" with administrator privileges just logged in to your WordPress site from IP address %2$s.', 'bc-security'), $username, self::formatRemoteAddress($this->remote_address) @@ -356,7 +356,7 @@ public function watchChecklistSingleCheckAlert(Checklist\Check $check, Checklist { $subject = __('Checklist monitoring alert', 'bc-security'); $message = [ - sprintf(__('An issue has been found during checklist monitoring of "%s" check:', 'bc-security'), $check->getName()), + \sprintf(__('An issue has been found during checklist monitoring of "%s" check:', 'bc-security'), $check->getName()), '', $result->getMessageAsPlainText(), ]; @@ -379,7 +379,7 @@ public function watchChecklistMultipleChecksAlert(array $issues) foreach ($issues as $issue) { $message[] = ''; - $message[] = sprintf("%s: %s", $issue['check']->getName(), $issue['result']->getMessageAsPlainText()); + $message[] = \sprintf("%s: %s", $issue['check']->getName(), $issue['result']->getMessageAsPlainText()); } $this->notify($subject, $message); diff --git a/classes/BlueChip/Security/Modules/Services/ReverseDnsLookup/Resolver.php b/classes/BlueChip/Security/Modules/Services/ReverseDnsLookup/Resolver.php index a663dcc..5dcb64c 100644 --- a/classes/BlueChip/Security/Modules/Services/ReverseDnsLookup/Resolver.php +++ b/classes/BlueChip/Security/Modules/Services/ReverseDnsLookup/Resolver.php @@ -77,7 +77,7 @@ public function resolveHostname(string $ip_address, string $action, array $conte */ public function resolveHostnameInBackground(string $ip_address, string $action, array $context = []) { - wp_schedule_single_event(time(), self::RESOLVE_REMOTE_ADDRESS, [$ip_address, $action, $context]); + wp_schedule_single_event(\time(), self::RESOLVE_REMOTE_ADDRESS, [$ip_address, $action, $context]); } @@ -92,7 +92,7 @@ public function resolveHostnameInForeground(string $ip_address): string // Check the cache first. if (empty($hostname = Transients::getForSite(self::TRANSIENT_KEY, $ip_address))) { // Cache empty, resolve the hostname. - if (empty($hostname = gethostbyaddr($ip_address) ?: '')) { + if (empty($hostname = \gethostbyaddr($ip_address) ?: '')) { // This should only happen on malformed IP address, but bail nevertheless. return ''; } diff --git a/classes/BlueChip/Security/Modules/Tools/AdminPage.php b/classes/BlueChip/Security/Modules/Tools/AdminPage.php index 9027e53..efc962e 100644 --- a/classes/BlueChip/Security/Modules/Tools/AdminPage.php +++ b/classes/BlueChip/Security/Modules/Tools/AdminPage.php @@ -103,10 +103,10 @@ private function printResetForm() { echo '<h2>' . esc_html__('Reset settings', 'bc-security') . '</h2>'; echo '<p>'; - echo sprintf( + echo \sprintf( /* translators: %s: link to plugin setup page */ esc_html__('Set all plugin settings (including %s) back to their default values.', 'bc-security'), - sprintf( + \sprintf( '<a href="%s">%s</a>', Setup\AdminPage::getPageUrl(), esc_html__('connection type', 'bc-security') @@ -127,7 +127,7 @@ private function printResetForm() */ private function processActions() { - $nonce = filter_input(INPUT_POST, self::NONCE_NAME, FILTER_SANITIZE_STRING); + $nonce = \filter_input(INPUT_POST, self::NONCE_NAME, FILTER_SANITIZE_STRING); if (empty($nonce)) { // No nonce, no action. return; @@ -159,12 +159,12 @@ private function processExportAction() } // Send headers. - $file_name = 'bc-security-export-' . date('Y-m-d') . '.json'; - header("Content-Disposition: attachment; filename={$file_name}"); - header("Content-Type: application/json; charset=utf-8"); + $file_name = 'bc-security-export-' . \date('Y-m-d') . '.json'; + \header("Content-Disposition: attachment; filename={$file_name}"); + \header("Content-Type: application/json; charset=utf-8"); // Send content. - echo json_encode($export, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE); + echo \json_encode($export, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE); exit; } @@ -182,19 +182,19 @@ private function processImportAction() AdminNotices::add(__('File failed to upload. Please try again.', 'bc-security'), AdminNotices::ERROR); return; } - if (pathinfo($import_file['name'], PATHINFO_EXTENSION) !== 'json') { + if (\pathinfo($import_file['name'], PATHINFO_EXTENSION) !== 'json') { AdminNotices::add(__('Incorrect file type!', 'bc-security'), AdminNotices::ERROR); return; } // Read the file. - if (empty($json = file_get_contents($import_file['tmp_name']))) { + if (empty($json = \file_get_contents($import_file['tmp_name']))) { AdminNotices::add(__('File could not be read!', 'bc-security'), AdminNotices::ERROR); return; } // Parse JSON. - if (empty($import = json_decode($json, true))) { // true -> convert objects into associative arrays + if (empty($import = \json_decode($json, true))) { // true -> convert objects into associative arrays AdminNotices::add(__('File is either empty or corrupted!', 'bc-security'), AdminNotices::ERROR); return; } @@ -209,7 +209,7 @@ private function processImportAction() } $data = $import[$option_name]; - if (!is_array($data)) { + if (!\is_array($data)) { $status = false; continue; } diff --git a/classes/BlueChip/Security/Setup/AdminPage.php b/classes/BlueChip/Security/Setup/AdminPage.php index 5bd6105..6e7deb3 100644 --- a/classes/BlueChip/Security/Setup/AdminPage.php +++ b/classes/BlueChip/Security/Setup/AdminPage.php @@ -39,7 +39,7 @@ public function loadPage() if (!empty($connection_type = Core::getConnectionType())) { // Connection type is set via constant. AdminNotices::add( - sprintf( + \sprintf( __('You have set <code>BC_SECURITY_CONNECTION_TYPE</code> to <code>%s</code>, therefore the setting below is ignored.', 'bc-security'), $connection_type ), @@ -100,7 +100,7 @@ public function printSiteConnectionHint() echo '<ol>'; foreach ($list as $type => $explanation) { if (($ip_address = IpAddress::getRaw($type))) { - echo '<li>' . sprintf('%s: <code>$_SERVER[<strong>%s</strong>] = <em>%s</em></code>', esc_html($explanation), $type, $ip_address) . '</li>'; + echo '<li>' . \sprintf('%s: <code>$_SERVER[<strong>%s</strong>] = <em>%s</em></code>', esc_html($explanation), $type, $ip_address) . '</li>'; } } echo '</ol>'; @@ -117,7 +117,7 @@ private function getConnectionOptions(): array $list = IpAddress::enlist(true); $options = []; foreach ($list as $type => $explanation) { - $options[$type] = sprintf('%s: %s', $type, $explanation); + $options[$type] = \sprintf('%s: %s', $type, $explanation); } return $options; } diff --git a/classes/BlueChip/Security/Setup/Core.php b/classes/BlueChip/Security/Setup/Core.php index 5dd9c8c..b6efa16 100644 --- a/classes/BlueChip/Security/Setup/Core.php +++ b/classes/BlueChip/Security/Setup/Core.php @@ -27,7 +27,7 @@ public function __construct(Settings $settings) */ public static function getConnectionType(): string { - return defined('BC_SECURITY_CONNECTION_TYPE') ? BC_SECURITY_CONNECTION_TYPE : ''; + return \defined('BC_SECURITY_CONNECTION_TYPE') ? BC_SECURITY_CONNECTION_TYPE : ''; } diff --git a/classes/BlueChip/Security/Setup/IpAddress.php b/classes/BlueChip/Security/Setup/IpAddress.php index 59600a5..3d027c5 100644 --- a/classes/BlueChip/Security/Setup/IpAddress.php +++ b/classes/BlueChip/Security/Setup/IpAddress.php @@ -40,7 +40,7 @@ public static function enlist(bool $explain = false): array self::HTTP_X_REAL_IP => __('Behind a reverse proxy or load balancer', 'bc-security'), ]; - return $explain ? $list : array_keys($list); + return $explain ? $list : \array_keys($list); } @@ -52,7 +52,7 @@ public static function enlist(bool $explain = false): array */ public static function get(string $type): string { - if (!in_array($type, self::enlist(), true)) { + if (!\in_array($type, self::enlist(), true)) { // Invalid type, fall back to direct address. $type = self::REMOTE_ADDR; } @@ -84,7 +84,7 @@ public static function get(string $type): string */ public static function getRaw(string $type): string { - return (in_array($type, self::enlist(), true) && isset($_SERVER[$type])) ? $_SERVER[$type] : ''; + return (\in_array($type, self::enlist(), true) && isset($_SERVER[$type])) ? $_SERVER[$type] : ''; } @@ -108,7 +108,7 @@ public static function getServer(): string private static function getFirst(string $ip_addresses): string { // Note: explode always return an array with at least one item. - $ips = array_map('trim', explode(',', $ip_addresses)); + $ips = \array_map('trim', \explode(',', $ip_addresses)); return $ips[0]; } } diff --git a/classes/BlueChip/Security/Setup/Settings.php b/classes/BlueChip/Security/Setup/Settings.php index 1ab629d..fca0872 100644 --- a/classes/BlueChip/Security/Setup/Settings.php +++ b/classes/BlueChip/Security/Setup/Settings.php @@ -36,6 +36,6 @@ class Settings extends \BlueChip\Security\Core\Settings */ public static function sanitizeConnectionType(string $value): string { - return in_array($value, IpAddress::enlist(), true) ? $value : self::DEFAULTS[self::CONNECTION_TYPE]; + return \in_array($value, IpAddress::enlist(), true) ? $value : self::DEFAULTS[self::CONNECTION_TYPE]; } } From 333be388511d01f63ea0c9347425d02ea3eccf96 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C4=8Ceslav=20Przywara?= <ceslav@przywara.cz> Date: Tue, 24 Sep 2019 20:54:00 +0200 Subject: [PATCH 07/19] Improve code with help of PHP-CS-Fixer Applied rules: is_null, ternary_to_null_coalescing, function_to_constant. --- classes/BlueChip/Security/Core/Admin/SettingsPage.php | 2 +- classes/BlueChip/Security/Core/ListTable.php | 2 +- classes/BlueChip/Security/Core/Settings.php | 2 +- classes/BlueChip/Security/Helpers/Is.php | 2 +- .../Modules/Checklist/Checks/PhpVersionSupported.php | 2 +- classes/BlueChip/Security/Modules/IpBlacklist/Manager.php | 2 +- classes/BlueChip/Security/Modules/Log/ListTable.php | 6 +++--- 7 files changed, 9 insertions(+), 9 deletions(-) diff --git a/classes/BlueChip/Security/Core/Admin/SettingsPage.php b/classes/BlueChip/Security/Core/Admin/SettingsPage.php index 218475f..9f1271f 100644 --- a/classes/BlueChip/Security/Core/Admin/SettingsPage.php +++ b/classes/BlueChip/Security/Core/Admin/SettingsPage.php @@ -105,7 +105,7 @@ protected function getFieldBaseProperties(string $key, $value = null): array '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, + 'value' => null === $value ? $this->settings[$key] : $value, ]; } diff --git a/classes/BlueChip/Security/Core/ListTable.php b/classes/BlueChip/Security/Core/ListTable.php index 8362325..a698058 100644 --- a/classes/BlueChip/Security/Core/ListTable.php +++ b/classes/BlueChip/Security/Core/ListTable.php @@ -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] ?? ''; } diff --git a/classes/BlueChip/Security/Core/Settings.php b/classes/BlueChip/Security/Core/Settings.php index 9d93bab..d538193 100644 --- a/classes/BlueChip/Security/Core/Settings.php +++ b/classes/BlueChip/Security/Core/Settings.php @@ -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 { diff --git a/classes/BlueChip/Security/Helpers/Is.php b/classes/BlueChip/Security/Helpers/Is.php index be4ee9a..a1d5c76 100644 --- a/classes/BlueChip/Security/Helpers/Is.php +++ b/classes/BlueChip/Security/Helpers/Is.php @@ -31,7 +31,7 @@ public static function admin(\WP_User $user): bool */ public static function cli(): bool { - return \php_sapi_name() === 'cli'; + return \PHP_SAPI === 'cli'; } diff --git a/classes/BlueChip/Security/Modules/Checklist/Checks/PhpVersionSupported.php b/classes/BlueChip/Security/Modules/Checklist/Checks/PhpVersionSupported.php index b0f521e..b203cab 100644 --- a/classes/BlueChip/Security/Modules/Checklist/Checks/PhpVersionSupported.php +++ b/classes/BlueChip/Security/Modules/Checklist/Checks/PhpVersionSupported.php @@ -37,7 +37,7 @@ protected function runInternal(): Checklist\CheckResult // Get oldest supported version (as <major>.<minor>): $oldest_supported_version = self::getOldestSupportedPhpVersion(); - if (\is_null($oldest_supported_version)) { + if (null === $oldest_supported_version) { $message = \sprintf( esc_html__('List of supported PHP versions is out-dated. Consider updating the plugin. Btw. you are running PHP %1$s.', 'bc-security'), self::formatPhpVersion() diff --git a/classes/BlueChip/Security/Modules/IpBlacklist/Manager.php b/classes/BlueChip/Security/Modules/IpBlacklist/Manager.php index 4f95ecb..a4b8be9 100644 --- a/classes/BlueChip/Security/Modules/IpBlacklist/Manager.php +++ b/classes/BlueChip/Security/Modules/IpBlacklist/Manager.php @@ -417,6 +417,6 @@ protected function getId(string $ip_address, int $scope, int $reason): ?int // Execute query. $result = $this->wpdb->get_var($query); // Return result. - return \is_null($result) ? $result : \intval($result); + return null === $result ? $result : \intval($result); } } diff --git a/classes/BlueChip/Security/Modules/Log/ListTable.php b/classes/BlueChip/Security/Modules/Log/ListTable.php index c4d3c0b..1781f8e 100644 --- a/classes/BlueChip/Security/Modules/Log/ListTable.php +++ b/classes/BlueChip/Security/Modules/Log/ListTable.php @@ -73,7 +73,7 @@ public function column_default($item, $column_name) // phpcs:ignore // Value can be an array, in such case output array values separated by ",". return \is_array($value) ? \implode(', ', $value) : $value; } else { - return isset($item[$column_name]) ? $item[$column_name] : ''; + return $item[$column_name] ?? ''; } } @@ -170,13 +170,13 @@ public function get_sortable_columns() // phpcs:ignore */ protected function get_views() // phpcs:ignore { - $event_id = \is_null($this->event) ? null : $this->event->getId(); + $event_id = null === $this->event ? null : $this->event->getId(); $views = [ 'all' => \sprintf( '<a href="%s" class="%s">%s</a> (%d)', remove_query_arg([self::VIEW_EVENT], $this->url), - \is_null($event_id) ? 'current' : '', + null === $event_id ? 'current' : '', esc_html__('All', 'bc-security'), $this->logger->countAll() ), From 0c17c471a98dbdfaa2c50ac13e19bcee40f3dc82 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Viktor=20Sz=C3=A9pe?= <viktor@szepe.net> Date: Tue, 24 Sep 2019 22:07:10 +0200 Subject: [PATCH 08/19] Modernize coding style Just landed in PSR: https://www.php-fig.org/psr/psr-12/ --- phpcs.xml | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/phpcs.xml b/phpcs.xml index 034d2ef..19429ad 100644 --- a/phpcs.xml +++ b/phpcs.xml @@ -10,14 +10,10 @@ <file>bc-security.php</file> <file>uninstall.php</file> - <!-- Use PSR-1 as a base --> - <rule ref="PSR1"> - </rule> - - <!-- Use PSR-2 as a base --> - <rule ref="PSR2"> - <!-- Disable PSR-2 line length warnings --> + <!-- Use PSR-12 --> + <rule ref="PSR12"> + <!-- Disable PSR-12 line length warnings --> <exclude name="Generic.Files.LineLength"/> </rule> -</ruleset> \ No newline at end of file +</ruleset> From 938a89715432720e870e84ccd405ffa97f51a480 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C4=8Ceslav=20Przywara?= <ceslav@przywara.cz> Date: Wed, 25 Sep 2019 00:01:35 +0200 Subject: [PATCH 09/19] Replace list() with [] --- classes/BlueChip/Security/Modules/IpBlacklist/AdminPage.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/classes/BlueChip/Security/Modules/IpBlacklist/AdminPage.php b/classes/BlueChip/Security/Modules/IpBlacklist/AdminPage.php index 59fc4fd..1d1f0a7 100644 --- a/classes/BlueChip/Security/Modules/IpBlacklist/AdminPage.php +++ b/classes/BlueChip/Security/Modules/IpBlacklist/AdminPage.php @@ -141,7 +141,7 @@ private function printBlacklistingForm() // Transform number of seconds into the biggest fitting time unit. // For example 172800 seconds are 2 days: $duration = 172800; => $duration_units = 2; $duration_unit_in_seconds => 86400; - list($duration_units, $duration_unit_in_seconds) = $this->transformSecondsIntoFittingUnit($duration, \array_keys($units_in_seconds)); + [$duration_units, $duration_unit_in_seconds] = $this->transformSecondsIntoFittingUnit($duration, \array_keys($units_in_seconds)); // Simple styling echo '<style>form.bc-security { overflow: hidden; } span.bc-security { float: left; margin-right: 1.5em; margin-bottom: 0.5em; } span.bc-security label { display: block; margin-left: 0.25em; margin-bottom: 0.25em; } span.bc-security input, span.bc-security select { vertical-align: middle; } </style>'; From 28da49da1ba2426fd167a0114516698e3849148e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C4=8Ceslav=20Przywara?= <ceslav@przywara.cz> Date: Wed, 25 Sep 2019 00:06:48 +0200 Subject: [PATCH 10/19] Fix PSR-12 violations --- classes/BlueChip/Security/Core/Admin/SettingsPage.php | 2 +- classes/BlueChip/Security/Modules/Checklist/AdminPage.php | 2 +- classes/BlueChip/Security/Modules/Hardening/AdminPage.php | 2 +- classes/BlueChip/Security/Modules/Login/AdminPage.php | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/classes/BlueChip/Security/Core/Admin/SettingsPage.php b/classes/BlueChip/Security/Core/Admin/SettingsPage.php index 9f1271f..c344ecb 100644 --- a/classes/BlueChip/Security/Core/Admin/SettingsPage.php +++ b/classes/BlueChip/Security/Core/Admin/SettingsPage.php @@ -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(); diff --git a/classes/BlueChip/Security/Modules/Checklist/AdminPage.php b/classes/BlueChip/Security/Modules/Checklist/AdminPage.php index 8b2d286..d252924 100644 --- a/classes/BlueChip/Security/Modules/Checklist/AdminPage.php +++ b/classes/BlueChip/Security/Modules/Checklist/AdminPage.php @@ -109,7 +109,7 @@ public function printContents() echo '<button type="button" class="button button-large bcs-run-checks" data-check-class="bcs-check">' . esc_html__('Run all checks', 'bc-security') . '</button>'; echo '</p>'; - echo '<form method="post" action="' . admin_url('options.php') .'">'; + echo '<form method="post" action="' . admin_url('options.php') . '">'; $this->printBasicChecksSection($this->checklist_manager->getBasicChecks()); diff --git a/classes/BlueChip/Security/Modules/Hardening/AdminPage.php b/classes/BlueChip/Security/Modules/Hardening/AdminPage.php index 28acfdc..e6f083c 100644 --- a/classes/BlueChip/Security/Modules/Hardening/AdminPage.php +++ b/classes/BlueChip/Security/Modules/Hardening/AdminPage.php @@ -143,7 +143,7 @@ function () { /* translators: 1: password validation label */ esc_html__('When %1$s is enabled, passwords are checked against the Pwned Passwords database when new user is being created or existing user\'s password is being changed via profile update page or through password reset form. If there is a match, the operation is aborted with an error message asking for a different password.', 'bc-security'), '<strong>' . esc_html__('password validation', 'bc-security') . '</strong>' - ). '</li>'; + ) . '</li>'; echo '<li>' . \sprintf( /* translators: 1: password check label */ esc_html__('When %1$s is enabled, passwords are checked against the Pwned Passwords database when user logs in to the backend. If there is a match, a non-dismissible warning is displayed on all back-end pages encouraging the user to change its password.', 'bc-security'), diff --git a/classes/BlueChip/Security/Modules/Login/AdminPage.php b/classes/BlueChip/Security/Modules/Login/AdminPage.php index e750ef5..f90bd14 100644 --- a/classes/BlueChip/Security/Modules/Login/AdminPage.php +++ b/classes/BlueChip/Security/Modules/Login/AdminPage.php @@ -106,7 +106,7 @@ function () { 'username-blacklist', _x('Username blacklist', 'Settings section title', 'bc-security'), function () { - echo '<p>' . esc_html__('Enter any usernames that should never exist on the system. The blacklist serves two purposes:', 'bc-security') .'</p>'; + echo '<p>' . esc_html__('Enter any usernames that should never exist on the system. The blacklist serves two purposes:', 'bc-security') . '</p>'; echo '<ol>'; echo '<li>' . esc_html__('No new account can be registered with username on the blacklist.', 'bc-security') . '</li>'; echo '<li>' . esc_html__('Every login attempt using non-existing username on the blacklist immediately triggers long lockout.', 'bc-security') . '</li>'; From adba55dfac41be0c7c157c91fc413939971f11a4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C4=8Ceslav=20Przywara?= <ceslav@przywara.cz> Date: Wed, 25 Sep 2019 00:11:21 +0200 Subject: [PATCH 11/19] Update Composer dependencies --- composer.lock | 414 +++++++++++++++++++++++++++++++------------------- 1 file changed, 257 insertions(+), 157 deletions(-) diff --git a/composer.lock b/composer.lock index 62bf9c7..3c197bd 100644 --- a/composer.lock +++ b/composer.lock @@ -8,16 +8,16 @@ "packages": [ { "name": "composer/installers", - "version": "v1.6.0", + "version": "v1.7.0", "source": { "type": "git", "url": "https://github.com/composer/installers.git", - "reference": "cfcca6b1b60bc4974324efb5783c13dca6932b5b" + "reference": "141b272484481432cda342727a427dc1e206bfa0" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/composer/installers/zipball/cfcca6b1b60bc4974324efb5783c13dca6932b5b", - "reference": "cfcca6b1b60bc4974324efb5783c13dca6932b5b", + "url": "https://api.github.com/repos/composer/installers/zipball/141b272484481432cda342727a427dc1e206bfa0", + "reference": "141b272484481432cda342727a427dc1e206bfa0", "shasum": "" }, "require": { @@ -73,6 +73,7 @@ "RadPHP", "SMF", "Thelia", + "Whmcs", "WolfCMS", "agl", "aimeos", @@ -95,6 +96,7 @@ "installer", "itop", "joomla", + "known", "kohana", "laravel", "lavalite", @@ -124,7 +126,7 @@ "zend", "zikula" ], - "time": "2018-08-27T06:10:37+00:00" + "time": "2019-08-12T15:00:31+00:00" } ], "packages-dev": [ @@ -235,16 +237,16 @@ }, { "name": "composer/xdebug-handler", - "version": "1.3.2", + "version": "1.3.3", "source": { "type": "git", "url": "https://github.com/composer/xdebug-handler.git", - "reference": "d17708133b6c276d6e42ef887a877866b909d892" + "reference": "46867cbf8ca9fb8d60c506895449eb799db1184f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/composer/xdebug-handler/zipball/d17708133b6c276d6e42ef887a877866b909d892", - "reference": "d17708133b6c276d6e42ef887a877866b909d892", + "url": "https://api.github.com/repos/composer/xdebug-handler/zipball/46867cbf8ca9fb8d60c506895449eb799db1184f", + "reference": "46867cbf8ca9fb8d60c506895449eb799db1184f", "shasum": "" }, "require": { @@ -275,7 +277,7 @@ "Xdebug", "performance" ], - "time": "2019-01-28T20:25:53+00:00" + "time": "2019-05-27T17:52:04+00:00" }, { "name": "doctrine/instantiator", @@ -333,22 +335,22 @@ }, { "name": "giacocorsiglia/wordpress-stubs", - "version": "v5.1.0", + "version": "v5.1.1", "source": { "type": "git", "url": "https://github.com/GiacoCorsiglia/wordpress-stubs.git", - "reference": "833d104a73fe5964cb9abd93e3557c385f5aeb5f" + "reference": "1c6f011f5c241bab7293315d7fb7fca27fe79473" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/GiacoCorsiglia/wordpress-stubs/zipball/833d104a73fe5964cb9abd93e3557c385f5aeb5f", - "reference": "833d104a73fe5964cb9abd93e3557c385f5aeb5f", + "url": "https://api.github.com/repos/GiacoCorsiglia/wordpress-stubs/zipball/1c6f011f5c241bab7293315d7fb7fca27fe79473", + "reference": "1c6f011f5c241bab7293315d7fb7fca27fe79473", "shasum": "" }, "require-dev": { "ext-gettext": "*", "giacocorsiglia/stubs-generator": "^0.5.0", - "johnpbloch/wordpress": "5.1.0", + "johnpbloch/wordpress": "5.1.1", "php": "^7.1" }, "type": "library", @@ -368,7 +370,7 @@ "static analysis", "wordpress" ], - "time": "2019-03-02T03:38:47+00:00" + "time": "2019-03-13T21:16:05+00:00" }, { "name": "hamcrest/hamcrest-php", @@ -657,16 +659,16 @@ }, { "name": "nette/di", - "version": "v3.0.0", + "version": "v3.0.1", "source": { "type": "git", "url": "https://github.com/nette/di.git", - "reference": "19d83539245aaacb59470828919182411061841f" + "reference": "4aff517a1c6bb5c36fa09733d4cea089f529de6d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nette/di/zipball/19d83539245aaacb59470828919182411061841f", - "reference": "19d83539245aaacb59470828919182411061841f", + "url": "https://api.github.com/repos/nette/di/zipball/4aff517a1c6bb5c36fa09733d4cea089f529de6d", + "reference": "4aff517a1c6bb5c36fa09733d4cea089f529de6d", "shasum": "" }, "require": { @@ -726,20 +728,20 @@ "nette", "static" ], - "time": "2019-04-03T19:35:46+00:00" + "time": "2019-08-07T12:11:33+00:00" }, { "name": "nette/finder", - "version": "v2.5.0", + "version": "v2.5.1", "source": { "type": "git", "url": "https://github.com/nette/finder.git", - "reference": "6be1b83ea68ac558aff189d640abe242e0306fe2" + "reference": "14164e1ddd69e9c5f627ff82a10874b3f5bba5fe" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nette/finder/zipball/6be1b83ea68ac558aff189d640abe242e0306fe2", - "reference": "6be1b83ea68ac558aff189d640abe242e0306fe2", + "url": "https://api.github.com/repos/nette/finder/zipball/14164e1ddd69e9c5f627ff82a10874b3f5bba5fe", + "reference": "14164e1ddd69e9c5f627ff82a10874b3f5bba5fe", "shasum": "" }, "require": { @@ -788,7 +790,7 @@ "iterator", "nette" ], - "time": "2019-02-28T18:13:25+00:00" + "time": "2019-07-11T18:02:17+00:00" }, { "name": "nette/neon", @@ -853,16 +855,16 @@ }, { "name": "nette/php-generator", - "version": "v3.2.2", + "version": "v3.2.3", "source": { "type": "git", "url": "https://github.com/nette/php-generator.git", - "reference": "acff8b136fad84b860a626d133e791f95781f9f5" + "reference": "aea6e81437bb238e5f0e5b5ce06337433908e63b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nette/php-generator/zipball/acff8b136fad84b860a626d133e791f95781f9f5", - "reference": "acff8b136fad84b860a626d133e791f95781f9f5", + "url": "https://api.github.com/repos/nette/php-generator/zipball/aea6e81437bb238e5f0e5b5ce06337433908e63b", + "reference": "aea6e81437bb238e5f0e5b5ce06337433908e63b", "shasum": "" }, "require": { @@ -908,7 +910,7 @@ "php", "scaffolding" ], - "time": "2019-03-15T03:41:13+00:00" + "time": "2019-07-05T13:01:56+00:00" }, { "name": "nette/robot-loader", @@ -1107,16 +1109,16 @@ }, { "name": "nikic/php-parser", - "version": "v4.2.1", + "version": "v4.2.4", "source": { "type": "git", "url": "https://github.com/nikic/PHP-Parser.git", - "reference": "5221f49a608808c1e4d436df32884cbc1b821ac0" + "reference": "97e59c7a16464196a8b9c77c47df68e4a39a45c4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/5221f49a608808c1e4d436df32884cbc1b821ac0", - "reference": "5221f49a608808c1e4d436df32884cbc1b821ac0", + "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/97e59c7a16464196a8b9c77c47df68e4a39a45c4", + "reference": "97e59c7a16464196a8b9c77c47df68e4a39a45c4", "shasum": "" }, "require": { @@ -1124,7 +1126,7 @@ "php": ">=7.0" }, "require-dev": { - "phpunit/phpunit": "^6.5 || ^7.0" + "phpunit/phpunit": "^6.5 || ^7.0 || ^8.0" }, "bin": [ "bin/php-parse" @@ -1154,38 +1156,39 @@ "parser", "php" ], - "time": "2019-02-16T20:54:15+00:00" + "time": "2019-09-01T07:51:21+00:00" }, { "name": "ocramius/package-versions", - "version": "1.4.0", + "version": "1.5.1", "source": { "type": "git", "url": "https://github.com/Ocramius/PackageVersions.git", - "reference": "a4d4b60d0e60da2487bd21a2c6ac089f85570dbb" + "reference": "1d32342b8c1eb27353c8887c366147b4c2da673c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Ocramius/PackageVersions/zipball/a4d4b60d0e60da2487bd21a2c6ac089f85570dbb", - "reference": "a4d4b60d0e60da2487bd21a2c6ac089f85570dbb", + "url": "https://api.github.com/repos/Ocramius/PackageVersions/zipball/1d32342b8c1eb27353c8887c366147b4c2da673c", + "reference": "1d32342b8c1eb27353c8887c366147b4c2da673c", "shasum": "" }, "require": { "composer-plugin-api": "^1.0.0", - "php": "^7.1.0" + "php": "^7.3.0" }, "require-dev": { - "composer/composer": "^1.6.3", - "doctrine/coding-standard": "^5.0.1", + "composer/composer": "^1.8.6", + "doctrine/coding-standard": "^6.0.0", "ext-zip": "*", - "infection/infection": "^0.7.1", - "phpunit/phpunit": "^7.0.0" + "infection/infection": "^0.13.4", + "phpunit/phpunit": "^8.2.5", + "vimeo/psalm": "^3.4.9" }, "type": "composer-plugin", "extra": { "class": "PackageVersions\\Installer", "branch-alias": { - "dev-master": "2.0.x-dev" + "dev-master": "1.6.x-dev" } }, "autoload": { @@ -1204,7 +1207,7 @@ } ], "description": "Composer plugin that provides efficient querying for installed package versions (no runtime IO)", - "time": "2019-02-21T12:16:21+00:00" + "time": "2019-07-17T15:49:50+00:00" }, { "name": "phar-io/manifest", @@ -1525,16 +1528,16 @@ }, { "name": "phpstan/phpdoc-parser", - "version": "0.3.3", + "version": "0.3.5", "source": { "type": "git", "url": "https://github.com/phpstan/phpdoc-parser.git", - "reference": "472d3161d289f652713a5e353532fa4592663a57" + "reference": "8c4ef2aefd9788238897b678a985e1d5c8df6db4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpdoc-parser/zipball/472d3161d289f652713a5e353532fa4592663a57", - "reference": "472d3161d289f652713a5e353532fa4592663a57", + "url": "https://api.github.com/repos/phpstan/phpdoc-parser/zipball/8c4ef2aefd9788238897b678a985e1d5c8df6db4", + "reference": "8c4ef2aefd9788238897b678a985e1d5c8df6db4", "shasum": "" }, "require": { @@ -1568,20 +1571,20 @@ "MIT" ], "description": "PHPDoc parser with support for nullable, intersection and generic types", - "time": "2019-04-23T20:26:19+00:00" + "time": "2019-06-07T19:13:52+00:00" }, { "name": "phpstan/phpstan", - "version": "0.11.7", + "version": "0.11.16", "source": { "type": "git", "url": "https://github.com/phpstan/phpstan.git", - "reference": "32d87d746c70785f78d239855782d27cde0eb6ee" + "reference": "635cf20f3b92ce34ee94a8d2f282d62eb9dc6e1b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpstan/zipball/32d87d746c70785f78d239855782d27cde0eb6ee", - "reference": "32d87d746c70785f78d239855782d27cde0eb6ee", + "url": "https://api.github.com/repos/phpstan/phpstan/zipball/635cf20f3b92ce34ee94a8d2f282d62eb9dc6e1b", + "reference": "635cf20f3b92ce34ee94a8d2f282d62eb9dc6e1b", "shasum": "" }, "require": { @@ -1592,9 +1595,9 @@ "nette/robot-loader": "^3.0.1", "nette/schema": "^1.0", "nette/utils": "^2.4.5 || ^3.0", - "nikic/php-parser": "^4.0.2", + "nikic/php-parser": "^4.2.3", "php": "~7.1", - "phpstan/phpdoc-parser": "^0.3", + "phpstan/phpdoc-parser": "^0.3.5", "symfony/console": "~3.2 || ~4.0", "symfony/finder": "~3.2 || ~4.0" }, @@ -1602,11 +1605,12 @@ "symfony/console": "3.4.16 || 4.1.5" }, "require-dev": { - "brianium/paratest": "^2.0", + "brianium/paratest": "^2.0 || ^3.0", "consistence/coding-standard": "^3.5", "dealerdirect/phpcodesniffer-composer-installer": "^0.4.4", "ext-intl": "*", "ext-mysqli": "*", + "ext-simplexml": "*", "ext-soap": "*", "ext-zip": "*", "jakub-onderka/php-parallel-lint": "^1.0", @@ -1616,7 +1620,7 @@ "phpstan/phpstan-php-parser": "^0.11", "phpstan/phpstan-phpunit": "^0.11", "phpstan/phpstan-strict-rules": "^0.11", - "phpunit/phpunit": "^7.0", + "phpunit/phpunit": "^7.5.14 || ^8.0", "slevomat/coding-standard": "^4.7.2", "squizlabs/php_codesniffer": "^3.3.2" }, @@ -1632,8 +1636,7 @@ "autoload": { "psr-4": { "PHPStan\\": [ - "src/", - "build/PHPStan" + "src/" ] } }, @@ -1642,7 +1645,7 @@ "MIT" ], "description": "PHPStan - PHP Static Analysis Tool", - "time": "2019-05-19T17:36:42+00:00" + "time": "2019-09-17T11:19:51+00:00" }, { "name": "phpunit/php-code-coverage", @@ -1980,6 +1983,55 @@ ], "time": "2019-02-07T14:15:04+00:00" }, + { + "name": "psr/container", + "version": "1.0.0", + "source": { + "type": "git", + "url": "https://github.com/php-fig/container.git", + "reference": "b7ce3b176482dbbc1245ebf52b181af44c2cf55f" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/container/zipball/b7ce3b176482dbbc1245ebf52b181af44c2cf55f", + "reference": "b7ce3b176482dbbc1245ebf52b181af44c2cf55f", + "shasum": "" + }, + "require": { + "php": ">=5.3.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Container\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "http://www.php-fig.org/" + } + ], + "description": "Common Container Interface (PHP FIG PSR-11)", + "homepage": "https://github.com/php-fig/container", + "keywords": [ + "PSR-11", + "container", + "container-interface", + "container-interop", + "psr" + ], + "time": "2017-02-14T16:28:37+00:00" + }, { "name": "psr/log", "version": "1.1.0", @@ -2646,25 +2698,27 @@ }, { "name": "symfony/console", - "version": "v4.2.8", + "version": "v4.3.4", "source": { "type": "git", "url": "https://github.com/symfony/console.git", - "reference": "e2840bb38bddad7a0feaf85931e38fdcffdb2f81" + "reference": "de63799239b3881b8a08f8481b22348f77ed7b36" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/console/zipball/e2840bb38bddad7a0feaf85931e38fdcffdb2f81", - "reference": "e2840bb38bddad7a0feaf85931e38fdcffdb2f81", + "url": "https://api.github.com/repos/symfony/console/zipball/de63799239b3881b8a08f8481b22348f77ed7b36", + "reference": "de63799239b3881b8a08f8481b22348f77ed7b36", "shasum": "" }, "require": { "php": "^7.1.3", - "symfony/contracts": "^1.0", - "symfony/polyfill-mbstring": "~1.0" + "symfony/polyfill-mbstring": "~1.0", + "symfony/polyfill-php73": "^1.8", + "symfony/service-contracts": "^1.1" }, "conflict": { "symfony/dependency-injection": "<3.4", + "symfony/event-dispatcher": "<4.3", "symfony/process": "<3.3" }, "provide": { @@ -2674,9 +2728,10 @@ "psr/log": "~1.0", "symfony/config": "~3.4|~4.0", "symfony/dependency-injection": "~3.4|~4.0", - "symfony/event-dispatcher": "~3.4|~4.0", + "symfony/event-dispatcher": "^4.3", "symfony/lock": "~3.4|~4.0", - "symfony/process": "~3.4|~4.0" + "symfony/process": "~3.4|~4.0", + "symfony/var-dumper": "^4.3" }, "suggest": { "psr/log": "For using the console logger", @@ -2687,7 +2742,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "4.2-dev" + "dev-master": "4.3-dev" } }, "autoload": { @@ -2714,91 +2769,20 @@ ], "description": "Symfony Console Component", "homepage": "https://symfony.com", - "time": "2019-04-08T14:23:48+00:00" - }, - { - "name": "symfony/contracts", - "version": "v1.1.0", - "source": { - "type": "git", - "url": "https://github.com/symfony/contracts.git", - "reference": "d3636025e8253c6144358ec0a62773cae588395b" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/contracts/zipball/d3636025e8253c6144358ec0a62773cae588395b", - "reference": "d3636025e8253c6144358ec0a62773cae588395b", - "shasum": "" - }, - "require": { - "php": "^7.1.3" - }, - "require-dev": { - "psr/cache": "^1.0", - "psr/container": "^1.0", - "symfony/polyfill-intl-idn": "^1.10" - }, - "suggest": { - "psr/cache": "When using the Cache contracts", - "psr/container": "When using the Service contracts", - "symfony/cache-contracts-implementation": "", - "symfony/event-dispatcher-implementation": "", - "symfony/http-client-contracts-implementation": "", - "symfony/service-contracts-implementation": "", - "symfony/translation-contracts-implementation": "" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.1-dev" - } - }, - "autoload": { - "psr-4": { - "Symfony\\Contracts\\": "" - }, - "exclude-from-classmap": [ - "**/Tests/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Nicolas Grekas", - "email": "p@tchwork.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "A set of abstractions extracted out of the Symfony components", - "homepage": "https://symfony.com", - "keywords": [ - "abstractions", - "contracts", - "decoupling", - "interfaces", - "interoperability", - "standards" - ], - "time": "2019-04-27T14:29:50+00:00" + "time": "2019-08-26T08:26:39+00:00" }, { "name": "symfony/finder", - "version": "v4.2.8", + "version": "v4.3.4", "source": { "type": "git", "url": "https://github.com/symfony/finder.git", - "reference": "e45135658bd6c14b61850bf131c4f09a55133f69" + "reference": "86c1c929f0a4b24812e1eb109262fc3372c8e9f2" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/finder/zipball/e45135658bd6c14b61850bf131c4f09a55133f69", - "reference": "e45135658bd6c14b61850bf131c4f09a55133f69", + "url": "https://api.github.com/repos/symfony/finder/zipball/86c1c929f0a4b24812e1eb109262fc3372c8e9f2", + "reference": "86c1c929f0a4b24812e1eb109262fc3372c8e9f2", "shasum": "" }, "require": { @@ -2807,7 +2791,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "4.2-dev" + "dev-master": "4.3-dev" } }, "autoload": { @@ -2834,7 +2818,7 @@ ], "description": "Symfony Finder Component", "homepage": "https://symfony.com", - "time": "2019-04-06T13:51:08+00:00" + "time": "2019-08-14T12:26:46+00:00" }, { "name": "symfony/polyfill-ctype", @@ -2896,16 +2880,16 @@ }, { "name": "symfony/polyfill-mbstring", - "version": "v1.11.0", + "version": "v1.12.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-mbstring.git", - "reference": "fe5e94c604826c35a32fa832f35bd036b6799609" + "reference": "b42a2f66e8f1b15ccf25652c3424265923eb4f17" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/fe5e94c604826c35a32fa832f35bd036b6799609", - "reference": "fe5e94c604826c35a32fa832f35bd036b6799609", + "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/b42a2f66e8f1b15ccf25652c3424265923eb4f17", + "reference": "b42a2f66e8f1b15ccf25652c3424265923eb4f17", "shasum": "" }, "require": { @@ -2917,7 +2901,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "1.11-dev" + "dev-master": "1.12-dev" } }, "autoload": { @@ -2951,7 +2935,123 @@ "portable", "shim" ], - "time": "2019-02-06T07:57:58+00:00" + "time": "2019-08-06T08:03:45+00:00" + }, + { + "name": "symfony/polyfill-php73", + "version": "v1.12.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-php73.git", + "reference": "2ceb49eaccb9352bff54d22570276bb75ba4a188" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-php73/zipball/2ceb49eaccb9352bff54d22570276bb75ba4a188", + "reference": "2ceb49eaccb9352bff54d22570276bb75ba4a188", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.12-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Polyfill\\Php73\\": "" + }, + "files": [ + "bootstrap.php" + ], + "classmap": [ + "Resources/stubs" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill backporting some PHP 7.3+ features to lower PHP versions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "polyfill", + "portable", + "shim" + ], + "time": "2019-08-06T08:03:45+00:00" + }, + { + "name": "symfony/service-contracts", + "version": "v1.1.6", + "source": { + "type": "git", + "url": "https://github.com/symfony/service-contracts.git", + "reference": "ea7263d6b6d5f798b56a45a5b8d686725f2719a3" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/service-contracts/zipball/ea7263d6b6d5f798b56a45a5b8d686725f2719a3", + "reference": "ea7263d6b6d5f798b56a45a5b8d686725f2719a3", + "shasum": "" + }, + "require": { + "php": "^7.1.3", + "psr/container": "^1.0" + }, + "suggest": { + "symfony/service-implementation": "" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.1-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Contracts\\Service\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Generic abstractions related to writing services", + "homepage": "https://symfony.com", + "keywords": [ + "abstractions", + "contracts", + "decoupling", + "interfaces", + "interoperability", + "standards" + ], + "time": "2019-08-20T14:44:19+00:00" }, { "name": "theseer/tokenizer", From 7eef527a9fb4714050c08ffe604ca500131e1681 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C4=8Ceslav=20Przywara?= <cp@bluechip.at> Date: Fri, 25 Oct 2019 12:51:14 +0200 Subject: [PATCH 12/19] Detect "live" environment instead of "production" and make the test filterable Fixes #87. --- README.md | 3 ++- classes/BlueChip/Security/Helpers/Hooks.php | 8 ++++++++ classes/BlueChip/Security/Helpers/Is.php | 19 ++++++++++++++++--- .../Checks/DisplayOfPhpErrorsIsOff.php | 7 ++++--- .../Security/Modules/Checklist/Manager.php | 2 +- 5 files changed, 31 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index 91ea3be..1a0e08a 100644 --- a/README.md +++ b/README.md @@ -31,7 +31,7 @@ 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 [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)? @@ -121,6 +121,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. diff --git a/classes/BlueChip/Security/Helpers/Hooks.php b/classes/BlueChip/Security/Helpers/Hooks.php index 0c651ff..fb07f24 100644 --- a/classes/BlueChip/Security/Helpers/Hooks.php +++ b/classes/BlueChip/Security/Helpers/Hooks.php @@ -18,6 +18,14 @@ interface Hooks const IS_ADMIN = 'bc-security/filter:is-admin'; + /** + * Filter: allows to change return value of Is::live() helper. + * + * @see \BlueChip\Security\Helpers\Is::live() + */ + const IS_LIVE = 'bc-security/filter:is-live'; + + /** * Filter: allows to change plugin's changelog URL. * diff --git a/classes/BlueChip/Security/Helpers/Is.php b/classes/BlueChip/Security/Helpers/Is.php index a1d5c76..34633e5 100644 --- a/classes/BlueChip/Security/Helpers/Is.php +++ b/classes/BlueChip/Security/Helpers/Is.php @@ -11,7 +11,7 @@ class Is { /** - * Return true, if current user is an admin. + * Return true if current user is an admin. * * @param \WP_User $user * @return bool @@ -27,7 +27,7 @@ public static function admin(\WP_User $user): bool /** - * @return bool True, if current webserver interface is CLI, false otherwise. + * @return bool True if current webserver interface is CLI, false otherwise. */ public static function cli(): bool { @@ -36,7 +36,20 @@ public static function cli(): bool /** - * Return true, if current request is of given $type. + * @return bool True if the website is running in live environment, false otherwise. + */ + public static function live(): bool + { + // Consider both production and staging environment as live. + return apply_filters( + Hooks::IS_LIVE, + \defined('WP_ENV') && ((WP_ENV === 'production') || (WP_ENV === 'staging')) + ); + } + + + /** + * Return true if current request is of given $type. * * @param string $type One of: admin, ajax, cron, frontend or wp-cli. * @return bool True, if current request is of given $type, false otherwise. diff --git a/classes/BlueChip/Security/Modules/Checklist/Checks/DisplayOfPhpErrorsIsOff.php b/classes/BlueChip/Security/Modules/Checklist/Checks/DisplayOfPhpErrorsIsOff.php index 35f4231..3bdc0b8 100644 --- a/classes/BlueChip/Security/Modules/Checklist/Checks/DisplayOfPhpErrorsIsOff.php +++ b/classes/BlueChip/Security/Modules/Checklist/Checks/DisplayOfPhpErrorsIsOff.php @@ -5,6 +5,7 @@ namespace BlueChip\Security\Modules\Checklist\Checks; +use BlueChip\Security\Helpers\Is; use BlueChip\Security\Modules\Checklist; class DisplayOfPhpErrorsIsOff extends Checklist\BasicCheck @@ -15,7 +16,7 @@ public function __construct() __('Display of PHP errors is off', 'bc-security'), \sprintf( /* translators: 1: link to PHP manual documentation on display-errors php.ini setting, 2: link to WordPress Handbook article */ - esc_html__('%1$s to the screen as part of the output on production systems. In WordPress environment, %2$s when directly loading certain files.', 'bc-security'), + esc_html__('%1$s to the screen as part of the output on live system. In WordPress environment, %2$s when directly loading certain files.', 'bc-security'), '<a href="' . esc_url(__('https://secure.php.net/manual/en/errorfunc.configuration.php#ini.display-errors', 'bc-security')) . '" rel="noreferrer">' . esc_html__('Errors should never be printed', 'bc-security') . '</a>', '<a href="' . esc_url(__('https://make.wordpress.org/core/handbook/testing/reporting-security-vulnerabilities/#why-are-there-path-disclosures-when-directly-loading-certain-files', 'bc-security')) . '" rel="noreferrer">' . esc_html__('display of errors can lead to path disclosures', 'bc-security') . '</a>' ) @@ -24,13 +25,13 @@ public function __construct() /** - * Check makes sense only in production environment. + * Check makes sense only in live environment. * * @return bool */ public function isMeaningful(): bool { - return \defined('WP_ENV') && (WP_ENV === 'production'); + return Is::live(); } diff --git a/classes/BlueChip/Security/Modules/Checklist/Manager.php b/classes/BlueChip/Security/Modules/Checklist/Manager.php index 4105350..e2beaf6 100644 --- a/classes/BlueChip/Security/Modules/Checklist/Manager.php +++ b/classes/BlueChip/Security/Modules/Checklist/Manager.php @@ -76,7 +76,7 @@ public function constructChecks(\wpdb $wpdb): array // PHP files in uploads directory should not be accessible on frontend. Checks\NoAccessToPhpFilesInUploadsDirectory::getId() => new Checks\NoAccessToPhpFilesInUploadsDirectory(), - // Display of erros should be off in production environment. + // Display of errors should be off in live environment. Checks\DisplayOfPhpErrorsIsOff::getId() => new Checks\DisplayOfPhpErrorsIsOff(), // Error log should not be publicly visible, if debugging is on. From e98b3fe2bbe3b78dbef1a2aad7c0a10752cdc085 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C4=8Ceslav=20Przywara?= <cp@bluechip.at> Date: Fri, 25 Oct 2019 13:01:02 +0200 Subject: [PATCH 13/19] Improve wording in README.md --- README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 1a0e08a..775b390 100644 --- a/README.md +++ b/README.md @@ -39,7 +39,9 @@ Basic checks cover common security practices. They do not require any informatio #### 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 From 7fac55bfe9474584af7e2504e6ef7e8fa2debb04 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C4=8Ceslav=20Przywara?= <cp@bluechip.at> Date: Tue, 19 Nov 2019 21:02:58 +0100 Subject: [PATCH 14/19] Replace empty() check with faster alternative --- classes/BlueChip/Security/Core/Settings.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/classes/BlueChip/Security/Core/Settings.php b/classes/BlueChip/Security/Core/Settings.php index d538193..6d2fada 100644 --- a/classes/BlueChip/Security/Core/Settings.php +++ b/classes/BlueChip/Security/Core/Settings.php @@ -223,7 +223,7 @@ 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])) { From cff0faa03b4c1cbca2e111c0e61eb97175454f47 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C4=8Ceslav=20Przywara?= <cp@bluechip.at> Date: Mon, 2 Dec 2019 11:48:53 +0100 Subject: [PATCH 15/19] Raise required PHP version to 7.2 Fixes #82 --- README.md | 2 +- bc-security.php | 6 +++--- composer.json | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 775b390..4907ae1 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ Helps keeping WordPress websites secure. ## Requirements -* [PHP](https://secure.php.net/) 7.1 or newer +* [PHP](https://secure.php.net/) 7.2 or newer * [WordPress](https://wordpress.org/) 5.1 or newer ## Limitations diff --git a/bc-security.php b/bc-security.php index b16f8cb..14f7940 100644 --- a/bc-security.php +++ b/bc-security.php @@ -6,20 +6,20 @@ * Version: develop * Author: Česlav Przywara <ceslav@przywara.cz> * Author URI: https://www.chesio.com - * Requires PHP: 7.1 + * Requires PHP: 7.2 * Requires WP: 5.1 * Tested up to: 5.2 * 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 ) ); diff --git a/composer.json b/composer.json index d60dbfc..0c226e7 100644 --- a/composer.json +++ b/composer.json @@ -17,7 +17,7 @@ "issues": "https://github.com/chesio/bc-security/issues" }, "require": { - "php": ">=7.1.0", + "php": ">=7.2.0", "composer/installers": "~1.0" }, "require-dev": { From 6cff496f710e6b19d9113490aa85d82b9dec6a75 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C4=8Ceslav=20Przywara?= <cp@bluechip.at> Date: Mon, 2 Dec 2019 11:51:31 +0100 Subject: [PATCH 16/19] Update internal list of supported PHP version Also fix the EOL date for PHP 7.2 by the way. Fixes #88 --- .../Modules/Checklist/Checks/PhpVersionSupported.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/classes/BlueChip/Security/Modules/Checklist/Checks/PhpVersionSupported.php b/classes/BlueChip/Security/Modules/Checklist/Checks/PhpVersionSupported.php index b203cab..183b70b 100644 --- a/classes/BlueChip/Security/Modules/Checklist/Checks/PhpVersionSupported.php +++ b/classes/BlueChip/Security/Modules/Checklist/Checks/PhpVersionSupported.php @@ -13,9 +13,9 @@ class PhpVersionSupported extends Checklist\BasicCheck * @var array List of supported PHP versions and their end-of-life dates */ const SUPPORTED_VERSIONS = [ - '7.1' => '2019-12-01', - '7.2' => '2020-10-30', + '7.2' => '2020-11-30', '7.3' => '2021-12-06', + '7.4' => '2022-11-28', ]; @@ -26,7 +26,7 @@ public function __construct() \sprintf( /* translators: 1: link to official page on supported PHP versions */ esc_html__('Running an %1$s may pose a security risk.', 'bc-security'), - '<a href="' . esc_url(__('https://secure.php.net/supported-versions.php', 'bc-security')) . '" rel="noreferrer">' . esc_html__('unsupported PHP version', 'bc-security') . '</a>' + '<a href="' . esc_url(__('https://www.php.net/supported-versions.php', 'bc-security')) . '" rel="noreferrer">' . esc_html__('unsupported PHP version', 'bc-security') . '</a>' ) ); } @@ -84,7 +84,7 @@ private static function formatPhpVersion(): string /** - * @return string Oldest supported version of PHP as of today or null, if it can not be determined from data available. + * @return string Oldest supported version of PHP as of today or null if it can not be determined from data available. */ private static function getOldestSupportedPhpVersion(): ?string { From fb56cf8e63ddc71c9bc3cd67f66f67077b60edd5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C4=8Ceslav=20Przywara?= <cp@bluechip.at> Date: Mon, 2 Dec 2019 12:14:18 +0100 Subject: [PATCH 17/19] Update install-wp-tests.sh script See https://github.com/wp-cli/scaffold-command/blob/master/templates/install-wp-tests.sh --- tests/integration/bin/install-wp-tests.sh | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/tests/integration/bin/install-wp-tests.sh b/tests/integration/bin/install-wp-tests.sh index 878881f..1005bf4 100755 --- a/tests/integration/bin/install-wp-tests.sh +++ b/tests/integration/bin/install-wp-tests.sh @@ -25,7 +25,11 @@ download() { fi } -if [[ $WP_VERSION =~ ^[0-9]+\.[0-9]+$ ]]; then +if [[ $WP_VERSION =~ ^[0-9]+\.[0-9]+\-(beta|RC)[0-9]+$ ]]; then + WP_BRANCH=${WP_VERSION%\-*} + WP_TESTS_TAG="branches/$WP_BRANCH" + +elif [[ $WP_VERSION =~ ^[0-9]+\.[0-9]+$ ]]; then WP_TESTS_TAG="branches/$WP_VERSION" elif [[ $WP_VERSION =~ [0-9]+\.[0-9]+\.[0-9]+ ]]; then if [[ $WP_VERSION =~ [0-9]+\.[0-9]+\.[0] ]]; then @@ -47,7 +51,6 @@ else fi WP_TESTS_TAG="tags/$LATEST_VERSION" fi - set -ex install_wp() { @@ -95,7 +98,7 @@ install_wp() { install_test_suite() { # portable in-place argument for both GNU sed and Mac OSX sed if [[ $(uname -s) == 'Darwin' ]]; then - local ioption='-i .bak' + local ioption='-i.bak' else local ioption='-i' fi @@ -104,8 +107,8 @@ install_test_suite() { if [ ! -d $WP_TESTS_DIR ]; then # set up testing suite mkdir -p $WP_TESTS_DIR - svn co --quiet https://develop.svn.wordpress.org/${WP_TESTS_TAG}/tests/phpunit/includes/ $WP_TESTS_DIR/includes - svn co --quiet https://develop.svn.wordpress.org/${WP_TESTS_TAG}/tests/phpunit/data/ $WP_TESTS_DIR/data + svn co --quiet --ignore-externals https://develop.svn.wordpress.org/${WP_TESTS_TAG}/tests/phpunit/includes/ $WP_TESTS_DIR/includes + svn co --quiet --ignore-externals https://develop.svn.wordpress.org/${WP_TESTS_TAG}/tests/phpunit/data/ $WP_TESTS_DIR/data fi if [ ! -f wp-tests-config.php ]; then From 49443416b43b3c049ff832c9f10fd95e36cca461 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C4=8Ceslav=20Przywara?= <cp@bluechip.at> Date: Mon, 2 Dec 2019 12:16:12 +0100 Subject: [PATCH 18/19] Bump "Tested up to" header to 5.3 --- bc-security.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bc-security.php b/bc-security.php index 14f7940..494c044 100644 --- a/bc-security.php +++ b/bc-security.php @@ -8,7 +8,7 @@ * Author URI: https://www.chesio.com * Requires PHP: 7.2 * Requires WP: 5.1 - * Tested up to: 5.2 + * Tested up to: 5.3 * Text Domain: bc-security * GitHub Plugin URI: https://github.com/chesio/bc-security */ From c24a184f1d342c40f8c026fd465e0703ff926b79 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C4=8Ceslav=20Przywara?= <cp@bluechip.at> Date: Mon, 2 Dec 2019 12:20:55 +0100 Subject: [PATCH 19/19] Bump version to 0.14 --- bc-security.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bc-security.php b/bc-security.php index 494c044..e13f3df 100644 --- a/bc-security.php +++ b/bc-security.php @@ -3,7 +3,7 @@ * Plugin Name: BC Security * Plugin URI: https://github.com/chesio/bc-security * Description: Helps keeping WordPress websites secure. - * Version: develop + * Version: 0.14.0 * Author: Česlav Przywara <ceslav@przywara.cz> * Author URI: https://www.chesio.com * Requires PHP: 7.2