PluginProbe
Defender Security – Malware Scanner, Login Security & Firewall / 3.0.1
Defender Security – Malware Scanner, Login Security & Firewall v3.0.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 / component / blacklist-lockout.php

blacklist-lockout.php in Defender Security – Malware Scanner, Login Security & Firewall 3.0.1, at src/component/blacklist-lockout.php

380 lines 9.9 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace WP_Defender\Component;
4
5 use WP_Defender\Component;
6 use WP_Defender\Integrations\MaxMind_Geolocation;
7 use WP_Defender\Model\Setting\Blacklist_Lockout as Model_Blacklist_Lockout;
8
9 class Blacklist_Lockout extends Component {
10 use \WP_Defender\Traits\Country;
11 use \WP_Defender\Traits\IP;
12
13 /**
14 * Queue hooks when this class init.
15 */
16 public function add_hooks() {
17 add_filter( 'defender_ip_lockout_assets', array( &$this, 'output_scripts_data' ) );
18 }
19
20 /**
21 * @param array $data
22 *
23 * @return mixed
24 * @throws \MaxMind\Db\Reader\InvalidDatabaseException
25 */
26 public function output_scripts_data( $data ) {
27 $model = new Model_Blacklist_Lockout();
28 $user_ip = $this->get_user_ip();
29 $exist_geodb = $this->is_geodb_downloaded();
30 // If MaxMind GeoIP DB is downloaded then display the required data.
31 if ( $exist_geodb ) {
32 $current_country = $this->get_current_country( $user_ip );
33 $current_country = $current_country['iso'] ?? false;
34 $country_list = $this->countries_list();
35 $blacklist_countries = array_merge( array( 'all' => __( 'Block all', 'wpdef' ) ), $country_list );
36 $whitelist_countries = array_merge( array( 'all' => __( 'Allow all', 'wpdef' ) ), $country_list );
37 } else {
38 $current_country = false;
39 $blacklist_countries = array();
40 $whitelist_countries = array();
41 }
42 $data['blacklist'] = array(
43 'model' => $model->export(),
44 'summary' => array(
45 'day' => 0,
46 ),
47 'misc' => array(
48 'geo_db_downloaded' => $exist_geodb,
49 'current_country' => $current_country,
50 'blacklist_countries' => $blacklist_countries,
51 'whitelist_countries' => $whitelist_countries,
52 'user_ip' => $user_ip,
53 ),
54 'class' => Model_Blacklist_Lockout::class,
55 );
56
57 return $data;
58 }
59
60 /**
61 * @param string $ip
62 *
63 * @return bool
64 */
65 public function is_country_whitelist( $ip ) {
66 // Check Firewall > IP Banning > Locations section is activated or not.
67 $country = $this->get_current_country( $ip );
68 if ( false === $country ) {
69 return false;
70 }
71 $model = new Model_Blacklist_Lockout();
72 $whitelist = $model->get_country_whitelist();
73 if ( empty( $whitelist ) ) {
74 return false;
75 }
76 if ( ! empty( $country['iso'] ) && in_array( strtoupper( $country['iso'] ), $whitelist, true ) ) {
77 return true;
78 }
79
80 return false;
81 }
82
83 /**
84 * Return the default ips need to whitelisted, e.g. HUB ips.
85 *
86 * @return array
87 */
88 private function get_default_ip_whitelisted() {
89 $ips = array(
90 '192.241.148.185',
91 '104.236.132.222',
92 '192.241.140.159',
93 '192.241.228.89',
94 '198.199.88.192',
95 '54.197.28.242',
96 '54.221.174.186',
97 '54.236.233.244',
98 '18.204.159.253',
99 '66.135.60.59',
100 '34.196.51.17',
101 '52.57.5.20',
102 '127.0.0.1',
103 array_key_exists( 'SERVER_ADDR', $_SERVER )
104 ? $_SERVER['SERVER_ADDR']
105 : ( $_SERVER['LOCAL_ADDR'] ?? null ),
106 );
107
108 return apply_filters( 'ip_lockout_default_whitelist_ip', $ips );
109 }
110
111 /**
112 * @param string $ip
113 * @param array $arr_ips
114 *
115 * @return bool
116 */
117 private function is_ip_in_format( $ip, $arr_ips ) {
118 foreach ( $arr_ips as $wip ) {
119 if ( false === strpos( $wip, '-' ) && false === strpos( $wip, '/' ) && trim( $wip ) === $ip ) {
120 return true;
121 } elseif ( false !== strpos( $wip, '-' ) ) {
122 $ips = explode( '-', $wip );
123 if ( $this->compare_in_range( $ip, $ips[0], $ips[1] ) ) {
124 return true;
125 }
126 } elseif ( false !== strpos( $wip, '/' ) && $this->compare_cidr( $ip, $wip ) ) {
127 return true;
128 }
129 }
130
131 return false;
132 }
133
134 /**
135 * Is IP on Whitelist?
136 *
137 * @param string $ip
138 *
139 * @return bool
140 */
141 public function is_ip_whitelisted( $ip ) {
142 if ( in_array( $ip, $this->get_default_ip_whitelisted(), true ) ) {
143 return true;
144 }
145
146 $blacklist_settings = new Model_Blacklist_Lockout();
147
148 return $this->is_ip_in_format( $ip, $blacklist_settings->get_list( 'allowlist' ) );
149 }
150
151 /**
152 * Is IP on Blocklist?
153 *
154 * @param string $ip
155 *
156 * @return bool
157 */
158 public function is_blacklist( $ip ) {
159 $blacklist_settings = new Model_Blacklist_Lockout();
160
161 return $this->is_ip_in_format( $ip, $blacklist_settings->get_list( 'blocklist' ) );
162 }
163
164 /**
165 * Is country on Blacklist?
166 *
167 * @param string $ip
168 *
169 * @return bool
170 */
171 public function is_country_blacklist( $ip ) {
172 // Check Firewall > IP Banning > Locations section is activated or not.
173 $country = $this->get_current_country( $ip );
174 if ( false === $country ) {
175 return false;
176 }
177 $blacklist_settings = new Model_Blacklist_Lockout();
178 $blacklisted = $blacklist_settings->get_country_blacklist();
179 if ( empty( $blacklisted ) ) {
180 return false;
181 }
182 if ( in_array( 'all', $blacklisted, true ) ) {
183 return true;
184 }
185 if ( ! empty( $country['iso'] ) && in_array( strtoupper( $country['iso'] ), $blacklisted, true ) ) {
186 return true;
187 }
188
189 return false;
190 }
191
192 /**
193 * Validate import file is in right format and usable for IP Lockout.
194 *
195 * @param $file
196 *
197 * @return array|bool
198 */
199 public function verify_import_file( $file ) {
200 $fp = fopen( $file, 'r' );
201 $data = array();
202 while ( ( $line = fgetcsv( $fp ) ) !== false ) { //phpcs:ignore
203 if ( 2 !== count( $line ) ) {
204 return false;
205 }
206
207 if ( ! in_array( $line[1], array( 'allowlist', 'blocklist' ), true ) ) {
208 return false;
209 }
210
211 if ( false === $this->validate_ip( $line[0] ) ) {
212 continue;
213 }
214
215 $data[] = $line;
216 }
217 fclose( $fp );
218
219 return $data;
220 }
221
222 /**
223 * @param Model_Blacklist_Lockout $model
224 * @param string $country_iso
225 *
226 * @return object
227 * @since 2.8.0
228 */
229 public function add_default_whitelisted_country( Model_Blacklist_Lockout $model, $country_iso ) {
230 if ( empty( $model->country_whitelist ) ) {
231 $model->country_whitelist[] = $country_iso;
232 } elseif ( ! in_array( $country_iso, $model->country_whitelist, true ) ) {
233 $model->country_whitelist[] = $country_iso;
234 }
235
236 return $model;
237 }
238
239 /**
240 * Like download_geodb.
241 */
242 public function download_geo_ip() {
243 $url = 'http://geolite.maxmind.com/download/geoip/database/GeoLite2-Country.tar.gz';
244 if ( ! function_exists( 'download_url' ) ) {
245 require_once ABSPATH . 'wp-admin/includes/file.php';
246 }
247 $this->download_by_url( $url );
248 }
249
250 /**
251 * @param string $url
252 *
253 * @return bool
254 */
255 public function download_by_url( $url ) {
256 $tmp = download_url( $url );
257 if ( ! is_wp_error( $tmp ) ) {
258 $phar = new \PharData( $tmp );
259 $path = $this->get_tmp_path() . DIRECTORY_SEPARATOR . 'maxmind';
260 if ( ! is_dir( $path ) ) {
261 wp_mkdir_p( $path );
262 }
263 $phar->extractTo( $path, null, true );
264 $model = new Model_Blacklist_Lockout();
265 $service_geo = wd_di()->get( MaxMind_Geolocation::class );
266 $model->geodb_path = $path . DIRECTORY_SEPARATOR . $phar->current()->getFileName() . DIRECTORY_SEPARATOR . $service_geo->get_db_full_name();
267
268 if ( file_exists( $tmp ) ) {
269 unlink( $tmp );
270 }
271
272 if ( empty( $model->country_whitelist ) ) {
273 $country = $this->get_current_country( $this->get_user_ip() );
274 if ( false === $country ) {
275 return false;
276 }
277 if ( ! empty( $country['iso'] ) ) {
278 $model = $this->add_default_whitelisted_country( $model, $country['iso'] );
279 }
280 }
281 $model->save();
282
283 return true;
284 }
285
286 return false;
287 }
288
289 /**
290 * @param string $license_key
291 *
292 * @return bool|string|\WP_Error
293 */
294 public function get_maxmind_downloaded_url( $license_key ) {
295 $url = "https://download.maxmind.com/app/geoip_download?edition_id=GeoLite2-Country&license_key=$license_key&suffix=tar.gz";
296 if ( ! function_exists( 'download_url' ) ) {
297 require_once ABSPATH . 'wp-admin/includes/file.php';
298 }
299
300 return download_url( $url );
301 }
302
303 /**
304 * Check downloaded GeoDB.
305 *
306 * @return bool
307 */
308 public function is_geodb_downloaded() {
309 $model = new Model_Blacklist_Lockout();
310 // Likely the case after the config import with existed MaxMind license key.
311 if (
312 ! empty( $model->maxmind_license_key )
313 && ( is_null( $model->geodb_path ) || ! is_file( $model->geodb_path ) )
314 ) {
315 $service_geo = wd_di()->get( MaxMind_Geolocation::class );
316 $tmp = $service_geo->get_downloaded_url( $model->maxmind_license_key );
317 if ( ! is_wp_error( $tmp ) ) {
318 $phar = new \PharData( $tmp );
319 $path = $this->get_tmp_path() . DIRECTORY_SEPARATOR . 'maxmind';
320 if ( ! is_dir( $path ) ) {
321 wp_mkdir_p( $path );
322 }
323 $phar->extractTo( $path, null, true );
324 $model->geodb_path = $path . DIRECTORY_SEPARATOR . $phar->current()->getFileName() . DIRECTORY_SEPARATOR . $service_geo->get_db_full_name();
325 // Save because we'll check for a saved path.
326 $model->save();
327
328 if ( file_exists( $tmp ) ) {
329 unlink( $tmp );
330 }
331
332 if ( empty( $model->country_whitelist ) ) {
333 $country = $this->get_current_country( $this->get_user_ip() );
334 if ( false === $country ) {
335 return false;
336 }
337 if ( ! empty( $country['iso'] ) ) {
338 $model = $this->add_default_whitelisted_country( $model, $country['iso'] );
339 }
340 }
341 $model->save();
342 }
343 }
344
345 // Check again.
346 if ( is_null( $model->geodb_path ) || ! is_file( $model->geodb_path ) ) {
347 return false;
348 }
349
350 // Check if the file exists on the site. The file can exist on the same server but for different sites.
351 // For example, after config importing.
352 $path_parts = pathinfo( $model->geodb_path );
353 if ( preg_match( '/(\/wp-content\/.+)/', $path_parts['dirname'], $matches ) ) {
354 $rel_path = $matches[1];
355 $rel_path = ltrim( $rel_path, '/' );
356 $abs_path = ABSPATH . $rel_path;
357 if ( ! is_dir( $abs_path ) ) {
358 wp_mkdir_p( $abs_path );
359 }
360
361 $rel_path = $abs_path . DIRECTORY_SEPARATOR . $path_parts['basename'];
362 if ( file_exists( $rel_path ) ) {
363 return true;
364 } elseif ( ! empty( $model->geodb_path ) && file_exists( $model->geodb_path ) ) {
365 // The case if ABSPATH was changed e.g. in wp-config.php.
366 return true;
367 }
368
369 if ( move_uploaded_file( $model->geodb_path, $rel_path ) ) {
370 $model->geodb_path = $rel_path;
371 $model->save();
372 } else {
373 return false;
374 }
375 }
376
377 return true;
378 }
379 }
380