| @@ -12,10 +12,12 @@ | ||
| 12 | 12 | use Calotes\Component\Response; |
| 13 | 13 | use WP_Defender\Traits\Setting; |
| 14 | 14 | use WP_Defender\Traits\Formats; |
| 15 | 15 | use WP_Defender\Behavior\WPMUDEV; |
| 16 | +use WP_Defender\Component\Network_Cron_Manager; | |
| 16 | 17 | use WP_Defender\Model\Setting\Global_Ip_Lockout; |
| 17 | 18 | use WP_Defender\Component\Config\Config_Hub_Helper; |
| 19 | +use WP_Defender\Component\IP\Antibot_Global_Firewall; | |
| 18 | 20 | use WP_Defender\Component\IP\Global_IP as Global_IP_Component; |
| 19 | 21 | |
| 20 | 22 | /** |
| 21 | 23 | * Handles global IP lockout settings. |
| @@ -25,8 +27,15 @@ | ||
| 25 | 27 | use Setting; |
| 26 | 28 | use Formats; |
| 27 | 29 | |
| 28 | 30 | /** |
| 31 | + * Module slug for identifying Custom IP sync auto-enable after Hub connection. | |
| 32 | + * | |
| 33 | + * @const string | |
| 34 | + */ | |
| 35 | + public const MODULE_SLUG = 'custom-ip-sync'; | |
| 36 | + | |
| 37 | + /** | |
| 29 | 38 | * The slug identifier for this controller. |
| 30 | 39 | * |
| 31 | 40 | * @var string |
| 32 | 41 | */ |
| @@ -62,16 +71,48 @@ | ||
| 62 | 71 | $this->model = wd_di()->get( Global_Ip_Lockout::class ); |
| 63 | 72 | $this->service = wd_di()->get( Global_IP_Component::class ); |
| 64 | 73 | $this->wpmudev = wd_di()->get( WPMUDEV::class ); |
| 65 | 74 | |
| 66 | - if ( ! wp_next_scheduled( 'wpdef_fetch_global_ip_list' ) ) { | |
| 67 | - wp_schedule_event( time(), 'hourly', 'wpdef_fetch_global_ip_list' ); | |
| 75 | + /** | |
| 76 | + * Network Cron Manager | |
| 77 | + * | |
| 78 | + * @var Network_Cron_Manager $network_cron_manager | |
| 79 | + */ | |
| 80 | + $network_cron_manager = wd_di()->get( Network_Cron_Manager::class ); | |
| 81 | + $network_cron_manager->register_callback( | |
| 82 | + 'wpdef_fetch_global_ip_list', | |
| 83 | + array( $this, 'fetch_global_ip_list' ), | |
| 84 | + HOUR_IN_SECONDS | |
| 85 | + ); | |
| 86 | + | |
| 87 | + add_action( 'init', array( $this->service, 'handle_expired_membership' ) ); | |
| 88 | + if ( $this->wpmudev->is_wpmu_hosting() ) { | |
| 89 | + // sync_state must run before can_blocklist_autosync is evaluated, so both hooks use priority 10. | |
| 90 | + add_action( 'init', array( $this, 'sync_state' ) ); | |
| 68 | 91 | } |
| 69 | - add_action( 'wpdef_fetch_global_ip_list', array( $this, 'fetch_global_ip_list' ) ); | |
| 92 | + // Register after sync_state so the model reflects the current Hosting state. | |
| 93 | + add_action( 'init', array( $this, 'maybe_register_blocklist_autosync_hook' ) ); | |
| 94 | + // admin_init priority 20 runs after Hub_Connector sets the transient (priority 10); | |
| 95 | + // the other two hooks cover async-sync cases. | |
| 96 | + add_action( 'admin_init', array( $this, 'maybe_hcm_connection_attempt' ), 20 ); | |
| 97 | + add_action( 'wpdef_hub_connector_synced', array( $this, 'maybe_hcm_connection_attempt' ) ); | |
| 98 | + add_action( 'wpmudev_hub_connector_first_sync_completed', array( $this, 'maybe_hcm_connection_attempt' ) ); | |
| 99 | + } | |
| 70 | 100 | |
| 71 | - if ( $this->service->can_blocklist_autosync() ) { | |
| 72 | - add_action( 'wd_blacklist_this_ip', array( $this, 'blacklist_an_ip' ) ); | |
| 101 | + /** | |
| 102 | + * Auto-enable Custom IP list sync after Hub connection if user triggered from Custom Rules page. | |
| 103 | + * | |
| 104 | + * @return void | |
| 105 | + */ | |
| 106 | + public function maybe_hcm_connection_attempt(): void { | |
| 107 | + $data = get_site_transient( Hub_Connector::TRANSIENT_KEY ); | |
| 108 | + $module_slug = $data['module_slug'] ?? ''; | |
| 109 | + | |
| 110 | + if ( self::MODULE_SLUG !== $module_slug || ! self::get_hcm_status() ) { | |
| 111 | + return; | |
| 73 | 112 | } |
| 113 | + | |
| 114 | + delete_site_transient( Hub_Connector::TRANSIENT_KEY ); | |
| 74 | 115 | } |
| 75 | 116 | |
| 76 | 117 | /** |
| 77 | 118 | * Save settings. |
| @@ -102,9 +143,9 @@ | ||
| 102 | 143 | $message_type = 'antibot'; |
| 103 | 144 | unset( $data['module_title'] ); |
| 104 | 145 | } |
| 105 | 146 | |
| 106 | - $old_enabled = (bool) $this->model->enabled; | |
| 147 | + $old_enabled = $this->model->enabled; | |
| 107 | 148 | $old_self_unlock = $this->model->allow_self_unlock; |
| 108 | 149 | |
| 109 | 150 | $this->model->import( $data ); |
| 110 | 151 | if ( $this->model->validate() ) { |
| @@ -110,14 +151,17 @@ | ||
| 110 | 151 | if ( $this->model->validate() ) { |
| 111 | 152 | $this->model->save(); |
| 112 | 153 | Config_Hub_Helper::set_clear_active_flag(); |
| 113 | 154 | if ( 'central_ip' === $message_type ) { |
| 155 | + if ( isset( $data['enabled'] ) && $old_enabled !== $this->model->enabled ) { | |
| 156 | + $this->service->toggle_on_hosting( $this->model->enabled ); | |
| 157 | + } | |
| 114 | 158 | $message = $this->get_update_message( $data, $old_enabled, Global_Ip_Lockout::get_module_name() ); |
| 115 | 159 | } else { |
| 116 | 160 | $message = ''; |
| 117 | - if ( ! empty( $data['allow_self_unlock'] ) ) { | |
| 161 | + if ( $data['allow_self_unlock'] ?? false ) { | |
| 118 | 162 | $message = esc_html__( 'Temporary self unlock CAPTCHA challenge is enabled successfully.', 'defender-security' ); |
| 119 | - } elseif ( ! empty( $old_self_unlock ) && empty( $data['allow_self_unlock'] ) ) { | |
| 163 | + } elseif ( true === $old_self_unlock && ! ( $data['allow_self_unlock'] ?? false ) ) { | |
| 120 | 164 | $message = esc_html__( 'Temporary self unlock CAPTCHA challenge is disabled successfully.', 'defender-security' ); |
| 121 | 165 | } |
| 122 | 166 | } |
| 123 | 167 | |
| @@ -143,10 +187,10 @@ | ||
| 143 | 187 | * Enqueues scripts and styles for this page. |
| 144 | 188 | * Only enqueues assets if the page is active. |
| 145 | 189 | */ |
| 146 | 190 | public function enqueue_assets() { |
| 147 | - if ( $this->is_page_active() ) { | |
| 148 | - wp_localize_script( 'def-iplockout', 'global_ip', $this->data_frontend() ); | |
| 191 | + if ( ! $this->is_page_active() ) { | |
| 192 | + return; | |
| 149 | 193 | } |
| 150 | 194 | } |
| 151 | 195 | |
| 152 | 196 | /** |
| @@ -167,12 +211,15 @@ | ||
| 167 | 211 | esc_html__( 'Connect to a WPMU DEV account to activate %s.', 'defender-security' ), |
| 168 | 212 | Global_Ip_Lockout::get_module_name() |
| 169 | 213 | ), |
| 170 | 214 | 'is_show_dashboard_notice' => $this->service->is_show_dashboard_notice(), |
| 215 | + 'is_expired_membership' => $this->service->is_expired_membership_type(), | |
| 171 | 216 | ), |
| 172 | 217 | 'hub' => array( |
| 173 | 218 | 'global_ip_list' => $this->service->get_formated_global_ip_list(), |
| 174 | - 'global_ip_setting_url' => $this->wpmudev->get_api_base_url() . 'hub2/ip-banning', | |
| 219 | + 'global_ip_setting_url' => defender_is_unlimited_hosting() | |
| 220 | + ? wd_di()->get( Antibot_Global_Firewall::class )->get_uh_site_tools_link() | |
| 221 | + : $this->wpmudev->get_api_base_url() . 'hub2/security-center/custom-ip-list', | |
| 175 | 222 | ), |
| 176 | 223 | ), |
| 177 | 224 | $this->dump_routes_and_nonces() |
| 178 | 225 | ); |
| @@ -192,15 +239,13 @@ | ||
| 192 | 239 | |
| 193 | 240 | /** |
| 194 | 241 | * Refresh Global IP list. |
| 195 | 242 | * |
| 196 | - * @param Request $request The request object. | |
| 197 | - * | |
| 198 | 243 | * @return Response |
| 199 | 244 | * @defender_route |
| 200 | 245 | * @since 3.4.0 |
| 201 | 246 | */ |
| 202 | - public function refresh_global_ip_list( Request $request ): Response { | |
| 247 | + public function refresh_global_ip_list(): Response { | |
| 203 | 248 | $data = $this->service->fetch_global_ip_list(); |
| 204 | 249 | |
| 205 | 250 | if ( ! is_wp_error( $data ) ) { |
| 206 | 251 | return new Response( |
| @@ -289,6 +334,36 @@ | ||
| 289 | 334 | * @return array An array of strings. |
| 290 | 335 | */ |
| 291 | 336 | public function export_strings() { |
| 292 | 337 | return array(); |
| 338 | + } | |
| 339 | + | |
| 340 | + /** | |
| 341 | + * Register the blocklist autosync hook after sync_state has updated the model. | |
| 342 | + * | |
| 343 | + * @return void | |
| 344 | + */ | |
| 345 | + public function maybe_register_blocklist_autosync_hook(): void { | |
| 346 | + if ( $this->service->can_blocklist_autosync() ) { | |
| 347 | + // No need to run Rate mechanism for IP lockouts because we do it in Blacklist class. | |
| 348 | + add_action( 'wd_blacklist_this_ip', array( $this, 'blacklist_an_ip' ) ); | |
| 349 | + } | |
| 350 | + } | |
| 351 | + | |
| 352 | + /** | |
| 353 | + * Sync custom ip list status with Hosting. | |
| 354 | + * | |
| 355 | + * @return void | |
| 356 | + */ | |
| 357 | + public function sync_state(): void { | |
| 358 | + $hosting_enabled = defender_get_hosting_feature_state( 'globaliplist' ); | |
| 359 | + if ( '' === $hosting_enabled ) { | |
| 360 | + return; | |
| 361 | + } | |
| 362 | + $hosting_enabled = (bool) $hosting_enabled; | |
| 363 | + if ( $hosting_enabled !== $this->model->enabled ) { | |
| 364 | + $this->model->enabled = $hosting_enabled; | |
| 365 | + $this->model->blocklist_autosync = $hosting_enabled; | |
| 366 | + $this->model->save(); | |
| 367 | + } | |
| 293 | 368 | } |
| 294 | 369 | } |