PluginProbe
Patchstack – WordPress & Plugins Security / 2.2.11
Patchstack – WordPress & Plugins Security v2.2.11
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 +67 -32 2.1.122.2.11 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.12
7 + * Version: 2.2.11
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.12';
62 + const VERSION = '2.2.11';
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,12 +139,12 @@
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 - protected $notice;
153 147 protected $admin_ajax;
154 148 protected $admin_general;
155 149 protected $admin_menu;
156 150 protected $admin_options;
@@ -175,8 +169,13 @@
175 169 $this->basename = plugin_basename( __FILE__ );
176 170 $this->url = plugin_dir_url( __FILE__ );
177 171 $names = explode( '/', $this->basename );
178 172 $this->name = $names[0];
173 +
174 + // Define WP_CLI command.
175 + if ( defined( 'WP_CLI' ) && WP_CLI && method_exists('\WP_CLI', 'add_command')) {
176 + \WP_CLI::add_command( 'patchstack activate', [ $this, 'cli_activate' ] );
177 + }
179 178 }
180 179
181 180 /**
182 181 * Call the constructor of all the Patchstack related classes.
@@ -184,9 +183,9 @@
184 183 * @return void
185 184 */
186 185 public function plugin_classes() {
187 186 // Define the array of the classes.
188 - foreach ( array(
187 + foreach ( [
189 188 'admin_options' => 'P_Admin_Options',
190 189 'cron' => 'P_Cron',
191 190 'api' => 'P_Api',
192 191 'login' => 'P_Login',
@@ -195,20 +194,21 @@
195 194 'htaccess' => 'P_Htaccess',
196 195 'hacker_log' => 'P_Hacker_Log',
197 196 'upload' => 'P_Upload',
198 197 'rules' => 'P_Rules',
199 - 'listener' => 'P_Listener',
198 + 'hide_login' => 'P_Hide_Login',
200 199 'event_log' => 'P_Event_Log',
201 200 'activation' => 'P_Activation',
201 + 'listener' => 'P_Listener',
202 202 'multisite' => 'P_Multisite',
203 - 'notice' => 'P_Cookie_Notice',
204 203 'admin_ajax' => 'P_Admin_Ajax',
205 204 'admin_general' => 'P_Admin_General',
206 205 'admin_menu' => 'P_Admin_Menu',
207 - ) as $var => $class ) {
206 + ] as $var => $class ) {
208 207 $this->$var = new $class( $this );
209 208 }
210 209
210 + // Load firewall base functionality.
211 211 $this->firewall_base = new P_Firewall( true, $this, true );
212 212 }
213 213
214 214 /**
@@ -221,28 +221,63 @@
221 221 $this->activation->activate( $this );
222 222 }
223 223
224 224 /**
225 - * Deactivate the plugin.
225 + * Connects the Patchstack plugin to the API with the license id and secret key.
226 226 *
227 - * @return void
227 + * Returns an error if the connection was not successful.
228 + *
229 + * ## OPTIONS
230 + *
231 + * [<id>]
232 + * : The API client id.
233 + *
234 + * [<secret>]
235 + * : The API secret key.
236 + *
237 + * <secret-id>
238 + * : The API client id and secret key merged together, found in the App. E.g. 2b072e8b60402e30d481df351fc08183906254e0-123456
239 + *
240 + * ## EXAMPLES
241 + *
242 + * $ wp patchstack activate 123456 2b072e8b60402e30d481df351fc08183906254e0
243 + * Success: The Patchstack plugin has been successfully connected.
244 + *
245 + * or
246 + *
247 + * $ wp patchstack activate 2b072e8b60402e30d481df351fc08183906254e0-123456
248 + * Success: The Patchstack plugin has been successfully connected.
228 249 */
229 - public function deactivate() {
230 - $this->plugin_classes();
231 - $this->activation->deactivate();
250 + public function cli_activate( $args ) {
251 + // Handle both ways to activate the plugin.
252 + if ( count( $args ) === 1 && strpos( $args[0], '-' ) !== false ) {
253 + list( $secret, $id ) = explode( '-', $args[0] );
254 + } else {
255 + $id = isset( $args[0] ) ? trim( $args[0] ) : '';
256 + $secret = isset( $args[1] ) ? trim( $args[1] ) : '';
257 + }
258 +
259 + $result = $this->activation->alter_license( $id, $secret, 'activate' );
260 + if ( $result['result'] == 'error' ) {
261 + \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.' );
262 + return;
263 + }
264 +
265 + \WP_CLI::success( 'The Patchstack plugin has been successfully connected.' );
232 266 }
233 267
234 268 /**
235 - * Boot Patchstack and its classes.
269 + * Deactivate the plugin.
236 270 *
237 271 * @return void
238 272 */
239 - public function hooks() {
240 - add_action( 'init', array( $this, 'init' ), ~PHP_INT_MAX );
273 + public function deactivate() {
274 + $this->plugin_classes();
275 + $this->activation->deactivate();
241 276 }
242 277
243 278 /**
244 - * Boot Patchstack
279 + * Boot Patchstack.
245 280 *
246 281 * @return void
247 282 */
248 283 public function init() {
@@ -259,9 +294,9 @@
259 294 if ( get_option( 'patchstack_api_token', '' ) == '' && get_option( 'patchstack_license_expiry', '' ) == '' ) {
260 295 $this->api->update_license_status();
261 296 }
262 297
263 - // Determine if the license is activated and not expired.
298 + // Run firewall if not disabled and license activated.
264 299 if ( get_option( 'patchstack_license_activated', 0 ) == 1 && get_option( 'patchstack_basic_firewall', 0 ) == 1 && get_option( 'patchstack_license_free', 0 ) == 0 ) {
265 300 $this->firewall = new P_Firewall( true, $this );
266 301 }
267 302 }
@@ -316,9 +351,9 @@
316 351 * @return void
317 352 */
318 353 function patchstack_uninstall() {
319 354 // 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' );
355 + $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 356 foreach ( $options as $option ) {
322 357 delete_option( $option );
323 358
324 359 if ( is_multisite() ) {
@@ -327,9 +362,9 @@
327 362 }
328 363
329 364 // Drop all Patchstack tables.
330 365 global $wpdb;
331 - $tables = array( 'patchstack_user_log', 'patchstack_visitor_log', 'patchstack_firewall_log', 'patchstack_file_hashes', 'patchstack_logic', 'patchstack_ip', 'patchstack_event_log' );
366 + $tables = [ 'patchstack_user_log', 'patchstack_visitor_log', 'patchstack_firewall_log', 'patchstack_file_hashes', 'patchstack_logic', 'patchstack_ip', 'patchstack_event_log' ];
332 367 foreach ( $tables as $table ) {
333 368 $wpdb->query( 'DROP TABLE IF EXISTS ' . $wpdb->prefix . $table );
334 369 }
335 370 }
@@ -346,10 +381,10 @@
346 381 }
347 382 }
348 383
349 384 // Kick it off.
350 -add_action( 'plugins_loaded', array( patchstack(), 'hooks' ) );
385 +add_action( 'plugins_loaded', [ patchstack(), 'init' ] );
351 386
352 387 // Activation and deactivation hooks.
353 -register_activation_hook( __FILE__, array( patchstack(), 'activate' ) );
354 -register_deactivation_hook( __FILE__, array( patchstack(), 'deactivate' ) );
388 +register_activation_hook( __FILE__, [ patchstack(), 'activate' ] );
389 +register_deactivation_hook( __FILE__, [ patchstack(), 'deactivate' ] );
355 390 register_uninstall_hook( __FILE__, 'patchstack_uninstall' );