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 +173 -47 5.3.1 → 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,24 +91,124 @@
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 - $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();
96 100
97 101 $this->model->import( $data );
98 102 if ( $this->model->validate() ) {
103 + $arr_blocklist = $this->model->get_lockout_list( 'blocklist' );
104 + if ( is_array( $arr_blocklist ) && array() !== $arr_blocklist ) {
105 + // Update 'Custom User Agents' if 'Blocklist Presets' is enabled.
106 + if (
107 + $data['blocklist_presets']
108 + && is_array( $data['blocklist_preset_values'] )
109 + && array() !== $data['blocklist_preset_values']
110 + ) {
111 + // Check and remove duplicates.
112 + $common_result = array_intersect( $arr_blocklist, $data['blocklist_preset_values'] );
113 + if ( array() !== $common_result ) {
114 + $arr_blocklist = User_Agent_Service::check_and_remove_duplicates(
115 + $arr_blocklist,
116 + $common_result
117 + );
118 + $this->model->blacklist = implode( PHP_EOL, $arr_blocklist );
119 + }
120 + }
121 + // Update 'Custom User Agents' if 'Scripts Presets' is enabled.
122 + if (
123 + $data['script_presets']
124 + && is_array( $data['script_preset_values'] )
125 + && array() !== $data['script_preset_values']
126 + ) {
127 + // Check and remove duplicates.
128 + $common_result = array_intersect( $arr_blocklist, $data['script_preset_values'] );
129 + if ( array() !== $common_result ) {
130 + $arr_blocklist = User_Agent_Service::check_and_remove_duplicates(
131 + $arr_blocklist,
132 + $common_result
133 + );
134 + $this->model->blacklist = implode( PHP_EOL, $arr_blocklist );
135 + }
136 + }
137 + }
138 +
99 139 $this->model->save();
100 140 Config_Hub_Helper::set_clear_active_flag();
141 + // Attention: next actions after saving model changes.
142 + if (
143 + ( ! $this->model->enabled && $old_enabled ) ||
144 + ( ! $this->model->malicious_bot_enabled && $old_malicious_bot_enabled )
145 + ) {
146 + wd_di()->get( Malicious_Bot::class )->remove_data();
147 + } elseif (
148 + ( $this->model->enabled && ! $old_enabled && $this->model->malicious_bot_enabled ) ||
149 + ( $this->model->malicious_bot_enabled && ! $old_malicious_bot_enabled && $this->model->enabled )
150 + ) {
151 + wd_di()->get( Malicious_Bot::class )->rotate_hash();
152 + }
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 +
101 161 // Maybe track.
102 - if ( ! defender_is_wp_cli() && $this->is_feature_state_changed( $prev_data, $data ) ) {
103 - $track_data = array(
104 - 'Action' => $data['enabled'] ? 'Enabled' : 'Disabled',
105 - 'No of Bots in the Whitelist' => count( $this->model->get_lockout_list( 'allowlist', false ) ),
106 - 'No of Bots in the Blocklist' => count( $this->model->get_lockout_list( 'blocklist', false ) ),
107 - );
108 - $this->track_feature( 'def_user_agent_banning', $track_data );
162 + if ( ! defender_is_wp_cli() ) {
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 + ) {
168 + $track_data = array(
169 + 'Action' => $data['enabled'] ? 'Enabled' : 'Disabled',
170 + 'No of Bots in the Whitelist' => count( $this->model->get_lockout_list( 'allowlist', false ) ),
171 + 'No of Bots in the Blocklist' => count( $this->model->get_lockout_list( 'blocklist', false ) ),
172 + );
173 + $this->track_feature( 'def_user_agent_banning', $track_data );
174 + }
175 + // New one for 'Blocklist Presets'.
176 + if (
177 + ( $prev_data['blocklist_presets'] !== $data['blocklist_presets'] ) ||
178 + ( count( $prev_data['blocklist_preset_values'] ) !==
179 + count( array_intersect( $prev_data['blocklist_preset_values'], $data['blocklist_preset_values'] ) )
180 + )
181 + ) {
182 + $track_data = array(
183 + 'Action' => $data['blocklist_presets'] ? 'Enabled' : 'Disabled',
184 + 'List of Activated Bots' => implode( ', ', $data['blocklist_preset_values'] ),
185 + );
186 + $this->track_feature( 'def_ua_blocklist_preset', $track_data );
187 + }
188 + // New one for 'Script Presets'.
189 + if (
190 + ( $prev_data['script_presets'] !== $data['script_presets'] ) ||
191 + ( count( $prev_data['script_preset_values'] ) !==
192 + count( array_intersect( $prev_data['script_preset_values'], $data['script_preset_values'] ) )
193 + )
194 + ) {
195 + $track_data = array(
196 + 'Action' => $data['script_presets'] ? 'Enabled' : 'Disabled',
197 + 'List of Activated Scripts' => implode( ', ', $data['script_preset_values'] ),
198 + );
199 + $this->track_feature( 'def_ua_scripts_preset', $track_data );
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 + }
109 211 }
110 212
111 213 return new Response(
112 214 true,
@@ -158,16 +260,28 @@
158 260 */
159 261 public function data_frontend(): array {
160 262 $arr_model = $this->model->export();
161 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 +
162 280 return array_merge(
163 281 array(
164 282 'model' => $arr_model,
165 - 'misc' => array(
166 - 'no_ua' => '' === $arr_model['blacklist'] && '' === $arr_model['whitelist'],
167 - 'module_name' => User_Agent_Lockout::get_module_name(),
168 - 'spam_ua_list' => User_Agent_Service::get_spam_user_agent_list(),
169 - ),
283 + 'misc' => $misc,
170 284 ),
171 285 $this->dump_routes_and_nonces()
172 286 );
173 287 }
@@ -208,9 +322,9 @@
208 322 * @throws Exception If table is not defined.
209 323 */
210 324 public function import_data( array $data ): void {
211 325 $model = $this->get_model();
212 - if ( ! empty( $data ) ) {
326 + if ( array() !== $data ) {
213 327 $data = $this->adapt_data( $data );
214 328 $model->import( $data );
215 329 if ( $model->validate() ) {
216 330 $model->save();
@@ -233,34 +347,34 @@
233 347 * @defender_route
234 348 * @since 2.6.0
235 349 */
236 350 public function export_ua(): void {
237 - $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 + }
238 357
239 - foreach ( $this->model->get_lockout_list( 'blocklist', false ) as $ua ) {
240 - $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(
241 366 'ua' => $ua,
242 - 'type' => 'blocklist',
367 + 'type' => 'allowlist',
243 368 );
244 369 }
245 - foreach ( $this->model->get_lockout_list( 'allowlist', false ) as $ua ) {
246 - $data[] = array(
370 +
371 + foreach ( $this->model->get_all_selected_blocklist_ua( false ) as $ua ) {
372 + yield array(
247 373 'ua' => $ua,
248 - 'type' => 'allowlist',
374 + 'type' => 'blocklist',
249 375 );
250 376 }
251 - // WP_Filesystem class doesn’t directly provide a function for opening a stream to php://memory with the 'w' mode.
252 - $fp = fopen( 'php://memory', 'w' ); // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_operations_fopen
253 - foreach ( $data as $fields ) {
254 - fputcsv( $fp, $fields, ',', '"', '\\' );
255 - }
256 - $filename = 'wdf-ua-export-' . wp_date( 'ymdHis' ) . '.csv';
257 - fseek( $fp, 0 );
258 - header( 'Content-Type: text/csv' );
259 - header( 'Content-Disposition: attachment; filename="' . $filename . '";' );
260 - // Make php send the generated csv lines to the browser.
261 - fpassthru( $fp );
262 - exit();
263 377 }
264 378
265 379 /**
266 380 * Importing UAs from exporter.
@@ -278,18 +392,27 @@
278 392 ),
279 393 )
280 394 );
281 395
282 - $attached_id = $data['id'];
283 - if ( ! is_object( get_post( $attached_id ) ) ) {
284 - return new Response(
285 - false,
286 - array( 'message' => esc_html__( 'Your file is invalid!', 'defender-security' ) )
287 - );
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 + }
288 412 }
289 413
290 - $file = get_attached_file( $attached_id );
291 - if ( ! is_file( $file ) ) {
414 + if ( ! is_string( $file ) || '' === $file || ! is_file( $file ) ) {
292 415 return new Response(
293 416 false,
294 417 array( 'message' => esc_html__( 'Your file is invalid!', 'defender-security' ) )
295 418 );
@@ -311,11 +434,14 @@
311 434 }
312 435
313 436 return new Response(
314 437 true,
315 - array(
316 - 'message' => esc_html__( 'Your blocklist and allowlist have been successfully imported.', 'defender-security' ),
317 - '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()
318 444 )
319 445 );
320 446 }
321 447