PluginProbe
Patchstack – WordPress & Plugins Security / 2.2.2
Patchstack – WordPress & Plugins Security v2.2.2
2.3.7 trunk 2.1.0 2.1.1 2.1.10 2.1.11 2.1.12 2.1.13 2.1.14 2.1.15 2.1.16 2.1.17 2.1.18 2.1.19 2.1.2 2.1.20 2.1.21 2.1.22 2.1.23 2.1.24 2.1.25 2.1.3 2.1.4 2.1.5 2.1.6 All 49 releases
← All changes | patchstack.php +53 -29 2.1.62.2.2 View file →
@@ -1,10 +1,11 @@
1 1 <?php
2 2 /**
3 3 * Plugin Name: Patchstack Security
4 - * Plugin URI: https://patchstack.com
4 + * Plugin URI: https://patchstack.com/?utm_medium=wp&utm_source=dashboard&utm_campaign=patchstack%20plugin
5 + * Author URI: https://patchstack.com/?utm_medium=wp&utm_source=dashboard&utm_campaign=patchstack%20plugin
5 6 * Description: Patchstack identifies security vulnerabilities in WordPress plugins, themes, and core.
6 - * Version: 2.1.6
7 + * Version: 2.2.2
7 8 * Author: Patchstack
8 9 * License: GPLv3
9 10 * Text Domain: patchstack
10 11 * Domain Path: /languages
@@ -32,9 +33,9 @@
32 33
33 34 // Set up our filename.
34 35 $file_name = strtolower( str_replace( '_', '-', substr( $class_name, strlen( 'P_' ) ) ) );
35 36 $dir = trailingslashit( dirname( __FILE__ ) ) . 'includes/';
36 - $target = array( $dir . $file_name . '.php', $dir . 'admin/' . str_replace( 'admin-', '', $file_name ) . '.php' );
37 + $target = [ $dir . $file_name . '.php', $dir . 'admin/' . str_replace( 'admin-', '', $file_name ) . '.php' ];
37 38
38 39 // Attempt each target and load if it exists.
39 40 foreach ( $target as $file ) {
40 41 if ( file_exists( $file ) ) {
@@ -57,9 +58,9 @@
57 58 * The plugin version.
58 59 *
59 60 * @var string
60 61 */
61 - const VERSION = '2.1.6';
62 + const VERSION = '2.2.2';
62 63
63 64 /**
64 65 * API URL of Patchstack to communicate with.
65 66 *
@@ -88,15 +89,8 @@
88 89 */
89 90 const PRIVATE_KEY = 'PATCHSTACK_PRIVATE_KEY';
90 91
91 92 /**
92 - * Known IP addresses.
93 - *
94 - * @var array
95 - */
96 - protected $ips = array( '18.221.197.243', '52.15.237.250', '3.19.3.34', '3.18.238.17', '13.58.49.77', '18.222.191.77', '3.131.108.250', '3.23.157.140', '18.220.70.233', '3.140.84.221', '185.212.171.100' );
97 -
98 - /**
99 93 * URL of the plugin directory.
100 94 *
101 95 * @var string
102 96 */
@@ -120,9 +114,9 @@
120 114 * Detailed activation error messages.
121 115 *
122 116 * @var array
123 117 */
124 - protected $activation_errors = array();
118 + protected $activation_errors = [];
125 119
126 120 /**
127 121 * Singleton instance of plugin.
128 122 *
@@ -145,8 +139,9 @@
145 139 protected $htaccess;
146 140 protected $hacker_log;
147 141 protected $upload;
148 142 protected $rules;
143 + protected $hide_login;
149 144 protected $listener;
150 145 protected $event_log;
151 146 protected $multisite;
152 147 protected $notice;
@@ -175,8 +170,13 @@
175 170 $this->basename = plugin_basename( __FILE__ );
176 171 $this->url = plugin_dir_url( __FILE__ );
177 172 $names = explode( '/', $this->basename );
178 173 $this->name = $names[0];
174 +
175 + // Define WP_CLI command.
176 + if ( defined( 'WP_CLI' ) && WP_CLI && method_exists('\WP_CLI', 'add_command')) {
177 + \WP_CLI::add_command( 'patchstack activate', [ $this, 'cli_activate' ] );
178 + }
179 179 }
180 180
181 181 /**
182 182 * Call the constructor of all the Patchstack related classes.
@@ -184,9 +184,9 @@
184 184 * @return void
185 185 */
186 186 public function plugin_classes() {
187 187 // Define the array of the classes.
188 - foreach ( array(
188 + foreach ( [
189 189 'admin_options' => 'P_Admin_Options',
190 190 'cron' => 'P_Cron',
191 191 'api' => 'P_Api',
192 192 'login' => 'P_Login',
@@ -195,8 +195,9 @@
195 195 'htaccess' => 'P_Htaccess',
196 196 'hacker_log' => 'P_Hacker_Log',
197 197 'upload' => 'P_Upload',
198 198 'rules' => 'P_Rules',
199 + 'hide_login' => 'P_Hide_Login',
199 200 'listener' => 'P_Listener',
200 201 'event_log' => 'P_Event_Log',
201 202 'activation' => 'P_Activation',
202 203 'multisite' => 'P_Multisite',
@@ -203,12 +204,13 @@
203 204 'notice' => 'P_Cookie_Notice',
204 205 'admin_ajax' => 'P_Admin_Ajax',
205 206 'admin_general' => 'P_Admin_General',
206 207 'admin_menu' => 'P_Admin_Menu',
207 - ) as $var => $class ) {
208 + ] as $var => $class ) {
208 209 $this->$var = new $class( $this );
209 210 }
210 211
212 + // Load firewall base functionality.
211 213 $this->firewall_base = new P_Firewall( true, $this, true );
212 214 }
213 215
214 216 /**
@@ -221,28 +223,50 @@
221 223 $this->activation->activate( $this );
222 224 }
223 225
224 226 /**
225 - * Deactivate the plugin.
227 + * Connects the Patchstack plugin to the API with the license id and secret key.
226 228 *
227 - * @return void
229 + * Returns an error if the connection was not successful.
230 + *
231 + * ## OPTIONS
232 + *
233 + * <id>
234 + * : The API client id.
235 + *
236 + * <secret>
237 + * : The API secret key.
238 + *
239 + * ## EXAMPLES
240 + *
241 + * $ wp patchstack activate 123456 2b072e8b60402e30d481df351fc08183906254e0
242 + * Success: The Patchstack plugin has been successfully connected.
228 243 */
229 - public function deactivate() {
230 - $this->plugin_classes();
231 - $this->activation->deactivate();
244 + public function cli_activate( $args ) {
245 + $id = isset( $args[0] ) ? trim( $args[0] ) : '';
246 + $secret = isset( $args[1] ) ? trim( $args[1] ) : '';
247 +
248 + $result = $this->activation->alter_license( $id, $secret, 'activate' );
249 + if ( $result['result'] == 'error' ) {
250 + \WP_CLI::error( 'The Patchstack plugin could not be connected. Make sure the id and secret key are valid and that api.patchstack.com is not blocked.' );
251 + return;
252 + }
253 +
254 + \WP_CLI::success( 'The Patchstack plugin has been successfully connected.' );
232 255 }
233 256
234 257 /**
235 - * Boot Patchstack and its classes.
258 + * Deactivate the plugin.
236 259 *
237 260 * @return void
238 261 */
239 - public function hooks() {
240 - add_action( 'init', array( $this, 'init' ), ~PHP_INT_MAX );
262 + public function deactivate() {
263 + $this->plugin_classes();
264 + $this->activation->deactivate();
241 265 }
242 266
243 267 /**
244 - * Boot Patchstack
268 + * Boot Patchstack.
245 269 *
246 270 * @return void
247 271 */
248 272 public function init() {
@@ -259,9 +283,9 @@
259 283 if ( get_option( 'patchstack_api_token', '' ) == '' && get_option( 'patchstack_license_expiry', '' ) == '' ) {
260 284 $this->api->update_license_status();
261 285 }
262 286
263 - // Determine if the license is activated and not expired.
287 + // Run firewall if not disabled and license activated.
264 288 if ( get_option( 'patchstack_license_activated', 0 ) == 1 && get_option( 'patchstack_basic_firewall', 0 ) == 1 && get_option( 'patchstack_license_free', 0 ) == 0 ) {
265 289 $this->firewall = new P_Firewall( true, $this );
266 290 }
267 291 }
@@ -316,9 +340,9 @@
316 340 * @return void
317 341 */
318 342 function patchstack_uninstall() {
319 343 // Delete most of the Patchstack options.
320 - $options = array( 'patchstack_eventlog_lastid', 'patchstack_api_token', 'patchstack_dashboardlock', 'patchstack_pluginedit', 'patchstack_move_logs', 'patchstack_userenum', 'patchstack_basicscanblock', 'patchstack_hidewpcontent', 'patchstack_hidewpversionk', 'patchstack_prevent_default_file_access', 'patchstack_basic_firewall', 'patchstack_known_blacklist', 'patchstack_block_debug_log_access', 'patchstack_block_fake_bots', 'patchstack_index_views', 'patchstack_proxy_comment_posting', 'patchstack_bad_query_strings', 'patchstack_advanced_character_string_filter', 'patchstack_advanced_blacklist_firewall', 'patchstack_forbid_rfi', 'patchstack_image_hotlinking', 'patchstack_add_security_headers', 'patchstack_firewall_log_lastid', 'patchstack_user_log_lastid', 'patchstack_captcha_public_key', 'patchstack_captcha_private_key', 'patchstack_scan_interval', 'patchstack_scan_day', 'patchstack_scan_time', 'patchstack_hackers_log', 'patchstack_users_log', 'patchstack_visitors_log', 'external_updates-webarx', 'patchstack_wp_stats', 'patchstack_captcha_login_form', 'patchstack_license_activated', 'patchstack_license_expiry', 'patchstack_software_data_hash', 'patchstack_mv_wp_login', 'patchstack_rename_wp_login', 'patchstack_googledrive_backup_is_running', 'patchstack_googledrive_upload_state', 'patchstack_googledrive_access_token', 'patchstack_googledrive_refresh_token', 'patchstack_cron_offset', 'patchstack_htaccess_rules_hash' );
344 + $options = [ 'patchstack_eventlog_lastid', 'patchstack_api_token', 'patchstack_dashboardlock', 'patchstack_pluginedit', 'patchstack_move_logs', 'patchstack_userenum', 'patchstack_basicscanblock', 'patchstack_hidewpcontent', 'patchstack_hidewpversionk', 'patchstack_prevent_default_file_access', 'patchstack_basic_firewall', 'patchstack_known_blacklist', 'patchstack_block_debug_log_access', 'patchstack_block_fake_bots', 'patchstack_index_views', 'patchstack_proxy_comment_posting', 'patchstack_bad_query_strings', 'patchstack_advanced_character_string_filter', 'patchstack_advanced_blacklist_firewall', 'patchstack_forbid_rfi', 'patchstack_image_hotlinking', 'patchstack_add_security_headers', 'patchstack_firewall_log_lastid', 'patchstack_user_log_lastid', 'patchstack_captcha_public_key', 'patchstack_captcha_private_key', 'patchstack_scan_interval', 'patchstack_scan_day', 'patchstack_scan_time', 'patchstack_hackers_log', 'patchstack_users_log', 'patchstack_visitors_log', 'external_updates-webarx', 'patchstack_wp_stats', 'patchstack_captcha_login_form', 'patchstack_license_activated', 'patchstack_license_expiry', 'patchstack_software_data_hash', 'patchstack_mv_wp_login', 'patchstack_rename_wp_login', 'patchstack_googledrive_backup_is_running', 'patchstack_googledrive_upload_state', 'patchstack_googledrive_access_token', 'patchstack_googledrive_refresh_token', 'patchstack_cron_offset', 'patchstack_htaccess_rules_hash' ];
321 345 foreach ( $options as $option ) {
322 346 delete_option( $option );
323 347
324 348 if ( is_multisite() ) {
@@ -327,9 +351,9 @@
327 351 }
328 352
329 353 // Drop all Patchstack tables.
330 354 global $wpdb;
331 - $tables = array( 'patchstack_user_log', 'patchstack_visitor_log', 'patchstack_firewall_log', 'patchstack_file_hashes', 'patchstack_logic', 'patchstack_ip', 'patchstack_event_log' );
355 + $tables = [ 'patchstack_user_log', 'patchstack_visitor_log', 'patchstack_firewall_log', 'patchstack_file_hashes', 'patchstack_logic', 'patchstack_ip', 'patchstack_event_log' ];
332 356 foreach ( $tables as $table ) {
333 357 $wpdb->query( 'DROP TABLE IF EXISTS ' . $wpdb->prefix . $table );
334 358 }
335 359 }
@@ -346,10 +370,10 @@
346 370 }
347 371 }
348 372
349 373 // Kick it off.
350 -add_action( 'plugins_loaded', array( patchstack(), 'hooks' ) );
374 +add_action( 'plugins_loaded', [ patchstack(), 'init' ] );
351 375
352 376 // Activation and deactivation hooks.
353 -register_activation_hook( __FILE__, array( patchstack(), 'activate' ) );
354 -register_deactivation_hook( __FILE__, array( patchstack(), 'deactivate' ) );
377 +register_activation_hook( __FILE__, [ patchstack(), 'activate' ] );
378 +register_deactivation_hook( __FILE__, [ patchstack(), 'deactivate' ] );
355 379 register_uninstall_hook( __FILE__, 'patchstack_uninstall' );