Defender Security – Malware Scanner, Login Security & Firewall - Version 2.8.3

Version Description

( 2022-05-11) =

  • Enhance: PHP upgrade notice
  • Fix: Defender column country_iso_code missing from Lockout table
  • Fix: Defender sets all country iso codes as NULL
Download this release

Release Info

Developer BigTonny
Plugin Icon 128x128 Defender Security – Malware Scanner, Login Security & Firewall
Version 2.8.3
Comparing to
See all releases

Code changes from version 2.8.2 to 2.8.3

assets/img/modal/google-recaptcha@2x.png DELETED
Binary file
assets/img/modal/new-256@2x.png DELETED
Binary file
assets/img/modal/new-262@2x.png DELETED
Binary file
assets/img/modal/user-agent@2x.png DELETED
Binary file
assets/img/modal/woo-recaptcha@2x.png DELETED
Binary file
assets/img/tab-tutorial1@1x.png DELETED
Binary file
assets/img/tab-tutorial1@2x.png DELETED
Binary file
assets/img/tab-tutorial2@1x.png DELETED
Binary file
assets/img/tab-tutorial2@2x.png DELETED
Binary file
assets/img/tab-tutorial3@1x.png DELETED
Binary file
assets/img/tab-tutorial3@2x.png DELETED
Binary file
assets/img/tab-tutorial4@1x.png DELETED
Binary file
assets/img/tab-tutorial4@2x.png DELETED
Binary file
assets/img/tutorial1@2x.png DELETED
Binary file
assets/img/tutorial2@2x.png DELETED
Binary file
assets/img/tutorial3@2x.png DELETED
Binary file
assets/img/tutorial4@2x.png DELETED
Binary file
languages/wpdef-default.pot CHANGED
@@ -6,9 +6,9 @@
6
  #, fuzzy
7
  msgid ""
8
  msgstr ""
9
- "Project-Id-Version: wp-defender 2.8.2\n"
10
  "Report-Msgid-Bugs-To: \n"
11
- "POT-Creation-Date: 2022-04-08 13:43+0000\n"
12
  "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
13
  "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
14
  "Language-Team: LANGUAGE <LL@li.org>\n"
@@ -194,11 +194,11 @@ msgstr ""
194
  msgid "Generate leads with pop-ups, slide-ins and email opt-ins."
195
  msgstr ""
196
 
197
- #: free/bootstrap.php:268
198
  msgid "Get Secure!"
199
  msgstr ""
200
 
201
- #: free/bootstrap.php:280
202
  msgid ""
203
  "You're awesome for installing Defender! Are you interested in how to make "
204
  "the most of this plugin? We've collected all the best security resources we "
@@ -434,11 +434,11 @@ msgstr ""
434
  msgid "%s is disabled. Please contact your hosting provider to enable it."
435
  msgstr ""
436
 
437
- #: src/class-admin.php:96
438
  msgid "Go to Defender Settings"
439
  msgstr ""
440
 
441
- #: src/class-admin.php:96 src/component/audit/options-audit.php:227
442
  #: src/component/backup-settings.php:1173 src/controller/main-setting.php:27
443
  #: front/src/module/advanced-tools/screen/password-reset.vue:41
444
  #: front/src/module/audit/audit.vue:42 front/src/module/audit/audit.vue:49
@@ -459,15 +459,15 @@ msgstr ""
459
  msgid "Settings"
460
  msgstr ""
461
 
462
- #: src/class-admin.php:98
463
  msgid "Docs"
464
  msgstr ""
465
 
466
- #: src/class-admin.php:101
467
  msgid "Upgrade to Defender Pro"
468
  msgstr ""
469
 
470
- #: src/class-admin.php:101
471
  #: front/src/module/dashboard/component/file-scanning-free.vue:75
472
  #: front/src/module/dashboard/component/file-scanning-free.vue:90
473
  #: front/src/module/scan/screen/scan-result.vue:54
@@ -476,72 +476,89 @@ msgstr ""
476
  msgid "Upgrade"
477
  msgstr ""
478
 
479
- #: src/class-admin.php:103
480
  msgid "Renew Your Membership"
481
  msgstr ""
482
 
483
- #: src/class-admin.php:103
484
  msgid "Renew Membership"
485
  msgstr ""
486
 
487
- #: src/class-admin.php:130
488
  msgid "WPMU DEV"
489
  msgstr ""
490
 
491
- #: src/class-admin.php:132
492
  #, php-format
493
  msgid "By %s"
494
  msgstr ""
495
 
496
- #: src/class-admin.php:148
497
  #, php-format
498
  msgid "More information about %s"
499
  msgstr ""
500
 
501
- #: src/class-admin.php:150 src/class-admin.php:164
502
  msgid "View details"
503
  msgstr ""
504
 
505
- #: src/class-admin.php:156 src/class-admin.php:264
506
  msgid "Rate Defender"
507
  msgstr ""
508
 
509
- #: src/class-admin.php:157
510
  msgid "Support"
511
  msgstr ""
512
 
513
- #: src/class-admin.php:167
514
  msgid "Premium Support"
515
  msgstr ""
516
 
517
- #: src/class-admin.php:169
518
  msgid "Roadmap"
519
  msgstr ""
520
 
521
- #: src/class-admin.php:181
522
  msgid "Invalid request, you are not allowed to do that action."
523
  msgstr ""
524
 
525
- #: src/class-admin.php:190
526
  msgid "Invalid request, allowed data not provided."
527
  msgstr ""
528
 
529
  #. //wordpress.org
530
  #. 4 Email Button CTA
531
- #: src/class-admin.php:220
532
  msgid "Get Fast!"
533
  msgstr ""
534
 
535
- #: src/class-admin.php:260
536
  msgid ""
537
  "We've spent countless hours developing Defender and making it free for you "
538
  "to use. We would really appreciate it if you dropped us a quick rating!"
539
  msgstr ""
540
 
541
- #: src/class-admin.php:267
542
  msgid "Maybe later"
543
  msgstr ""
544
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
545
  #: src/component.php:19
546
  msgid "daily"
547
  msgstr ""
@@ -1488,38 +1505,38 @@ msgid ""
1488
  "page as a third AUTH method."
1489
  msgstr ""
1490
 
1491
- #: src/component/login-lockout.php:80
1492
  msgid ""
1493
  "You have been locked out by the administrator for attempting to login with a "
1494
  "banned username"
1495
  msgstr ""
1496
 
1497
- #: src/component/login-lockout.php:99
1498
  #, php-format
1499
  msgid "%d login attempts remaining"
1500
  msgstr ""
1501
 
1502
- #: src/component/login-lockout.php:214
1503
  #, php-format
1504
  msgid "Failed login attempt with username %s"
1505
  msgstr ""
1506
 
1507
- #: src/component/login-lockout.php:219
1508
  #, php-format
1509
  msgid "Failed login attempt with a ban username %s"
1510
  msgstr ""
1511
 
1512
- #: src/component/login-lockout.php:226
1513
  msgid "Lockout occurred: Too many failed login attempts"
1514
  msgstr ""
1515
 
1516
- #: src/component/notfound-lockout.php:311
1517
- #: src/component/notfound-lockout.php:315
1518
  #, php-format
1519
  msgid "Request for file %s which doesn't exist"
1520
  msgstr ""
1521
 
1522
- #: src/component/notfound-lockout.php:320
1523
  #, php-format
1524
  msgid "Lockout occurred: Too many 404 requests for %s"
1525
  msgstr ""
@@ -1939,14 +1956,7 @@ msgid "Information Disclosure"
1939
  msgstr ""
1940
 
1941
  #: src/component/security-tweaks/security-key.php:94
1942
- #: src/component/security-tweaks/servers/apache.php:78
1943
- #: src/component/security-tweaks/servers/apache.php:160
1944
- #: src/component/security-tweaks/servers/apache.php:378
1945
- #: src/component/security-tweaks/servers/apache.php:383
1946
- #: src/component/security-tweaks/servers/apache.php:414
1947
- #: src/component/security-tweaks/servers/apache.php:419
1948
- #: src/component/security-tweaks/servers/apache.php:495
1949
- #: src/component/security-tweaks/servers/apache.php:513
1950
  #, php-format
1951
  msgid "The file %s is not writable"
1952
  msgstr ""
@@ -2003,7 +2013,7 @@ msgstr ""
2003
  msgid "Security Keys"
2004
  msgstr ""
2005
 
2006
- #: src/component/security-tweaks/servers/apache.php:115
2007
  msgid ""
2008
  "The rules can't be applied. This can be either because your host doesn't "
2009
  "allow editing the file, or you've selected the wrong server type."
@@ -2263,15 +2273,15 @@ msgstr ""
2263
  msgid "Whoops, the passcode you entered was incorrect or expired."
2264
  msgstr ""
2265
 
2266
- #: src/component/user-agent-lockout.php:69
2267
  msgid "Locked out due to empty User-Agent and Referer headers"
2268
  msgstr ""
2269
 
2270
- #: src/component/user-agent-lockout.php:74
2271
  msgid "Locked out due to attempted login with banned user agent"
2272
  msgstr ""
2273
 
2274
- #: src/component/user-agent-lockout.php:133
2275
  #: src/model/setting/user-agent-lockout.php:56
2276
  msgid "You have been blocked from accessing this website."
2277
  msgstr ""
6
  #, fuzzy
7
  msgid ""
8
  msgstr ""
9
+ "Project-Id-Version: wp-defender 2.8.3\n"
10
  "Report-Msgid-Bugs-To: \n"
11
+ "POT-Creation-Date: 2022-05-10 14:27+0300\n"
12
  "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
13
  "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
14
  "Language-Team: LANGUAGE <LL@li.org>\n"
194
  msgid "Generate leads with pop-ups, slide-ins and email opt-ins."
195
  msgstr ""
196
 
197
+ #: free/bootstrap.php:270
198
  msgid "Get Secure!"
199
  msgstr ""
200
 
201
+ #: free/bootstrap.php:282
202
  msgid ""
203
  "You're awesome for installing Defender! Are you interested in how to make "
204
  "the most of this plugin? We've collected all the best security resources we "
434
  msgid "%s is disabled. Please contact your hosting provider to enable it."
435
  msgstr ""
436
 
437
+ #: src/class-admin.php:110
438
  msgid "Go to Defender Settings"
439
  msgstr ""
440
 
441
+ #: src/class-admin.php:110 src/component/audit/options-audit.php:227
442
  #: src/component/backup-settings.php:1173 src/controller/main-setting.php:27
443
  #: front/src/module/advanced-tools/screen/password-reset.vue:41
444
  #: front/src/module/audit/audit.vue:42 front/src/module/audit/audit.vue:49
459
  msgid "Settings"
460
  msgstr ""
461
 
462
+ #: src/class-admin.php:112
463
  msgid "Docs"
464
  msgstr ""
465
 
466
+ #: src/class-admin.php:115
467
  msgid "Upgrade to Defender Pro"
468
  msgstr ""
469
 
470
+ #: src/class-admin.php:115
471
  #: front/src/module/dashboard/component/file-scanning-free.vue:75
472
  #: front/src/module/dashboard/component/file-scanning-free.vue:90
473
  #: front/src/module/scan/screen/scan-result.vue:54
476
  msgid "Upgrade"
477
  msgstr ""
478
 
479
+ #: src/class-admin.php:117
480
  msgid "Renew Your Membership"
481
  msgstr ""
482
 
483
+ #: src/class-admin.php:117
484
  msgid "Renew Membership"
485
  msgstr ""
486
 
487
+ #: src/class-admin.php:144
488
  msgid "WPMU DEV"
489
  msgstr ""
490
 
491
+ #: src/class-admin.php:146
492
  #, php-format
493
  msgid "By %s"
494
  msgstr ""
495
 
496
+ #: src/class-admin.php:162
497
  #, php-format
498
  msgid "More information about %s"
499
  msgstr ""
500
 
501
+ #: src/class-admin.php:164 src/class-admin.php:178
502
  msgid "View details"
503
  msgstr ""
504
 
505
+ #: src/class-admin.php:170 src/class-admin.php:278
506
  msgid "Rate Defender"
507
  msgstr ""
508
 
509
+ #: src/class-admin.php:171
510
  msgid "Support"
511
  msgstr ""
512
 
513
+ #: src/class-admin.php:181
514
  msgid "Premium Support"
515
  msgstr ""
516
 
517
+ #: src/class-admin.php:183
518
  msgid "Roadmap"
519
  msgstr ""
520
 
521
+ #: src/class-admin.php:195
522
  msgid "Invalid request, you are not allowed to do that action."
523
  msgstr ""
524
 
525
+ #: src/class-admin.php:204
526
  msgid "Invalid request, allowed data not provided."
527
  msgstr ""
528
 
529
  #. //wordpress.org
530
  #. 4 Email Button CTA
531
+ #: src/class-admin.php:234
532
  msgid "Get Fast!"
533
  msgstr ""
534
 
535
+ #: src/class-admin.php:274
536
  msgid ""
537
  "We've spent countless hours developing Defender and making it free for you "
538
  "to use. We would really appreciate it if you dropped us a quick rating!"
539
  msgstr ""
540
 
541
+ #: src/class-admin.php:281
542
  msgid "Maybe later"
543
  msgstr ""
544
 
545
+ #: src/class-admin.php:337
546
+ msgid ""
547
+ "There is a new version of Defender available - Deprecating PHP version 7.1. "
548
+ "and lower."
549
+ msgstr ""
550
+
551
+ #: src/class-admin.php:340
552
+ msgid "Important Upgrade Notice:"
553
+ msgstr ""
554
+
555
+ #: src/class-admin.php:344
556
+ #, php-format
557
+ msgid ""
558
+ "The upcoming version %s is compatible only with PHP 7.2.0 and higher. Please "
559
+ "make sure to upgrade your PHP version."
560
+ msgstr ""
561
+
562
  #: src/component.php:19
563
  msgid "daily"
564
  msgstr ""
1505
  "page as a third AUTH method."
1506
  msgstr ""
1507
 
1508
+ #: src/component/login-lockout.php:81
1509
  msgid ""
1510
  "You have been locked out by the administrator for attempting to login with a "
1511
  "banned username"
1512
  msgstr ""
1513
 
1514
+ #: src/component/login-lockout.php:100
1515
  #, php-format
1516
  msgid "%d login attempts remaining"
1517
  msgstr ""
1518
 
1519
+ #: src/component/login-lockout.php:221
1520
  #, php-format
1521
  msgid "Failed login attempt with username %s"
1522
  msgstr ""
1523
 
1524
+ #: src/component/login-lockout.php:226
1525
  #, php-format
1526
  msgid "Failed login attempt with a ban username %s"
1527
  msgstr ""
1528
 
1529
+ #: src/component/login-lockout.php:233
1530
  msgid "Lockout occurred: Too many failed login attempts"
1531
  msgstr ""
1532
 
1533
+ #: src/component/notfound-lockout.php:317
1534
+ #: src/component/notfound-lockout.php:321
1535
  #, php-format
1536
  msgid "Request for file %s which doesn't exist"
1537
  msgstr ""
1538
 
1539
+ #: src/component/notfound-lockout.php:326
1540
  #, php-format
1541
  msgid "Lockout occurred: Too many 404 requests for %s"
1542
  msgstr ""
1956
  msgstr ""
1957
 
1958
  #: src/component/security-tweaks/security-key.php:94
1959
+ #: src/component/security-tweaks/servers/apache.php:72
 
 
 
 
 
 
 
1960
  #, php-format
1961
  msgid "The file %s is not writable"
1962
  msgstr ""
2013
  msgid "Security Keys"
2014
  msgstr ""
2015
 
2016
+ #: src/component/security-tweaks/servers/apache.php:128
2017
  msgid ""
2018
  "The rules can't be applied. This can be either because your host doesn't "
2019
  "allow editing the file, or you've selected the wrong server type."
2273
  msgid "Whoops, the passcode you entered was incorrect or expired."
2274
  msgstr ""
2275
 
2276
+ #: src/component/user-agent-lockout.php:75
2277
  msgid "Locked out due to empty User-Agent and Referer headers"
2278
  msgstr ""
2279
 
2280
+ #: src/component/user-agent-lockout.php:80
2281
  msgid "Locked out due to attempted login with banned user agent"
2282
  msgstr ""
2283
 
2284
+ #: src/component/user-agent-lockout.php:139
2285
  #: src/model/setting/user-agent-lockout.php:56
2286
  msgid "You have been blocked from accessing this website."
2287
  msgstr ""
readme.txt CHANGED
@@ -1,13 +1,13 @@
1
  === Defender Security - Malware Scanner, Login Security & Firewall ===
2
  Plugin Name: Defender Security - Malware Scanner, Login Security & Firewall
3
- Version: 2.8.2
4
  Author: WPMU DEV
5
  Author URI: https://wpmudev.com/
6
  Contributors: WPMUDEV
7
  Tags: security plugin, security, firewall, malware, malware scanner, antivirus, ip blocking, login security, brute force attacks, two-factor authentication, activity log, audit logs, block hackers, 2fa, hack
8
  Requires at least: 5.2
9
- Tested up to: 5.9.3
10
- Stable tag: 2.8.2
11
  Requires PHP: 5.6.20
12
  License: GPL v2 - http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
13
 
@@ -244,11 +244,17 @@ Please open a new thread in Defender’s [support forum](https://wordpress.org/s
244
 
245
  == Changelog ==
246
 
247
- = 2.8.2 ( 2022-04-25 ) =
 
 
 
 
 
 
248
 
249
  - Fix: All site visitors are blocked
250
 
251
- = 2.8.1 ( 2022-04-25 ) =
252
 
253
  - Enhance: Hide write permissions error notices for Tweaks while applying config
254
  - Enhance: Update the default Auth method on the Users page
1
  === Defender Security - Malware Scanner, Login Security & Firewall ===
2
  Plugin Name: Defender Security - Malware Scanner, Login Security & Firewall
3
+ Version: 2.8.3
4
  Author: WPMU DEV
5
  Author URI: https://wpmudev.com/
6
  Contributors: WPMUDEV
7
  Tags: security plugin, security, firewall, malware, malware scanner, antivirus, ip blocking, login security, brute force attacks, two-factor authentication, activity log, audit logs, block hackers, 2fa, hack
8
  Requires at least: 5.2
9
+ Tested up to: 6.0
10
+ Stable tag: 2.8.3
11
  Requires PHP: 5.6.20
12
  License: GPL v2 - http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
13
 
244
 
245
  == Changelog ==
246
 
247
+ = 2.8.3 ( 2022-05-11) =
248
+
249
+ - Enhance: PHP upgrade notice
250
+ - Fix: Defender column country_iso_code missing from Lockout table
251
+ - Fix: Defender sets all country iso codes as NULL
252
+
253
+ = 2.8.2 ( 2022-04-08 ) =
254
 
255
  - Fix: All site visitors are blocked
256
 
257
+ = 2.8.1 ( 2022-04-07 ) =
258
 
259
  - Enhance: Hide write permissions error notices for Tweaks while applying config
260
  - Enhance: Update the default Auth method on the Users page
src/bootstrap.php CHANGED
@@ -150,10 +150,12 @@ class Bootstrap {
150
  `user_agent` varchar(255) DEFAULT NULL,
151
  `blog_id` int(11) DEFAULT NULL,
152
  `tried` varchar(255),
 
153
  PRIMARY KEY (`id`),
154
  KEY `ip` (`ip`),
155
  KEY `type` (`type`),
156
- KEY `tried` (`tried`)
 
157
  ) $charset_collate;";
158
  $wpdb->query( $sql );
159
  }
@@ -479,10 +481,8 @@ class Bootstrap {
479
  add_action( 'init', function () {
480
  require_once WP_DEFENDER_DIR . 'src/routes.php';
481
  }, 9 );
482
- // Include admin class.
483
- if ( is_admin() ) {
484
- ( new \WP_Defender\Admin() )->init();
485
- }
486
  // Add WP-CLI commands.
487
  if ( defined( 'WP_CLI' ) && WP_CLI ) {
488
  \WP_CLI::add_command( 'defender', Cli::class );
150
  `user_agent` varchar(255) DEFAULT NULL,
151
  `blog_id` int(11) DEFAULT NULL,
152
  `tried` varchar(255),
153
+ `country_iso_code` char(2) DEFAULT NULL,
154
  PRIMARY KEY (`id`),
155
  KEY `ip` (`ip`),
156
  KEY `type` (`type`),
157
+ KEY `tried` (`tried`),
158
+ KEY `country_iso_code` (`country_iso_code`)
159
  ) $charset_collate;";
160
  $wpdb->query( $sql );
161
  }
481
  add_action( 'init', function () {
482
  require_once WP_DEFENDER_DIR . 'src/routes.php';
483
  }, 9 );
484
+ // Include admin class. Don't use is_admin().
485
+ add_action( 'admin_init', [ ( new \WP_Defender\Admin() ), 'init' ] );
 
 
486
  // Add WP-CLI commands.
487
  if ( defined( 'WP_CLI' ) && WP_CLI ) {
488
  \WP_CLI::add_command( 'defender', Cli::class );
src/class-admin.php CHANGED
@@ -32,6 +32,8 @@ class Admin {
32
  add_filter( 'plugin_row_meta', array( $this, 'plugin_row_meta' ), 10, 3 );
33
  // Only for wordpress.org members.
34
  if ( ! $this->is_pro ) {
 
 
35
  if ( $is_def_page && ! is_multisite() ) {
36
  add_action( 'admin_notices', array( $this, 'show_rating_notice' ) );
37
  } elseif ( $is_def_page && is_multisite() && is_main_site() ) {
@@ -39,6 +41,18 @@ class Admin {
39
  }
40
  add_action( 'wp_ajax_defender_dismiss_notification', array( $this, 'dismiss_notice' ) );
41
  add_action( 'admin_init', array( $this, 'register_free_modules' ), 20 );
 
 
 
 
 
 
 
 
 
 
 
 
42
  }
43
  }
44
 
@@ -298,4 +312,47 @@ class Admin {
298
 
299
  <?php
300
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
301
  }
32
  add_filter( 'plugin_row_meta', array( $this, 'plugin_row_meta' ), 10, 3 );
33
  // Only for wordpress.org members.
34
  if ( ! $this->is_pro ) {
35
+ // Add plugin upgrade notification.
36
+ add_action( 'in_plugin_update_message-' . DEFENDER_PLUGIN_BASENAME, array( $this, 'show_upgrade_notice' ), 10, 2 );
37
  if ( $is_def_page && ! is_multisite() ) {
38
  add_action( 'admin_notices', array( $this, 'show_rating_notice' ) );
39
  } elseif ( $is_def_page && is_multisite() && is_main_site() ) {
41
  }
42
  add_action( 'wp_ajax_defender_dismiss_notification', array( $this, 'dismiss_notice' ) );
43
  add_action( 'admin_init', array( $this, 'register_free_modules' ), 20 );
44
+ } else {
45
+ // For Pro version.
46
+ add_action(
47
+ 'load-plugins.php',
48
+ function () {
49
+ add_action( 'after_plugin_row_' . DEFENDER_PLUGIN_BASENAME, array(
50
+ $this,
51
+ 'show_upgrade_notice'
52
+ ), 10, 2 );
53
+ },
54
+ 22
55
+ );
56
  }
57
  }
58
 
312
 
313
  <?php
314
  }
315
+
316
+ /**
317
+ * Show plugin update notice.
318
+ *
319
+ * @param string $plugin_file
320
+ * @param array $response
321
+ *
322
+ * @since 2.8.3
323
+ */
324
+ public function show_upgrade_notice( $plugin_file, $response ) {
325
+ if ( version_compare( PHP_VERSION, '7.2', '>=' ) ) {
326
+ return;
327
+ }
328
+ $plugin_data = (object) $response;
329
+ // Preparing for the next major plugin v3.0.0 and subsequent versions.
330
+ if ( isset( $plugin_data->new_version )
331
+ && '3' === substr( trim( $plugin_data->new_version ), 0, 1 )
332
+ && version_compare( DEFENDER_VERSION, '3', '<' )
333
+ ){
334
+ // Major plugin version or subsequent versions.
335
+ $new_version = ( '3' === $plugin_data->new_version ) ? '3.0.0' : $plugin_data->new_version;
336
+ // Collect notice.
337
+ $notice = '<p>' . esc_html__( 'There is a new version of Defender available - Deprecating PHP version 7.1. and lower.', 'wpdef' ) . '</p>';
338
+ $notice .= '<span style="display: inherit;background: #D63638;color: #FFFFFF;margin-top: 12px;padding: 10px 12px;border-radius: 2px;">';
339
+ $notice .= '<strong>';
340
+ $notice .= esc_html__( 'Important Upgrade Notice:', 'wpdef' );
341
+ $notice .= '</strong> ';
342
+ $notice .= sprintf(
343
+ /* translators: %s: Version number. */
344
+ esc_html__( 'The upcoming version %s is compatible only with PHP 7.2.0 and higher. Please make sure to upgrade your PHP version.', 'wpdef' ),
345
+ $new_version
346
+ );
347
+ $notice .= '</span>';
348
+
349
+ echo "<script type='text/javascript'>
350
+ (function ($) {
351
+ $(document).ready(function () {
352
+ $( '.wp-list-table tr[data-plugin=\"" . esc_attr( $plugin_data->plugin ) . "\"] .notice-warning' ).html( '" . addslashes( $notice ) . "' ).css('padding-bottom', '10px');
353
+ });
354
+ })(jQuery);
355
+ </script>";
356
+ }
357
+ }
358
  }
src/component/login-lockout.php CHANGED
@@ -65,13 +65,14 @@ class Login_Lockout extends \WP_Defender\Component {
65
  */
66
  public function show_attempt_left( $user, $username, $password ) {
67
  if ( is_wp_error( $user )
68
- && 'POST' == $_SERVER['REQUEST_METHOD']
69
  && ! in_array(
70
  $user->get_error_code(),
71
  array(
72
  'empty_username',
73
  'empty_password',
74
- )
 
75
  )
76
  ) {
77
  $model = Lockout_Ip::get( $this->get_user_ip() );
@@ -199,15 +200,21 @@ class Login_Lockout extends \WP_Defender\Component {
199
  * @param $scenario
200
  */
201
  public function log_event( $ip, $username, $scenario ) {
202
- $model = new Lockout_Log();
203
- $model->ip = $ip;
204
- $model->user_agent = isset( $_SERVER['HTTP_USER_AGENT'] )
205
  ? User_Agent::fast_cleaning( $_SERVER['HTTP_USER_AGENT'] )
206
  : null;
207
- $model->date = time();
208
- $model->tried = $username;
209
- $model->blog_id = get_current_blog_id();
210
- $model->country_iso_code = $this->ip_to_country( $ip )['iso'];
 
 
 
 
 
 
211
  switch ( $scenario ) {
212
  case self::SCENARIO_LOGIN_FAIL:
213
  $model->type = Lockout_Log::AUTH_FAIL;
@@ -227,7 +234,7 @@ class Login_Lockout extends \WP_Defender\Component {
227
  break;
228
  }
229
  $model->save();
230
- if ( $model->type === Lockout_Log::AUTH_LOCK ) {
231
  do_action( 'defender_notify', 'firewall-notification', $model );
232
  }
233
  }
65
  */
66
  public function show_attempt_left( $user, $username, $password ) {
67
  if ( is_wp_error( $user )
68
+ && 'POST' === $_SERVER['REQUEST_METHOD']
69
  && ! in_array(
70
  $user->get_error_code(),
71
  array(
72
  'empty_username',
73
  'empty_password',
74
+ ),
75
+ true
76
  )
77
  ) {
78
  $model = Lockout_Ip::get( $this->get_user_ip() );
200
  * @param $scenario
201
  */
202
  public function log_event( $ip, $username, $scenario ) {
203
+ $model = new Lockout_Log();
204
+ $model->ip = $ip;
205
+ $model->user_agent = isset( $_SERVER['HTTP_USER_AGENT'] )
206
  ? User_Agent::fast_cleaning( $_SERVER['HTTP_USER_AGENT'] )
207
  : null;
208
+ $model->date = time();
209
+ $model->tried = $username;
210
+ $model->blog_id = get_current_blog_id();
211
+
212
+ $ip_to_country = $this->ip_to_country( $ip );
213
+
214
+ if ( ! empty( $ip_to_country ) && isset( $ip_to_country['iso'] ) ) {
215
+ $model->country_iso_code = $ip_to_country['iso'];
216
+ }
217
+
218
  switch ( $scenario ) {
219
  case self::SCENARIO_LOGIN_FAIL:
220
  $model->type = Lockout_Log::AUTH_FAIL;
234
  break;
235
  }
236
  $model->save();
237
+ if ( Lockout_Log::AUTH_LOCK === $model->type ) {
238
  do_action( 'defender_notify', 'firewall-notification', $model );
239
  }
240
  }
src/component/notfound-lockout.php CHANGED
@@ -296,15 +296,21 @@ class Notfound_Lockout extends Component {
296
  * @param string $scenario
297
  */
298
  public function log_event( $ip, $uri, $scenario ) {
299
- $model = new Lockout_Log();
300
- $model->ip = $ip;
301
- $model->user_agent = isset( $_SERVER['HTTP_USER_AGENT'] )
302
  ? User_Agent::fast_cleaning( $_SERVER['HTTP_USER_AGENT'] )
303
  : null;
304
- $model->date = time();
305
- $model->tried = $uri;
306
- $model->blog_id = get_current_blog_id();
307
- $model->country_iso_code = $this->ip_to_country( $ip )['iso'];
 
 
 
 
 
 
308
  switch ( $scenario ) {
309
  case self::SCENARIO_ERROR_404:
310
  $model->type = Lockout_Log::ERROR_404;
@@ -321,7 +327,7 @@ class Notfound_Lockout extends Component {
321
  break;
322
  }
323
  $model->save();
324
- if ( $model->type === Lockout_Log::LOCKOUT_404 ) {
325
  do_action( 'defender_notify', 'firewall-notification', $model );
326
  }
327
  }
296
  * @param string $scenario
297
  */
298
  public function log_event( $ip, $uri, $scenario ) {
299
+ $model = new Lockout_Log();
300
+ $model->ip = $ip;
301
+ $model->user_agent = isset( $_SERVER['HTTP_USER_AGENT'] )
302
  ? User_Agent::fast_cleaning( $_SERVER['HTTP_USER_AGENT'] )
303
  : null;
304
+ $model->date = time();
305
+ $model->tried = $uri;
306
+ $model->blog_id = get_current_blog_id();
307
+
308
+ $ip_to_country = $this->ip_to_country( $ip );
309
+
310
+ if ( ! empty( $ip_to_country ) && isset( $ip_to_country['iso'] ) ) {
311
+ $model->country_iso_code = $ip_to_country['iso'];
312
+ }
313
+
314
  switch ( $scenario ) {
315
  case self::SCENARIO_ERROR_404:
316
  $model->type = Lockout_Log::ERROR_404;
327
  break;
328
  }
329
  $model->save();
330
+ if ( Lockout_Log::LOCKOUT_404 === $model->type ) {
331
  do_action( 'defender_notify', 'firewall-notification', $model );
332
  }
333
  }
src/component/security-tweaks/servers/apache.php CHANGED
@@ -11,7 +11,7 @@ class Apache {
11
  *
12
  * @var array
13
  */
14
- public $new_htaccess_config = [];
15
 
16
  /**
17
  * The htaccess inside wp-content.
@@ -58,6 +58,23 @@ class Apache {
58
  return Server::ping_test_failed( $url );
59
  }
60
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
61
  /**
62
  * Process the rule.
63
  *
@@ -66,19 +83,15 @@ class Apache {
66
  public function process() {
67
  if ( 'protect-information' === $this->type ) {
68
  $ht_access_path = ABSPATH . '.htaccess';
69
-
70
- if ( ! is_file( $ht_access_path ) ) {
71
- file_put_contents( $ht_access_path, '', LOCK_EX );
 
 
72
  }
73
-
74
  if ( ! is_writable( $ht_access_path ) ) {
75
- return new WP_Error(
76
- 'defender_file_not_editable',
77
- sprintf(
78
- __( 'The file %s is not writable', 'wpdef' ),
79
- $ht_access_path
80
- )
81
- );
82
  }
83
 
84
  $ht_access_config = file( $ht_access_path );
@@ -87,12 +100,12 @@ class Apache {
87
  $contains_search = array_diff( array_map( 'trim', $rules ), $ht_access_config );
88
 
89
  if ( count( $contains_search ) < count( $rules ) ) {
90
- //search the wrapper block
91
  $ht_access_content = file_get_contents( $ht_access_path );
92
  preg_match( '/## WP Defender(.*?)## WP Defender - End ##/s', $ht_access_content, $matches );
93
 
94
  if ( count( $matches ) ) {
95
- //remove the whole parts as it partial done
96
  $ht_access_content = str_replace( $matches[0], '', $ht_access_content );
97
  $ht_access_config = explode( PHP_EOL, $ht_access_content );
98
  $ht_access_config = array_merge( $ht_access_config, $rules );
@@ -152,15 +165,13 @@ class Apache {
152
  public function revert() {
153
  if ( 'protect-information' === $this->type ) {
154
  $ht_access_path = ABSPATH . '.htaccess';
 
 
 
 
155
 
156
  if ( ! is_writable( $ht_access_path ) ) {
157
- return new WP_Error(
158
- 'defender_file_not_editable',
159
- sprintf(
160
- __( "The file %s is not writable", 'wpdef' ),
161
- $ht_access_path
162
- )
163
- );
164
  }
165
 
166
  $ht_access_config = file_get_contents( $ht_access_path );
@@ -180,28 +191,26 @@ class Apache {
180
  }
181
 
182
  if ( 'prevent-php-executed' === $this->type ) {
 
183
  $response = $this->unprotect_content_directory();
184
-
185
  if ( is_wp_error( $response ) ) {
186
- return wp_send_json_error( array(
187
- 'message' => $response->get_error_message()
188
- ) );
189
  }
190
-
191
  $response = $this->unprotect_includes_directory();
192
-
193
  if ( is_wp_error( $response ) ) {
194
- return wp_send_json_error( array(
195
- 'message' => $response->get_error_message()
196
- ) );
197
  }
198
-
199
  $response = $this->unprotect_upload_directory();
200
-
201
  if ( is_wp_error( $response ) ) {
202
- return wp_send_json_error( array(
203
- 'message' => $response->get_error_message()
204
- ) );
205
  }
206
 
207
  return delete_site_option( "defender_security_tweeks_{$this->type}" );
@@ -214,7 +223,7 @@ class Apache {
214
  * @return array
215
  */
216
  public function get_rules() {
217
- $rules = [
218
  PHP_EOL . '## WP Defender - Prevent information disclosure ##' . PHP_EOL,
219
  '<FilesMatch "\.(md|exe|sh|bak|inc|pot|po|mo|log|sql)$">' . PHP_EOL .
220
  'Require all denied' . PHP_EOL .
@@ -225,11 +234,11 @@ class Apache {
225
  '<Files ads.txt>' . PHP_EOL .
226
  'Require all granted' . PHP_EOL .
227
  '</Files>' . PHP_EOL,
228
- '## WP Defender - End ##'
229
- ];
230
 
231
  if ( version_compare( $this->get_version(), '2.4', '<' ) ) {
232
- $rules = [
233
  PHP_EOL . '## WP Defender - Prevent information disclosure ##' . PHP_EOL,
234
  '<FilesMatch "\.(md|exe|sh|bak|inc|pot|po|mo|log|sql)$">' . PHP_EOL .
235
  'Order allow,deny' . PHP_EOL .
@@ -241,8 +250,8 @@ class Apache {
241
  '<Files ads.txt>' . PHP_EOL .
242
  'Allow from all' . PHP_EOL .
243
  '</Files>' . PHP_EOL,
244
- '## WP Defender - End ##'
245
- ];
246
  }
247
 
248
  return $rules;
@@ -257,7 +266,7 @@ class Apache {
257
  $rules = '';
258
 
259
  if ( 'prevent-php-executed' === $this->type ) {
260
- $rules = '## WP Defender - Protect PHP Executed ##' . PHP_EOL;
261
  $rules .= PHP_EOL;
262
  $rules .= '<Files *.php>' . PHP_EOL;
263
  $rules .= 'Require all denied' . PHP_EOL;
@@ -266,7 +275,7 @@ class Apache {
266
  $rules .= '## WP Defender - End ##' . PHP_EOL;
267
 
268
  if ( version_compare( $this->get_version(), '2.4', '<' ) ) {
269
- $rules = '## WP Defender - Protect PHP Executed ##' . PHP_EOL;
270
  $rules .= PHP_EOL;
271
  $rules .= '<Files *.php>' . PHP_EOL;
272
  $rules .= 'Order allow,deny' . PHP_EOL;
@@ -278,7 +287,7 @@ class Apache {
278
  }
279
 
280
  if ( 'protect-information' === $this->type ) {
281
- $rules = '## WP Defender - Prevent information disclosure ##' . PHP_EOL;
282
  $rules .= PHP_EOL;
283
  $rules .= '<FilesMatch "\.(md|exe|sh|bak|inc|pot|po|mo|log|sql)$">' . PHP_EOL;
284
  $rules .= 'Require all denied' . PHP_EOL;
@@ -295,7 +304,7 @@ class Apache {
295
  $rules .= '## WP Defender - End ##';
296
 
297
  if ( version_compare( $this->get_version(), '2.4', '>' ) ) {
298
- $rules = '## WP Defender - Prevent information disclosure ##' . PHP_EOL;
299
  $rules .= PHP_EOL;
300
  $rules .= '<FilesMatch "\.(md|exe|sh|bak|inc|pot|po|mo|log|sql)$">' . PHP_EOL;
301
  $rules .= 'Order allow,deny' . PHP_EOL;
@@ -325,7 +334,8 @@ class Apache {
325
  */
326
  public function get_version() {
327
  if ( ! function_exists( 'apache_get_version' ) ) {
328
- $version = '2.2'; //default supported is 2.2
 
329
  $url = home_url();
330
  $apache_version = get_site_transient( 'defender_apache_version' );
331
 
@@ -336,14 +346,14 @@ class Apache {
336
  if ( isset( $apache_version[ $url ] ) && ! empty( $apache_version[ $url ] ) ) {
337
  return strtolower( $apache_version[ $url ] );
338
  }
339
-
340
- $apache_version[ $url ] = $version; //default is 2.2
341
 
342
  if ( isset( $_SERVER['SERVER_SOFTWARE'] ) ) {
343
- $server = explode( " ", $_SERVER['SERVER_SOFTWARE'] );
344
  if ( is_array( $server ) && count( $server ) > 1 ) {
345
  $server = $server[0];
346
- $server = explode( "/", $server );
347
  if ( is_array( $server ) && count( $server ) > 1 ) {
348
  $version = $server[1];
349
  $apache_version[ $url ] = $version;
@@ -368,29 +378,27 @@ class Apache {
368
  public function protect_content_directory() {
369
  $ht_access_path = $this->contentdir_path;
370
 
371
- if ( $ht_access_path == null ) {
372
  $ht_access_path = WP_CONTENT_DIR . '/' . '.htaccess';
373
  }
374
-
375
- if ( ! file_exists( $ht_access_path ) ) {
376
- if ( false === file_put_contents( $ht_access_path, '', LOCK_EX ) ) {
377
- return new WP_Error( 'defender_file_not_editable',
378
- sprintf( __( 'The file %s is not writable', 'wpdef' ), $ht_access_path )
379
- );
380
- }
381
- } elseif ( ! is_writable( $ht_access_path ) ) {
382
- return new WP_Error( 'defender_file_not_editable',
383
- sprintf( __( 'The file %s is not writable', 'wpdef' ), $ht_access_path )
384
- );
385
  }
386
 
387
  $exists_rules = $this->cleanup_old_rules( file_get_contents( $ht_access_path ) );
388
- $rule = [
389
  '## WP Defender - Protect PHP Executed ##',
390
  '<Files *.php>',
391
  $this->generate_htaccess_rule( false ),
392
  '</Files>',
393
- ];
394
 
395
  $rule[] = '## WP Defender - End ##';
396
  file_put_contents( $ht_access_path, $exists_rules . implode( PHP_EOL, $rule ), LOCK_EX );
@@ -404,25 +412,23 @@ class Apache {
404
  public function protect_includes_directory() {
405
  $ht_access_path = $this->includedir_path;
406
 
407
- if ( $ht_access_path == null ) {
408
  $ht_access_path = ABSPATH . WPINC . '/' . '.htaccess';
409
  }
410
-
411
- if ( ! is_file( $ht_access_path ) ) {
412
- if ( file_put_contents( $ht_access_path, '', LOCK_EX ) === false ) {
413
- return new WP_Error( 'defender_file_not_editable',
414
- sprintf( __( 'The file %s is not writable', 'wpdef' ), $ht_access_path )
415
- );
416
- }
417
- } elseif ( ! is_writable( $ht_access_path ) ) {
418
- return new \WP_Error( 'defender_file_not_editable',
419
- sprintf( __( 'The file %s is not writable', 'wpdef' ), $ht_access_path )
420
- );
421
  }
422
 
423
  $exists_rules = $this->cleanup_old_rules( file_get_contents( $ht_access_path ) );
424
 
425
- $rule = [
426
  '## WP Defender - Protect PHP Executed ##',
427
  '<Files *.php>',
428
  $this->generate_htaccess_rule( false ),
@@ -434,7 +440,7 @@ class Apache {
434
  $this->generate_htaccess_rule( true ),
435
  '</Files>',
436
  '## WP Defender - End ##',
437
- ];
438
 
439
  file_put_contents( $ht_access_path, $exists_rules . implode( PHP_EOL, $rule ), LOCK_EX );
440
  }
@@ -470,29 +476,29 @@ class Apache {
470
  public function protect_uploads_directory() {
471
  if ( defined( 'UPLOADS' ) ) {
472
  $this->contentdir_path = ABSPATH . UPLOADS . '/' . '.htaccess';
 
473
  return $this->protect_content_directory();
474
  }
475
  }
476
 
477
  /**
478
- * UnProtect content directory.
479
  *
480
  * @return void|WP_Error
481
  */
482
  public function unprotect_content_directory() {
483
  $ht_access_path = $this->contentdir_path;
484
 
485
- if ( $ht_access_path == null ) {
486
  $ht_access_path = WP_CONTENT_DIR . '/' . '.htaccess';
487
  }
488
-
489
- if ( ! file_exists( $ht_access_path ) ) {
490
  return;
491
  }
492
-
493
  if ( ! is_writable( $ht_access_path ) ) {
494
- return new WP_Error( 'defender_file_not_editable',
495
- sprintf( __( "The file %s is not writable", 'wpdef' ), $ht_access_path ) );
496
  }
497
 
498
  $ht_config = $this->cleanup_old_rules( file_get_contents( $ht_access_path ) );
@@ -501,17 +507,25 @@ class Apache {
501
  file_put_contents( $ht_access_path, trim( $ht_config ), LOCK_EX );
502
  }
503
 
 
 
 
 
 
 
504
  public function unprotect_includes_directory() {
505
  $ht_access_path = $this->includedir_path;
506
 
507
- if ( $ht_access_path == null ) {
508
  $ht_access_path = ABSPATH . WPINC . '/' . '.htaccess';
509
  }
510
-
 
 
 
 
511
  if ( ! is_writable( $ht_access_path ) ) {
512
- return new WP_Error( 'defender_file_not_editable',
513
- sprintf( __( 'The file %s is not writable', 'wpdef' ), $ht_access_path )
514
- );
515
  }
516
 
517
  $ht_config = $this->cleanup_old_rules( file_get_contents( $ht_access_path ) );
@@ -519,7 +533,7 @@ class Apache {
519
  }
520
 
521
  /**
522
- * UnProtect upload directory.
523
  *
524
  * @return void
525
  */
@@ -535,7 +549,7 @@ class Apache {
535
  *
536
  * @param array $config
537
  */
538
- public function set_new_htaccess_config( $config = [] ) {
539
  if ( ! empty( $config ) ) {
540
  $this->new_htaccess_config = $config;
541
  }
11
  *
12
  * @var array
13
  */
14
+ public $new_htaccess_config = array();
15
 
16
  /**
17
  * The htaccess inside wp-content.
58
  return Server::ping_test_failed( $url );
59
  }
60
 
61
+ /**
62
+ * @param string $file_path
63
+ *
64
+ * @return WP_Error
65
+ * @since 2.8.3
66
+ */
67
+ public function get_error_by_file_path( $file_path ) {
68
+ return new WP_Error(
69
+ 'defender_file_not_writable',
70
+ sprintf(
71
+ /* translators: %s - file path */
72
+ __( 'The file %s is not writable', 'wpdef' ),
73
+ $file_path
74
+ )
75
+ );
76
+ }
77
+
78
  /**
79
  * Process the rule.
80
  *
83
  public function process() {
84
  if ( 'protect-information' === $this->type ) {
85
  $ht_access_path = ABSPATH . '.htaccess';
86
+ // Create a htaccess-file if it doesn't exist.
87
+ if ( ! is_file( $ht_access_path )
88
+ && false === (bool) file_put_contents( $ht_access_path, '', LOCK_EX )
89
+ ) {
90
+ return $this->get_error_by_file_path( $ht_access_path );
91
  }
92
+ // If the htaccess-file is existed.
93
  if ( ! is_writable( $ht_access_path ) ) {
94
+ return $this->get_error_by_file_path( $ht_access_path );
 
 
 
 
 
 
95
  }
96
 
97
  $ht_access_config = file( $ht_access_path );
100
  $contains_search = array_diff( array_map( 'trim', $rules ), $ht_access_config );
101
 
102
  if ( count( $contains_search ) < count( $rules ) ) {
103
+ // Search the wrapper block.
104
  $ht_access_content = file_get_contents( $ht_access_path );
105
  preg_match( '/## WP Defender(.*?)## WP Defender - End ##/s', $ht_access_content, $matches );
106
 
107
  if ( count( $matches ) ) {
108
+ // Remove the whole parts as its partial done.
109
  $ht_access_content = str_replace( $matches[0], '', $ht_access_content );
110
  $ht_access_config = explode( PHP_EOL, $ht_access_content );
111
  $ht_access_config = array_merge( $ht_access_config, $rules );
165
  public function revert() {
166
  if ( 'protect-information' === $this->type ) {
167
  $ht_access_path = ABSPATH . '.htaccess';
168
+ // Quick exit if the file does not exist.
169
+ if ( ! is_file( $ht_access_path ) ) {
170
+ return true;
171
+ }
172
 
173
  if ( ! is_writable( $ht_access_path ) ) {
174
+ return $this->get_error_by_file_path( $ht_access_path );
 
 
 
 
 
 
175
  }
176
 
177
  $ht_access_config = file_get_contents( $ht_access_path );
191
  }
192
 
193
  if ( 'prevent-php-executed' === $this->type ) {
194
+ // Content-folder.
195
  $response = $this->unprotect_content_directory();
 
196
  if ( is_wp_error( $response ) ) {
197
+ return wp_send_json_error(
198
+ array( 'message' => $response->get_error_message() )
199
+ );
200
  }
201
+ // Includes-folder.
202
  $response = $this->unprotect_includes_directory();
 
203
  if ( is_wp_error( $response ) ) {
204
+ return wp_send_json_error(
205
+ array( 'message' => $response->get_error_message() )
206
+ );
207
  }
208
+ // Uploads-folder.
209
  $response = $this->unprotect_upload_directory();
 
210
  if ( is_wp_error( $response ) ) {
211
+ return wp_send_json_error(
212
+ array( 'message' => $response->get_error_message() )
213
+ );
214
  }
215
 
216
  return delete_site_option( "defender_security_tweeks_{$this->type}" );
223
  * @return array
224
  */
225
  public function get_rules() {
226
+ $rules = array(
227
  PHP_EOL . '## WP Defender - Prevent information disclosure ##' . PHP_EOL,
228
  '<FilesMatch "\.(md|exe|sh|bak|inc|pot|po|mo|log|sql)$">' . PHP_EOL .
229
  'Require all denied' . PHP_EOL .
234
  '<Files ads.txt>' . PHP_EOL .
235
  'Require all granted' . PHP_EOL .
236
  '</Files>' . PHP_EOL,
237
+ '## WP Defender - End ##',
238
+ );
239
 
240
  if ( version_compare( $this->get_version(), '2.4', '<' ) ) {
241
+ $rules = array(
242
  PHP_EOL . '## WP Defender - Prevent information disclosure ##' . PHP_EOL,
243
  '<FilesMatch "\.(md|exe|sh|bak|inc|pot|po|mo|log|sql)$">' . PHP_EOL .
244
  'Order allow,deny' . PHP_EOL .
250
  '<Files ads.txt>' . PHP_EOL .
251
  'Allow from all' . PHP_EOL .
252
  '</Files>' . PHP_EOL,
253
+ '## WP Defender - End ##',
254
+ );
255
  }
256
 
257
  return $rules;
266
  $rules = '';
267
 
268
  if ( 'prevent-php-executed' === $this->type ) {
269
+ $rules = '## WP Defender - Protect PHP Executed ##' . PHP_EOL;
270
  $rules .= PHP_EOL;
271
  $rules .= '<Files *.php>' . PHP_EOL;
272
  $rules .= 'Require all denied' . PHP_EOL;
275
  $rules .= '## WP Defender - End ##' . PHP_EOL;
276
 
277
  if ( version_compare( $this->get_version(), '2.4', '<' ) ) {
278
+ $rules = '## WP Defender - Protect PHP Executed ##' . PHP_EOL;
279
  $rules .= PHP_EOL;
280
  $rules .= '<Files *.php>' . PHP_EOL;
281
  $rules .= 'Order allow,deny' . PHP_EOL;
287
  }
288
 
289
  if ( 'protect-information' === $this->type ) {
290
+ $rules = '## WP Defender - Prevent information disclosure ##' . PHP_EOL;
291
  $rules .= PHP_EOL;
292
  $rules .= '<FilesMatch "\.(md|exe|sh|bak|inc|pot|po|mo|log|sql)$">' . PHP_EOL;
293
  $rules .= 'Require all denied' . PHP_EOL;
304
  $rules .= '## WP Defender - End ##';
305
 
306
  if ( version_compare( $this->get_version(), '2.4', '>' ) ) {
307
+ $rules = '## WP Defender - Prevent information disclosure ##' . PHP_EOL;
308
  $rules .= PHP_EOL;
309
  $rules .= '<FilesMatch "\.(md|exe|sh|bak|inc|pot|po|mo|log|sql)$">' . PHP_EOL;
310
  $rules .= 'Order allow,deny' . PHP_EOL;
334
  */
335
  public function get_version() {
336
  if ( ! function_exists( 'apache_get_version' ) ) {
337
+ // The default support is 2.2.
338
+ $version = '2.2';
339
  $url = home_url();
340
  $apache_version = get_site_transient( 'defender_apache_version' );
341
 
346
  if ( isset( $apache_version[ $url ] ) && ! empty( $apache_version[ $url ] ) ) {
347
  return strtolower( $apache_version[ $url ] );
348
  }
349
+ // The default support is 2.2.
350
+ $apache_version[ $url ] = $version;
351
 
352
  if ( isset( $_SERVER['SERVER_SOFTWARE'] ) ) {
353
+ $server = explode( ' ', $_SERVER['SERVER_SOFTWARE'] );
354
  if ( is_array( $server ) && count( $server ) > 1 ) {
355
  $server = $server[0];
356
+ $server = explode( '/', $server );
357
  if ( is_array( $server ) && count( $server ) > 1 ) {
358
  $version = $server[1];
359
  $apache_version[ $url ] = $version;
378
  public function protect_content_directory() {
379
  $ht_access_path = $this->contentdir_path;
380
 
381
+ if ( empty( $ht_access_path ) ) {
382
  $ht_access_path = WP_CONTENT_DIR . '/' . '.htaccess';
383
  }
384
+ // Create a htaccess-file if it doesn't exist.
385
+ if ( ! is_file( $ht_access_path )
386
+ && false === (bool) file_put_contents( $ht_access_path, '', LOCK_EX )
387
+ ) {
388
+ return $this->get_error_by_file_path( $ht_access_path );
389
+ }
390
+ // If the htaccess-file is existed.
391
+ if ( ! is_writable( $ht_access_path ) ) {
392
+ return $this->get_error_by_file_path( $ht_access_path );
 
 
393
  }
394
 
395
  $exists_rules = $this->cleanup_old_rules( file_get_contents( $ht_access_path ) );
396
+ $rule = array(
397
  '## WP Defender - Protect PHP Executed ##',
398
  '<Files *.php>',
399
  $this->generate_htaccess_rule( false ),
400
  '</Files>',
401
+ );
402
 
403
  $rule[] = '## WP Defender - End ##';
404
  file_put_contents( $ht_access_path, $exists_rules . implode( PHP_EOL, $rule ), LOCK_EX );
412
  public function protect_includes_directory() {
413
  $ht_access_path = $this->includedir_path;
414
 
415
+ if ( empty( $ht_access_path ) ) {
416
  $ht_access_path = ABSPATH . WPINC . '/' . '.htaccess';
417
  }
418
+ // Create a htaccess-file if it doesn't exist.
419
+ if ( ! is_file( $ht_access_path )
420
+ && false === (bool) file_put_contents( $ht_access_path, '', LOCK_EX )
421
+ ) {
422
+ return $this->get_error_by_file_path( $ht_access_path );
423
+ }
424
+ // If the htaccess-file is existed.
425
+ if ( ! is_writable( $ht_access_path ) ) {
426
+ return $this->get_error_by_file_path( $ht_access_path );
 
 
427
  }
428
 
429
  $exists_rules = $this->cleanup_old_rules( file_get_contents( $ht_access_path ) );
430
 
431
+ $rule = array(
432
  '## WP Defender - Protect PHP Executed ##',
433
  '<Files *.php>',
434
  $this->generate_htaccess_rule( false ),
440
  $this->generate_htaccess_rule( true ),
441
  '</Files>',
442
  '## WP Defender - End ##',
443
+ );
444
 
445
  file_put_contents( $ht_access_path, $exists_rules . implode( PHP_EOL, $rule ), LOCK_EX );
446
  }
476
  public function protect_uploads_directory() {
477
  if ( defined( 'UPLOADS' ) ) {
478
  $this->contentdir_path = ABSPATH . UPLOADS . '/' . '.htaccess';
479
+
480
  return $this->protect_content_directory();
481
  }
482
  }
483
 
484
  /**
485
+ * Unprotect content directory.
486
  *
487
  * @return void|WP_Error
488
  */
489
  public function unprotect_content_directory() {
490
  $ht_access_path = $this->contentdir_path;
491
 
492
+ if ( empty( $ht_access_path ) ) {
493
  $ht_access_path = WP_CONTENT_DIR . '/' . '.htaccess';
494
  }
495
+ // Quick exit if the file does not exist.
496
+ if ( ! is_file( $ht_access_path ) ) {
497
  return;
498
  }
499
+ // If the htaccess-file is existed.
500
  if ( ! is_writable( $ht_access_path ) ) {
501
+ return $this->get_error_by_file_path( $ht_access_path );
 
502
  }
503
 
504
  $ht_config = $this->cleanup_old_rules( file_get_contents( $ht_access_path ) );
507
  file_put_contents( $ht_access_path, trim( $ht_config ), LOCK_EX );
508
  }
509
 
510
+ /**
511
+ * Unprotect includes-directory.
512
+ * Todo: can be combined with unprotect_content_directory()?
513
+ *
514
+ * @return void|WP_Error
515
+ */
516
  public function unprotect_includes_directory() {
517
  $ht_access_path = $this->includedir_path;
518
 
519
+ if ( empty( $ht_access_path ) ) {
520
  $ht_access_path = ABSPATH . WPINC . '/' . '.htaccess';
521
  }
522
+ // Quick exit if the file does not exist.
523
+ if ( ! is_file( $ht_access_path ) ) {
524
+ return;
525
+ }
526
+ // If the htaccess-file is existed.
527
  if ( ! is_writable( $ht_access_path ) ) {
528
+ return $this->get_error_by_file_path( $ht_access_path );
 
 
529
  }
530
 
531
  $ht_config = $this->cleanup_old_rules( file_get_contents( $ht_access_path ) );
533
  }
534
 
535
  /**
536
+ * Unprotect upload directory.
537
  *
538
  * @return void
539
  */
549
  *
550
  * @param array $config
551
  */
552
+ public function set_new_htaccess_config( $config = array() ) {
553
  if ( ! empty( $config ) ) {
554
  $this->new_htaccess_config = $config;
555
  }
src/component/user-agent-lockout.php CHANGED
@@ -54,14 +54,20 @@ class User_Agent extends Component {
54
  * @param string $reason
55
  */
56
  private function log_event( $ip, $user_agent, $reason ) {
57
- $model = new Lockout_Log();
58
- $model->ip = $ip;
59
- $model->user_agent = $user_agent;
60
- $model->date = time();
61
- $model->tried = $user_agent;
62
- $model->blog_id = get_current_blog_id();
63
- $model->type = Lockout_Log::LOCKOUT_UA;
64
- $model->country_iso_code = $this->ip_to_country( $ip )['iso'];
 
 
 
 
 
 
65
  switch ( $reason ) {
66
  case self::REASON_BAD_POST:
67
  // Distinguish between different block cases of User agent lockouts.
54
  * @param string $reason
55
  */
56
  private function log_event( $ip, $user_agent, $reason ) {
57
+ $model = new Lockout_Log();
58
+ $model->ip = $ip;
59
+ $model->user_agent = $user_agent;
60
+ $model->date = time();
61
+ $model->tried = $user_agent;
62
+ $model->blog_id = get_current_blog_id();
63
+ $model->type = Lockout_Log::LOCKOUT_UA;
64
+
65
+ $ip_to_country = $this->ip_to_country( $ip );
66
+
67
+ if ( ! empty( $ip_to_country ) && isset( $ip_to_country['iso'] ) ) {
68
+ $model->country_iso_code = $ip_to_country['iso'];
69
+ }
70
+
71
  switch ( $reason ) {
72
  case self::REASON_BAD_POST:
73
  // Distinguish between different block cases of User agent lockouts.
src/traits/country.php CHANGED
@@ -339,6 +339,12 @@ trait Country {
339
 
340
  if ( is_wp_error( $response ) || 200 !== (int) wp_remote_retrieve_response_code( $response ) ) {
341
 
 
 
 
 
 
 
342
  return false;
343
 
344
  }
339
 
340
  if ( is_wp_error( $response ) || 200 !== (int) wp_remote_retrieve_response_code( $response ) ) {
341
 
342
+ $log_message = 'HTTP Status Code: ' . wp_remote_retrieve_response_code( $response ) . PHP_EOL;
343
+ $log_message .= 'HTTP Response Message: ' . wp_remote_retrieve_response_message( $response ) . PHP_EOL;
344
+ $log_message .= 'API URL: ' . $url . PHP_EOL;
345
+
346
+ $this->log( $log_message, 'firewall.log' );
347
+
348
  return false;
349
 
350
  }
src/upgrader.php CHANGED
@@ -311,8 +311,8 @@ class Upgrader {
311
  if ( version_compare( $db_version, '2.8.0', '<' ) ) {
312
  $this->upgrade_2_8_0();
313
  }
314
- if ( version_compare( $db_version, '2.8.1', '<' ) ) {
315
- $this->upgrade_2_8_1();
316
  }
317
 
318
  defender_no_fresh_install();
@@ -941,12 +941,12 @@ Your temporary password is {{passcode}}. To finish logging in, copy and paste th
941
  }
942
 
943
  /**
944
- * Upgrade to 2.8.1.
945
  *
946
- * @since 2.8.1
947
  * @return void
948
  */
949
- private function upgrade_2_8_1() {
950
  $this->add_country_iso_code_column();
951
  }
952
  }
311
  if ( version_compare( $db_version, '2.8.0', '<' ) ) {
312
  $this->upgrade_2_8_0();
313
  }
314
+ if ( version_compare( $db_version, '2.8.3', '<' ) ) {
315
+ $this->upgrade_2_8_3();
316
  }
317
 
318
  defender_no_fresh_install();
941
  }
942
 
943
  /**
944
+ * Upgrade to 2.8.3.
945
  *
946
+ * @since 2.8.3
947
  * @return void
948
  */
949
+ private function upgrade_2_8_3() {
950
  $this->add_country_iso_code_column();
951
  }
952
  }
wp-defender.php CHANGED
@@ -2,7 +2,7 @@
2
  /**
3
  * Plugin Name: Defender
4
  * Plugin URI: https://wpmudev.com/project/wp-defender/
5
- * Version: 2.8.2
6
  * Description: Get regular security scans, vulnerability reports, safety recommendations and customized hardening for your site in just a few clicks. Defender is the analyst and enforcer who never sleeps.
7
  * Author: WPMU DEV
8
  * Author URI: https://wpmudev.com/
@@ -33,10 +33,10 @@ if ( ! defined( 'ABSPATH' ) ) {
33
  die;
34
  }
35
  if ( ! defined( 'DEFENDER_VERSION' ) ) {
36
- define( 'DEFENDER_VERSION', '2.8.2' );
37
  }
38
  if ( ! defined( 'DEFENDER_DB_VERSION' ) ) {
39
- define( 'DEFENDER_DB_VERSION', '2.8.2' );
40
  }
41
  if ( ! defined( 'DEFENDER_SUI' ) ) {
42
  define( 'DEFENDER_SUI', '2-12-2' );
2
  /**
3
  * Plugin Name: Defender
4
  * Plugin URI: https://wpmudev.com/project/wp-defender/
5
+ * Version: 2.8.3
6
  * Description: Get regular security scans, vulnerability reports, safety recommendations and customized hardening for your site in just a few clicks. Defender is the analyst and enforcer who never sleeps.
7
  * Author: WPMU DEV
8
  * Author URI: https://wpmudev.com/
33
  die;
34
  }
35
  if ( ! defined( 'DEFENDER_VERSION' ) ) {
36
+ define( 'DEFENDER_VERSION', '2.8.3' );
37
  }
38
  if ( ! defined( 'DEFENDER_DB_VERSION' ) ) {
39
+ define( 'DEFENDER_DB_VERSION', '2.8.3' );
40
  }
41
  if ( ! defined( 'DEFENDER_SUI' ) ) {
42
  define( 'DEFENDER_SUI', '2-12-2' );