PluginProbe
Patchstack – WordPress & Plugins Security / 2.2.8
Patchstack – WordPress & Plugins Security v2.2.8
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 +65 -30 2.1.02.2.8 View file →
@@ -1,10 +1,11 @@
1 1 <?php
2 2 /**
3 - * Plugin Name: Patchstack
4 - * Plugin URI: https://patchstack.com
3 + * Plugin Name: Patchstack Security
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.0
7 + * Version: 2.2.8
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.0';
62 + const VERSION = '2.2.8';
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 *
@@ -176,8 +170,13 @@
176 170 $this->basename = plugin_basename( __FILE__ );
177 171 $this->url = plugin_dir_url( __FILE__ );
178 172 $names = explode( '/', $this->basename );
179 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 + }
180 179 }
181 180
182 181 /**
183 182 * Call the constructor of all the Patchstack related classes.
@@ -185,9 +184,9 @@
185 184 * @return void
186 185 */
187 186 public function plugin_classes() {
188 187 // Define the array of the classes.
189 - foreach ( array(
188 + foreach ( [
190 189 'admin_options' => 'P_Admin_Options',
191 190 'cron' => 'P_Cron',
192 191 'api' => 'P_Api',
193 192 'login' => 'P_Login',
@@ -205,12 +204,13 @@
205 204 'notice' => 'P_Cookie_Notice',
206 205 'admin_ajax' => 'P_Admin_Ajax',
207 206 'admin_general' => 'P_Admin_General',
208 207 'admin_menu' => 'P_Admin_Menu',
209 - ) as $var => $class ) {
208 + ] as $var => $class ) {
210 209 $this->$var = new $class( $this );
211 210 }
212 211
212 + // Load firewall base functionality.
213 213 $this->firewall_base = new P_Firewall( true, $this, true );
214 214 }
215 215
216 216 /**
@@ -223,28 +223,63 @@
223 223 $this->activation->activate( $this );
224 224 }
225 225
226 226 /**
227 - * Deactivate the plugin.
227 + * Connects the Patchstack plugin to the API with the license id and secret key.
228 228 *
229 - * @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 + * <secret-id>
240 + * : The API client id and secret key merged together, found in the App. E.g. 2b072e8b60402e30d481df351fc08183906254e0-123456
241 + *
242 + * ## EXAMPLES
243 + *
244 + * $ wp patchstack activate 123456 2b072e8b60402e30d481df351fc08183906254e0
245 + * Success: The Patchstack plugin has been successfully connected.
246 + *
247 + * or
248 + *
249 + * $ wp patchstack activate 2b072e8b60402e30d481df351fc08183906254e0-123456
250 + * Success: The Patchstack plugin has been successfully connected.
230 251 */
231 - public function deactivate() {
232 - $this->plugin_classes();
233 - $this->activation->deactivate();
252 + public function cli_activate( $args ) {
253 + // Handle both ways to activate the plugin.
254 + if ( count( $args ) === 1 && strpos( $args[0], '-' ) !== false ) {
255 + list( $secret, $id ) = explode( '-', $args[0] );
256 + } else {
257 + $id = isset( $args[0] ) ? trim( $args[0] ) : '';
258 + $secret = isset( $args[1] ) ? trim( $args[1] ) : '';
259 + }
260 +
261 + $result = $this->activation->alter_license( $id, $secret, 'activate' );
262 + if ( $result['result'] == 'error' ) {
263 + \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.' );
264 + return;
265 + }
266 +
267 + \WP_CLI::success( 'The Patchstack plugin has been successfully connected.' );
234 268 }
235 269
236 270 /**
237 - * Boot Patchstack and its classes.
271 + * Deactivate the plugin.
238 272 *
239 273 * @return void
240 274 */
241 - public function hooks() {
242 - add_action( 'init', array( $this, 'init' ), ~PHP_INT_MAX );
275 + public function deactivate() {
276 + $this->plugin_classes();
277 + $this->activation->deactivate();
243 278 }
244 279
245 280 /**
246 - * Boot Patchstack
281 + * Boot Patchstack.
247 282 *
248 283 * @return void
249 284 */
250 285 public function init() {
@@ -261,9 +296,9 @@
261 296 if ( get_option( 'patchstack_api_token', '' ) == '' && get_option( 'patchstack_license_expiry', '' ) == '' ) {
262 297 $this->api->update_license_status();
263 298 }
264 299
265 - // Determine if the license is activated and not expired.
300 + // Run firewall if not disabled and license activated.
266 301 if ( get_option( 'patchstack_license_activated', 0 ) == 1 && get_option( 'patchstack_basic_firewall', 0 ) == 1 && get_option( 'patchstack_license_free', 0 ) == 0 ) {
267 302 $this->firewall = new P_Firewall( true, $this );
268 303 }
269 304 }
@@ -318,9 +353,9 @@
318 353 * @return void
319 354 */
320 355 function patchstack_uninstall() {
321 356 // Delete most of the Patchstack options.
322 - $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' );
357 + $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' ];
323 358 foreach ( $options as $option ) {
324 359 delete_option( $option );
325 360
326 361 if ( is_multisite() ) {
@@ -329,9 +364,9 @@
329 364 }
330 365
331 366 // Drop all Patchstack tables.
332 367 global $wpdb;
333 - $tables = array( 'patchstack_user_log', 'patchstack_visitor_log', 'patchstack_firewall_log', 'patchstack_file_hashes', 'patchstack_logic', 'patchstack_ip', 'patchstack_event_log' );
368 + $tables = [ 'patchstack_user_log', 'patchstack_visitor_log', 'patchstack_firewall_log', 'patchstack_file_hashes', 'patchstack_logic', 'patchstack_ip', 'patchstack_event_log' ];
334 369 foreach ( $tables as $table ) {
335 370 $wpdb->query( 'DROP TABLE IF EXISTS ' . $wpdb->prefix . $table );
336 371 }
337 372 }
@@ -348,10 +383,10 @@
348 383 }
349 384 }
350 385
351 386 // Kick it off.
352 -add_action( 'plugins_loaded', array( patchstack(), 'hooks' ) );
387 +add_action( 'plugins_loaded', [ patchstack(), 'init' ] );
353 388
354 389 // Activation and deactivation hooks.
355 -register_activation_hook( __FILE__, array( patchstack(), 'activate' ) );
356 -register_deactivation_hook( __FILE__, array( patchstack(), 'deactivate' ) );
390 +register_activation_hook( __FILE__, [ patchstack(), 'activate' ] );
391 +register_deactivation_hook( __FILE__, [ patchstack(), 'deactivate' ] );
357 392 register_uninstall_hook( __FILE__, 'patchstack_uninstall' );