| @@ -112,8 +112,9 @@ | ||
| 112 | 112 | // are registered on AJAX requests originating from the Tools tab. |
| 113 | 113 | // Guarded to AJAX only to prevent a duplicate admin menu entry on normal page loads. |
| 114 | 114 | if ( wp_doing_ajax() ) { |
| 115 | 115 | wd_di()->get( Firewall::class ); |
| 116 | + wd_di()->get( Audit_Logging::class ); | |
| 116 | 117 | } |
| 117 | 118 | } |
| 118 | 119 | |
| 119 | 120 | /** |
| @@ -182,8 +183,9 @@ | ||
| 182 | 183 | |
| 183 | 184 | // Include Module data for the Tools tab. |
| 184 | 185 | $scan_controller = wd_di()->get( Scan::class ); |
| 185 | 186 | $firewall_controller = wd_di()->get( Firewall::class ); |
| 187 | + $audit_logging_controller = wd_di()->get( Audit_Logging::class ); | |
| 186 | 188 | $blocklist_monitor_controller = wd_di()->get( Blocklist_Monitor::class ); |
| 187 | 189 | $notification_controller = wd_di()->get( Notification::class ); |
| 188 | 190 | $recipients_controller = wd_di()->get( Recipients::class ); |
| 189 | 191 | wp_localize_script( |
| @@ -195,8 +197,9 @@ | ||
| 195 | 197 | array( |
| 196 | 198 | 'settings' => array_merge( $data, array( 'security_headers' => $sh_data ) ), |
| 197 | 199 | 'scan' => $scan_controller->data_frontend(), |
| 198 | 200 | 'firewall' => $firewall_controller->data_frontend(), |
| 201 | + 'audit_logging' => $audit_logging_controller->settings_data_frontend(), | |
| 199 | 202 | 'blocklist_monitor' => $blocklist_monitor_controller->data_frontend(), |
| 200 | 203 | 'notification' => $notification_controller->data_frontend(), |
| 201 | 204 | 'recipients' => $recipients_controller->data_frontend(), |
| 202 | 205 | 'routes' => $routes, |
| @@ -206,9 +209,9 @@ | ||
| 206 | 209 | ); |
| 207 | 210 | |
| 208 | 211 | wp_enqueue_style( |
| 209 | 212 | $handle, |
| 210 | - WP_DEFENDER_BASE_URL . 'assets/css/showcase.css', | |
| 213 | + WP_DEFENDER_BASE_URL . 'assets/css/core-ui.css', | |
| 211 | 214 | array(), |
| 212 | 215 | DEFENDER_VERSION |
| 213 | 216 | ); |
| 214 | 217 | |
| @@ -393,9 +396,14 @@ | ||
| 393 | 396 | */ |
| 394 | 397 | public function import_data( array $data ) { |
| 395 | 398 | $model = $this->get_model(); |
| 396 | 399 | |
| 400 | + // Preserve Usage Tracking; it is a user privacy choice that a config must not change. | |
| 401 | + $current_usage_tracking = $model->usage_tracking; | |
| 402 | + | |
| 397 | 403 | $model->import( $data ); |
| 404 | + $model->usage_tracking = $current_usage_tracking; | |
| 405 | + | |
| 398 | 406 | if ( $model->validate() ) { |
| 399 | 407 | $model->save(); |
| 400 | 408 | } |
| 401 | 409 | } |
| @@ -409,9 +417,29 @@ | ||
| 409 | 417 | * |
| 410 | 418 | * @return bool Returns true if the importer data is valid, false otherwise. |
| 411 | 419 | */ |
| 412 | 420 | private function validate_importer( $importer ): bool { |
| 413 | - return $this->service->verify_config_data( $importer ); | |
| 421 | + if ( ! $this->service->verify_config_data( $importer ) || ! is_array( $importer['configs'] ) ) { | |
| 422 | + return false; | |
| 423 | + } | |
| 424 | + | |
| 425 | + $sample = $this->service->gather_data(); | |
| 426 | + foreach ( $importer['configs'] as $slug => $module ) { | |
| 427 | + // Ignore whole modules unavailable on this site, such as Pro-only modules in Free builds. | |
| 428 | + if ( ! isset( $sample[ $slug ] ) ) { | |
| 429 | + continue; | |
| 430 | + } | |
| 431 | + | |
| 432 | + if ( | |
| 433 | + ! is_array( $module ) | |
| 434 | + || ! is_array( $sample[ $slug ] ) | |
| 435 | + || array() !== array_diff_key( $module, $sample[ $slug ] ) | |
| 436 | + ) { | |
| 437 | + return false; | |
| 438 | + } | |
| 439 | + } | |
| 440 | + | |
| 441 | + return true; | |
| 414 | 442 | } |
| 415 | 443 | |
| 416 | 444 | /** |
| 417 | 445 | * Import config. |
| @@ -438,9 +466,8 @@ | ||
| 438 | 466 | ) |
| 439 | 467 | ); |
| 440 | 468 | } |
| 441 | 469 | |
| 442 | - | |
| 443 | 470 | if ( ! $this->validate_importer( $importer ) ) { |
| 444 | 471 | return new Response( |
| 445 | 472 | false, |
| 446 | 473 | array( |
| @@ -470,9 +497,9 @@ | ||
| 470 | 497 | 'configs' => $this->local_store->get_frontend_configs(), |
| 471 | 498 | ); |
| 472 | 499 | |
| 473 | 500 | if ( ! $this->wpmudev->is_pro() ) { |
| 474 | - $sample = $this->service->gather_data(); | |
| 501 | + $sample = $this->service->gather_data(); | |
| 475 | 502 | $pro_modules = array(); |
| 476 | 503 | |
| 477 | 504 | foreach ( $importer['configs'] as $slug => $module ) { |
| 478 | 505 | // Modules present in the imported config but NOT in Free's sample data are Pro-only. |
| @@ -480,21 +507,21 @@ | ||
| 480 | 507 | $pro_modules[] = $slug; |
| 481 | 508 | } |
| 482 | 509 | } |
| 483 | 510 | |
| 484 | - if ( ! empty( $pro_modules ) ) { | |
| 511 | + if ( array() !== $pro_modules ) { | |
| 485 | 512 | $module_names = array_map( |
| 486 | 513 | function ( $slug ) { |
| 487 | 514 | $names = array( |
| 488 | - 'audit' => esc_html__( 'Audit Logs', 'defender-security' ), | |
| 489 | - 'waf' => esc_html__( 'Web Application Firewall (WAF)', 'defender-security' ), | |
| 490 | - 'blocklist_monitor' => esc_html__( 'Blocklist Monitor', 'defender-security' ), | |
| 491 | - 'pwned_passwords' => esc_html__( 'Pwned Passwords', 'defender-security' ), | |
| 515 | + 'audit' => esc_html__( 'Audit Logs', 'defender-security' ), | |
| 516 | + 'waf' => esc_html__( 'Web Application Firewall (WAF)', 'defender-security' ), | |
| 517 | + 'blocklist_monitor' => esc_html__( 'Blocklist Monitor', 'defender-security' ), | |
| 518 | + 'pwned_passwords' => esc_html__( 'Pwned Passwords', 'defender-security' ), | |
| 492 | 519 | 'force_strong_password' => esc_html__( 'Strong Passwords', 'defender-security' ), |
| 493 | - 'session_protection' => esc_html__( 'Session Protection', 'defender-security' ), | |
| 494 | - 'two_factor' => esc_html__( 'Two-Factor Authentication', 'defender-security' ), | |
| 495 | - 'mask_login' => esc_html__( 'Hide Login URL', 'defender-security' ), | |
| 496 | - 'security_headers' => esc_html__( 'Security Policies', 'defender-security' ), | |
| 520 | + 'session_protection' => esc_html__( 'Session Protection', 'defender-security' ), | |
| 521 | + 'two_factor' => esc_html__( 'Two-Factor Authentication', 'defender-security' ), | |
| 522 | + 'mask_login' => esc_html__( 'Hide Login URL', 'defender-security' ), | |
| 523 | + 'security_headers' => esc_html__( 'Security Policies', 'defender-security' ), | |
| 497 | 524 | ); |
| 498 | 525 | |
| 499 | 526 | return $names[ $slug ] ?? $slug; |
| 500 | 527 | }, |
| @@ -1182,20 +1209,20 @@ | ||
| 1182 | 1209 | return $key; |
| 1183 | 1210 | } |
| 1184 | 1211 | |
| 1185 | 1212 | /** |
| 1186 | - * Generates an error message for when there is an issue applying some tweaks from the Recommendations tab. | |
| 1213 | + * Generates an error message for when there is an issue applying some tweaks from the Hardening tab. | |
| 1187 | 1214 | * |
| 1188 | 1215 | * @return Response The response object containing the error message and fresh frontend configurations. |
| 1189 | 1216 | */ |
| 1190 | 1217 | private function apply_config_recommendations_error_message(): Response { |
| 1191 | 1218 | $message = sprintf( |
| 1192 | - /* translators: 1: Recommendations tab, 2: wp-config.php file, 3: Documentation. */ | |
| 1219 | + /* translators: 1: Hardening tab, 2: wp-config.php file, 3: Documentation. */ | |
| 1193 | 1220 | esc_html__( |
| 1194 | 1221 | 'There was an issue with applying some of the tweaks from the %1$s tab because we cannot make changes to your %2$s file. Please see our %3$s to apply the changes manually.', |
| 1195 | 1222 | 'defender-security' |
| 1196 | 1223 | ), |
| 1197 | - '<strong>' . esc_html__( 'Recommendations', 'defender-security' ) . '</strong>', | |
| 1224 | + '<strong>' . esc_html__( 'Hardening', 'defender-security' ) . '</strong>', | |
| 1198 | 1225 | '<strong>' . esc_html__( 'wp-config.php', 'defender-security' ) . '</strong>', |
| 1199 | 1226 | '<a href="' . WP_DEFENDER_DOCS_LINK . '#manually-applying-recommendations" target="_blank">' . esc_html__( 'documentation', 'defender-security' ) . '</a>' |
| 1200 | 1227 | ); |
| 1201 | 1228 | |