PluginProbe
Defender Security – Malware Scanner, Login Security & Firewall / 5.3.1
Defender Security – Malware Scanner, Login Security & Firewall v5.3.1
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
defender-security / src / controller / class-ua-lockout.php

class-ua-lockout.php in Defender Security – Malware Scanner, Login Security & Firewall 5.3.1, at src/controller/class-ua-lockout.php

331 lines 8.0 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Handles user agent lockout.
4 *
5 * @package WP_Defender\Controller
6 */
7
8 namespace WP_Defender\Controller;
9
10 use Exception;
11 use WP_Defender\Event;
12 use Calotes\Component\Request;
13 use Calotes\Component\Response;
14 use WP_Defender\Traits\Setting;
15 use WP_Defender\Model\Setting\User_Agent_Lockout;
16 use WP_Defender\Component\Config\Config_Hub_Helper;
17 use WP_Defender\Component\User_Agent as User_Agent_Service;
18
19 /**
20 * Handles user agent lockout.
21 *
22 * @since 2.6.0
23 */
24 class UA_Lockout extends Event {
25
26 use Setting;
27
28 /**
29 * The slug identifier for this controller.
30 *
31 * @var string
32 */
33 public $slug = 'wdf-ip-lockout';
34
35 /**
36 * The model for handling the data.
37 *
38 * @var User_Agent_Lockout
39 */
40 protected $model;
41
42 /**
43 * Service for handling logic.
44 *
45 * @var User_Agent_Service
46 */
47 protected $service;
48
49 /**
50 * Initializes the model and service, registers routes, and sets up scheduled events if the model is active.
51 */
52 public function __construct() {
53 $this->register_routes();
54 $this->model = $this->get_model();
55 $this->service = wd_di()->get( User_Agent_Service::class );
56 add_action( 'defender_enqueue_assets', array( $this, 'enqueue_assets' ) );
57 }
58
59 /**
60 * Returns an instance of the User_Agent_Lockout model class.
61 *
62 * @return User_Agent_Lockout The User_Agent_Lockout model class.
63 */
64 private function get_model() {
65 if ( is_object( $this->model ) ) {
66 return $this->model;
67 }
68
69 return new User_Agent_Lockout();
70 }
71
72 /**
73 * Enqueues scripts and styles for this page.
74 * Only enqueues assets if the page is active.
75 */
76 public function enqueue_assets() {
77 if ( ! $this->is_page_active() ) {
78 return;
79 }
80 wp_localize_script( 'def-iplockout', 'ua_lockout', $this->data_frontend() );
81 }
82
83 /**
84 * Save settings.
85 *
86 * @param Request $request The request object containing new settings data.
87 *
88 * @return Response
89 * @defender_route
90 * @throws Exception If the table is not defined.
91 */
92 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();
96
97 $this->model->import( $data );
98 if ( $this->model->validate() ) {
99 $this->model->save();
100 Config_Hub_Helper::set_clear_active_flag();
101 // 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 );
109 }
110
111 return new Response(
112 true,
113 array_merge(
114 array(
115 'message' => $this->get_update_message(
116 $data,
117 $old_enabled,
118 User_Agent_Lockout::get_module_name()
119 ),
120 'auto_close' => true,
121 ),
122 $this->data_frontend()
123 )
124 );
125 }
126
127 return new Response(
128 false,
129 array( 'message' => $this->model->get_formatted_errors() )
130 );
131 }
132
133 /**
134 * Removes settings for all submodules.
135 */
136 public function remove_settings() {
137 }
138
139 /**
140 * Delete all the data & the cache.
141 */
142 public function remove_data() {
143 }
144
145 /**
146 * Converts the current object state to an array.
147 *
148 * @return array The array representation of the object.
149 */
150 public function to_array(): array {
151 return array();
152 }
153
154 /**
155 * Provides data for the frontend.
156 *
157 * @return array An array of data for the frontend.
158 */
159 public function data_frontend(): array {
160 $arr_model = $this->model->export();
161
162 return array_merge(
163 array(
164 '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 ),
170 ),
171 $this->dump_routes_and_nonces()
172 );
173 }
174
175 /**
176 * Adapt the given data array by adding additional fields if necessary.
177 *
178 * @param array $data The data array to adapt.
179 *
180 * @return array The adapted data array.
181 */
182 private function adapt_data( array $data ): array {
183 $adapted_data = array();
184 if ( isset( $data['ua_banning_enabled'] ) ) {
185 $adapted_data['enabled'] = (bool) $data['ua_banning_enabled'];
186 }
187 if ( isset( $data['ua_banning_message'] ) ) {
188 $adapted_data['message'] = $data['ua_banning_message'];
189 }
190 if ( isset( $data['ua_banning_blacklist'] ) ) {
191 $adapted_data['blacklist'] = $data['ua_banning_blacklist'];
192 }
193 if ( isset( $data['ua_banning_whitelist'] ) ) {
194 $adapted_data['whitelist'] = $data['ua_banning_whitelist'];
195 }
196 if ( isset( $data['ua_banning_empty_headers'] ) ) {
197 $adapted_data['empty_headers'] = (bool) $data['ua_banning_empty_headers'];
198 }
199
200 return array_merge( $data, $adapted_data );
201 }
202
203 /**
204 * Imports data into the model.
205 *
206 * @param array $data Data to be imported into the model.
207 *
208 * @throws Exception If table is not defined.
209 */
210 public function import_data( array $data ): void {
211 $model = $this->get_model();
212 if ( ! empty( $data ) ) {
213 $data = $this->adapt_data( $data );
214 $model->import( $data );
215 if ( $model->validate() ) {
216 $model->save();
217 }
218 } else {
219 $default_ua_values = $model->get_default_values();
220 $model->enabled = false;
221 $model->message = $default_ua_values['message'];
222 $model->blacklist = $default_ua_values['blacklist'];
223 $model->whitelist = $default_ua_values['whitelist'];
224 $model->empty_headers = false;
225 $model->save();
226 }
227 }
228
229 /**
230 * Exports User Agents to a CSV file.
231 *
232 * @return void
233 * @defender_route
234 * @since 2.6.0
235 */
236 public function export_ua(): void {
237 $data = array();
238
239 foreach ( $this->model->get_lockout_list( 'blocklist', false ) as $ua ) {
240 $data[] = array(
241 'ua' => $ua,
242 'type' => 'blocklist',
243 );
244 }
245 foreach ( $this->model->get_lockout_list( 'allowlist', false ) as $ua ) {
246 $data[] = array(
247 'ua' => $ua,
248 'type' => 'allowlist',
249 );
250 }
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 }
264
265 /**
266 * Importing UAs from exporter.
267 *
268 * @param Request $request The request object.
269 *
270 * @defender_route
271 * @return Response
272 */
273 public function import_ua( Request $request ) {
274 $data = $request->get_data(
275 array(
276 'id' => array(
277 'type' => 'int',
278 ),
279 )
280 );
281
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 );
288 }
289
290 $file = get_attached_file( $attached_id );
291 if ( ! is_file( $file ) ) {
292 return new Response(
293 false,
294 array( 'message' => esc_html__( 'Your file is invalid!', 'defender-security' ) )
295 );
296 }
297
298 $data = $this->service->verify_import_file( $file );
299 if ( ! $data ) {
300 return new Response(
301 false,
302 array(
303 'message' => esc_html__( 'Your file content is invalid! Please use a CSV file format and try again.', 'defender-security' ),
304 )
305 );
306 }
307
308 // All good, start to import.
309 foreach ( $data as $line ) {
310 $this->model->add_to_list( $line[0], $line[1] );
311 }
312
313 return new Response(
314 true,
315 array(
316 'message' => esc_html__( 'Your blocklist and allowlist have been successfully imported.', 'defender-security' ),
317 'interval' => 1,
318 )
319 );
320 }
321
322 /**
323 * Exports strings.
324 *
325 * @return array An array of strings.
326 */
327 public function export_strings(): array {
328 return array();
329 }
330 }
331