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

Version Description

( 2022-09-29 ) =

  • Fix: Encrypt 2FA secret keys
Download this release

Release Info

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

Code changes from version 3.3.1 to 3.3.2

languages/wpdef-default.pot CHANGED
@@ -6,9 +6,9 @@
6
  #, fuzzy
7
  msgid ""
8
  msgstr ""
9
- "Project-Id-Version: wp-defender 3.3.1\n"
10
  "Report-Msgid-Bugs-To: \n"
11
- "POT-Creation-Date: 2022-09-21 09:52+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"
@@ -1090,7 +1090,7 @@ msgstr ""
1090
  msgid "password reset"
1091
  msgstr ""
1092
 
1093
- #: src/component/backup-settings.php:529 src/upgrader.php:646
1094
  msgid "Basic Config"
1095
  msgstr ""
1096
 
@@ -1128,8 +1128,8 @@ msgstr ""
1128
  #: src/controller/password-protection.php:290
1129
  #: src/controller/password-protection.php:296 src/controller/recaptcha.php:1017
1130
  #: src/controller/scan.php:661 src/controller/scan.php:694
1131
- #: src/controller/security-headers.php:167 src/controller/two-factor.php:1131
1132
- #: src/controller/two-factor.php:1143
1133
  #: front/src/module/dashboard/component/advanced-tools.vue:30
1134
  #: front/src/module/dashboard/component/advanced-tools.vue:52
1135
  #: front/src/module/dashboard/component/advanced-tools.vue:93
@@ -1147,8 +1147,8 @@ msgstr ""
1147
  #: src/controller/mask-login.php:757 src/controller/password-protection.php:278
1148
  #: src/controller/password-protection.php:295 src/controller/recaptcha.php:1017
1149
  #: src/controller/scan.php:659 src/controller/scan.php:693
1150
- #: src/controller/security-headers.php:167 src/controller/two-factor.php:1131
1151
- #: src/controller/two-factor.php:1143
1152
  #: front/src/module/dashboard/component/advanced-tools.vue:29
1153
  #: front/src/module/dashboard/component/advanced-tools.vue:53
1154
  #: front/src/module/dashboard/component/advanced-tools.vue:92
@@ -1201,7 +1201,7 @@ msgid "Firewall"
1201
  msgstr ""
1202
 
1203
  #: src/component/backup-settings.php:1195 src/controller/two-factor.php:68
1204
- #: src/controller/two-factor.php:1412
1205
  msgid "2FA"
1206
  msgstr ""
1207
 
@@ -1987,7 +1987,7 @@ msgstr ""
1987
  msgid "Your token is invalid."
1988
  msgstr ""
1989
 
1990
- #: src/component/two-fa.php:477 src/controller/two-factor.php:969
1991
  #: src/view/two-fa/user-options.php:12
1992
  #: front/src/module/dashboard/component/preset-config.vue:123
1993
  #: front/src/module/dashboard/component/two-fa.vue:6
@@ -2027,7 +2027,7 @@ msgid "Generate non-expirable backup codes that can be used to log in once."
2027
  msgstr ""
2028
 
2029
  #: src/component/two-factor/providers/backup-codes.php:77
2030
- #: src/controller/two-factor.php:1290
2031
  msgid "Each backup code can only be used to log in once."
2032
  msgstr ""
2033
 
@@ -2045,7 +2045,7 @@ msgstr ""
2045
 
2046
  #: src/component/two-factor/providers/backup-codes.php:138
2047
  #: src/component/two-factor/providers/fallback-email.php:107
2048
- #: src/component/two-factor/providers/totp.php:117
2049
  msgid "Authenticate"
2050
  msgstr ""
2051
 
@@ -2062,7 +2062,7 @@ msgid "Generate Backup Codes"
2062
  msgstr ""
2063
 
2064
  #: src/component/two-factor/providers/backup-codes.php:233
2065
- #: src/controller/two-factor.php:1289
2066
  msgid "Get New Codes"
2067
  msgstr ""
2068
 
@@ -2104,41 +2104,41 @@ msgstr ""
2104
  msgid "ERROR: Invalid passcode."
2105
  msgstr ""
2106
 
2107
- #: src/component/two-factor/providers/totp.php:86
2108
  msgid "TOTP Authenticator App"
2109
  msgstr ""
2110
 
2111
- #: src/component/two-factor/providers/totp.php:93
2112
  msgid "TOTP Authentication"
2113
  msgstr ""
2114
 
2115
- #: src/component/two-factor/providers/totp.php:100
2116
  msgid "TOTP"
2117
  msgstr ""
2118
 
2119
  #. translators: %s: style class
2120
- #: src/component/two-factor/providers/totp.php:140
2121
  #, php-format
2122
  msgid ""
2123
  "<button type=\"button\" class=\"button reset-totp-keys button-secondary hide-"
2124
  "if-no-js\" %s>Reset Keys</button>"
2125
  msgstr ""
2126
 
2127
- #: src/component/two-factor/providers/totp.php:145
2128
  msgid "TOTP Authentication method is active for this site"
2129
  msgstr ""
2130
 
2131
- #: src/component/two-factor/providers/totp.php:146
2132
  msgid "Use an authenticator app to sign in with a separate passcode."
2133
  msgstr ""
2134
 
2135
- #: src/component/two-factor/providers/totp.php:223
2136
  #: src/controller/two-factor.php:401
2137
  msgid "Whoops, the passcode you entered was incorrect or expired."
2138
  msgstr ""
2139
 
2140
  #: src/component/two-factor/providers/webauthn.php:46
2141
- #: src/controller/two-factor.php:1093
2142
  msgid "Beta"
2143
  msgstr ""
2144
 
@@ -2298,7 +2298,7 @@ msgstr ""
2298
  #: src/controller/firewall.php:144 src/controller/main-setting.php:97
2299
  #: src/controller/mask-login.php:312 src/controller/password-protection.php:218
2300
  #: src/controller/password-reset.php:198 src/controller/scan.php:361
2301
- #: src/controller/security-headers.php:74 src/controller/two-factor.php:879
2302
  #: src/traits/setting.php:21
2303
  msgid "Your settings have been updated."
2304
  msgstr ""
@@ -2946,24 +2946,24 @@ msgstr ""
2946
  msgid "You have logged in successfully."
2947
  msgstr ""
2948
 
2949
- #: src/controller/two-factor.php:639
2950
  msgid "Please input a valid OTP code."
2951
  msgstr ""
2952
 
2953
- #: src/controller/two-factor.php:669
2954
  msgid "Your OTP code is incorrect. Please try again."
2955
  msgstr ""
2956
 
2957
- #: src/controller/two-factor.php:981
2958
  msgid "Test email has been sent to your email."
2959
  msgstr ""
2960
 
2961
- #: src/controller/two-factor.php:986
2962
  msgid "Test email failed."
2963
  msgstr ""
2964
 
2965
  #. translators: %s: link
2966
- #: src/controller/two-factor.php:1096
2967
  #, php-format
2968
  msgid ""
2969
  "Web Authentication is now available. <a target=\"_blank\" href=\"%s\">Click "
@@ -2971,26 +2971,26 @@ msgid ""
2971
  msgstr ""
2972
 
2973
  #. translators: %s: count
2974
- #: src/controller/two-factor.php:1286
2975
  #, php-format
2976
  msgid "2FA Backup Codes for %s:"
2977
  msgstr ""
2978
 
2979
- #: src/controller/two-factor.php:1315
2980
  msgid "Reset two factor"
2981
  msgstr ""
2982
 
2983
  #. translators: %s: URL to regenerate code
2984
- #: src/controller/two-factor.php:1360
2985
  #, php-format
2986
  msgid "Two factor authentication has been reset for <b>%s.</b>"
2987
  msgstr ""
2988
 
2989
- #: src/controller/two-factor.php:1385 src/controller/two-factor.php:1386
2990
  msgid "Save changes"
2991
  msgstr ""
2992
 
2993
- #: src/controller/two-factor.php:1438
2994
  msgid "Two-Factor settings updated successfully."
2995
  msgstr ""
2996
 
@@ -4225,7 +4225,7 @@ msgstr ""
4225
  msgid "Hub"
4226
  msgstr ""
4227
 
4228
- #: src/upgrader.php:645
4229
  msgid "Basic config"
4230
  msgstr ""
4231
 
6
  #, fuzzy
7
  msgid ""
8
  msgstr ""
9
+ "Project-Id-Version: wp-defender 3.3.2\n"
10
  "Report-Msgid-Bugs-To: \n"
11
+ "POT-Creation-Date: 2022-09-29 12:54+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"
1090
  msgid "password reset"
1091
  msgstr ""
1092
 
1093
+ #: src/component/backup-settings.php:529 src/upgrader.php:649
1094
  msgid "Basic Config"
1095
  msgstr ""
1096
 
1128
  #: src/controller/password-protection.php:290
1129
  #: src/controller/password-protection.php:296 src/controller/recaptcha.php:1017
1130
  #: src/controller/scan.php:661 src/controller/scan.php:694
1131
+ #: src/controller/security-headers.php:167 src/controller/two-factor.php:1134
1132
+ #: src/controller/two-factor.php:1146
1133
  #: front/src/module/dashboard/component/advanced-tools.vue:30
1134
  #: front/src/module/dashboard/component/advanced-tools.vue:52
1135
  #: front/src/module/dashboard/component/advanced-tools.vue:93
1147
  #: src/controller/mask-login.php:757 src/controller/password-protection.php:278
1148
  #: src/controller/password-protection.php:295 src/controller/recaptcha.php:1017
1149
  #: src/controller/scan.php:659 src/controller/scan.php:693
1150
+ #: src/controller/security-headers.php:167 src/controller/two-factor.php:1134
1151
+ #: src/controller/two-factor.php:1146
1152
  #: front/src/module/dashboard/component/advanced-tools.vue:29
1153
  #: front/src/module/dashboard/component/advanced-tools.vue:53
1154
  #: front/src/module/dashboard/component/advanced-tools.vue:92
1201
  msgstr ""
1202
 
1203
  #: src/component/backup-settings.php:1195 src/controller/two-factor.php:68
1204
+ #: src/controller/two-factor.php:1415
1205
  msgid "2FA"
1206
  msgstr ""
1207
 
1987
  msgid "Your token is invalid."
1988
  msgstr ""
1989
 
1990
+ #: src/component/two-fa.php:477 src/controller/two-factor.php:968
1991
  #: src/view/two-fa/user-options.php:12
1992
  #: front/src/module/dashboard/component/preset-config.vue:123
1993
  #: front/src/module/dashboard/component/two-fa.vue:6
2027
  msgstr ""
2028
 
2029
  #: src/component/two-factor/providers/backup-codes.php:77
2030
+ #: src/controller/two-factor.php:1293
2031
  msgid "Each backup code can only be used to log in once."
2032
  msgstr ""
2033
 
2045
 
2046
  #: src/component/two-factor/providers/backup-codes.php:138
2047
  #: src/component/two-factor/providers/fallback-email.php:107
2048
+ #: src/component/two-factor/providers/totp.php:118
2049
  msgid "Authenticate"
2050
  msgstr ""
2051
 
2062
  msgstr ""
2063
 
2064
  #: src/component/two-factor/providers/backup-codes.php:233
2065
+ #: src/controller/two-factor.php:1292
2066
  msgid "Get New Codes"
2067
  msgstr ""
2068
 
2104
  msgid "ERROR: Invalid passcode."
2105
  msgstr ""
2106
 
2107
+ #: src/component/two-factor/providers/totp.php:87
2108
  msgid "TOTP Authenticator App"
2109
  msgstr ""
2110
 
2111
+ #: src/component/two-factor/providers/totp.php:94
2112
  msgid "TOTP Authentication"
2113
  msgstr ""
2114
 
2115
+ #: src/component/two-factor/providers/totp.php:101
2116
  msgid "TOTP"
2117
  msgstr ""
2118
 
2119
  #. translators: %s: style class
2120
+ #: src/component/two-factor/providers/totp.php:141
2121
  #, php-format
2122
  msgid ""
2123
  "<button type=\"button\" class=\"button reset-totp-keys button-secondary hide-"
2124
  "if-no-js\" %s>Reset Keys</button>"
2125
  msgstr ""
2126
 
2127
+ #: src/component/two-factor/providers/totp.php:146
2128
  msgid "TOTP Authentication method is active for this site"
2129
  msgstr ""
2130
 
2131
+ #: src/component/two-factor/providers/totp.php:147
2132
  msgid "Use an authenticator app to sign in with a separate passcode."
2133
  msgstr ""
2134
 
2135
+ #: src/component/two-factor/providers/totp.php:224
2136
  #: src/controller/two-factor.php:401
2137
  msgid "Whoops, the passcode you entered was incorrect or expired."
2138
  msgstr ""
2139
 
2140
  #: src/component/two-factor/providers/webauthn.php:46
2141
+ #: src/controller/two-factor.php:1096
2142
  msgid "Beta"
2143
  msgstr ""
2144
 
2298
  #: src/controller/firewall.php:144 src/controller/main-setting.php:97
2299
  #: src/controller/mask-login.php:312 src/controller/password-protection.php:218
2300
  #: src/controller/password-reset.php:198 src/controller/scan.php:361
2301
+ #: src/controller/security-headers.php:74 src/controller/two-factor.php:878
2302
  #: src/traits/setting.php:21
2303
  msgid "Your settings have been updated."
2304
  msgstr ""
2946
  msgid "You have logged in successfully."
2947
  msgstr ""
2948
 
2949
+ #: src/controller/two-factor.php:638
2950
  msgid "Please input a valid OTP code."
2951
  msgstr ""
2952
 
2953
+ #: src/controller/two-factor.php:668
2954
  msgid "Your OTP code is incorrect. Please try again."
2955
  msgstr ""
2956
 
2957
+ #: src/controller/two-factor.php:980
2958
  msgid "Test email has been sent to your email."
2959
  msgstr ""
2960
 
2961
+ #: src/controller/two-factor.php:985
2962
  msgid "Test email failed."
2963
  msgstr ""
2964
 
2965
  #. translators: %s: link
2966
+ #: src/controller/two-factor.php:1099
2967
  #, php-format
2968
  msgid ""
2969
  "Web Authentication is now available. <a target=\"_blank\" href=\"%s\">Click "
2971
  msgstr ""
2972
 
2973
  #. translators: %s: count
2974
+ #: src/controller/two-factor.php:1289
2975
  #, php-format
2976
  msgid "2FA Backup Codes for %s:"
2977
  msgstr ""
2978
 
2979
+ #: src/controller/two-factor.php:1318
2980
  msgid "Reset two factor"
2981
  msgstr ""
2982
 
2983
  #. translators: %s: URL to regenerate code
2984
+ #: src/controller/two-factor.php:1363
2985
  #, php-format
2986
  msgid "Two factor authentication has been reset for <b>%s.</b>"
2987
  msgstr ""
2988
 
2989
+ #: src/controller/two-factor.php:1388 src/controller/two-factor.php:1389
2990
  msgid "Save changes"
2991
  msgstr ""
2992
 
2993
+ #: src/controller/two-factor.php:1441
2994
  msgid "Two-Factor settings updated successfully."
2995
  msgstr ""
2996
 
4225
  msgid "Hub"
4226
  msgstr ""
4227
 
4228
+ #: src/upgrader.php:648
4229
  msgid "Basic config"
4230
  msgstr ""
4231
 
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: 3.3.1
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, limit login attempts, custom login url, activity log, audit logs, block hackers, two-factor authentication, 2fa, hack, captcha, webauthn, authentication, fido2, fingerprint, face verification, yubikey, USB keys, woocommerce
8
  Requires at least: 5.2
9
  Tested up to: 6.0.2
10
- Stable tag: 3.3.1
11
  Requires PHP: 7.2.0
12
  License: GPL v2 - http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
13
 
@@ -247,6 +247,10 @@ Please open a new thread in Defender’s [support forum](https://wordpress.org/s
247
 
248
  == Changelog ==
249
 
 
 
 
 
250
  = 3.3.1 ( 2022-09-21 ) =
251
 
252
  - Enhance: 2FA security improvements
@@ -315,20 +319,6 @@ Please open a new thread in Defender’s [support forum](https://wordpress.org/s
315
  - Fix: Pwned Password updated with simple password on Profile page
316
  - Fix: Storing the MaxMind DB file path relatively instead of a full path
317
 
318
- = 3.0.1 ( 2022-06-14 ) =
319
-
320
- - Fix: Beehive Pro plugin flagged issues
321
-
322
- = 3.0.0 ( 2022-06-06 ) =
323
-
324
- - New: Biometric Authentication
325
- - New: Giveaway Opt-in for Free version
326
- - Enhance: PHP version upgrade
327
- - Enhance: Compatibility with WordPress 6.0
328
- - Enhance: WP-CLI command to show Scan details
329
- - Enhance: Update SUI to the latest version
330
- - Fix: Audit events logged not showing after applying some date range
331
-
332
 
333
  [Changelog for previous versions](https://wpmudev.com/project/wp-defender/#view-changelog).
334
 
1
  === Defender Security - Malware Scanner, Login Security & Firewall ===
2
  Plugin Name: Defender Security - Malware Scanner, Login Security & Firewall
3
+ Version: 3.3.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, limit login attempts, custom login url, activity log, audit logs, block hackers, two-factor authentication, 2fa, hack, captcha, webauthn, authentication, fido2, fingerprint, face verification, yubikey, USB keys, woocommerce
8
  Requires at least: 5.2
9
  Tested up to: 6.0.2
10
+ Stable tag: 3.3.2
11
  Requires PHP: 7.2.0
12
  License: GPL v2 - http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
13
 
247
 
248
  == Changelog ==
249
 
250
+ = 3.3.2 ( 2022-09-29 ) =
251
+
252
+ - Fix: Encrypt 2FA secret keys
253
+
254
  = 3.3.1 ( 2022-09-21 ) =
255
 
256
  - Enhance: 2FA security improvements
319
  - Fix: Pwned Password updated with simple password on Profile page
320
  - Fix: Storing the MaxMind DB file path relatively instead of a full path
321
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
322
 
323
  [Changelog for previous versions](https://wpmudev.com/project/wp-defender/#view-changelog).
324
 
src/component/crypt.php CHANGED
@@ -12,7 +12,7 @@ class Crypt extends \Calotes\Base\Component {
12
  *
13
  * @return string
14
  */
15
- public function random_bytes( int $bytes ): string {
16
  // Try with random_bytes.
17
  if ( function_exists( 'random_bytes' ) ) {
18
  try {
@@ -21,7 +21,8 @@ class Crypt extends \Calotes\Base\Component {
21
  return $rand;
22
  }
23
  } catch ( \Exception $e ) {
24
- $this->log( $e->getMessage(), 'internal.log' );
 
25
  }
26
  }
27
  // Try with openssl_random_pseudo_bytes.
@@ -48,16 +49,17 @@ class Crypt extends \Calotes\Base\Component {
48
  *
49
  * @return int
50
  */
51
- public function random_int( $min = 0, $max = 0x7FFFFFFF ): int {
52
  if ( function_exists( 'random_int' ) ) {
53
  try {
54
  return random_int( $min, $max );
55
  } catch ( \Exception $e ) {
56
- $this->log( $e->getMessage(), 'internal.log' );
 
57
  }
58
  }
59
  $diff = $max - $min;
60
- $bytes = $this->random_bytes( 4 );
61
  if ( 4 !== strlen( $bytes ) ) {
62
  throw new \RuntimeException( 'Unable to get 4 bytes' );
63
  }
@@ -94,4 +96,58 @@ class Crypt extends \Calotes\Base\Component {
94
 
95
  return 0 === $result;
96
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
97
  }
12
  *
13
  * @return string
14
  */
15
+ public static function random_bytes( int $bytes ): string {
16
  // Try with random_bytes.
17
  if ( function_exists( 'random_bytes' ) ) {
18
  try {
21
  return $rand;
22
  }
23
  } catch ( \Exception $e ) {
24
+ $_this = new self();
25
+ $_this->log( $e->getMessage(), 'internal.log' );
26
  }
27
  }
28
  // Try with openssl_random_pseudo_bytes.
49
  *
50
  * @return int
51
  */
52
+ public static function random_int( $min = 0, $max = 0x7FFFFFFF ): int {
53
  if ( function_exists( 'random_int' ) ) {
54
  try {
55
  return random_int( $min, $max );
56
  } catch ( \Exception $e ) {
57
+ $_this = new self();
58
+ $_this->log( $e->getMessage(), 'internal.log' );
59
  }
60
  }
61
  $diff = $max - $min;
62
+ $bytes = self::random_bytes( 4 );
63
  if ( 4 !== strlen( $bytes ) ) {
64
  throw new \RuntimeException( 'Unable to get 4 bytes' );
65
  }
96
 
97
  return 0 === $result;
98
  }
99
+
100
+ /**
101
+ * @param string $plaintext
102
+ * @param string $key
103
+ *
104
+ * @return string
105
+ */
106
+ private static function encrypt_data( $plaintext, $key ) {
107
+ $cipher = 'aes-256-cbc';
108
+ $iv_len = openssl_cipher_iv_length( $cipher );
109
+ $iv = self::random_bytes( $iv_len );
110
+ $ciphertext_raw = openssl_encrypt( $plaintext, 'aes-256-cbc', $key, OPENSSL_RAW_DATA, $iv );
111
+ $hmac = hash_hmac( 'sha256', $ciphertext_raw, $key, true );
112
+
113
+ return base64_encode( $iv . $hmac . $ciphertext_raw );
114
+ }
115
+
116
+ /**
117
+ * @param string $encrypt_data
118
+ * @param string $key
119
+ *
120
+ * @return string
121
+ */
122
+ private static function decrypt_data( $encrypt_data, $key ) {
123
+ $str = base64_decode( $encrypt_data );
124
+ $cipher = 'aes-256-cbc';
125
+ $iv_len = openssl_cipher_iv_length( $cipher );
126
+ $iv = substr( $str, 0, $iv_len );
127
+ $ciphertext_raw = substr( $str, $iv_len + 32 );
128
+
129
+ return openssl_decrypt( $ciphertext_raw, $cipher, $key, OPENSSL_RAW_DATA, $iv );
130
+ }
131
+
132
+ /**
133
+ * @param string $data
134
+ *
135
+ * @return string
136
+ */
137
+ public static function get_decrypted_string( $data ): string {
138
+ $key = file_get_contents( __DIR__ . '/def.key' );
139
+
140
+ return false !== $key ? self::decrypt_data( $data, $key ) : '';
141
+ }
142
+
143
+ /**
144
+ * @param string $data
145
+ *
146
+ * @return string
147
+ */
148
+ public static function get_encrypted_string( $data ): string {
149
+ $key = file_get_contents( __DIR__ . '/def.key' );
150
+
151
+ return false !== $key ? self::encrypt_data( $data, $key ) : '';
152
+ }
153
  }
src/component/def.key ADDED
@@ -0,0 +1,17 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ -----BEGIN CERTIFICATE-----
2
+ MIICoDCCAYgCAQAwWzELMAkGA1UEBhMCVVMxEDAOBgNVBAgMB0FsYWJhbWExEzAR
3
+ BgNVBAcMCkJpcm1pbmdoYW0xDzANBgNVBAoMBkluY3N1YjEUMBIGA1UEAwwLd3Bt
4
+ dWRldi5jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDADv0IRzpr
5
+ vGgteGzbzlXXI6JKd6nTM8q9jLXoFfnrmlGxbYJxnVd+86/99nUK9Z1cVwDEMNXO
6
+ NCdbX+7OFPSQs0A59VDS/qFwSc3LviLJU2QcwTxT1/04WWDUNgeAfBFXBDc/4AY7
7
+ 0qEkiw5BVnsYGGSK/ZtDYxHgUjiAcw+pThCikRhfbz6XnEcKOBlrBuPa7vn4IS3Y
8
+ /v9GRLn3eBwsWJ93sBDuTyncKoCvwtPiWZS6XYNl5JgUmTALiAyNf0HM4g+mIwGU
9
+ rsneWofNS+VXVmc1zG8DnhYjVmv5kj18gA9ak25L+lXCBReDrlySP23JfhFOgmXh
10
+ PyKxjSRfaGhbAgMBAAGgADANBgkqhkiG9w0BAQsFAAOCAQEARJavBbMdiMOq5soH
11
+ KYcLMqS8XwEJRGmIed4j0JpLAADMHSU047XXhgXLHEb4XI2vdkz7SVzPALstAkQW
12
+ H8rrmCfjVdt8zDCm/wzqq3LsFaKECYDIOBEsuFpNOkmCFHwEPJfEWKS9dhganVQe
13
+ Y1HZMcxFX51x0CsMOWCgZCtpgJZN0lRuAuhKg9hX++kifNEKYHSwLwNw974M/+EM
14
+ Lykj8K1C4Jl9TfsR1JVaeJfCzWC8qXWkiaRSu95ffsO+MLuPCrmKRQ/WjAfgwAH9
15
+ WatxlmyzEKlJyrUeLaJXcJY3fXv8aOowEnXYvZfvJ/JOsrc3LY2azS8KnaMDgEy2
16
+ Wo3AaQ==
17
+ -----END CERTIFICATE-----
src/component/two-factor/providers/totp.php CHANGED
@@ -4,6 +4,7 @@ declare( strict_types = 1 );
4
  namespace WP_Defender\Component\Two_Factor\Providers;
5
 
6
  use Calotes\Helper\HTTP;
 
7
  use WP_Defender\Component\Two_Factor\Two_Factor_Provider;
8
  use WP_Defender\Extra\Base2n;
9
  use WP_Defender\Traits\IO;
@@ -228,88 +229,6 @@ class Totp extends Two_Factor_Provider {
228
  return $this->get_component()->verify_otp( $otp, $user );
229
  }
230
 
231
- /**
232
- * @return bool|array
233
- */
234
- public function get_2fa_keys() {
235
- $file = $this->get_2fa_lock_path();
236
- if( file_exists( $file ) ) {
237
- $content = file_get_contents( $file );
238
- if ( trim( $content ) ) {
239
- return preg_split( '/[\r\n]+/', $content );
240
- }
241
- }
242
-
243
- return false;
244
- }
245
-
246
- /**
247
- * @param int $user_id
248
- * @param array $data
249
- *
250
- * @return string
251
- */
252
- public function get_2fa_key_by( $user_id, $data ) {
253
- if ( is_array( $data ) && ! empty( $data ) ) {
254
- foreach ( $data as $key => $line ) {
255
- if( 0 === strpos( $line, $user_id . '://:' ) ) {
256
- [ $uid, $secret_key ] = explode( '://:', $line );
257
- if ( $user_id === (int) $uid ) {
258
- return $secret_key;
259
- }
260
- }
261
- }
262
- }
263
-
264
- return '';
265
- }
266
-
267
- /**
268
- * @param string $line
269
- *
270
- * @return false|int
271
- */
272
- public function add_2fa_line( $line ) {
273
- $file = $this->get_2fa_lock_path();
274
-
275
- return file_put_contents( $file, $line, FILE_APPEND | LOCK_EX );
276
- }
277
-
278
- /**
279
- * @param string $line
280
- *
281
- * @return false|int
282
- */
283
- public function remove_2fa_line( $line ) {
284
-
285
- $file = $this->get_2fa_lock_path();
286
- $content = file_get_contents( $file );
287
- $new_content = str_replace( $line, '', $content );
288
-
289
- return file_put_contents( $file, $new_content, LOCK_EX );
290
- }
291
-
292
- /**
293
- * @param int $user_id
294
- *
295
- * @return void
296
- */
297
- public function remove_2fa_line_by( $user_id ) {
298
- $data = $this->get_2fa_keys();
299
- if ( is_array( $data ) && ! empty( $data ) ) {
300
- foreach ( $data as $key => $line ) {
301
- [ $uid, $secret_key ] = explode( '://:', $line );
302
- if ( $user_id === (int) $uid ) {
303
- $file = $this->get_2fa_lock_path();
304
- $content = file_get_contents( $file );
305
- $new_content = str_replace( $line . "\r\n", '', $content );
306
- file_put_contents( $file, $new_content, LOCK_EX );
307
- break;
308
- }
309
- }
310
- }
311
- }
312
-
313
  /**
314
  * @param WP_User|null $user
315
  *
@@ -323,17 +242,16 @@ class Totp extends Two_Factor_Provider {
323
  $user_id = get_current_user_id();
324
  }
325
 
326
- $_this = new self();
327
- $arr = $_this->get_2fa_keys();
328
- $secret = $_this->get_2fa_key_by( $user_id , $arr );
329
- if ( ! empty( $secret ) ) {
330
- return $secret;
331
  }
332
  // No data then add new one.
333
- $secret = defender_generate_random_string( self::TOTP_LENGTH, self::TOTP_CHARACTERS );
334
- $_this->add_2fa_line( $user_id . '://:' . $secret . "\r\n" );
 
335
 
336
- return $secret;
337
  }
338
 
339
  /**
4
  namespace WP_Defender\Component\Two_Factor\Providers;
5
 
6
  use Calotes\Helper\HTTP;
7
+ use WP_Defender\Component\Crypt;
8
  use WP_Defender\Component\Two_Factor\Two_Factor_Provider;
9
  use WP_Defender\Extra\Base2n;
10
  use WP_Defender\Traits\IO;
229
  return $this->get_component()->verify_otp( $otp, $user );
230
  }
231
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
232
  /**
233
  * @param WP_User|null $user
234
  *
242
  $user_id = get_current_user_id();
243
  }
244
 
245
+ $data = get_user_meta( $user_id, self::TOTP_SECRET_KEY, true );
246
+ if ( ! empty( $data ) ) {
247
+ return Crypt::get_decrypted_string( $data );
 
 
248
  }
249
  // No data then add new one.
250
+ $plaintext = defender_generate_random_string( self::TOTP_LENGTH, self::TOTP_CHARACTERS );
251
+ $secret = Crypt::get_encrypted_string( $plaintext );
252
+ update_user_meta( $user_id, self::TOTP_SECRET_KEY, $secret );
253
 
254
+ return $plaintext;
255
  }
256
 
257
  /**
src/controller/two-factor.php CHANGED
@@ -410,8 +410,7 @@ class Two_Factor extends Controller {
410
  * @return string
411
  */
412
  public function get_token( int $user_id ): string {
413
- $crypt = new Crypt();
414
- $token = bin2hex( $crypt->random_bytes( 32 ) );
415
  update_user_meta( $user_id, Two_Fa_Component::TOKEN_USER_KEY, wp_hash( $user_id . $token ) );
416
 
417
  return $token;
@@ -600,7 +599,7 @@ class Two_Factor extends Controller {
600
  $user_id = get_current_user_id();
601
  update_user_meta( $user_id, Totp::TOTP_AUTH_KEY, 0 );
602
  // Remove secret key.
603
- ( new Totp() )->remove_2fa_line_by( $user_id );
604
  // Remove TOTP from enabled providers.
605
  $enabled_providers = get_user_meta( $user_id, Two_Fa_Component::ENABLED_PROVIDERS_USER_KEY, true );
606
  if ( isset( $enabled_providers ) && ! empty( $enabled_providers ) ) {
@@ -1048,8 +1047,12 @@ class Two_Factor extends Controller {
1048
  $wpdb->query( $query );
1049
  // From Webauthn.
1050
  wd_di()->get( Webauthn_Controller::class )->remove_data();
1051
- // Delete 2fa file.
1052
- @unlink( $this->get_2fa_lock_path() );
 
 
 
 
1053
  }
1054
 
1055
  /**
410
  * @return string
411
  */
412
  public function get_token( int $user_id ): string {
413
+ $token = bin2hex( Crypt::random_bytes( 32 ) );
 
414
  update_user_meta( $user_id, Two_Fa_Component::TOKEN_USER_KEY, wp_hash( $user_id . $token ) );
415
 
416
  return $token;
599
  $user_id = get_current_user_id();
600
  update_user_meta( $user_id, Totp::TOTP_AUTH_KEY, 0 );
601
  // Remove secret key.
602
+ delete_user_meta( $user_id, Totp::TOTP_SECRET_KEY );
603
  // Remove TOTP from enabled providers.
604
  $enabled_providers = get_user_meta( $user_id, Two_Fa_Component::ENABLED_PROVIDERS_USER_KEY, true );
605
  if ( isset( $enabled_providers ) && ! empty( $enabled_providers ) ) {
1047
  $wpdb->query( $query );
1048
  // From Webauthn.
1049
  wd_di()->get( Webauthn_Controller::class )->remove_data();
1050
+ // Check if 2fa file exists.
1051
+ $file = $this->get_2fa_lock_path();
1052
+ if ( is_file( $file ) && is_readable( $file ) ) {
1053
+ // Delete 2fa file. It's actual for prev v3.3.1.
1054
+ @unlink( $file );
1055
+ }
1056
  }
1057
 
1058
  /**
src/functions.php CHANGED
@@ -520,9 +520,8 @@ function defender_generate_random_string( $length = 16, $strings = 'ABCDEFGHIJKL
520
  }
521
 
522
  $secret = [];
523
- $crypt = new \WP_Defender\Component\Crypt();
524
  for ( $i = 0; $i < $length; $i ++ ) {
525
- $secret[] = $strings[ $crypt->random_int( 0, strlen( $strings ) - 1 ) ];
526
  }
527
 
528
  return implode( '', $secret );
520
  }
521
 
522
  $secret = [];
 
523
  for ( $i = 0; $i < $length; $i ++ ) {
524
+ $secret[] = $strings[ \WP_Defender\Component\Crypt::random_int( 0, strlen( $strings ) - 1 ) ];
525
  }
526
 
527
  return implode( '', $secret );
src/upgrader.php CHANGED
@@ -321,6 +321,9 @@ class Upgrader {
321
  if ( version_compare( $db_version, '3.3.1', '<' ) ) {
322
  $this->upgrade_3_3_1();
323
  }
 
 
 
324
 
325
  defender_no_fresh_install();
326
  // Don't run any function below this line.
@@ -1067,9 +1070,8 @@ Your temporary password is {{passcode}}. To finish logging in, copy and paste th
1067
  );
1068
  if ( $query->get_total() > 0 ) {
1069
  // Hashed tokens.
1070
- $crypt = new Crypt();
1071
  foreach ( $query->get_results() as $user_id ) {
1072
- $token = bin2hex( $crypt->random_bytes( 32 ) );
1073
  update_user_meta( $user_id, Two_Fa_Component::TOKEN_USER_KEY, wp_hash( $user_id . $token ) );
1074
  }
1075
  }
@@ -1093,7 +1095,83 @@ Your temporary password is {{passcode}}. To finish logging in, copy and paste th
1093
  }
1094
  }
1095
  }
1096
- // Update auth secrets.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1097
  $query = new \WP_User_Query(
1098
  [
1099
  'blog_id' => 0,
@@ -1102,21 +1180,17 @@ Your temporary password is {{passcode}}. To finish logging in, copy and paste th
1102
  ]
1103
  );
1104
  if ( $query->get_total() > 0 ) {
1105
- $file = $this->get_2fa_lock_path();
1106
- if ( ! is_file( $file ) && false === file_put_contents( $file, '' ) ) {
1107
- $this->log( 'You don\'t have permission to write data.', 'internal.log' );
1108
- return;
1109
- }
1110
- // Convert data from user meta to file system.
1111
  foreach ( $query->get_results() as $user_id ) {
1112
- $secret = get_user_meta( $user_id, Totp::TOTP_SECRET_KEY, true );
1113
- $content = file_get_contents( $file );
1114
- if ( false === strpos( $content, $secret ) ) {
1115
- $res = file_put_contents( $file, $user_id . '://:' . $secret . "\r\n", FILE_APPEND | LOCK_EX );
1116
- // Remove old data.
1117
- if ( false !== $res ) {
1118
- delete_user_meta( $user_id, Totp::TOTP_SECRET_KEY );
1119
- }
 
 
1120
  }
1121
  }
1122
  }
321
  if ( version_compare( $db_version, '3.3.1', '<' ) ) {
322
  $this->upgrade_3_3_1();
323
  }
324
+ if ( version_compare( $db_version, '3.3.2', '<' ) ) {
325
+ $this->upgrade_3_3_2();
326
+ }
327
 
328
  defender_no_fresh_install();
329
  // Don't run any function below this line.
1070
  );
1071
  if ( $query->get_total() > 0 ) {
1072
  // Hashed tokens.
 
1073
  foreach ( $query->get_results() as $user_id ) {
1074
+ $token = bin2hex( Crypt::random_bytes( 32 ) );
1075
  update_user_meta( $user_id, Two_Fa_Component::TOKEN_USER_KEY, wp_hash( $user_id . $token ) );
1076
  }
1077
  }
1095
  }
1096
  }
1097
  }
1098
+ }
1099
+
1100
+ /**
1101
+ * @param string $file
1102
+ * @param array $arr_user_ids
1103
+ *
1104
+ * @return array
1105
+ */
1106
+ private function convert_2fa_lines( $file, &$arr_user_ids ): array {
1107
+ if ( is_file( $file ) && is_readable( $file ) ) {
1108
+ $content = file_get_contents( $file );
1109
+ if ( trim( $content ) ) {
1110
+ $lines = preg_split( '/[\r\n]+/', $content );
1111
+ if ( is_array( $lines ) && ! empty( $lines ) ) {
1112
+ foreach ( $lines as $line ) {
1113
+ if ( ! empty( trim( $line ) ) ) {
1114
+ [ $user_id, $skey ] = explode( '://:', $line );
1115
+ $user_id = (int) $user_id;
1116
+ // User ID's can be repeated for MU. Repetition must be avoided.
1117
+ if ( in_array( $user_id, $arr_user_ids, true ) ) {
1118
+ continue;
1119
+ }
1120
+ $plaintext = get_user_meta( $user_id, Totp::TOTP_SECRET_KEY, true );
1121
+ // Check that the plaintext of the key exists.
1122
+ if ( ! empty( $plaintext ) ) {
1123
+ // User_meta has an advantage over lock-file.
1124
+ $secret = Crypt::get_encrypted_string( $plaintext );
1125
+ } else {
1126
+ $secret = Crypt::get_encrypted_string( $skey );
1127
+ }
1128
+ // Update value.
1129
+ update_user_meta( $user_id, Totp::TOTP_SECRET_KEY, $secret );
1130
+ $arr_user_ids[] = $user_id;
1131
+ }
1132
+ }
1133
+ }
1134
+ }
1135
+ // Delete 2fa file.
1136
+ @unlink( $file );
1137
+ }
1138
+
1139
+ return $arr_user_ids;
1140
+ }
1141
+
1142
+ /**
1143
+ * @return array
1144
+ */
1145
+ private function encrypt_secret_keys(): array {
1146
+ $arr_user_ids = [];
1147
+ // It's for a single site or for the main site on MU.
1148
+ $file = $this->get_2fa_lock_path();
1149
+ $arr_user_ids = $this->convert_2fa_lines( $file, $arr_user_ids );
1150
+ // For other subsites on MU.
1151
+ if ( is_multisite() ) {
1152
+ $site_ids = get_sites( [ 'fields' => 'ids', 'site__not_in' => get_main_site_id() ] );
1153
+ if ( ! empty( $site_ids ) ) {
1154
+ $upload_dir = wp_upload_dir()['basedir'];
1155
+ foreach ( $site_ids as $site_id ) {
1156
+ $file = $upload_dir . DIRECTORY_SEPARATOR . 'sites' . DIRECTORY_SEPARATOR . $site_id
1157
+ . DIRECTORY_SEPARATOR . 'wp-defender' . DIRECTORY_SEPARATOR . 'two-fa.lock';
1158
+ $arr_user_ids = $this->convert_2fa_lines( $file, $arr_user_ids );
1159
+ }
1160
+ }
1161
+ }
1162
+
1163
+ return $arr_user_ids;
1164
+ }
1165
+
1166
+ /**
1167
+ * Upgrade to 3.3.2: update auth secret keys.
1168
+ *
1169
+ * @return void
1170
+ */
1171
+ private function upgrade_3_3_2() {
1172
+ // Data from a 2FA file. It's after the previous v3.3.1.
1173
+ $excluded_ids = $this->encrypt_secret_keys();
1174
+ // Data from plugin versions where the 2FA file concept was not used, before v3.3.1.
1175
  $query = new \WP_User_Query(
1176
  [
1177
  'blog_id' => 0,
1180
  ]
1181
  );
1182
  if ( $query->get_total() > 0 ) {
 
 
 
 
 
 
1183
  foreach ( $query->get_results() as $user_id ) {
1184
+ // Exclude users whose data we have already updated.
1185
+ if ( in_array( $user_id, $excluded_ids, true ) ) {
1186
+ continue;
1187
+ }
1188
+ $plaintext = get_user_meta( $user_id, Totp::TOTP_SECRET_KEY, true );
1189
+ // Check that the plaintext is existed and no encrypted. Encrypted line has '=' symbol.
1190
+ if ( ! empty( $plaintext ) && false === strpos( $plaintext, '=' ) ) {
1191
+ $secret = Crypt::get_encrypted_string( $plaintext );
1192
+ // Update value.
1193
+ update_user_meta( $user_id, Totp::TOTP_SECRET_KEY, $secret );
1194
  }
1195
  }
1196
  }
wp-defender.php CHANGED
@@ -2,7 +2,7 @@
2
  /**
3
  * Plugin Name: Defender
4
  * Plugin URI: https://wpmudev.com/project/wp-defender/
5
- * Version: 3.3.1
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', '3.3.1' );
37
  }
38
  if ( ! defined( 'DEFENDER_DB_VERSION' ) ) {
39
- define( 'DEFENDER_DB_VERSION', '3.3.1' );
40
  }
41
  if ( ! defined( 'DEFENDER_SUI' ) ) {
42
  define( 'DEFENDER_SUI', '2-12-8' );
2
  /**
3
  * Plugin Name: Defender
4
  * Plugin URI: https://wpmudev.com/project/wp-defender/
5
+ * Version: 3.3.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
  die;
34
  }
35
  if ( ! defined( 'DEFENDER_VERSION' ) ) {
36
+ define( 'DEFENDER_VERSION', '3.3.2' );
37
  }
38
  if ( ! defined( 'DEFENDER_DB_VERSION' ) ) {
39
+ define( 'DEFENDER_DB_VERSION', '3.3.2' );
40
  }
41
  if ( ! defined( 'DEFENDER_SUI' ) ) {
42
  define( 'DEFENDER_SUI', '2-12-8' );