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 | includes/core.php +57 -71 trunk2.2.2 View file →
@@ -22,9 +22,9 @@
22 22 * Whether or not the site is a multisite.
23 23 *
24 24 * @var boolean
25 25 */
26 - public $is_multi_site = false;
26 + private $is_multi_site = false;
27 27
28 28 /**
29 29 * Allowed HTML for the wp_kses function used to render certain paragraphs of texts.
30 30 *
@@ -91,8 +91,30 @@
91 91 ]
92 92 ];
93 93
94 94 /**
95 + * Some of the IP addresses of Patchstack.
96 + *
97 + * @var array
98 + */
99 + public $ips = [
100 + '18.221.197.243',
101 + '52.15.237.250',
102 + '3.19.3.34',
103 + '3.18.238.17',
104 + '13.58.49.77',
105 + '18.222.191.77',
106 + '3.131.108.250',
107 + '3.23.157.140',
108 + '18.220.70.233',
109 + '3.140.84.221',
110 + '185.212.171.100',
111 + '3.133.121.93',
112 + '18.219.61.133',
113 + '3.14.29.150'
114 + ];
115 +
116 + /**
95 117 * @param Patchstack $plugin
96 118 * @return void
97 119 */
98 120 public function __construct( $plugin ) {
@@ -116,14 +138,8 @@
116 138
117 139 // Get the setting of the current site.
118 140 $secondary = get_option( $name, $default );
119 141
120 - // On single-site installs there is no network option to reconcile, so
121 - // avoid the extra get_site_option() lookup on every read.
122 - if ( ! is_multisite() ) {
123 - return $secondary;
124 - }
125 -
126 142 // Get the setting of the network and in case there's a difference,
127 143 // return the value of site.
128 144 $main = get_site_option( $name, $default );
129 145 return $main != $secondary ? $secondary : $main;
@@ -173,9 +189,9 @@
173 189 return true;
174 190 }
175 191
176 192 $expiry = get_option( 'patchstack_license_expiry', '' );
177 - if ( $expiry != '' && ( strtotime( $expiry ) > ( time() - ( 3600 * 24 ) ) ) ) {
193 + if ( $expiry != '' && ( strtotime( $expiry ) < ( time() + ( 3600 * 24 ) ) ) ) {
178 194 return true;
179 195 }
180 196
181 197 return false;
@@ -181,8 +197,38 @@
181 197 return false;
182 198 }
183 199
184 200 /**
201 + * Convert the subscription class name to its text variant.
202 + *
203 + * @param int $class
204 + * @return string
205 + */
206 + public function get_subscription_name( $class ) {
207 + switch ( $class ) {
208 + case 0:
209 + return 'Community';
210 + case 1:
211 + case 6:
212 + return 'Developer';
213 + case 7:
214 + return 'Business';
215 + default:
216 + return 'Unknown';
217 + }
218 + }
219 +
220 + /**
221 + * Determine if the user is a community user.
222 + *
223 + * @return boolean
224 + */
225 + public function is_community() {
226 + $class = get_option( 'patchstack_subscription_class', '');
227 + return $class != '' && (int) $class === 0;
228 + }
229 +
230 + /**
185 231 * Determine if the plugin is connected to the API.
186 232 *
187 233 * @return boolean
188 234 */
@@ -187,9 +233,9 @@
187 233 * @return boolean
188 234 */
189 235 public function is_connected() {
190 236 // Determine if the API client id is set.
191 - if ( $this->plugin->client_id == 'PATCHSTACK_CLIENT_ID' && ! get_option( 'patchstack_clientid' ) ) {
237 + if ( $this->plugin->client_id == 'PATCHSTACK_CLIENT_ID' && get_option( 'patchstack_clientid', false ) === false ) {
192 238 return false;
193 239 }
194 240
195 241 // Determine if we have an API token.
@@ -211,63 +257,12 @@
211 257 *
212 258 * @return boolean
213 259 */
214 260 public function is_protected() {
215 - return (int) get_option( 'patchstack_license_free', 0 ) == 0;
261 + return get_option( 'patchstack_license_free', false) == 0;
216 262 }
217 263
218 264 /**
219 - * Format a UNIX timestamp as a short relative-time string for the connection card.
220 - * Returns "Never" for empty/zero, otherwise "Just now" / "Xm ago" / "Xh ago" / "Xd ago".
221 - *
222 - * The returned string is the raw translated value — escape it at the call site.
223 - *
224 - * @param int $timestamp UNIX timestamp.
225 - * @return string Translated relative-time label (not escaped).
226 - */
227 - public function format_relative_time( $timestamp ) {
228 - $timestamp = (int) $timestamp;
229 - if ( $timestamp <= 0 ) {
230 - return __( 'Never', 'patchstack' );
231 - }
232 -
233 - $diff = time() - $timestamp;
234 - if ( $diff < 60 ) {
235 - return __( 'Just now', 'patchstack' );
236 - }
237 - if ( $diff < 3600 ) {
238 - /* translators: %d: number of minutes since the last sync. */
239 - return sprintf( __( '%dm ago', 'patchstack' ), (int) floor( $diff / 60 ) );
240 - }
241 - if ( $diff < 86400 ) {
242 - /* translators: %d: number of hours since the last sync. */
243 - return sprintf( __( '%dh ago', 'patchstack' ), (int) floor( $diff / 3600 ) );
244 - }
245 - /* translators: %d: number of days since the last sync. */
246 - return sprintf( __( '%dd ago', 'patchstack' ), (int) floor( $diff / 86400 ) );
247 - }
248 -
249 - /**
250 - * Get the timestamp of the last successful API sync.
251 - *
252 - * Prefers patchstack_last_sync, which is stamped on every successful (200 OK)
253 - * API request (log/software uploads, rule pulls, license verify, ping, etc.),
254 - * so it reflects real sync activity rather than only license verification.
255 - * Falls back to patchstack_last_license_check for sites that have not synced
256 - * yet since this option was introduced.
257 - *
258 - * @return int UNIX timestamp, or 0 if never synced.
259 - */
260 - public function get_last_sync_time() {
261 - $last_sync = (int) get_option( 'patchstack_last_sync', 0 );
262 - if ( $last_sync > 0 ) {
263 - return $last_sync;
264 - }
265 -
266 - return (int) get_option( 'patchstack_last_license_check', 0 );
267 - }
268 -
269 - /**
270 265 * Grab the IP address of the user. Give the override IP header priority.
271 266 * If this does not exist, we should always default to REMOTE_ADDR.
272 267 *
273 268 * @return string
@@ -272,9 +267,9 @@
272 267 *
273 268 * @return string
274 269 */
275 270 public function get_ip() {
276 - $override = get_option( 'patchstack_firewall_ip_header', '' );
271 + $override = get_site_option( 'patchstack_firewall_ip_header', '' );
277 272 if ( $override != '' && isset( $_SERVER[ $override ] ) ) {
278 273 return $_SERVER[ $override ];
279 274 }
280 275
@@ -378,14 +373,8 @@
378 373 ];
379 374 }
380 375
381 376 // Use the Sodium polyfill library part of WordPress core.
382 - if ( ! file_exists( ABSPATH . WPINC . '/sodium_compat/autoload.php' ) ) {
383 - return [
384 - 'cipher' => $message,
385 - 'nonce' => ''
386 - ];
387 - }
388 377 require_once ABSPATH . WPINC . '/sodium_compat/autoload.php';
389 378 $key = \Sodium\crypto_generichash( AUTH_KEY );
390 379
391 380 return [
@@ -420,11 +409,8 @@
420 409 if ( $enc_type == 'native' ) {
421 410 $key = sodium_crypto_generichash( AUTH_KEY );
422 411 $dec = sodium_crypto_secretbox_open( sodium_hex2bin( $cipher ), sodium_hex2bin( $nonce ), $key );
423 412 } else {
424 - if ( ! file_exists( ABSPATH . WPINC . '/sodium_compat/autoload.php' ) ) {
425 - return $cipher;
426 - }
427 413 require_once ABSPATH . WPINC . '/sodium_compat/autoload.php';
428 414 $key = \Sodium\crypto_generichash( AUTH_KEY );
429 415 $dec = \Sodium\crypto_secretbox_open( sodium_hex2bin( $cipher ), sodium_hex2bin( $nonce ), $key );
430 416 }