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 / model / setting / class-user-agent-lockout.php

class-user-agent-lockout.php in Defender Security – Malware Scanner, Login Security & Firewall 5.3.1, at src/model/setting/class-user-agent-lockout.php

309 lines 8.3 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Handle user agent lockout settings.
4 *
5 * @package WP_Defender\Model\Setting
6 */
7
8 namespace WP_Defender\Model\Setting;
9
10 use Calotes\Model\Setting;
11
12 /**
13 * Model for user agent lockout settings.
14 */
15 class User_Agent_Lockout extends Setting {
16
17 /**
18 * Option name.
19 *
20 * @var string
21 */
22 protected $table = 'wd_user_agent_settings';
23
24 /**
25 * Is module enabled.
26 *
27 * @var bool
28 * @defender_property
29 */
30 public $enabled = false;
31
32 /**
33 * Blacklist User Agents.
34 *
35 * @var string
36 * @defender_property
37 */
38 public $blacklist = '';
39
40 /**
41 * Whitelist User Agents.
42 *
43 * @var string
44 * @defender_property
45 */
46 public $whitelist = '';
47
48 /**
49 * Message to display for user agent lockout.
50 *
51 * @var string
52 * @defender_property
53 * @sanitize sanitize_textarea_field
54 */
55 public $message = '';
56
57 /**
58 * Is empty headers allowed?
59 *
60 * @var bool
61 * @defender_property
62 */
63 public $empty_headers = false;
64
65 /**
66 * Rules for validation.
67 *
68 * @var array
69 */
70 protected $rules = array(
71 array( array( 'enabled', 'empty_headers' ), 'boolean' ),
72 );
73
74 /**
75 * Get default values.
76 *
77 * @return array
78 */
79 public function get_default_values(): array {
80 // Allowled User Agents.
81 $whitelist = "a6-indexer\nadsbot-google\naolbuild\napis-google\nbaidu\nbingbot\nbingpreview";
82 $whitelist .= "\nbutterfly\ncloudflare\nchrome\nduckduckbot\nembedly\nfacebookexternalhit\nfacebot\ngoogle page speed";
83 $whitelist .= "\ngooglebot\nia_archiver\nlinkedinbot\nmediapartners-google\nmsnbot\nnetcraftsurvey";
84 $whitelist .= "\noutbrain\npinterest\nquora\nslackbot\nslurp\ntweetmemebot\ntwitterbot\nuptimerobot";
85 $whitelist .= "\nurlresolver\nvkshare\nw3c_validator\nwordpress\nwp rocket\nyandex";
86
87 return array(
88 'message' => esc_html__( 'You have been blocked from accessing this website.', 'defender-security' ),
89 'whitelist' => $whitelist,
90 // Blocked User Agents.
91 'blacklist' => "MJ12Bot\nDotBot",
92 );
93 }
94
95 /**
96 * Initializes the object by setting default values for the message, whitelist, and blacklist properties.
97 * This function retrieves the default values from the get_default_values() method and assigns them to the
98 * corresponding properties of the object.
99 *
100 * @return void
101 */
102 protected function before_load(): void {
103 $default_values = $this->get_default_values();
104 $this->message = $default_values['message'];
105 $this->whitelist = $default_values['whitelist'];
106 $this->blacklist = $default_values['blacklist'];
107 }
108
109 /**
110 * Checks if the User Agent Lockout feature is active.
111 *
112 * @return bool Returns true if the User Agent Lockout feature is active, false otherwise.
113 */
114 public function is_active(): bool {
115 return (bool) apply_filters(
116 'wd_user_agents_enable',
117 $this->enabled
118 );
119 }
120
121 /**
122 * Get list of blocklisted or allowlisted data.
123 *
124 * @param string $type blocklist|allowlist.
125 * @param bool $lower Whether to convert the list to lowercase.
126 *
127 * @return array
128 */
129 public function get_lockout_list( $type = 'blocklist', $lower = true ): array {
130 $data = ( 'blocklist' === $type ) ? $this->blacklist : $this->whitelist;
131 $arr = is_array( $data ) ? $data : array_filter( preg_split( "/\r\n|\n|\r/", $data ) );
132 $arr = array_map( 'trim', $arr );
133 if ( $lower ) {
134 $arr = array_map( 'strtolower', $arr );
135 }
136
137 return $arr;
138 }
139
140 /**
141 * Define settings labels.
142 *
143 * @return array
144 */
145 public function labels(): array {
146 return array(
147 'enabled' => self::get_module_name(),
148 'message' => esc_html__( 'Message', 'defender-security' ),
149 'blacklist' => esc_html__( 'Blocklist', 'defender-security' ),
150 'whitelist' => esc_html__( 'Allowlist', 'defender-security' ),
151 'empty_headers' => esc_html__( 'Empty Headers', 'defender-security' ),
152 );
153 }
154
155 /**
156 * Get the access status of this UA.
157 *
158 * @param string $ua User Agent.
159 *
160 * @return array
161 */
162 public function get_access_status( $ua ): array {
163 $blocklist = str_replace( '#', '\#', $this->get_lockout_list( 'blocklist' ) );
164 $allowlist = str_replace( '#', '\#', $this->get_lockout_list( 'allowlist' ) );
165
166 $blocklist_regex_pattern = '#' . implode( '|', $blocklist ) . '#i';
167 $allowlist_regex_pattern = '#' . implode( '|', $allowlist ) . '#i';
168
169 $blocklist_match = preg_match( $blocklist_regex_pattern, $ua );
170 $allowlist_match = preg_match( $allowlist_regex_pattern, $ua );
171
172 if ( empty( $blocklist_match ) && empty( $allowlist_match ) ) {
173
174 return array( 'na' );
175 }
176
177 $result = array();
178
179 if ( ! empty( $blocklist_match ) && empty( $allowlist_match ) ) {
180 $result[] = 'banned';
181 }
182 if ( ! empty( $allowlist_match ) ) {
183 $result[] = 'allowlist';
184 }
185
186 return $result;
187 }
188
189 /**
190 * Checks if a user agent is present in a given list.
191 *
192 * @param string $ua The user agent to check.
193 * @param string $collection The type of list to check against ('blocklist' or 'allowlist').
194 *
195 * @return bool Returns true if the user agent is in the list, false otherwise.
196 */
197 public function is_ua_in_list( $ua, $collection ): bool {
198 $arr = str_replace( '#', '\#', $this->get_lockout_list( $collection ) );
199
200 $list_regex_pattern = '#' . implode( '|', $arr ) . '#i';
201
202 $list_match = preg_match( $list_regex_pattern, $ua );
203
204 return ! empty( $list_match );
205 }
206
207 /**
208 * Remove User Agent from a list.
209 *
210 * @param string $ua The user agent to remove.
211 * @param string $collection blocklist|allowlist.
212 *
213 * @return void
214 */
215 public function remove_from_list( $ua, $collection ) {
216 $arr = $this->get_lockout_list( $collection );
217 // Array can contain uppercase.
218 $orig_arr = str_replace( '#', '\#', $this->get_lockout_list( $collection, false ) );
219
220 $list_regex_pattern = '#' . implode( '|', $arr ) . '#i';
221
222 $list_match = preg_match( $list_regex_pattern, $ua );
223
224 if ( false !== $list_match ) {
225
226 // Plain string match. For e.g. r.n regex matches ran & run but we can add/block UA string name if user send the useragent name as run then we include that in allowlist so run won't be blocked but ran will be blocked.
227 $key = array_search( $ua, $arr, true );
228
229 if ( false !== $key && isset( $orig_arr[ $key ] ) ) {
230 unset( $orig_arr[ $key ] );
231 $is_string_match = true;
232 } else {
233 // If plain string not matched then add the user agent in opposite list if unban is clicked then add that string to allow list, else if ban user agent clicked then add that string to blocklist though allow list take higher priority i.e. in allow list r.n present then adding r.n or run or ran in blocklist won't block the user agent because of priority.
234 $is_string_match = false;
235 }
236
237 if ( 'blocklist' === $collection ) {
238 $this->blacklist = implode( PHP_EOL, $orig_arr );
239
240 if ( false === $is_string_match ) {
241 $this->whitelist = $this->push_ua_to_list( $ua, 'allowlist' );
242 }
243 } elseif ( 'allowlist' === $collection ) {
244 $this->whitelist = implode( PHP_EOL, $orig_arr );
245
246 if ( false === $is_string_match ) {
247 $this->blacklist = $this->push_ua_to_list( $ua, 'blocklist' );
248 }
249 }
250
251 $this->save();
252 }
253 }
254
255 /**
256 * Add an UA to the list.
257 *
258 * @param string $ua User agent name.
259 * @param string $collection blocklist|allowlist.
260 *
261 * @return void
262 */
263 public function add_to_list( $ua, $collection ) {
264 if ( 'blocklist' === $collection ) {
265 $this->blacklist = $this->push_ua_to_list( $ua, $collection );
266 } elseif ( 'allowlist' === $collection ) {
267 $this->whitelist = $this->push_ua_to_list( $ua, $collection );
268 }
269
270 $this->save();
271 }
272
273 /**
274 * Push the UA to either blocklist or allowlist
275 *
276 * @param string $ua User agent name.
277 * @param string $collection List type i.e. blocklist or allowlist.
278 *
279 * @return string List as string format with UA delimited with newline character.
280 */
281 private function push_ua_to_list( string $ua, string $collection ): string {
282 $arr = $this->get_lockout_list( $collection, false );
283 $arr[] = trim( $ua );
284 $arr = array_unique( $arr );
285
286 return implode( PHP_EOL, $arr );
287 }
288
289 /**
290 * Get the module name.
291 *
292 * @return string
293 */
294 public static function get_module_name(): string {
295 return esc_html__( 'User Agent Banning', 'defender-security' );
296 }
297
298 /**
299 * Get the module state.
300 *
301 * @param bool $flag Module state.
302 *
303 * @return string
304 */
305 public static function get_module_state( $flag ): string {
306 return $flag ? esc_html__( 'active', 'defender-security' ) : esc_html__( 'inactive', 'defender-security' );
307 }
308 }
309