PluginProbe
Defender Security – Malware Scanner, Login Security & Firewall / 5.7.2
Defender Security – Malware Scanner, Login Security & Firewall v5.7.2
6.3.0 6.2.3 6.2.4 6.2.0 6.2.1 6.2.2 6.1.0 5.3.1 5.4.0 5.4.1 5.5.0 5.5.1 5.6.0 5.6.1 5.6.2 5.7.0 5.7.1 5.7.2 5.8.0 5.8.1 5.9.0 6.0.0 6.0.1 3.0.1 3.1.0 All 141 releases
defender-security / src / component / config / class-config-hub-helper.php

class-config-hub-helper.php in Defender Security – Malware Scanner, Login Security & Firewall 5.7.2, at src/component/config/class-config-hub-helper.php

511 lines 13.2 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Handles interactions with the WPMU DEV Hub for configurations storage and retrieval.
4 *
5 * @package WP_Defender\Component\Config
6 */
7
8 namespace WP_Defender\Component\Config;
9
10 use WP_Defender\Behavior\WPMUDEV;
11 use WP_Defender\Component\Backup_Settings;
12
13 /**
14 * Handles configuration settings related to the WPMU DEV Hub.
15 */
16 class Config_Hub_Helper {
17
18 public const CONFIGS_TRANSIENT_KEY = 'wpdefender_preset_configs';
19 public const CONFIGS_TRANSIENT_TIME_KEY = 'wpdefender_preset_configs_transient_time';
20 public const ACTIVE_FLAG_CLEAR_KEY = 'wpdefender_config_clear_active_tag';
21 public const CONFIGS_TRANSIENT_TIME = 600; // 600 = 10 minutes.
22
23 /**
24 * WPMU DEV Plugin ID.
25 */
26 public const WDP_ID = 1081723;
27
28 /**
29 * Service class.
30 *
31 * @var Backup_Settings
32 */
33 private $service;
34
35 /**
36 * Get configs from transient.
37 *
38 * @param Backup_Settings $service Config service.
39 *
40 * @return mixed|array
41 */
42 public static function get_configs( Backup_Settings $service ) {
43 $configs = get_site_transient( self::CONFIGS_TRANSIENT_KEY );
44
45 if ( false === $configs ) {
46 $_this = new self();
47 $_this->service = $service;
48 $configs = $_this->fetch_current_configs();
49
50 set_site_transient( self::CONFIGS_TRANSIENT_KEY, $configs, self::CONFIGS_TRANSIENT_TIME );
51 update_site_option( self::CONFIGS_TRANSIENT_TIME_KEY, time() );
52 }
53
54 return $configs;
55 }
56
57 /**
58 * Get our special WDP ID header line from the file.
59 *
60 * @return array Plugin details: name, id.
61 */
62 private function get_plugin_details(): array {
63 $wpmudev = new WPMUDEV();
64
65 return array(
66 'name' => 'Defender' . ( $wpmudev->is_pro() ? ' Pro' : '' ),
67 'id' => (string) self::WDP_ID,
68 );
69 }
70
71 /**
72 * Fetch and prepare configs to store to transient.
73 *
74 * @return array
75 */
76 private function fetch_current_configs(): array {
77 $stored_configs = $this->service->get_configs();
78 $wpmudev = new WPMUDEV();
79 $def_details = $this->get_plugin_details();
80
81 // Check config has `hub_id`. If not then send request to HUB and set it.
82 $stored_configs = $this->check_and_save_configs_to_hub( $stored_configs, $def_details, $wpmudev );
83
84 if ( defined( WPMUDEV::class . '::API_PACKAGE_CONFIGS' ) ) {
85 // Fetch configs from API.
86 $response = $wpmudev->make_wpmu_request(
87 WPMUDEV::API_PACKAGE_CONFIGS,
88 array( 'package_id' => $def_details['id'] ),
89 array( 'method' => 'GET' )
90 );
91 } else {
92 $response = false;
93 }
94
95 $final_configs = array();
96
97 // Loop to set default config.
98 // Exclude default config from match with HUB config.
99 foreach ( $stored_configs as $sc_key => $sc_value ) {
100 if ( 0 === strpos( $sc_key, 'wp_defender_config_default' ) ) {
101 $final_configs[ $sc_key ] = $sc_value;
102 break;
103 }
104
105 // Sometimes key does not match for default config.
106 if ( isset( $sc_value['immortal'] ) && $sc_value['immortal'] ) {
107 $final_configs[ $sc_key ] = $sc_value;
108 break;
109 }
110 }
111
112 return $this->prepare_hub_configs_response( $response, $final_configs, $stored_configs );
113 }
114
115 /**
116 * Check configs are saved on hub. If not in hub then create it.
117 *
118 * @param array $stored_configs All configs from DB.
119 * @param array $def_details Defender plugin details.
120 * @param WPMUDEV $wpmudev Defender plugin details.
121 *
122 * @return array
123 */
124 private function check_and_save_configs_to_hub( array $stored_configs, array $def_details, $wpmudev ): array {
125 foreach ( $stored_configs as $sc_key => &$sc_value ) {
126 // Check it is for default config.
127 if ( 0 === strpos( $sc_key, 'wp_defender_config_default' ) ) {
128 continue;
129 }
130
131 // Sometimes key does not match for default config.
132 if ( isset( $sc_value['immortal'] ) && $sc_value['immortal'] ) {
133 continue;
134 }
135
136 if ( isset( $sc_value['hub_id'] ) ) {
137 continue;
138 }
139
140 $hub_id = $this->insert_to_hub( $sc_value, $def_details, $wpmudev );
141
142 // If data is not inserted to HUB.
143 if ( ! $hub_id ) {
144 continue;
145 }
146
147 $sc_value['hub_id'] = $hub_id;
148
149 update_site_option( $sc_key, $sc_value );
150 }
151
152 return $stored_configs;
153 }
154
155 /**
156 * Insert new config to hub.
157 *
158 * @param array $sc_value Single config from DB.
159 * @param array $def_details Defender plugin details.
160 * @param WPMUDEV $wpmudev Defender plugin details.
161 *
162 * @return bool|int ID from hub.
163 */
164 private function insert_to_hub( array $sc_value, array $def_details, $wpmudev ) {
165 if ( ! defined( WPMUDEV::class . '::API_PACKAGE_CONFIGS' ) ) {
166 return false;
167 }
168
169 if ( empty( $sc_value['configs'] ) ) {
170 return false;
171 }
172
173 if ( empty( $sc_value['labels'] ) ) {
174 $config_component = wd_di()->get( Backup_Settings::class );
175 $sc_value['labels'] = $config_component->prepare_config_labels( $sc_value['configs'] );
176 }
177
178 $data = array(
179 'name' => $sc_value['name'],
180 'description' => $sc_value['description'],
181 'package' => $def_details,
182 'config' => wp_json_encode(
183 array(
184 'strings' => $sc_value['strings'],
185 'configs' => $sc_value['configs'],
186 'labels' => $sc_value['labels'],
187 )
188 ),
189 );
190
191 $response = $wpmudev->make_wpmu_request(
192 WPMUDEV::API_PACKAGE_CONFIGS,
193 $data,
194 array( 'method' => 'POST' )
195 );
196
197 if ( is_wp_error( $response ) ) {
198 return false;
199 }
200
201 return $response['id'];
202 }
203
204 /**
205 * Add config to HUB.
206 *
207 * @param array $data Config data.
208 *
209 * @return bool|int
210 */
211 public static function add_configs_to_hub( array $data ) {
212 $_this = new self();
213 $wpmudev = new WPMUDEV();
214 $def_details = $_this->get_plugin_details();
215
216 delete_site_transient( self::CONFIGS_TRANSIENT_KEY );
217
218 return $_this->insert_to_hub( $data, $def_details, $wpmudev );
219 }
220
221 /**
222 * Delete config from HUB.
223 *
224 * @param int $hub_id ID of config from HUB.
225 *
226 * @return bool
227 */
228 public static function delete_configs_from_hub( int $hub_id ): bool {
229 if ( ! defined( WPMUDEV::class . '::API_PACKAGE_CONFIGS' ) ) {
230 return false;
231 }
232
233 $wpmudev = new WPMUDEV();
234 $url = $wpmudev->get_endpoint( WPMUDEV::API_PACKAGE_CONFIGS );
235 $response = self::send_request(
236 $url . '/' . $hub_id,
237 array(),
238 $wpmudev->get_apikey(),
239 'DELETE'
240 );
241
242 if ( isset( $response['deleted'] ) && $response['deleted'] ) {
243 delete_site_transient( self::CONFIGS_TRANSIENT_KEY );
244
245 return true;
246 }
247
248 return false;
249 }
250
251 /**
252 * Update config on HUB.
253 *
254 * @param array $config Full config data.
255 *
256 * @return bool
257 */
258 public static function update_on_hub( array $config ): bool {
259 if ( ! isset( $config['hub_id'] ) ) {
260 return false;
261 }
262
263 if ( ! defined( WPMUDEV::class . '::API_PACKAGE_CONFIGS' ) ) {
264 return false;
265 }
266
267 $wpmudev = new WPMUDEV();
268 $url = $wpmudev->get_endpoint( WPMUDEV::API_PACKAGE_CONFIGS );
269
270 $data = array(
271 'name' => $config['name'],
272 'description' => $config['description'],
273 );
274
275 $response = self::send_request(
276 $url . '/' . $config['hub_id'],
277 $data,
278 $wpmudev->get_apikey(),
279 'PUT'
280 );
281
282 if ( isset( $response['id'] ) && $response['id'] ) {
283 delete_site_transient( self::CONFIGS_TRANSIENT_KEY );
284
285 return true;
286 }
287
288 return false;
289 }
290
291 /**
292 * Sends an API request to the specified URL.
293 *
294 * @param string $url URL to send the request to.
295 * @param array $body Body of the request.
296 * @param mixed $api_key API key for authorization.
297 * @param string $method HTTP method to be used (GET, POST, PUT, DELETE).
298 *
299 * @return bool|array
300 */
301 private static function send_request( string $url, array $body, $api_key, string $method ) {
302 $request = wp_remote_request(
303 $url,
304 array(
305 'method' => $method,
306 'headers' => array(
307 'Authorization' => $api_key,
308 ),
309 'body' => $body,
310 )
311 );
312
313 if ( is_wp_error( $request ) ) {
314 return false;
315 }
316
317 return json_decode( $request['body'], true );
318 }
319
320 /**
321 * Delete transient for matching condition.
322 *
323 * @return void
324 */
325 public static function clear_config_transient(): void {
326 delete_site_transient( self::CONFIGS_TRANSIENT_KEY );
327 }
328
329 /**
330 * Prepare configs getting from HUB.
331 *
332 * @param mixed $response Response from the HUB.
333 * @param array $final_configs Final configurations to be prepared.
334 * @param array $stored_configs Stored configurations for comparison.
335 *
336 * @return array
337 */
338 private function prepare_hub_configs_response( $response, array $final_configs, array $stored_configs ): array {
339 if ( ! is_array( $response ) || is_wp_error( $response ) ) {
340 return $stored_configs;
341 }
342
343 // Store id of keys that need to delete. Because they are deleted on HUB.
344 $delete_hub_ids = array();
345 $once_delete_unset = array();
346
347 // Loop through all items found in the API.
348 foreach ( $response as $api_config ) {
349 $found = false;
350 $api_config_array = json_decode( $api_config['config'], true );
351
352 // Find key and value from stored configs.
353 foreach ( $stored_configs as $sc_key => $sc_value ) {
354 if ( isset( $sc_value['hub_id'] ) ) {
355 // Once it is unset from the deleted array don't re-add it.
356 if ( ! isset( $once_delete_unset[ $sc_value['hub_id'] ] ) ) {
357 $delete_hub_ids[ $sc_value['hub_id'] ] = $sc_key;
358 }
359
360 if ( $sc_value['hub_id'] === $api_config['id'] ) {
361 // Sanitize data.
362 $sc_value['name'] = sanitize_text_field( $api_config['name'] );
363 $sc_value['description'] = empty( $api_config['description'] )
364 ? ''
365 : sanitize_textarea_field( $api_config['description'] );
366 $sc_value['immortal'] = $api_config_array['immortal'] ?? $sc_value['immortal'];
367 $sc_value['is_removable'] = $api_config['is_removable'] ?? true;
368 $final_configs[ $sc_key ] = $sc_value;
369 $found = true;
370
371 unset( $delete_hub_ids[ $sc_value['hub_id'] ] );
372 $once_delete_unset[ $sc_value['hub_id'] ] = $sc_key;
373 break;
374 }
375 }
376 }
377
378 if ( $found ) {
379 continue;
380 }
381
382 // Need to prepare this data because these are coming from HUB.
383 $key = 'wp_defender_config_hub_' . $api_config['id'];
384 $final_configs[ $key ] = $this->format_hub_config_to_save( $api_config );
385 $this->service->index_key( $key );
386 }
387
388 $this->delete_hub_removed_configs( $delete_hub_ids );
389
390 return $final_configs;
391 }
392
393 /**
394 * Delete configs that are delete from HUB.
395 *
396 * @param array $delete_hub_ids Array of configuration IDs to be deleted.
397 *
398 * @return void
399 */
400 private function delete_hub_removed_configs( array $delete_hub_ids ): void {
401 foreach ( $delete_hub_ids as $key ) {
402 delete_site_option( $key );
403 $this->service->remove_index( $key );
404 }
405 }
406
407 /**
408 * Need to prepare this data because these are coming from HUB.
409 *
410 * @param array $api_config The hub config data.
411 *
412 * @return array
413 */
414 private function format_hub_config_to_save( array $api_config ): array {
415 $api_config_array = json_decode( $api_config['config'], true );
416 $api_config_array['hub_id'] = $api_config['id'];
417 // Sanitize data.
418 $api_config_array['name'] = sanitize_text_field( $api_config['name'] );
419 $api_config_array['description'] = empty( $api_config['description'] )
420 ? ''
421 : sanitize_textarea_field( $api_config['description'] );
422 $api_config_array['immortal'] = $api_config_array['immortal'] ?? false;
423 $api_config_array['is_removable'] = $api_config['is_removable'] ?? true;
424
425 unset( $api_config_array['labels'] );
426
427 return $api_config_array;
428 }
429
430 /**
431 * Delete config cache and create a new cache.
432 *
433 * @param Backup_Settings $service The backup settings service.
434 *
435 * @return mixed|array
436 */
437 public static function get_fresh_frontend_configs( Backup_Settings $service ) {
438 delete_site_transient( self::CONFIGS_TRANSIENT_KEY );
439
440 $configs = self::get_configs( $service );
441
442 foreach ( $configs as &$config ) {
443 unset( $config['configs'] );
444 }
445
446 return $configs;
447 }
448
449 /**
450 * Set a flag to clear active tag.
451 *
452 * @return void
453 */
454 public static function set_clear_active_flag(): void {
455 $value = get_site_option( self::ACTIVE_FLAG_CLEAR_KEY, 'cleared' );
456
457 if ( 'clear' !== $value ) {
458 update_site_option( self::ACTIVE_FLAG_CLEAR_KEY, 'clear' );
459 }
460 }
461
462 /**
463 * Check active flag need to remove or not.
464 *
465 * @return bool
466 */
467 public static function check_remove_active_flag(): bool {
468 $value = get_site_option( self::ACTIVE_FLAG_CLEAR_KEY, 'cleared' );
469
470 if ( 'clear' === $value ) {
471 update_site_option( self::ACTIVE_FLAG_CLEAR_KEY, 'cleared' );
472
473 return true;
474 }
475
476 return false;
477 }
478
479 /**
480 * Updates the active configuration from the given hub ID.
481 *
482 * @param int $hub_id The hub ID of the configuration to activate.
483 *
484 * @return void
485 */
486 public static function active_config_from_hub_id( int $hub_id ): void {
487 $config_component = wd_di()->get( Backup_Settings::class );
488 $configs = $config_component->get_configs();
489
490 foreach ( $configs as $key => $config ) {
491 $need_update = false;
492 // Remove previous active status.
493 if ( isset( $config['is_active'] ) && $config['is_active'] ) {
494 $config['is_active'] = false;
495 $need_update = true;
496 }
497 // Add current active status.
498 if ( isset( $config['hub_id'] ) && (int) $config['hub_id'] === $hub_id ) {
499 $config['is_active'] = true;
500 $need_update = true;
501 }
502
503 if ( $need_update ) {
504 update_site_option( $key, $config );
505 }
506 }
507 // Clear cache to reflect in frontend.
508 delete_site_transient( self::CONFIGS_TRANSIENT_KEY );
509 }
510 }
511