PluginProbe
Defender Security – Malware Scanner, Login Security & Firewall / 5.6.0
Defender Security – Malware Scanner, Login Security & Firewall v5.6.0
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 / traits / defender-bootstrap.php

defender-bootstrap.php in Defender Security – Malware Scanner, Login Security & Firewall 5.6.0, at src/traits/defender-bootstrap.php

693 lines 22.7 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Handle common bootstrap functionalities.
4 *
5 * @package WP_Defender\Traits
6 */
7
8 namespace WP_Defender\Traits;
9
10 use WP_CLI;
11 use Calotes\DB\Mapper;
12 use WP_Defender\Admin;
13 use WP_Defender\Component\Cli;
14 use Calotes\Helper\Array_Cache;
15 use WP_Defender\Controller\HUB;
16 use WP_Defender\Controller\WAF;
17 use WP_Defender\Controller\Scan;
18 use WP_Defender\Component\Crypt;
19 use WP_Defender\Behavior\WPMUDEV;
20 use WP_Defender\Controller\Onboard;
21 use WP_Defender\Controller\Webauthn;
22 use WP_Defender\Controller\Dashboard;
23 use WP_Defender\Controller\Recaptcha;
24 use WP_Defender\Controller\Mask_Login;
25 use WP_Defender\Controller\Quarantine;
26 use WP_Defender\Controller\Two_Factor;
27 use WP_Defender\Component\Hub_Connector;
28 use WP_Defender\Controller\Main_Setting;
29 use WP_Defender\Controller\Notification;
30 use WP_Defender\Controller\Audit_Logging;
31 use WP_Defender\Controller\Data_Tracking;
32 use WP_Defender\Controller\Advanced_Tools;
33 use WP_Defender\Controller\Password_Reset;
34 use WP_Defender\Controller\Strong_Password;
35 use WP_Defender\Controller\Expert_Services;
36 use WP_Defender\Controller\Security_Tweaks;
37 use WP_Defender\Controller\Security_Headers;
38 use WP_Defender\Controller\Blocklist_Monitor;
39 use WP_Defender\Controller\Session_Protection;
40 use WP_Defender\Controller\Password_Protection;
41 use WP_Defender\Component\Network_Cron_Manager;
42 use WP_Defender\Component\Logger\Rotation_Logger;
43 use WP_Defender\Component\Firewall as Firewall_Component;
44 use WP_Defender\Controller\Firewall as Firewall_Controller;
45 use WP_Defender\Controller\Hub_Connector as Hub_Connector_Controller;
46 use WP_Defender\Model\Onboard as Onboard_Model;
47 use WP_Defender\Controller\Rate as Rate_Controller;
48 use WP_Defender\Component\Rate as Rate_Component;
49
50 trait Defender_Bootstrap {
51 /**
52 * Table name for quarantine.
53 *
54 * @var string
55 */
56 private $quarantine_table = 'defender_quarantine';
57
58 /**
59 * Table name for scan item.
60 *
61 * @var string
62 */
63 private $scan_item_table = 'defender_scan_item';
64
65 /**
66 * Check is all quarantine dependent table is having storage engine InnoDB.
67 *
68 * @return bool True if all dependent table is InnoDB else false.
69 */
70 private function is_quarantine_dependent_tables_innodb(): bool {
71 global $wpdb;
72
73 $tables = array( $wpdb->users, $wpdb->base_prefix . $this->scan_item_table );
74 $total_table = count( $tables );
75
76 return $wpdb->get_var( // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
77 $wpdb->prepare(
78 "SELECT COUNT(`ENGINE`) = %d FROM information_schema.TABLES WHERE TABLE_SCHEMA = %s AND `ENGINE` = %s AND TABLE_NAME IN ( '{$wpdb->users}', '{$wpdb->base_prefix}defender_scan_item' );",
79 $total_table,
80 $wpdb->dbname,
81 'innodb',
82 )
83 ) === '1';
84 }
85
86 /**
87 * Creates the quarantine table if it doesn't exist.
88 *
89 * @return void
90 */
91 public function create_table_quarantine() {
92 global $wpdb;
93
94 // Define table names and charset.
95 $quarantine_table = $wpdb->base_prefix . $this->quarantine_table;
96 $scan_item_table = $wpdb->base_prefix . $this->scan_item_table;
97 $charset_collate = $wpdb->get_charset_collate();
98 $unique_id = uniqid( $wpdb->prefix );
99
100 $common_columns = <<<SQL
101 `id` bigint UNSIGNED NOT NULL AUTO_INCREMENT,
102 `defender_scan_item_id` int UNSIGNED DEFAULT NULL,
103 `file_hash` char(53) NOT NULL,
104 `file_full_path` text NOT NULL,
105 `file_original_name` tinytext NOT NULL,
106 `file_extension` varchar(16) DEFAULT NULL,
107 `file_mime_type` varchar(64) DEFAULT NULL,
108 `file_rw_permission` smallint UNSIGNED DEFAULT NULL,
109 `file_owner` varchar(255) DEFAULT NULL,
110 `file_group` varchar(255) DEFAULT NULL,
111 `file_version` varchar(32) DEFAULT NULL,
112 `file_category` tinyint UNSIGNED DEFAULT 0,
113 `file_modified_time` datetime NOT NULL,
114 `source_slug` varchar(255) NOT NULL,
115 `created_time` datetime NOT NULL,
116 `created_by` bigint UNSIGNED DEFAULT NULL,
117 PRIMARY KEY (`id`)
118 SQL;
119
120 // Define key names.
121 $scan_item_key = "{$unique_id}_defender_scan_item_id";
122 $created_by_key = "{$unique_id}_created_by";
123
124 // Build the SQL statement based on the storage engine.
125 if ( $this->is_quarantine_dependent_tables_innodb() ) {
126 $sql = <<<SQL
127 CREATE TABLE IF NOT EXISTS `{$quarantine_table}` (
128 $common_columns,
129 CONSTRAINT `{$scan_item_key}`
130 FOREIGN KEY (`defender_scan_item_id`) REFERENCES {$scan_item_table}(`id`)
131 ON UPDATE CASCADE ON DELETE SET NULL,
132 CONSTRAINT `{$created_by_key}`
133 FOREIGN KEY (`created_by`) REFERENCES {$wpdb->users}(`ID`)
134 ON UPDATE CASCADE ON DELETE SET NULL
135 ) {$charset_collate};
136 SQL;
137 } else {
138 $sql = <<<SQL
139 CREATE TABLE IF NOT EXISTS `{$quarantine_table}` (
140 $common_columns,
141 KEY `{$scan_item_key}` (`defender_scan_item_id`),
142 KEY `{$created_by_key}` (`created_by`)
143 ) {$charset_collate};
144 SQL;
145 }
146
147 // Execute the SQL query.
148 $wpdb->query( $sql ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared, WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
149 }
150
151 /**
152 * Activation.
153 */
154 private function activation_hook_common(): void {
155 $this->create_database_tables();
156 $this->on_activation();
157 // Create a file with a random key if it doesn't exist.
158 ( new Crypt() )->create_key_file();
159 // If this is a plugin reactivating, then track it. No need the check by 'wd_nofresh_install' key because the option is disabled by default.
160 $settings = wd_di()->get( Main_Setting::class );
161 $settings->set_intention( 'Reactivation' );
162 $settings->track_opt( true );
163
164 $service = wd_di()->get( Firewall_Component::class );
165 $service->auto_switch_ip_detection_option();
166 $service->maybe_show_misconfigured_ip_detection_option_notice();
167 $service->maybe_dismiss_cf_notice();
168 wp_schedule_single_event( time() + 5, 'wpdef_smart_ip_detection_ping' );
169 }
170
171 /**
172 * Deactivation.
173 */
174 public function deactivation_hook(): void {
175 wp_clear_scheduled_hook( 'firewall_clean_up_logs' );
176 wp_clear_scheduled_hook( 'audit_sync_events' );
177 wp_clear_scheduled_hook( 'audit_clean_up_logs' );
178 wp_clear_scheduled_hook( 'wdf_maybe_send_report' );
179 wp_clear_scheduled_hook( 'wp_defender_clear_logs' );
180 wp_clear_scheduled_hook( 'wpdef_sec_key_gen' );
181 wp_clear_scheduled_hook( 'wpdef_clear_scan_logs' );
182 wp_clear_scheduled_hook( 'wpdef_log_rotational_delete' );
183 wp_clear_scheduled_hook( 'wpdef_update_geoip' );
184 wp_clear_scheduled_hook( 'wpdef_fetch_global_ip_list' );
185 wp_clear_scheduled_hook( 'wpdef_quarantine_delete_expired' );
186 wp_clear_scheduled_hook( 'wpdef_firewall_clean_up_lockout' );
187 wp_clear_scheduled_hook( 'wpdef_firewall_send_compact_logs_to_api' );
188 wp_clear_scheduled_hook( 'wpdef_firewall_fetch_trusted_proxy_preset_ips' );
189 wp_clear_scheduled_hook( 'wpdef_firewall_clean_up_unlockout' );
190 wp_clear_scheduled_hook( 'wpdef_antibot_global_firewall_fetch_blocklist' );
191 wp_clear_scheduled_hook( 'wpdef_smart_ip_detection_ping' );
192 wp_clear_scheduled_hook( 'wpdef_confirm_antibot_toggle_on_hosting' );
193 wp_clear_scheduled_hook( 'wpdef_firewall_whitelist_server_public_ip' );
194 wp_clear_scheduled_hook( 'wpdef_rotate_malicious_bot_secret_hash' );
195
196 // Remove old legacy cron jobs if they exist.
197 wp_clear_scheduled_hook( 'lockoutReportCron' );
198 wp_clear_scheduled_hook( 'auditReportCron' );
199 wp_clear_scheduled_hook( 'cleanUpOldLog' );
200 wp_clear_scheduled_hook( 'scanReportCron' );
201 wp_clear_scheduled_hook( 'tweaksSendNotification' );
202 }
203
204 /**
205 * Creates the 'defender_unlockout' table if it doesn't exist in the database.
206 *
207 * @return void
208 */
209 public function create_table_unlockout() {
210 global $wpdb;
211
212 $charset_collate = $wpdb->get_charset_collate();
213
214 $sql = <<<SQL
215 CREATE TABLE IF NOT EXISTS {$wpdb->base_prefix}defender_unlockout (
216 `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
217 `ip` varchar(45) DEFAULT NULL,
218 `type` varchar(16) NOT NULL,
219 `email` varchar(255) NOT NULL,
220 `status` varchar(16) NOT NULL,
221 `timestamp` int(11) NOT NULL,
222 PRIMARY KEY (`id`),
223 KEY `ip` (`ip`),
224 KEY `type` (`type`),
225 KEY `email` (`email`),
226 KEY `status` (`status`)
227 ) {$charset_collate};
228 SQL;
229 $wpdb->query( $sql ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared, WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
230 }
231
232 /**
233 * Create blocklist table.
234 *
235 * @since 2.8.0
236 * @return void
237 */
238 public function create_table_blocklist(): void {
239 global $wpdb;
240
241 $charset_collate = $wpdb->get_charset_collate();
242
243 $sql = <<<SQL
244 CREATE TABLE IF NOT EXISTS {$wpdb->base_prefix}defender_antibot (
245 `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
246 `ip` varchar(45) NOT NULL,
247 `unlocked` tinyint(1) DEFAULT NULL,
248 `unlocked_at` int(11) DEFAULT NULL,
249 PRIMARY KEY (`id`),
250 UNIQUE KEY ip (ip)
251 ) {$charset_collate};
252 SQL;
253 $wpdb->query( $sql ); // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL.NotPrepared
254 }
255
256 /**
257 * Creates Defender's tables.
258 *
259 * @since 2.7.1 No use dbDelta because PHP v8.1 triggers an error when calling query "DESCRIBE {$table};" if the
260 * table doesn't exist.
261 */
262 protected function create_database_tables(): void {
263 global $wpdb;
264
265 $charset_collate = $wpdb->get_charset_collate();
266 // Hide errors.
267 $wpdb->hide_errors();
268 // Email log table.
269 $sql = "CREATE TABLE IF NOT EXISTS {$wpdb->base_prefix}defender_email_log (
270 `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
271 `timestamp` int NOT NULL,
272 `source` varchar(255) NOT NULL,
273 `to` varchar(255) NOT NULL,
274 PRIMARY KEY (`id`),
275 KEY `source` (`source`)
276 ) $charset_collate;";
277 $wpdb->query( $sql ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared, WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
278
279 // Audit log table. Though our data mainly store on API side, we will need a table for caching.
280 $sql = "CREATE TABLE IF NOT EXISTS {$wpdb->base_prefix}defender_audit_log (
281 `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
282 `timestamp` int NOT NULL,
283 `event_type` varchar(255) NOT NULL,
284 `action_type` varchar(255) NOT NULL,
285 `site_url` varchar(255) NOT NULL,
286 `user_id` int NOT NULL,
287 `context` varchar(255) NOT NULL,
288 `ip` varchar(45) NOT NULL,
289 `msg` varchar(255) NOT NULL,
290 `blog_id` int NOT NULL,
291 `synced` int NOT NULL,
292 `ttl` int NOT NULL,
293 PRIMARY KEY (`id`),
294 KEY `event_type` (`event_type`),
295 KEY `action_type` (`action_type`),
296 KEY `user_id` (`user_id`),
297 KEY `context` (`context`),
298 KEY `ip` (`ip`)
299 ) $charset_collate;";
300 $wpdb->query( $sql ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared, WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
301
302 // Scan item table.
303 $sql = "CREATE TABLE IF NOT EXISTS {$wpdb->base_prefix}defender_scan_item (
304 `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
305 `parent_id` int NOT NULL,
306 `type` varchar(255) NOT NULL,
307 `status` varchar(255) NOT NULL,
308 `raw_data` text NOT NULL,
309 PRIMARY KEY (`id`),
310 KEY `type` (`type`),
311 KEY `status` (`status`)
312 ) $charset_collate;";
313 $wpdb->query( $sql ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared, WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
314
315 // Scan table.
316 $sql = "CREATE TABLE IF NOT EXISTS {$wpdb->base_prefix}defender_scan (
317 `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
318 `percent` float NOT NULL,
319 `total_tasks` tinyint(4) NOT NULL,
320 `task_checkpoint` varchar(255) NOT NULL,
321 `status` varchar(255) NOT NULL,
322 `date_start` datetime NOT NULL,
323 `date_end` datetime NOT NULL,
324 `is_automation` bool NOT NULL,
325 PRIMARY KEY (`id`)
326 ) $charset_collate;";
327 $wpdb->query( $sql ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared, WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
328
329 // Lockout log table.
330 $sql = "CREATE TABLE IF NOT EXISTS {$wpdb->base_prefix}defender_lockout_log (
331 `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
332 `log` text,
333 `ip` varchar(45) DEFAULT NULL,
334 `date` int(11) DEFAULT NULL,
335 `type` varchar(16) DEFAULT NULL,
336 `user_agent` varchar(255) DEFAULT NULL,
337 `blog_id` int(11) DEFAULT NULL,
338 `tried` varchar(255),
339 `country_iso_code` char(2) DEFAULT NULL,
340 PRIMARY KEY (`id`),
341 KEY `ip` (`ip`),
342 KEY `type` (`type`),
343 KEY `tried` (`tried`),
344 KEY `country_iso_code` (`country_iso_code`)
345 ) $charset_collate;";
346 $wpdb->query( $sql ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared, WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
347
348 // Lockout table.
349 $sql = "CREATE TABLE IF NOT EXISTS {$wpdb->base_prefix}defender_lockout (
350 `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
351 `ip` varchar(45) DEFAULT NULL,
352 `status` varchar(16) DEFAULT NULL,
353 `lockout_message` text,
354 `release_time` int(11) DEFAULT NULL,
355 `lock_time` int(11) DEFAULT NULL,
356 `lock_time_404` int(11) DEFAULT NULL,
357 `attempt` int(11) DEFAULT NULL,
358 `attempt_404` int(11) DEFAULT NULL,
359 `meta` text,
360 PRIMARY KEY (`id`),
361 KEY `ip` (`ip`),
362 KEY `status` (`status`),
363 KEY `attempt` (`attempt`),
364 KEY `attempt_404` (`attempt_404`)
365 ) $charset_collate;";
366 $wpdb->query( $sql ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared, WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
367
368 $this->create_table_quarantine();
369
370 // Create Unlock table.
371 $this->create_table_unlockout();
372 // Create Blocklist table.
373 $this->create_table_blocklist();
374 }
375
376 /**
377 * Check if this is onboarding.
378 *
379 * @return bool
380 */
381 private function is_onboarding(): bool {
382 /**
383 * Display Onboarding if:
384 * it's a fresh install and there were no requests from the Hub before,
385 * after Reset Settings.
386 *
387 * @var HUB
388 */
389 $hub_class = wd_di()->get( HUB::class );
390 $hub_class->set_onboarding_status( Onboard_Model::maybe_show_onboarding() );
391
392 return $hub_class->get_onboarding_status() && ! defender_is_wp_cli();
393 }
394
395 /**
396 * Initialize the common modules of the application.
397 *
398 * @return void
399 */
400 private function init_modules_common(): void {
401 // Init main ORM.
402 Array_Cache::set( 'orm', new Mapper() );
403
404 if ( $this->is_onboarding() ) {
405 // If it's cli we should start this normally.
406 Array_Cache::set( 'onboard', wd_di()->get( Onboard::class ) );
407 } else {
408 // Initialize the main controllers of every module.
409 wd_di()->get( Dashboard::class );
410 }
411 wd_di()->get( Security_Tweaks::class );
412 wd_di()->get( Scan::class );
413 wd_di()->get( Audit_Logging::class );
414 wd_di()->get( Firewall_Controller::class );
415 wd_di()->get( WAF::class );
416 wd_di()->get( Two_Factor::class );
417 wd_di()->get( Advanced_Tools::class );
418 wd_di()->get( Mask_Login::class );
419 wd_di()->get( Security_Headers::class );
420 wd_di()->get( Recaptcha::class );
421 wd_di()->get( Notification::class );
422 wd_di()->get( Main_Setting::class );
423 wd_di()->get( Blocklist_Monitor::class );
424 wd_di()->get( Password_Protection::class );
425 wd_di()->get( Password_Reset::class );
426 wd_di()->get( Webauthn::class );
427 wd_di()->get( Expert_Services::class );
428 wd_di()->get( Hub_Connector_Controller::class );
429 wd_di()->get( Strong_Password::class );
430 wd_di()->get( Session_Protection::class );
431
432 if ( class_exists( 'WP_Defender\Controller\Quarantine' ) ) {
433 wd_di()->get( Quarantine::class );
434 }
435 wd_di()->get( Data_Tracking::class );
436 if ( defender_is_wp_org_version() ) {
437 wd_di()->get( Rate_Controller::class );
438 }
439
440 if ( is_multisite() ) {
441 wd_di()->get( Network_Cron_Manager::class );
442 }
443 }
444
445 /**
446 * Adds a specific class to the body tag if the current page is a Defender page.
447 *
448 * @param string $classes The existing body classes.
449 *
450 * @return string The modified body classes.
451 */
452 public function add_sui_to_body( $classes ) {
453 if ( ! is_defender_page() ) {
454 return $classes;
455 }
456 $classes .= sprintf( ' sui-%s ', DEFENDER_SUI );
457
458 return $classes;
459 }
460
461 /**
462 * Registers the necessary styles for the plugin.
463 *
464 * @return void
465 */
466 private function register_styles(): void {
467 wp_enqueue_style( 'defender-menu', WP_DEFENDER_BASE_URL . 'assets/css/defender-icon.css', array(), DEFENDER_VERSION );
468
469 $css_files = array(
470 'defender' => WP_DEFENDER_BASE_URL . 'assets/css/styles.css',
471 );
472
473 foreach ( $css_files as $slug => $file ) {
474 wp_register_style( $slug, $file, array(), DEFENDER_VERSION );
475 }
476 }
477
478 /**
479 * Registers the necessary scripts for the plugin.
480 *
481 * @return void
482 */
483 private function register_scripts(): void {
484 $base_url = WP_DEFENDER_BASE_URL;
485 $dependencies = array( 'def-vue', 'def-manifest', 'defender', 'wp-i18n' );
486 $js_files = array(
487 'wpmudev-sui' => array(
488 $base_url . 'assets/js/shared-ui.js',
489 ),
490 'defender' => array(
491 $base_url . 'assets/js/scripts.js',
492 ),
493 'def-vue' => array(
494 $base_url . 'assets/js/vendor.js',
495 ),
496 'def-manifest' => array(
497 $base_url . 'assets/js/manifest.js',
498 ),
499 'def-dashboard' => array(
500 $base_url . 'assets/app/dashboard.js',
501 $dependencies,
502 ),
503 'def-securitytweaks' => array(
504 $base_url . 'assets/app/security-tweak.js',
505 array_merge( $dependencies, array( 'clipboard', 'wpmudev-sui' ) ),
506 ),
507 'def-scan' => array(
508 $base_url . 'assets/app/scan.js',
509 array_merge( $dependencies, array( 'clipboard', 'wpmudev-sui' ) ),
510 ),
511 'def-audit' => array(
512 $base_url . 'assets/app/audit.js',
513 $dependencies,
514 ),
515 'def-iplockout' => array(
516 $base_url . 'assets/app/ip-lockout.js',
517 array_merge( $dependencies, array( 'wpmudev-sui' ) ),
518 ),
519 'def-advancedtools' => array(
520 $base_url . 'assets/app/advanced-tools.js',
521 $dependencies,
522 ),
523 'def-settings' => array(
524 $base_url . 'assets/app/settings.js',
525 $dependencies,
526 ),
527 'def-2fa' => array(
528 $base_url . 'assets/app/two-fa.js',
529 $dependencies,
530 ),
531 'def-notification' => array(
532 $base_url . 'assets/app/notification.js',
533 $dependencies,
534 ),
535 'def-waf' => array(
536 $base_url . 'assets/app/waf.js',
537 $dependencies,
538 ),
539 'def-onboard' => array(
540 $base_url . 'assets/app/onboard.js',
541 $dependencies,
542 ),
543 'def-expert-services' => array(
544 $base_url . '/assets/app/expert-services.js',
545 $dependencies,
546 ),
547 );
548
549 foreach ( $js_files as $slug => $file ) {
550 if ( isset( $file[1] ) ) {
551 wp_register_script( $slug, $file[0], $file[1], DEFENDER_VERSION, true );
552 wp_set_script_translations( $slug, 'defender-security' );
553 } else {
554 wp_register_script( $slug, $file[0], array( 'jquery' ), DEFENDER_VERSION, true );
555 }
556 }
557 }
558
559 /**
560 * Localizes the script by adding necessary data to the 'defender' object.
561 *
562 * @return void
563 */
564 private function localize_script(): void {
565 $wpmu_dev = new WPMUDEV();
566 global $wp_defender_central;
567
568 $misc = array();
569 $data_tracking = wd_di()->get( Data_Tracking::class );
570 $is_tracking = $data_tracking->show_tracking_modal();
571 if ( $is_tracking ) {
572 $misc = $data_tracking->get_tracking_modal();
573 }
574 $misc['high_contrast'] = defender_high_contrast();
575
576 if ( defender_is_wp_org_version() ) {
577 $misc['rating'] = array();
578 $rate_service = Rate_Component::is_achievement_displayed();
579 if ( $rate_service['is_displayed'] ) {
580 $misc['rating'] = wd_di()->get( Rate_Controller::class )->data_frontend();
581 $misc['rating']['text'] = Rate_Component::get_notice_by_slug( $rate_service['slug'] );
582 }
583
584 $misc['rating']['is_displayed'] = $rate_service['is_displayed'];
585 $misc['rating']['type'] = $rate_service['slug'];
586 } else {
587 $misc['rating']['is_displayed'] = false;
588 }
589
590 wp_localize_script(
591 'def-vue',
592 'defender',
593 array(
594 'whitelabel' => defender_white_label_status(),
595 'misc' => $misc,
596 'home_url' => network_home_url(),
597 'site_url' => network_site_url(),
598 'admin_url' => network_admin_url(),
599 'defender_url' => WP_DEFENDER_BASE_URL,
600 'is_free' => $wpmu_dev->is_pro() ? 0 : 1,
601 'is_membership' => true,
602 'is_whitelabel' => $wpmu_dev->is_whitelabel_enabled() ? 'enabled' : 'disabled',
603 'wpmu_dev_url_action' => $wpmu_dev->hide_wpmu_dev_urls() ? 'hide' : 'show',
604 'opcache_save_comments' => $wp_defender_central->is_opcache_save_comments_disabled() ? 'disabled' : 'enabled',
605 'opcache_message' => $wp_defender_central->display_opcache_message(),
606 'wpmudev_url' => WP_DEFENDER_DOCS_LINK,
607 'wpmudev_support_ticket_text' => defender_support_ticket_text(),
608 'wpmudev_api_base_url' => $wpmu_dev->get_api_base_url(),
609 'upgrade_title' => esc_html__( 'UPGRADE TO PRO', 'defender-security' ),
610 'tracking_modal' => $is_tracking ? 'show' : 'hide',
611 'hosted' => $wpmu_dev->is_wpmu_hosting(),
612 'file_upload_nonce' => wp_create_nonce( 'defender_file_upload' ),
613 'wpmudev_hub_link' => 'https://wpmudev.com/hub2/',
614 )
615 );
616
617 wp_localize_script( 'defender', 'defenderGetText', defender_gettext_translations() );
618 }
619
620 /**
621 * Register all core assets.
622 */
623 public function register_assets(): void {
624 $this->register_styles();
625 $this->register_scripts();
626 $this->localize_script();
627
628 do_action( 'defender_enqueue_assets' );
629 }
630
631 /**
632 * Trigger mandatory actions on activation.
633 */
634 private function on_activation(): void {
635 add_action(
636 'admin_init',
637 function () {
638 $security_tweaks = wd_di()->get( Security_Tweaks::class );
639 $security_tweaks->get_security_key()->cron_schedule();
640 }
641 );
642 }
643
644 /**
645 * Returns the cron schedules.
646 *
647 * @param array $schedules The existing cron schedules.
648 *
649 * @return array The updated cron schedules.
650 */
651 public function cron_schedules( array $schedules ) {
652 return defender_cron_schedules( $schedules );
653 }
654
655 /**
656 * Initialize the modules and register the plugin routes. Also include the admin class, adds WP-CLI commands.
657 *
658 * @return void
659 */
660 public function includes(): void {
661 // Initialize modules.
662 add_action(
663 'after_setup_theme',
664 function () {
665 add_filter( 'cron_schedules', array( $this, 'cron_schedules' ) );
666 $this->init_modules();
667 }
668 );
669 // Register routes.
670 add_action(
671 'init',
672 function () {
673 require_once WP_DEFENDER_DIR . 'src/routes.php';
674 },
675 9
676 );
677 // Register the Hub Connector early to handle the auth callback during the admin init hook.
678 add_action( 'plugins_loaded', array( wd_di()->get( Hub_Connector::class ), 'init' ) );
679 // Register the Cross-Sell module.
680 add_action( 'init', array( wd_di()->get( \WP_Defender\Component\Cross_Sell::class ), 'init' ), 9 );
681 // Include admin class. Don't use is_admin().
682 add_action( 'admin_init', array( ( new Admin() ), 'init' ) );
683 // Add WP-CLI commands.
684 if ( defender_is_wp_cli() ) {
685 WP_CLI::add_command( 'defender', Cli::class );
686 }
687 // Rotational logger initialization.
688 add_action( 'init', array( ( new Rotation_Logger() ), 'init' ), 99 );
689 // Handle plugin deactivation.
690 add_action( 'deactivated_plugin', array( ( new HUB() ), 'intercept_deactivate' ) );
691 }
692 }
693