| @@ -6,11 +6,16 @@ | ||
| 6 | 6 | */ |
| 7 | 7 | |
| 8 | 8 | namespace WP_Defender\Controller; |
| 9 | 9 | |
| 10 | +use WP_Defender\Component\Audit; | |
| 10 | 11 | use WP_Defender\Event; |
| 11 | 12 | use Calotes\Helper\HTTP; |
| 12 | 13 | use Calotes\Helper\Route; |
| 14 | +use WP_Defender\Model\Setting\Login_Lockout; | |
| 15 | +use WP_Defender\Model\Setting\Notfound_Lockout; | |
| 16 | +use WP_Defender\Model\Setting\User_Agent_Lockout; | |
| 17 | +use WP_Defender\Traits\Defender_Dashboard_Client; | |
| 13 | 18 | use WP_Defender\Traits\IO; |
| 14 | 19 | use Calotes\Component\Request; |
| 15 | 20 | use Calotes\Component\Response; |
| 16 | 21 | use WP_Defender\Traits\Formats; |
| @@ -15,14 +20,16 @@ | ||
| 15 | 20 | use Calotes\Component\Response; |
| 16 | 21 | use WP_Defender\Traits\Formats; |
| 17 | 22 | use WP_Defender\Behavior\WPMUDEV; |
| 18 | 23 | use WP_Defender\Component\Feature_Modal; |
| 19 | -use WP_Defender\Controller\Hub_Connector; | |
| 24 | +use WP_Defender\Component\Hub_Connector as Hub_Connector_Component; | |
| 25 | +use WP_Defender\Model\Setting\Audit_Logging as Audit_Logging_Settings; | |
| 26 | +use WP_Defender\Model\Audit_Log; | |
| 20 | 27 | use WP_Defender\Model\Setting\Global_Ip_Lockout; |
| 21 | 28 | use WP_Defender\Component\Config\Config_Hub_Helper; |
| 22 | 29 | use WP_Defender\Component\IP\Global_IP as Global_IP_Component; |
| 23 | -use WP_Defender\Controller\Antibot_Global_Firewall; | |
| 24 | 30 | use WP_Defender\Model\Setting\Session_Protection; |
| 31 | +use WP_Defender\Controller\Session_Protection as Session_Protection_Controller; | |
| 25 | 32 | |
| 26 | 33 | /** |
| 27 | 34 | * Handles the main admin page. |
| 28 | 35 | */ |
| @@ -29,8 +36,9 @@ | ||
| 29 | 36 | class Dashboard extends Event { |
| 30 | 37 | |
| 31 | 38 | use IO; |
| 32 | 39 | use Formats; |
| 40 | + use Defender_Dashboard_Client; | |
| 33 | 41 | |
| 34 | 42 | /** |
| 35 | 43 | * The slug identifier for this controller. |
| 36 | 44 | * |
| @@ -38,8 +46,18 @@ | ||
| 38 | 46 | */ |
| 39 | 47 | public $slug = 'wp-defender'; |
| 40 | 48 | |
| 41 | 49 | /** |
| 50 | + * Site option key for the one-time report-schedule upgrade notice. | |
| 51 | + */ | |
| 52 | + public const REPORT_SCHEDULE_NOTICE_OPTION = 'wd_show_report_schedule_notice'; | |
| 53 | + | |
| 54 | + /** | |
| 55 | + * Site-wide dismissal key for the Dashboard plugin required modal. | |
| 56 | + */ | |
| 57 | + public const DASHBOARD_REQUIRED_NOTICE_OPTION = 'wpdef_dashboard_required_notice_dismissed'; | |
| 58 | + | |
| 59 | + /** | |
| 42 | 60 | * Initializes the model and service, registers routes, and sets up scheduled events if the model is active. |
| 43 | 61 | */ |
| 44 | 62 | public function __construct() { |
| 45 | 63 | $this->attach_behavior( WPMUDEV::class, WPMUDEV::class ); |
| @@ -47,8 +65,9 @@ | ||
| 47 | 65 | $this->register_routes(); |
| 48 | 66 | add_action( 'defender_enqueue_assets', array( $this, 'enqueue_assets' ) ); |
| 49 | 67 | add_filter( 'custom_menu_order', '__return_true' ); |
| 50 | 68 | add_filter( 'menu_order', array( $this, 'menu_order' ) ); |
| 69 | + add_filter( 'plugins_api', array( $this, 'filter_dashboard_plugin_info' ), 101, 3 ); | |
| 51 | 70 | add_action( 'admin_init', array( $this, 'maybe_redirect_notification_request' ), 99 ); |
| 52 | 71 | } |
| 53 | 72 | |
| 54 | 73 | /** |
| @@ -53,11 +72,11 @@ | ||
| 53 | 72 | |
| 54 | 73 | /** |
| 55 | 74 | * Because we move the notifications on separate modules, so links from HUB should be redirected to correct URL. |
| 56 | 75 | * |
| 57 | - * @return void|null | |
| 76 | + * @return void | |
| 58 | 77 | */ |
| 59 | - public function maybe_redirect_notification_request() { | |
| 78 | + public function maybe_redirect_notification_request(): void { | |
| 60 | 79 | $page = HTTP::get( 'page' ); |
| 61 | 80 | if ( ! in_array( $page, array( 'wdf-scan', 'wdf-ip-lockout', 'wdf-hardener', 'wdf-logging' ), true ) ) { |
| 62 | 81 | return; |
| 63 | 82 | } |
| @@ -77,11 +96,12 @@ | ||
| 77 | 96 | */ |
| 78 | 97 | public function menu_order( $menu_order ) { |
| 79 | 98 | global $submenu; |
| 80 | 99 | if ( isset( $submenu['wp-defender'] ) ) { |
| 81 | - $defender_menu = $submenu['wp-defender']; | |
| 82 | - $defender_menu[0][0] = esc_html__( 'Dashboard', 'defender-security' ); | |
| 83 | - $defender_menu = array_values( $defender_menu ); | |
| 100 | + $defender_menu = $submenu['wp-defender']; | |
| 101 | + $defender_menu[0][0] = esc_html__( 'Dashboard', 'defender-security' ); | |
| 102 | + $defender_menu = array_values( $defender_menu ); | |
| 103 | + // Change the global $submenu variable, because otherwise the menu name/order will not change. | |
| 84 | 104 | $submenu['wp-defender'] = $defender_menu; // phpcs:ignore WordPress.WP.GlobalVariablesOverride.Prohibited |
| 85 | 105 | } |
| 86 | 106 | |
| 87 | 107 | global $menu; |
| @@ -88,12 +108,13 @@ | ||
| 88 | 108 | // Get the total scanning active issues. |
| 89 | 109 | $count = wd_di()->get( \WP_Defender\Component\Scan::class )->indicator_issue_count(); |
| 90 | 110 | |
| 91 | 111 | $indicator = $count > 0 |
| 92 | - ? ' <span class="update-plugins wd-issue-indicator-sidebar"><span class="plugin-count">' . $count . '</span></span>' | |
| 112 | + ? ' <span class="update-plugins wd-issue-indicator-sidebar"></span>' | |
| 93 | 113 | : null; |
| 94 | 114 | foreach ( $menu as $k => $item ) { |
| 95 | 115 | if ( 'wp-defender' === $item[2] ) { |
| 116 | + // Add a badge next to the "Defender" menu item in the global $menu variable. | |
| 96 | 117 | $menu[ $k ][0] .= $indicator; // phpcs:ignore WordPress.WP.GlobalVariablesOverride.Prohibited |
| 97 | 118 | } |
| 98 | 119 | } |
| 99 | 120 | |
| @@ -104,16 +125,14 @@ | ||
| 104 | 125 | * Registers the main page in the WordPress admin menu. |
| 105 | 126 | */ |
| 106 | 127 | protected function add_main_page() { |
| 107 | 128 | $this->register_page( |
| 108 | - $this->get_menu_title(), | |
| 129 | + $this->get_page_title(), | |
| 109 | 130 | $this->parent_slug, |
| 110 | - array( | |
| 111 | - &$this, | |
| 112 | - 'main_view', | |
| 113 | - ), | |
| 131 | + array( $this, 'main_view' ), | |
| 114 | 132 | null, |
| 115 | - $this->get_menu_icon() | |
| 133 | + $this->get_menu_icon(), | |
| 134 | + $this->get_menu_title() | |
| 116 | 135 | ); |
| 117 | 136 | } |
| 118 | 137 | |
| 119 | 138 | /** |
| @@ -123,8 +142,68 @@ | ||
| 123 | 142 | $this->render( 'main' ); |
| 124 | 143 | } |
| 125 | 144 | |
| 126 | 145 | /** |
| 146 | + * Page-specific data for a concrete controller. | |
| 147 | + * | |
| 148 | + * @return array | |
| 149 | + */ | |
| 150 | + protected function get_page_data(): array { | |
| 151 | + $security_tweaks = wd_di()->get( \WP_Defender\Controller\Security_Tweaks::class ); | |
| 152 | + $security_tweaks->refresh_tweaks_status(); | |
| 153 | + $security_tweaks_data = $security_tweaks->dashboard_widget(); | |
| 154 | + | |
| 155 | + $audit_model = wd_di()->get( Audit_Logging_Settings::class ); | |
| 156 | + $enabled_audit = $audit_model->is_active(); | |
| 157 | + // Audit summary. | |
| 158 | + $audit_events_logged = 0; | |
| 159 | + $last_event_time = esc_html__( '-', 'defender-security' ); | |
| 160 | + if ( $enabled_audit ) { | |
| 161 | + $audit_events_logged = Audit::get_audit_events_per_week(); | |
| 162 | + $audit_last = Audit_Log::get_last(); | |
| 163 | + if ( is_object( $audit_last ) ) { | |
| 164 | + $last_event_time = $this->get_date( $audit_last->timestamp ); | |
| 165 | + } | |
| 166 | + } | |
| 167 | + | |
| 168 | + // Firewall summary. | |
| 169 | + $firewall = wd_di()->get( Firewall::class )->get_summary(); | |
| 170 | + // Different lockout types. | |
| 171 | + $enabled_login = wd_di()->get( Login_Lockout::class )->enabled; | |
| 172 | + $enabled_nf = wd_di()->get( Notfound_Lockout::class )->enabled; | |
| 173 | + $enabled_ua = wd_di()->get( User_Agent_Lockout::class )->enabled; | |
| 174 | + | |
| 175 | + return array( | |
| 176 | + 'defenderSetupNonce' => wp_create_nonce( 'defender_quick_setup' ), | |
| 177 | + 'securityTweaks' => $security_tweaks_data['summary']['issues_count'], | |
| 178 | + 'scanData' => array( | |
| 179 | + 'numberIssues' => wd_di()->get( \WP_Defender\Component\Scan::class )->indicator_issue_count(), | |
| 180 | + 'settings' => wd_di()->get( \WP_Defender\Model\Setting\Scan::class )->export(), | |
| 181 | + // Scan routes & nonces are set above. | |
| 182 | + ), | |
| 183 | + 'firewallData' => array( | |
| 184 | + 'enabledLocalFirewall' => $enabled_login || $enabled_nf || $enabled_ua, | |
| 185 | + 'enabledLogin' => $enabled_login, | |
| 186 | + 'enabledNotFound' => $enabled_nf, | |
| 187 | + 'enabledUserAgent' => $enabled_ua, | |
| 188 | + 'loginLockoutMonth' => $firewall['lockout_login_this_month'], | |
| 189 | + 'nfLockoutMonth' => $firewall['lockout_404_this_month'], | |
| 190 | + 'uaLockoutMonth' => $firewall['lockout_ua_this_month'], | |
| 191 | + 'antibot' => wd_di()->get( Antibot_Global_Firewall::class )->data_frontend(), | |
| 192 | + ), | |
| 193 | + 'site_id' => wd_di()->get( WPMUDEV::class )->get_site_id(), | |
| 194 | + 'auditData' => array( | |
| 195 | + 'enabled' => $enabled_audit, | |
| 196 | + 'eventsLogged' => $audit_events_logged, | |
| 197 | + 'lastEvent' => $last_event_time, | |
| 198 | + ), | |
| 199 | + 'sessionProtection' => wd_di()->get( Session_Protection::class )->export(), | |
| 200 | + 'showReportScheduleNotice' => ! defender_is_wp_org_version() | |
| 201 | + && (bool) get_site_option( self::REPORT_SCHEDULE_NOTICE_OPTION, false ), | |
| 202 | + ); | |
| 203 | + } | |
| 204 | + | |
| 205 | + /** | |
| 127 | 206 | * Enqueues scripts and styles for this page. |
| 128 | 207 | * Only enqueues assets if the page is active. |
| 129 | 208 | */ |
| 130 | 209 | public function enqueue_assets() { |
| @@ -130,18 +209,197 @@ | ||
| 130 | 209 | public function enqueue_assets() { |
| 131 | 210 | if ( ! $this->is_page_active() ) { |
| 132 | 211 | return; |
| 133 | 212 | } |
| 213 | + | |
| 214 | + $wizard_action = HTTP::get( 'wizard_action' ); | |
| 215 | + $wizard_source = HTTP::get( 'source' ); | |
| 216 | + $nonce = HTTP::get( '_wpnonce' ); | |
| 217 | + | |
| 218 | + // Fallback completion marker for setup wizard integrations rendered on dashboard. | |
| 219 | + // This prevents onboarding loops if client-side completion request fails. | |
| 220 | + if ( | |
| 221 | + 'setup_wizard' === $wizard_source | |
| 222 | + && in_array( $wizard_action, array( 'view_results', 'close_wizard', 'finish_wizard' ), true ) | |
| 223 | + && current_user_can( 'manage_options' ) | |
| 224 | + && is_string( $nonce ) | |
| 225 | + && false !== wp_verify_nonce( $nonce, 'wpdef_setup_wizard' ) | |
| 226 | + ) { | |
| 227 | + update_site_option( 'wp_defender_shown_activator', true ); | |
| 228 | + } | |
| 229 | + | |
| 230 | + $show_onboarding = \WP_Defender\Model\Onboard::maybe_show_onboarding(); | |
| 231 | + $api_error = HTTP::get( 'api_error' ); | |
| 232 | + $hub_connection_source = HTTP::get( 'hub_connection_source' ); | |
| 233 | + $hub_connect_recovery = ! $show_onboarding | |
| 234 | + && is_string( $api_error ) | |
| 235 | + && '' !== $api_error | |
| 236 | + && 'profile_menu' !== $hub_connection_source | |
| 237 | + && ! Hub_Connector_Component::is_logged_in() | |
| 238 | + && ! Hub_Connector_Component::is_wpmudev_dashboard_connected(); | |
| 239 | + | |
| 240 | + if ( $show_onboarding || $hub_connect_recovery ) { | |
| 241 | + add_filter( 'admin_body_class', array( $this, 'admin_body_class' ) ); | |
| 242 | + } | |
| 243 | + | |
| 244 | + $handle = 'defender-ui-dashboard'; | |
| 245 | + wp_enqueue_script( | |
| 246 | + $handle, | |
| 247 | + WP_DEFENDER_BASE_URL . 'assets/js/dashboard-ui.js', | |
| 248 | + array( 'def-vue', 'def-manifest', 'def-core-ui', 'defender', 'wp-i18n' ), | |
| 249 | + DEFENDER_VERSION, | |
| 250 | + true | |
| 251 | + ); | |
| 252 | + wp_set_script_translations( $handle, 'wpdef' ); | |
| 253 | + | |
| 254 | + $setup_wizard_data = wd_di()->get( Setup_Wizard::class )->data_frontend(); | |
| 255 | + $tracking_data = wd_di()->get( Data_Tracking::class )->get_dashboard_notice_data(); | |
| 256 | + $dashboard_data = $this->dump_routes_and_nonces(); | |
| 257 | + $firewall_data = wd_di()->get( Firewall::class )->dump_routes_and_nonces(); | |
| 258 | + $scan_data = wd_di()->get( \WP_Defender\Controller\Scan::class )->dump_routes_and_nonces(); | |
| 259 | + $routes = array_merge( | |
| 260 | + $setup_wizard_data['routes'] ?? array(), | |
| 261 | + $tracking_data['routes'] ?? array(), | |
| 262 | + $dashboard_data['routes'] ?? array(), | |
| 263 | + $firewall_data['routes'] ?? array(), | |
| 264 | + $scan_data['routes'] ?? array(), | |
| 265 | + ); | |
| 266 | + $nonces = array_merge( | |
| 267 | + $setup_wizard_data['nonces'] ?? array(), | |
| 268 | + $tracking_data['nonces'] ?? array(), | |
| 269 | + $dashboard_data['nonces'] ?? array(), | |
| 270 | + $firewall_data['nonces'] ?? array(), | |
| 271 | + $scan_data['nonces'] ?? array(), | |
| 272 | + ); | |
| 273 | + unset( $setup_wizard_data['routes'], $setup_wizard_data['nonces'] ); | |
| 274 | + unset( $tracking_data['routes'], $tracking_data['nonces'] ); | |
| 275 | + unset( $firewall_data['routes'], $firewall_data['nonces'] ); | |
| 134 | 276 | wp_localize_script( |
| 135 | - 'def-dashboard', | |
| 136 | - 'dashboard', | |
| 137 | - array_merge( $this->data_frontend(), $this->dump_routes_and_nonces() ) | |
| 277 | + $handle, | |
| 278 | + 'defenderUIData', | |
| 279 | + array_merge( | |
| 280 | + $this->get_shared_data(), | |
| 281 | + $this->get_page_data(), | |
| 282 | + // Welcome modal's details. | |
| 283 | + wd_di()->get( Feature_Modal::class )->get_dashboard_modals(), | |
| 284 | + // Specific data. | |
| 285 | + array( | |
| 286 | + 'showOnboarding' => $show_onboarding, | |
| 287 | + 'dashboardRequiredNotice' => $this->get_dashboard_required_notice_data(), | |
| 288 | + 'routes' => $routes, | |
| 289 | + 'nonces' => $nonces, | |
| 290 | + ), | |
| 291 | + $setup_wizard_data, | |
| 292 | + $tracking_data, | |
| 293 | + wd_di()->get( \WP_Defender\Controller\Scan::class )->get_initial_scan_data() | |
| 294 | + ) | |
| 138 | 295 | ); |
| 139 | - wp_enqueue_script( 'def-dashboard' ); | |
| 296 | + | |
| 297 | + wp_enqueue_style( | |
| 298 | + $handle, | |
| 299 | + WP_DEFENDER_BASE_URL . 'assets/css/core-ui.css', | |
| 300 | + array(), | |
| 301 | + DEFENDER_VERSION | |
| 302 | + ); | |
| 303 | + | |
| 140 | 304 | $this->enqueue_main_assets(); |
| 141 | 305 | } |
| 142 | 306 | |
| 143 | 307 | /** |
| 308 | + * Get the state and action URLs for the Dashboard plugin required modal. | |
| 309 | + * | |
| 310 | + * @return array | |
| 311 | + */ | |
| 312 | + private function get_dashboard_required_notice_data(): array { | |
| 313 | + return array( | |
| 314 | + 'isProPlugin' => WP_DEFENDER_PRO_PATH === DEFENDER_PLUGIN_BASENAME, | |
| 315 | + 'dashboardActive' => $this->is_dash_activated(), | |
| 316 | + 'dashboardInstalled' => $this->is_dash_installed(), | |
| 317 | + 'dashboardPageUrl' => network_admin_url( 'admin.php?page=wpmudev' ), | |
| 318 | + 'activateUrl' => add_query_arg( | |
| 319 | + array( | |
| 320 | + '_wpnonce' => wp_create_nonce( 'activate-plugin_wpmudev-updates/update-notifications.php' ), | |
| 321 | + 'action' => 'activate', | |
| 322 | + 'plugin' => 'wpmudev-updates/update-notifications.php', | |
| 323 | + ), | |
| 324 | + network_admin_url( 'plugins.php' ) | |
| 325 | + ), | |
| 326 | + 'installUrl' => add_query_arg( | |
| 327 | + array( | |
| 328 | + '_wpnonce' => wp_create_nonce( 'install-plugin_install_wpmudev_dash' ), | |
| 329 | + 'action' => 'install-plugin', | |
| 330 | + 'plugin' => 'install_wpmudev_dash', | |
| 331 | + ), | |
| 332 | + network_admin_url( 'update.php' ) | |
| 333 | + ), | |
| 334 | + 'dismissed' => (bool) get_site_option( self::DASHBOARD_REQUIRED_NOTICE_OPTION, false ), | |
| 335 | + ); | |
| 336 | + } | |
| 337 | + | |
| 338 | + /** | |
| 339 | + * Supply WordPress with the WPMU DEV Dashboard package details. | |
| 340 | + * | |
| 341 | + * @param mixed $result Existing Plugins API result. | |
| 342 | + * @param string $action Requested Plugins API action. | |
| 343 | + * @param object $args Requested plugin arguments. | |
| 344 | + * | |
| 345 | + * @return mixed | |
| 346 | + */ | |
| 347 | + public function filter_dashboard_plugin_info( $result, $action, $args ) { | |
| 348 | + if ( | |
| 349 | + 'plugin_information' !== $action | |
| 350 | + || ! is_object( $args ) | |
| 351 | + || ! isset( $args->slug ) | |
| 352 | + || '' === trim( (string) $args->slug ) | |
| 353 | + || false === strpos( $args->slug, 'install_wpmudev_dash' ) | |
| 354 | + ) { | |
| 355 | + return $result; | |
| 356 | + } | |
| 357 | + | |
| 358 | + $plugin = new \stdClass(); | |
| 359 | + $plugin->name = 'WPMU DEV Dashboard'; | |
| 360 | + $plugin->slug = 'wpmu-dev-dashboard'; | |
| 361 | + $plugin->version = ''; | |
| 362 | + $plugin->rating = 100; | |
| 363 | + $plugin->homepage = 'https://wpmudev.com/project/wpmu-dev-dashboard/'; | |
| 364 | + $plugin->download_link = 'https://wpmudev.com/api/dashboard/v1/download-dashboard'; | |
| 365 | + $plugin->tested = get_bloginfo( 'version' ); | |
| 366 | + | |
| 367 | + return $plugin; | |
| 368 | + } | |
| 369 | + | |
| 370 | + /** | |
| 371 | + * Adds onboarding body classes on dashboard when onboarding wizard is active. | |
| 372 | + * | |
| 373 | + * @param string $classes Existing admin body classes. | |
| 374 | + * | |
| 375 | + * @return string | |
| 376 | + */ | |
| 377 | + public function admin_body_class( $classes ): string { | |
| 378 | + $classes .= ' wdf-onboarding-active '; | |
| 379 | + | |
| 380 | + return $classes; | |
| 381 | + } | |
| 382 | + | |
| 383 | + /** | |
| 384 | + * Returns the current hardening (security tweaks) issue count via AJAX. | |
| 385 | + * | |
| 386 | + * @return Response | |
| 387 | + * @defender_route | |
| 388 | + * @defender_redirect | |
| 389 | + */ | |
| 390 | + public function get_hardening_count(): Response { | |
| 391 | + $security_tweaks = wd_di()->get( \WP_Defender\Controller\Security_Tweaks::class )->dashboard_widget(); | |
| 392 | + | |
| 393 | + return new Response( | |
| 394 | + true, | |
| 395 | + array( | |
| 396 | + 'count' => (int) ( $security_tweaks['summary']['issues_count'] ?? 0 ), | |
| 397 | + ) | |
| 398 | + ); | |
| 399 | + } | |
| 400 | + | |
| 401 | + /** | |
| 144 | 402 | * Handles the request to hide new features modal. |
| 145 | 403 | * |
| 146 | 404 | * @param Request $request The request object containing data. |
| 147 | 405 | * |
| @@ -225,12 +483,74 @@ | ||
| 225 | 483 | return new Response( true, array() ); |
| 226 | 484 | } |
| 227 | 485 | |
| 228 | 486 | /** |
| 487 | + * Dismiss the one-time report-schedule notice set during the 6.1.0 upgrade. | |
| 488 | + * | |
| 489 | + * @return Response | |
| 490 | + * @defender_route | |
| 491 | + */ | |
| 492 | + public function dismiss_report_schedule_notice(): Response { | |
| 493 | + delete_site_option( self::REPORT_SCHEDULE_NOTICE_OPTION ); | |
| 494 | + | |
| 495 | + return new Response( true, array() ); | |
| 496 | + } | |
| 497 | + | |
| 498 | + /** | |
| 499 | + * Permanently dismiss the Dashboard plugin required modal for this site. | |
| 500 | + * | |
| 501 | + * @return Response | |
| 502 | + * @defender_route | |
| 503 | + */ | |
| 504 | + public function dismiss_dashboard_required_notice(): Response { | |
| 505 | + update_site_option( self::DASHBOARD_REQUIRED_NOTICE_OPTION, true ); | |
| 506 | + | |
| 507 | + return new Response( true, array() ); | |
| 508 | + } | |
| 509 | + | |
| 510 | + /** | |
| 511 | + * Toggle a dashboard feature by feature key. | |
| 512 | + * | |
| 513 | + * @param Request $request The current request data. | |
| 514 | + * | |
| 515 | + * @return Response | |
| 516 | + * @defender_route | |
| 517 | + */ | |
| 518 | + public function toggle_feature( Request $request ): Response { | |
| 519 | + $data = $request->get_data( | |
| 520 | + array( | |
| 521 | + 'feature' => array( | |
| 522 | + 'type' => 'string', | |
| 523 | + 'sanitize' => 'sanitize_text_field', | |
| 524 | + ), | |
| 525 | + ) | |
| 526 | + ); | |
| 527 | + $feature = $data['feature'] ?? ''; | |
| 528 | + | |
| 529 | + $feature_controllers = array( | |
| 530 | + 'antibot' => Antibot_Global_Firewall::class, | |
| 531 | + 'audit' => Audit_Logging::class, | |
| 532 | + 'session_protection' => Session_Protection_Controller::class, | |
| 533 | + ); | |
| 534 | + if ( isset( $feature_controllers[ $feature ] ) ) { | |
| 535 | + return wd_di()->get( $feature_controllers[ $feature ] )->save_settings( $request ); | |
| 536 | + } | |
| 537 | + | |
| 538 | + return new Response( | |
| 539 | + false, | |
| 540 | + array( | |
| 541 | + 'message' => esc_html__( 'Unsupported feature toggle request.', 'defender-security' ), | |
| 542 | + ) | |
| 543 | + ); | |
| 544 | + } | |
| 545 | + | |
| 546 | + /** | |
| 229 | 547 | * Removes settings for all submodules. |
| 230 | 548 | */ |
| 231 | 549 | public function remove_settings() { |
| 232 | 550 | wd_di()->get( Feature_Modal::class )->upgrade_site_options(); |
| 551 | + | |
| 552 | + delete_site_option( self::REPORT_SCHEDULE_NOTICE_OPTION ); | |
| 233 | 553 | } |
| 234 | 554 | |
| 235 | 555 | /** |
| 236 | 556 | * Delete all the data & the cache. |
| @@ -235,8 +555,9 @@ | ||
| 235 | 555 | /** |
| 236 | 556 | * Delete all the data & the cache. |
| 237 | 557 | */ |
| 238 | 558 | public function remove_data() { |
| 559 | + delete_site_option( self::DASHBOARD_REQUIRED_NOTICE_OPTION ); | |
| 239 | 560 | } |
| 240 | 561 | |
| 241 | 562 | /** |
| 242 | 563 | * Provides data for the frontend. |
| @@ -251,26 +572,22 @@ | ||
| 251 | 572 | wd_di()->get( Feature_Modal::class )->get_dashboard_modals(), |
| 252 | 573 | array( |
| 253 | 574 | 'scan' => wd_di()->get( Scan::class )->data_frontend(), |
| 254 | 575 | 'firewall' => $firewall->data_frontend(), |
| 255 | - 'waf' => wd_di()->get( WAF::class )->data_frontend(), | |
| 256 | - 'audit' => wd_di()->get( Audit_Logging::class )->data_frontend(), | |
| 576 | + 'blocklist_monitor' => wd_di()->get( Blocklist_Monitor::class )->data_frontend(), | |
| 257 | 577 | 'blacklist' => array( |
| 258 | 578 | 'nonces' => $nonces, |
| 259 | 579 | 'endpoints' => $endpoints, |
| 260 | 580 | ), |
| 261 | - 'blocklist_monitor' => wd_di()->get( Blocklist_Monitor::class )->data_frontend(), | |
| 262 | 581 | 'two_fa' => wd_di()->get( Two_Factor::class )->data_frontend(), |
| 263 | 582 | 'advanced_tools' => array( |
| 264 | - 'mask_login' => wd_di()->get( Mask_Login::class )->dashboard_widget(), | |
| 265 | - 'security_headers' => wd_di()->get( Security_Headers::class )->dashboard_widget(), | |
| 266 | - 'pwned_passwords' => wd_di()->get( Password_Protection::class )->dashboard_widget(), | |
| 267 | - 'recaptcha' => wd_di()->get( Recaptcha::class )->dashboard_widget(), | |
| 268 | - 'strong_passwords' => wd_di()->get( Strong_Password::class )->dashboard_widget(), | |
| 269 | - 'session_protection' => wd_di()->get( Session_Protection::class )->export(), | |
| 583 | + 'mask_login' => wd_di()->get( Mask_Login::class )->dashboard_widget(), | |
| 584 | + 'security_headers' => wd_di()->get( Security_Headers::class )->dashboard_widget(), | |
| 585 | + 'pwned_passwords' => wd_di()->get( Password_Protection::class )->dashboard_widget(), | |
| 586 | + 'captcha' => wd_di()->get( Captcha::class )->dashboard_widget(), | |
| 587 | + 'strong_passwords' => wd_di()->get( Strong_Password::class )->dashboard_widget(), | |
| 270 | 588 | ), |
| 271 | 589 | 'security_tweaks' => wd_di()->get( Security_Tweaks::class )->dashboard_widget(), |
| 272 | - 'tutorials' => wd_di()->get( Tutorial::class )->data_frontend(), | |
| 273 | 590 | 'notifications' => wd_di()->get( Notification::class )->data_frontend(), |
| 274 | 591 | 'settings' => wd_di()->get( Main_Setting::class )->data_frontend(), |
| 275 | 592 | 'countries' => $firewall->dashboard_widget(), |
| 276 | 593 | 'global_ip' => wd_di()->get( Global_Ip::class )->data_frontend(), |