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

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