PluginProbe
Defender Security – Malware Scanner, Login Security & Firewall / 6.3.0
Defender Security – Malware Scanner, Login Security & Firewall v6.3.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
← All changes | src/controller/class-ua-lockout.php +109 -54 5.4.0 → 6.3.0 View file →
@@ -7,13 +7,16 @@
7 7
8 8 namespace WP_Defender\Controller;
9 9
10 10 use Exception;
11 +use Generator;
11 12 use WP_Defender\Event;
12 13 use Calotes\Component\Request;
13 14 use Calotes\Component\Response;
14 15 use WP_Defender\Traits\Setting;
16 +use WP_Defender\Model\Lockout_Log;
15 17 use WP_Defender\Model\Setting\User_Agent_Lockout;
18 +use WP_Defender\Component\Export\Csv;
16 19 use WP_Defender\Component\Config\Config_Hub_Helper;
17 20 use WP_Defender\Component\User_Agent as User_Agent_Service;
18 21
19 22 /**
@@ -76,9 +79,8 @@
76 79 public function enqueue_assets() {
77 80 if ( ! $this->is_page_active() ) {
78 81 return;
79 82 }
80 - wp_localize_script( 'def-iplockout', 'ua_lockout', $this->data_frontend() );
81 83 }
82 84
83 85 /**
84 86 * Save settings.
@@ -89,22 +91,27 @@
89 91 * @defender_route
90 92 * @throws Exception If the table is not defined.
91 93 */
92 94 public function save_settings( Request $request ) {
93 - $data = $request->get_data_by_model( $this->model );
94 - $old_enabled = (bool) $this->model->enabled;
95 - $old_bot_trap_enabled = (bool) $this->model->bot_trap_enabled;
96 - $prev_data = $this->model->export();
95 + $data = $request->get_data_by_model( $this->model );
96 + $old_enabled = $this->model->enabled;
97 + $old_malicious_bot_enabled = $this->model->malicious_bot_enabled;
98 + $old_fake_bots_enabled = $this->model->fake_bots_enabled;
99 + $prev_data = $this->model->export();
97 100
98 101 $this->model->import( $data );
99 102 if ( $this->model->validate() ) {
100 103 $arr_blocklist = $this->model->get_lockout_list( 'blocklist' );
101 - if ( ! empty( $arr_blocklist ) ) {
104 + if ( is_array( $arr_blocklist ) && array() !== $arr_blocklist ) {
102 105 // Update 'Custom User Agents' if 'Blocklist Presets' is enabled.
103 - if ( $data['blocklist_presets'] && ! empty( $data['blocklist_preset_values'] ) ) {
106 + if (
107 + $data['blocklist_presets']
108 + && is_array( $data['blocklist_preset_values'] )
109 + && array() !== $data['blocklist_preset_values']
110 + ) {
104 111 // Check and remove duplicates.
105 112 $common_result = array_intersect( $arr_blocklist, $data['blocklist_preset_values'] );
106 - if ( ! empty( $common_result ) ) {
113 + if ( array() !== $common_result ) {
107 114 $arr_blocklist = User_Agent_Service::check_and_remove_duplicates(
108 115 $arr_blocklist,
109 116 $common_result
110 117 );
@@ -111,12 +118,16 @@
111 118 $this->model->blacklist = implode( PHP_EOL, $arr_blocklist );
112 119 }
113 120 }
114 121 // Update 'Custom User Agents' if 'Scripts Presets' is enabled.
115 - if ( $data['script_presets'] && ! empty( $data['script_preset_values'] ) ) {
122 + if (
123 + $data['script_presets']
124 + && is_array( $data['script_preset_values'] )
125 + && array() !== $data['script_preset_values']
126 + ) {
116 127 // Check and remove duplicates.
117 128 $common_result = array_intersect( $arr_blocklist, $data['script_preset_values'] );
118 - if ( ! empty( $common_result ) ) {
129 + if ( array() !== $common_result ) {
119 130 $arr_blocklist = User_Agent_Service::check_and_remove_duplicates(
120 131 $arr_blocklist,
121 132 $common_result
122 133 );
@@ -126,24 +137,35 @@
126 137 }
127 138
128 139 $this->model->save();
129 140 Config_Hub_Helper::set_clear_active_flag();
130 -
141 + // Attention: next actions after saving model changes.
131 142 if (
132 143 ( ! $this->model->enabled && $old_enabled ) ||
133 - ( ! $this->model->bot_trap_enabled && $old_bot_trap_enabled )
144 + ( ! $this->model->malicious_bot_enabled && $old_malicious_bot_enabled )
134 145 ) {
135 - wd_di()->get( Bot_Trap::class )->remove_data();
146 + wd_di()->get( Malicious_Bot::class )->remove_data();
136 147 } elseif (
137 - ( $this->model->enabled && ! $old_enabled && $this->model->bot_trap_enabled ) ||
138 - ( $this->model->bot_trap_enabled && ! $old_bot_trap_enabled && $this->model->enabled )
148 + ( $this->model->enabled && ! $old_enabled && $this->model->malicious_bot_enabled ) ||
149 + ( $this->model->malicious_bot_enabled && ! $old_malicious_bot_enabled && $this->model->enabled )
139 150 ) {
140 - wd_di()->get( Bot_Trap::class )->rotate_hash();
151 + wd_di()->get( Malicious_Bot::class )->rotate_hash();
141 152 }
142 153
154 + if (
155 + ( ! $this->model->enabled && $old_enabled ) ||
156 + ( ! $this->model->fake_bots_enabled && $old_fake_bots_enabled )
157 + ) {
158 + wd_di()->get( Fake_Bot_Detection::class )->remove_data();
159 + }
160 +
143 161 // Maybe track.
144 162 if ( ! defender_is_wp_cli() ) {
145 - if ( $this->is_feature_state_changed( $prev_data, $data ) ) {
163 + // Track if UA Module is activated/deactivated OR there is a change in State on Add/Remove Custom User Agents (Allowlist/Blocklist).
164 + if ( ( $old_enabled !== $data['enabled'] )
165 + || ( $this->is_feature_state_changed( $prev_data['blacklist'], $data['blacklist'] ) )
166 + || ( $this->is_feature_state_changed( $prev_data['whitelist'], $data['whitelist'] ) )
167 + ) {
146 168 $track_data = array(
147 169 'Action' => $data['enabled'] ? 'Enabled' : 'Disabled',
148 170 'No of Bots in the Whitelist' => count( $this->model->get_lockout_list( 'allowlist', false ) ),
149 171 'No of Bots in the Blocklist' => count( $this->model->get_lockout_list( 'blocklist', false ) ),
@@ -175,8 +197,18 @@
175 197 'List of Activated Scripts' => implode( ', ', $data['script_preset_values'] ),
176 198 );
177 199 $this->track_feature( 'def_ua_scripts_preset', $track_data );
178 200 }
201 + // Track "Fake Bots Detection".
202 + if ( $prev_data['fake_bots_enabled'] !== $data['fake_bots_enabled'] ||
203 + $prev_data['fake_bots_lockout_type'] !== $data['fake_bots_lockout_type']
204 + ) {
205 + $data = array(
206 + 'Action' => $data['fake_bots_enabled'] ? 'Enabled' : 'Disabled',
207 + 'Blocking type' => 'temporary' === $data['fake_bots_lockout_type'] ? 'Temporary' : 'Permanent',
208 + );
209 + $this->track_feature( 'def_fake_crawler', $data );
210 + }
179 211 }
180 212
181 213 return new Response(
182 214 true,
@@ -228,17 +260,28 @@
228 260 */
229 261 public function data_frontend(): array {
230 262 $arr_model = $this->model->export();
231 263
264 + // Check for empty Disallow line only if Bot Trap is enabled.
265 + $has_empty_disallow = false;
266 + if ( $this->model->enabled && $this->model->malicious_bot_enabled ) {
267 + $malicious_bot_service = wd_di()->get( \WP_Defender\Component\Malicious_Bot::class );
268 + $has_empty_disallow = $malicious_bot_service->has_empty_disallow_line();
269 + }
270 +
271 + $misc = array(
272 + 'no_ua' => '' === $arr_model['blacklist'] && '' === $arr_model['whitelist'],
273 + 'module_name' => User_Agent_Lockout::get_module_name(),
274 + 'blocklist_presets' => User_Agent_Service::get_blocklist_presets(),
275 + 'script_presets' => User_Agent_Service::get_script_presets(),
276 + 'has_empty_disallow_line' => $has_empty_disallow,
277 + 'lockouts_last_24_hours' => Lockout_Log::count_ua_lockouts_in_24_hours(),
278 + );
279 +
232 280 return array_merge(
233 281 array(
234 282 'model' => $arr_model,
235 - 'misc' => array(
236 - 'no_ua' => '' === $arr_model['blacklist'] && '' === $arr_model['whitelist'],
237 - 'module_name' => User_Agent_Lockout::get_module_name(),
238 - 'blocklist_presets' => User_Agent_Service::get_blocklist_presets(),
239 - 'script_presets' => User_Agent_Service::get_script_presets(),
240 - ),
283 + 'misc' => $misc,
241 284 ),
242 285 $this->dump_routes_and_nonces()
243 286 );
244 287 }
@@ -279,9 +322,9 @@
279 322 * @throws Exception If table is not defined.
280 323 */
281 324 public function import_data( array $data ): void {
282 325 $model = $this->get_model();
283 - if ( ! empty( $data ) ) {
326 + if ( array() !== $data ) {
284 327 $data = $this->adapt_data( $data );
285 328 $model->import( $data );
286 329 if ( $model->validate() ) {
287 330 $model->save();
@@ -304,34 +347,34 @@
304 347 * @defender_route
305 348 * @since 2.6.0
306 349 */
307 350 public function export_ua(): void {
308 - $data = array();
351 + try {
352 + Csv::to_browser( 'ua', $this->get_export_rows() );
353 + } catch ( \RuntimeException $e ) {
354 + $this->log( $e->getMessage(), 'ua-lockout' );
355 + }
356 + }
309 357
310 - foreach ( $this->model->get_lockout_list( 'blocklist', false ) as $ua ) {
311 - $data[] = array(
358 + /**
359 + * Generates User Agent export rows.
360 + *
361 + * @return Generator
362 + */
363 + private function get_export_rows(): Generator {
364 + foreach ( $this->model->get_lockout_list( 'allowlist', false ) as $ua ) {
365 + yield array(
312 366 'ua' => $ua,
313 - 'type' => 'blocklist',
367 + 'type' => 'allowlist',
314 368 );
315 369 }
316 - foreach ( $this->model->get_lockout_list( 'allowlist', false ) as $ua ) {
317 - $data[] = array(
370 +
371 + foreach ( $this->model->get_all_selected_blocklist_ua( false ) as $ua ) {
372 + yield array(
318 373 'ua' => $ua,
319 - 'type' => 'allowlist',
374 + 'type' => 'blocklist',
320 375 );
321 376 }
322 - // WP_Filesystem class doesn’t directly provide a function for opening a stream to php://memory with the 'w' mode.
323 - $fp = fopen( 'php://memory', 'w' ); // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_operations_fopen
324 - foreach ( $data as $fields ) {
325 - fputcsv( $fp, $fields, ',', '"', '\\' );
326 - }
327 - $filename = 'wdf-ua-export-' . wp_date( 'ymdHis' ) . '.csv';
328 - fseek( $fp, 0 );
329 - header( 'Content-Type: text/csv' );
330 - header( 'Content-Disposition: attachment; filename="' . $filename . '";' );
331 - // Make php send the generated csv lines to the browser.
332 - fpassthru( $fp );
333 - exit();
334 377 }
335 378
336 379 /**
337 380 * Importing UAs from exporter.
@@ -349,18 +392,27 @@
349 392 ),
350 393 )
351 394 );
352 395
353 - $attached_id = $data['id'];
354 - if ( ! is_object( get_post( $attached_id ) ) ) {
355 - return new Response(
356 - false,
357 - array( 'message' => esc_html__( 'Your file is invalid!', 'defender-security' ) )
358 - );
396 + $file = '';
397 + $attached_id = $data['id'] ?? 0;
398 + if ( 0 < $attached_id ) {
399 + if ( ! is_object( get_post( $attached_id ) ) ) {
400 + return new Response(
401 + false,
402 + array( 'message' => esc_html__( 'Your file is invalid!', 'defender-security' ) )
403 + );
404 + }
405 +
406 + $file = get_attached_file( $attached_id );
407 + } else {
408 + $file_data = defender_get_data_from_request( 'file', 'f' );
409 + if ( is_array( $file_data ) && isset( $file_data['tmp_name'] ) && is_uploaded_file( $file_data['tmp_name'] ) ) {
410 + $file = $file_data['tmp_name'];
411 + }
359 412 }
360 413
361 - $file = get_attached_file( $attached_id );
362 - if ( ! is_file( $file ) ) {
414 + if ( ! is_string( $file ) || '' === $file || ! is_file( $file ) ) {
363 415 return new Response(
364 416 false,
365 417 array( 'message' => esc_html__( 'Your file is invalid!', 'defender-security' ) )
366 418 );
@@ -382,11 +434,14 @@
382 434 }
383 435
384 436 return new Response(
385 437 true,
386 - array(
387 - 'message' => esc_html__( 'Your blocklist and allowlist have been successfully imported.', 'defender-security' ),
388 - 'interval' => 1,
438 + array_merge(
439 + array(
440 + 'message' => esc_html__( 'Your blocklist and allowlist have been successfully imported.', 'defender-security' ),
441 + 'auto_close' => true,
442 + ),
443 + $this->data_frontend()
389 444 )
390 445 );
391 446 }
392 447