Version Description
( 2022-10-20 ) =
- Enhance: 2FA flow for secret keys
Download this release
Release Info
Developer | BigTonny |
Plugin | Defender Security – Malware Scanner, Login Security & Firewall |
Version | 3.3.3 |
Comparing to | |
See all releases |
Code changes from version 3.3.2 to 3.3.3
- languages/wpdef-default.pot +59 -47
- readme.txt +7 -3
- src/bootstrap.php +2 -0
- src/component/crypt.php +134 -25
- src/component/error-code.php +10 -9
- src/component/legacy-versions.php +36 -0
- src/component/two-fa.php +56 -2
- src/component/two-factor/providers/totp.php +52 -11
- src/component/wp-defender-sample.php +8 -0
- src/controller/two-factor.php +25 -4
- src/upgrader.php +31 -91
- src/view/two-fa/providers/totp-disabled.php +21 -17
- wp-defender.php +3 -3
languages/wpdef-default.pot
CHANGED
@@ -6,9 +6,9 @@
|
|
6 |
#, fuzzy
|
7 |
msgid ""
|
8 |
msgstr ""
|
9 |
-
"Project-Id-Version: wp-defender 3.3.
|
10 |
"Report-Msgid-Bugs-To: \n"
|
11 |
-
"POT-Creation-Date: 2022-
|
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"
|
@@ -17,11 +17,11 @@ msgstr ""
|
|
17 |
"Content-Type: text/plain; charset=UTF-8\n"
|
18 |
"Content-Transfer-Encoding: 8bit\n"
|
19 |
|
20 |
-
#: free/bootstrap.php:
|
21 |
msgid "Get Secure!"
|
22 |
msgstr ""
|
23 |
|
24 |
-
#: free/bootstrap.php:
|
25 |
msgid ""
|
26 |
"You're awesome for installing Defender! Are you interested in how to make "
|
27 |
"the most of this plugin? We've collected all the best security resources we "
|
@@ -1090,7 +1090,7 @@ msgstr ""
|
|
1090 |
msgid "password reset"
|
1091 |
msgstr ""
|
1092 |
|
1093 |
-
#: src/component/backup-settings.php:529 src/upgrader.php:
|
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:
|
1132 |
-
#: src/controller/two-factor.php:
|
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:
|
1151 |
-
#: src/controller/two-factor.php:
|
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:
|
1205 |
msgid "2FA"
|
1206 |
msgstr ""
|
1207 |
|
@@ -1264,6 +1264,18 @@ msgstr ""
|
|
1264 |
msgid "Allow all"
|
1265 |
msgstr ""
|
1266 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1267 |
#. translators: %s: separator
|
1268 |
#: src/component/feature-modal.php:31
|
1269 |
msgid "What's new in Defender?"
|
@@ -1979,15 +1991,15 @@ msgstr ""
|
|
1979 |
msgid "100"
|
1980 |
msgstr ""
|
1981 |
|
1982 |
-
#: src/component/two-fa.php:
|
1983 |
msgid "The user is invalid."
|
1984 |
msgstr ""
|
1985 |
|
1986 |
-
#: src/component/two-fa.php:
|
1987 |
msgid "Your token is invalid."
|
1988 |
msgstr ""
|
1989 |
|
1990 |
-
#: src/component/two-fa.php:
|
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
|
@@ -1997,27 +2009,27 @@ msgstr ""
|
|
1997 |
msgid "Two-Factor Authentication"
|
1998 |
msgstr ""
|
1999 |
|
2000 |
-
#: src/component/two-fa.php:
|
2001 |
msgid "ERROR: Cheatin’ uh?"
|
2002 |
msgstr ""
|
2003 |
|
2004 |
-
#: src/component/two-fa.php:
|
2005 |
#, php-format
|
2006 |
msgid "Lockout occurred: Too many failed 2fa attempts for %s method."
|
2007 |
msgstr ""
|
2008 |
|
2009 |
-
#: src/component/two-fa.php:
|
2010 |
msgid "INVALID CODE: "
|
2011 |
msgstr ""
|
2012 |
|
2013 |
-
#: src/component/two-fa.php:
|
2014 |
msgid ""
|
2015 |
"The two-factor authentication code you entered is incorrect or has expired. "
|
2016 |
"Please try again."
|
2017 |
msgstr ""
|
2018 |
|
2019 |
#. translators: %s: count
|
2020 |
-
#: src/component/two-fa.php:
|
2021 |
#, php-format
|
2022 |
msgid "You have %s login attempt remaining."
|
2023 |
msgstr ""
|
@@ -2027,7 +2039,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:
|
2031 |
msgid "Each backup code can only be used to log in once."
|
2032 |
msgstr ""
|
2033 |
|
@@ -2045,7 +2057,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:
|
2049 |
msgid "Authenticate"
|
2050 |
msgstr ""
|
2051 |
|
@@ -2062,7 +2074,7 @@ msgid "Generate Backup Codes"
|
|
2062 |
msgstr ""
|
2063 |
|
2064 |
#: src/component/two-factor/providers/backup-codes.php:233
|
2065 |
-
#: src/controller/two-factor.php:
|
2066 |
msgid "Get New Codes"
|
2067 |
msgstr ""
|
2068 |
|
@@ -2104,41 +2116,41 @@ msgstr ""
|
|
2104 |
msgid "ERROR: Invalid passcode."
|
2105 |
msgstr ""
|
2106 |
|
2107 |
-
#: src/component/two-factor/providers/totp.php:
|
2108 |
msgid "TOTP Authenticator App"
|
2109 |
msgstr ""
|
2110 |
|
2111 |
-
#: src/component/two-factor/providers/totp.php:
|
2112 |
msgid "TOTP Authentication"
|
2113 |
msgstr ""
|
2114 |
|
2115 |
-
#: src/component/two-factor/providers/totp.php:
|
2116 |
msgid "TOTP"
|
2117 |
msgstr ""
|
2118 |
|
2119 |
#. translators: %s: style class
|
2120 |
-
#: src/component/two-factor/providers/totp.php:
|
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:
|
2128 |
msgid "TOTP Authentication method is active for this site"
|
2129 |
msgstr ""
|
2130 |
|
2131 |
-
#: src/component/two-factor/providers/totp.php:
|
2132 |
msgid "Use an authenticator app to sign in with a separate passcode."
|
2133 |
msgstr ""
|
2134 |
|
2135 |
-
#: src/component/two-factor/providers/totp.php:
|
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:
|
2142 |
msgid "Beta"
|
2143 |
msgstr ""
|
2144 |
|
@@ -2298,7 +2310,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:
|
2302 |
#: src/traits/setting.php:21
|
2303 |
msgid "Your settings have been updated."
|
2304 |
msgstr ""
|
@@ -2946,24 +2958,24 @@ msgstr ""
|
|
2946 |
msgid "You have logged in successfully."
|
2947 |
msgstr ""
|
2948 |
|
2949 |
-
#: src/controller/two-factor.php:
|
2950 |
msgid "Please input a valid OTP code."
|
2951 |
msgstr ""
|
2952 |
|
2953 |
-
#: src/controller/two-factor.php:
|
2954 |
msgid "Your OTP code is incorrect. Please try again."
|
2955 |
msgstr ""
|
2956 |
|
2957 |
-
#: src/controller/two-factor.php:
|
2958 |
msgid "Test email has been sent to your email."
|
2959 |
msgstr ""
|
2960 |
|
2961 |
-
#: src/controller/two-factor.php:
|
2962 |
msgid "Test email failed."
|
2963 |
msgstr ""
|
2964 |
|
2965 |
#. translators: %s: link
|
2966 |
-
#: src/controller/two-factor.php:
|
2967 |
#, php-format
|
2968 |
msgid ""
|
2969 |
"Web Authentication is now available. <a target=\"_blank\" href=\"%s\">Click "
|
@@ -2971,26 +2983,26 @@ msgid ""
|
|
2971 |
msgstr ""
|
2972 |
|
2973 |
#. translators: %s: count
|
2974 |
-
#: src/controller/two-factor.php:
|
2975 |
#, php-format
|
2976 |
msgid "2FA Backup Codes for %s:"
|
2977 |
msgstr ""
|
2978 |
|
2979 |
-
#: src/controller/two-factor.php:
|
2980 |
msgid "Reset two factor"
|
2981 |
msgstr ""
|
2982 |
|
2983 |
#. translators: %s: URL to regenerate code
|
2984 |
-
#: src/controller/two-factor.php:
|
2985 |
#, php-format
|
2986 |
msgid "Two factor authentication has been reset for <b>%s.</b>"
|
2987 |
msgstr ""
|
2988 |
|
2989 |
-
#: src/controller/two-factor.php:
|
2990 |
msgid "Save changes"
|
2991 |
msgstr ""
|
2992 |
|
2993 |
-
#: src/controller/two-factor.php:
|
2994 |
msgid "Two-Factor settings updated successfully."
|
2995 |
msgstr ""
|
2996 |
|
@@ -4225,7 +4237,7 @@ msgstr ""
|
|
4225 |
msgid "Hub"
|
4226 |
msgstr ""
|
4227 |
|
4228 |
-
#: src/upgrader.php:
|
4229 |
msgid "Basic config"
|
4230 |
msgstr ""
|
4231 |
|
@@ -4495,31 +4507,31 @@ msgstr ""
|
|
4495 |
msgid "2. Scan the QR code or enter the key"
|
4496 |
msgstr ""
|
4497 |
|
4498 |
-
#: src/view/two-fa/providers/totp-disabled.php:
|
4499 |
msgid ""
|
4500 |
"Open the authenticator app, and scan the QR code below or manually enter the "
|
4501 |
"setup key to add your new site."
|
4502 |
msgstr ""
|
4503 |
|
4504 |
-
#: src/view/two-fa/providers/totp-disabled.php:
|
4505 |
msgid "Copy"
|
4506 |
msgstr ""
|
4507 |
|
4508 |
-
#: src/view/two-fa/providers/totp-disabled.php:
|
4509 |
msgid "3. Enter passcode"
|
4510 |
msgstr ""
|
4511 |
|
4512 |
-
#: src/view/two-fa/providers/totp-disabled.php:
|
4513 |
msgid ""
|
4514 |
"Enter the 6 digit passcode that is shown on your device into the input field "
|
4515 |
"below and hit \"Verify\"."
|
4516 |
msgstr ""
|
4517 |
|
4518 |
-
#: src/view/two-fa/providers/totp-disabled.php:
|
4519 |
msgid "Enter passcode"
|
4520 |
msgstr ""
|
4521 |
|
4522 |
-
#: src/view/two-fa/providers/totp-disabled.php:
|
4523 |
msgid "Verify"
|
4524 |
msgstr ""
|
4525 |
|
6 |
#, fuzzy
|
7 |
msgid ""
|
8 |
msgstr ""
|
9 |
+
"Project-Id-Version: wp-defender 3.3.3\n"
|
10 |
"Report-Msgid-Bugs-To: \n"
|
11 |
+
"POT-Creation-Date: 2022-10-20 05:44+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"
|
17 |
"Content-Type: text/plain; charset=UTF-8\n"
|
18 |
"Content-Transfer-Encoding: 8bit\n"
|
19 |
|
20 |
+
#: free/bootstrap.php:281
|
21 |
msgid "Get Secure!"
|
22 |
msgstr ""
|
23 |
|
24 |
+
#: free/bootstrap.php:307
|
25 |
msgid ""
|
26 |
"You're awesome for installing Defender! Are you interested in how to make "
|
27 |
"the most of this plugin? We've collected all the best security resources we "
|
1090 |
msgid "password reset"
|
1091 |
msgstr ""
|
1092 |
|
1093 |
+
#: src/component/backup-settings.php:529 src/upgrader.php:650
|
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:1155
|
1132 |
+
#: src/controller/two-factor.php:1167
|
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:1155
|
1151 |
+
#: src/controller/two-factor.php:1167
|
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:1436
|
1205 |
msgid "2FA"
|
1206 |
msgstr ""
|
1207 |
|
1264 |
msgid "Allow all"
|
1265 |
msgstr ""
|
1266 |
|
1267 |
+
#: src/component/crypt.php:140 src/component/crypt.php:152
|
1268 |
+
msgid "Please re-setup 2FA TOTP method again."
|
1269 |
+
msgstr ""
|
1270 |
+
|
1271 |
+
#: src/component/crypt.php:213
|
1272 |
+
msgid "The Defender file with the random key does not exist."
|
1273 |
+
msgstr ""
|
1274 |
+
|
1275 |
+
#: src/component/crypt.php:224
|
1276 |
+
msgid "The Defender file with the random key is incorrect."
|
1277 |
+
msgstr ""
|
1278 |
+
|
1279 |
#. translators: %s: separator
|
1280 |
#: src/component/feature-modal.php:31
|
1281 |
msgid "What's new in Defender?"
|
1991 |
msgid "100"
|
1992 |
msgstr ""
|
1993 |
|
1994 |
+
#: src/component/two-fa.php:451
|
1995 |
msgid "The user is invalid."
|
1996 |
msgstr ""
|
1997 |
|
1998 |
+
#: src/component/two-fa.php:456
|
1999 |
msgid "Your token is invalid."
|
2000 |
msgstr ""
|
2001 |
|
2002 |
+
#: src/component/two-fa.php:481 src/controller/two-factor.php:983
|
2003 |
#: src/view/two-fa/user-options.php:12
|
2004 |
#: front/src/module/dashboard/component/preset-config.vue:123
|
2005 |
#: front/src/module/dashboard/component/two-fa.vue:6
|
2009 |
msgid "Two-Factor Authentication"
|
2010 |
msgstr ""
|
2011 |
|
2012 |
+
#: src/component/two-fa.php:505
|
2013 |
msgid "ERROR: Cheatin’ uh?"
|
2014 |
msgstr ""
|
2015 |
|
2016 |
+
#: src/component/two-fa.php:582
|
2017 |
#, php-format
|
2018 |
msgid "Lockout occurred: Too many failed 2fa attempts for %s method."
|
2019 |
msgstr ""
|
2020 |
|
2021 |
+
#: src/component/two-fa.php:595
|
2022 |
msgid "INVALID CODE: "
|
2023 |
msgstr ""
|
2024 |
|
2025 |
+
#: src/component/two-fa.php:596
|
2026 |
msgid ""
|
2027 |
"The two-factor authentication code you entered is incorrect or has expired. "
|
2028 |
"Please try again."
|
2029 |
msgstr ""
|
2030 |
|
2031 |
#. translators: %s: count
|
2032 |
+
#: src/component/two-fa.php:600
|
2033 |
#, php-format
|
2034 |
msgid "You have %s login attempt remaining."
|
2035 |
msgstr ""
|
2039 |
msgstr ""
|
2040 |
|
2041 |
#: src/component/two-factor/providers/backup-codes.php:77
|
2042 |
+
#: src/controller/two-factor.php:1314
|
2043 |
msgid "Each backup code can only be used to log in once."
|
2044 |
msgstr ""
|
2045 |
|
2057 |
|
2058 |
#: src/component/two-factor/providers/backup-codes.php:138
|
2059 |
#: src/component/two-factor/providers/fallback-email.php:107
|
2060 |
+
#: src/component/two-factor/providers/totp.php:128
|
2061 |
msgid "Authenticate"
|
2062 |
msgstr ""
|
2063 |
|
2074 |
msgstr ""
|
2075 |
|
2076 |
#: src/component/two-factor/providers/backup-codes.php:233
|
2077 |
+
#: src/controller/two-factor.php:1313
|
2078 |
msgid "Get New Codes"
|
2079 |
msgstr ""
|
2080 |
|
2116 |
msgid "ERROR: Invalid passcode."
|
2117 |
msgstr ""
|
2118 |
|
2119 |
+
#: src/component/two-factor/providers/totp.php:97
|
2120 |
msgid "TOTP Authenticator App"
|
2121 |
msgstr ""
|
2122 |
|
2123 |
+
#: src/component/two-factor/providers/totp.php:104
|
2124 |
msgid "TOTP Authentication"
|
2125 |
msgstr ""
|
2126 |
|
2127 |
+
#: src/component/two-factor/providers/totp.php:111
|
2128 |
msgid "TOTP"
|
2129 |
msgstr ""
|
2130 |
|
2131 |
#. translators: %s: style class
|
2132 |
+
#: src/component/two-factor/providers/totp.php:151
|
2133 |
#, php-format
|
2134 |
msgid ""
|
2135 |
"<button type=\"button\" class=\"button reset-totp-keys button-secondary hide-"
|
2136 |
"if-no-js\" %s>Reset Keys</button>"
|
2137 |
msgstr ""
|
2138 |
|
2139 |
+
#: src/component/two-factor/providers/totp.php:156
|
2140 |
msgid "TOTP Authentication method is active for this site"
|
2141 |
msgstr ""
|
2142 |
|
2143 |
+
#: src/component/two-factor/providers/totp.php:157
|
2144 |
msgid "Use an authenticator app to sign in with a separate passcode."
|
2145 |
msgstr ""
|
2146 |
|
2147 |
+
#: src/component/two-factor/providers/totp.php:249
|
2148 |
#: src/controller/two-factor.php:401
|
2149 |
msgid "Whoops, the passcode you entered was incorrect or expired."
|
2150 |
msgstr ""
|
2151 |
|
2152 |
#: src/component/two-factor/providers/webauthn.php:46
|
2153 |
+
#: src/controller/two-factor.php:1117
|
2154 |
msgid "Beta"
|
2155 |
msgstr ""
|
2156 |
|
2310 |
#: src/controller/firewall.php:144 src/controller/main-setting.php:97
|
2311 |
#: src/controller/mask-login.php:312 src/controller/password-protection.php:218
|
2312 |
#: src/controller/password-reset.php:198 src/controller/scan.php:361
|
2313 |
+
#: src/controller/security-headers.php:74 src/controller/two-factor.php:893
|
2314 |
#: src/traits/setting.php:21
|
2315 |
msgid "Your settings have been updated."
|
2316 |
msgstr ""
|
2958 |
msgid "You have logged in successfully."
|
2959 |
msgstr ""
|
2960 |
|
2961 |
+
#: src/controller/two-factor.php:645
|
2962 |
msgid "Please input a valid OTP code."
|
2963 |
msgstr ""
|
2964 |
|
2965 |
+
#: src/controller/two-factor.php:683
|
2966 |
msgid "Your OTP code is incorrect. Please try again."
|
2967 |
msgstr ""
|
2968 |
|
2969 |
+
#: src/controller/two-factor.php:995
|
2970 |
msgid "Test email has been sent to your email."
|
2971 |
msgstr ""
|
2972 |
|
2973 |
+
#: src/controller/two-factor.php:1000
|
2974 |
msgid "Test email failed."
|
2975 |
msgstr ""
|
2976 |
|
2977 |
#. translators: %s: link
|
2978 |
+
#: src/controller/two-factor.php:1120
|
2979 |
#, php-format
|
2980 |
msgid ""
|
2981 |
"Web Authentication is now available. <a target=\"_blank\" href=\"%s\">Click "
|
2983 |
msgstr ""
|
2984 |
|
2985 |
#. translators: %s: count
|
2986 |
+
#: src/controller/two-factor.php:1310
|
2987 |
#, php-format
|
2988 |
msgid "2FA Backup Codes for %s:"
|
2989 |
msgstr ""
|
2990 |
|
2991 |
+
#: src/controller/two-factor.php:1339
|
2992 |
msgid "Reset two factor"
|
2993 |
msgstr ""
|
2994 |
|
2995 |
#. translators: %s: URL to regenerate code
|
2996 |
+
#: src/controller/two-factor.php:1384
|
2997 |
#, php-format
|
2998 |
msgid "Two factor authentication has been reset for <b>%s.</b>"
|
2999 |
msgstr ""
|
3000 |
|
3001 |
+
#: src/controller/two-factor.php:1409 src/controller/two-factor.php:1410
|
3002 |
msgid "Save changes"
|
3003 |
msgstr ""
|
3004 |
|
3005 |
+
#: src/controller/two-factor.php:1462
|
3006 |
msgid "Two-Factor settings updated successfully."
|
3007 |
msgstr ""
|
3008 |
|
4237 |
msgid "Hub"
|
4238 |
msgstr ""
|
4239 |
|
4240 |
+
#: src/upgrader.php:649
|
4241 |
msgid "Basic config"
|
4242 |
msgstr ""
|
4243 |
|
4507 |
msgid "2. Scan the QR code or enter the key"
|
4508 |
msgstr ""
|
4509 |
|
4510 |
+
#: src/view/two-fa/providers/totp-disabled.php:32
|
4511 |
msgid ""
|
4512 |
"Open the authenticator app, and scan the QR code below or manually enter the "
|
4513 |
"setup key to add your new site."
|
4514 |
msgstr ""
|
4515 |
|
4516 |
+
#: src/view/two-fa/providers/totp-disabled.php:44
|
4517 |
msgid "Copy"
|
4518 |
msgstr ""
|
4519 |
|
4520 |
+
#: src/view/two-fa/providers/totp-disabled.php:52
|
4521 |
msgid "3. Enter passcode"
|
4522 |
msgstr ""
|
4523 |
|
4524 |
+
#: src/view/two-fa/providers/totp-disabled.php:57
|
4525 |
msgid ""
|
4526 |
"Enter the 6 digit passcode that is shown on your device into the input field "
|
4527 |
"below and hit \"Verify\"."
|
4528 |
msgstr ""
|
4529 |
|
4530 |
+
#: src/view/two-fa/providers/totp-disabled.php:65
|
4531 |
msgid "Enter passcode"
|
4532 |
msgstr ""
|
4533 |
|
4534 |
+
#: src/view/two-fa/providers/totp-disabled.php:67
|
4535 |
msgid "Verify"
|
4536 |
msgstr ""
|
4537 |
|
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.
|
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.
|
10 |
-
Stable tag: 3.3.
|
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.2 ( 2022-09-29 ) =
|
251 |
|
252 |
- Fix: Encrypt 2FA secret keys
|
1 |
=== Defender Security - Malware Scanner, Login Security & Firewall ===
|
2 |
Plugin Name: Defender Security - Malware Scanner, Login Security & Firewall
|
3 |
+
Version: 3.3.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, 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.1
|
10 |
+
Stable tag: 3.3.3
|
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.3 ( 2022-10-20 ) =
|
251 |
+
|
252 |
+
- Enhance: 2FA flow for secret keys
|
253 |
+
|
254 |
= 3.3.2 ( 2022-09-29 ) =
|
255 |
|
256 |
- Fix: Encrypt 2FA secret keys
|
src/bootstrap.php
CHANGED
@@ -39,6 +39,8 @@ class Bootstrap {
|
|
39 |
$this->create_database_tables();
|
40 |
$this->set_free_installation_timestamp();
|
41 |
$this->on_activation();
|
|
|
|
|
42 |
}
|
43 |
|
44 |
/**
|
39 |
$this->create_database_tables();
|
40 |
$this->set_free_installation_timestamp();
|
41 |
$this->on_activation();
|
42 |
+
// Create a file with a random key if it doesn't exist.
|
43 |
+
( new \WP_Defender\Component\Crypt() )->create_key_file();
|
44 |
}
|
45 |
|
46 |
/**
|
src/component/crypt.php
CHANGED
@@ -3,7 +3,17 @@ declare( strict_types = 1 );
|
|
3 |
|
4 |
namespace WP_Defender\Component;
|
5 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
6 |
class Crypt extends \Calotes\Base\Component {
|
|
|
7 |
|
8 |
/**
|
9 |
* Generates cryptographically secure pseudo-random bytes.
|
@@ -98,56 +108,155 @@ class Crypt extends \Calotes\Base\Component {
|
|
98 |
}
|
99 |
|
100 |
/**
|
101 |
-
*
|
|
|
|
|
102 |
* @param string $key
|
103 |
*
|
104 |
* @return string
|
|
|
105 |
*/
|
106 |
-
private static function
|
107 |
-
$
|
108 |
-
$
|
109 |
-
$
|
110 |
-
|
111 |
-
|
112 |
-
|
113 |
-
return base64_encode( $iv . $hmac . $ciphertext_raw );
|
114 |
}
|
115 |
|
116 |
/**
|
117 |
-
*
|
|
|
|
|
118 |
* @param string $key
|
119 |
*
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
120 |
* @return string
|
121 |
*/
|
122 |
-
|
123 |
-
|
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
|
138 |
-
$key =
|
|
|
|
|
|
|
139 |
|
140 |
-
return
|
141 |
}
|
142 |
|
143 |
/**
|
|
|
|
|
144 |
* @param string $data
|
145 |
*
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
146 |
* @return string
|
147 |
*/
|
148 |
-
|
149 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
150 |
|
151 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
152 |
}
|
153 |
}
|
3 |
|
4 |
namespace WP_Defender\Component;
|
5 |
|
6 |
+
use WP_Defender\Traits\IO;
|
7 |
+
use WP_Error;
|
8 |
+
|
9 |
+
/**
|
10 |
+
* Class Crypt.
|
11 |
+
*
|
12 |
+
* @since 3.3.1
|
13 |
+
* @package WP_Defender\Component
|
14 |
+
*/
|
15 |
class Crypt extends \Calotes\Base\Component {
|
16 |
+
use IO;
|
17 |
|
18 |
/**
|
19 |
* Generates cryptographically secure pseudo-random bytes.
|
108 |
}
|
109 |
|
110 |
/**
|
111 |
+
* Encrypt data.
|
112 |
+
*
|
113 |
+
* @param string $value
|
114 |
* @param string $key
|
115 |
*
|
116 |
* @return string
|
117 |
+
* @throws \SodiumException
|
118 |
*/
|
119 |
+
private static function encrypt( $value, $key ): string {
|
120 |
+
$key = base64_decode( $key );
|
121 |
+
$nonce = self::random_bytes( SODIUM_CRYPTO_SECRETBOX_NONCEBYTES );
|
122 |
+
$ciphertext = sodium_crypto_secretbox( $value, $nonce, $key );
|
123 |
+
|
124 |
+
return base64_encode( $nonce . $ciphertext );
|
|
|
|
|
125 |
}
|
126 |
|
127 |
/**
|
128 |
+
* Decrypt encrypted data.
|
129 |
+
*
|
130 |
+
* @param string $encoded_value
|
131 |
* @param string $key
|
132 |
*
|
133 |
+
* @return string|WP_Error
|
134 |
+
* @throws \SodiumException
|
135 |
+
*/
|
136 |
+
private static function decrypt( $encoded_value, $key ) {
|
137 |
+
if ( ! $encoded_value || '' === $key ) {
|
138 |
+
return new WP_Error(
|
139 |
+
Error_Code::TFA_DECRYPT_ERROR,
|
140 |
+
__( 'Please re-setup 2FA TOTP method again.', 'wpdef' )
|
141 |
+
);
|
142 |
+
}
|
143 |
+
$key = base64_decode( $key );
|
144 |
+
$decoded = base64_decode( $encoded_value );
|
145 |
+
$nonce = mb_substr( $decoded, 0, SODIUM_CRYPTO_SECRETBOX_NONCEBYTES, '8bit' );
|
146 |
+
$ciphertext = mb_substr( $decoded, SODIUM_CRYPTO_SECRETBOX_NONCEBYTES, null, '8bit' );
|
147 |
+
|
148 |
+
$decrypted = sodium_crypto_secretbox_open( $ciphertext, $nonce, $key );
|
149 |
+
if ( false === $decrypted) {
|
150 |
+
return new WP_Error(
|
151 |
+
Error_Code::TFA_DECRYPT_ERROR,
|
152 |
+
__( 'Please re-setup 2FA TOTP method again.', 'wpdef' )
|
153 |
+
);
|
154 |
+
}
|
155 |
+
|
156 |
+
return $decrypted;
|
157 |
+
}
|
158 |
+
|
159 |
+
/**
|
160 |
+
* Get the path to a file with a random key. This is used for 2FA TOTP.
|
161 |
+
*
|
162 |
* @return string
|
163 |
*/
|
164 |
+
public static function get_path_to_key_file() {
|
165 |
+
return wp_normalize_path( WP_CONTENT_DIR ) . DIRECTORY_SEPARATOR . 'wp-defender-secrets.php';
|
|
|
|
|
|
|
|
|
|
|
|
|
166 |
}
|
167 |
|
168 |
/**
|
169 |
+
* Get decrypted data.
|
170 |
+
*
|
171 |
* @param string $data
|
172 |
*
|
173 |
+
* @return string|WP_Error
|
174 |
+
* @throws \SodiumException
|
175 |
*/
|
176 |
+
public static function get_decrypted_data( $data ) {
|
177 |
+
$key = self::get_random_key();
|
178 |
+
if ( is_wp_error( $key ) ) {
|
179 |
+
return $key;
|
180 |
+
}
|
181 |
|
182 |
+
return self::decrypt( $data, $key );
|
183 |
}
|
184 |
|
185 |
/**
|
186 |
+
* Get encrypted data.
|
187 |
+
*
|
188 |
* @param string $data
|
189 |
*
|
190 |
+
* @return string|WP_Error
|
191 |
+
* @throws \SodiumException
|
192 |
+
*/
|
193 |
+
public static function get_encrypted_data( $data ) {
|
194 |
+
$key = self::get_random_key();
|
195 |
+
if ( is_wp_error( $key ) ) {
|
196 |
+
return $key;
|
197 |
+
}
|
198 |
+
|
199 |
+
return self::encrypt( $data, $key );
|
200 |
+
}
|
201 |
+
|
202 |
+
/**
|
203 |
+
* Get random key.
|
204 |
+
*
|
205 |
+
* @return string|WP_Error
|
206 |
+
* @throws \SodiumException
|
207 |
+
*/
|
208 |
+
private static function get_random_key() {
|
209 |
+
$file = self::get_path_to_key_file();
|
210 |
+
if ( ! file_exists( $file ) ) {
|
211 |
+
return new WP_Error(
|
212 |
+
Error_Code::IS_EMPTY,
|
213 |
+
__( 'The Defender file with the random key does not exist.', 'wpdef' )
|
214 |
+
);
|
215 |
+
}
|
216 |
+
|
217 |
+
if ( ! defined( 'WP_DEFENDER_TOTP_KEY' ) ) {
|
218 |
+
require_once $file;
|
219 |
+
}
|
220 |
+
|
221 |
+
if ( '{{__REPLACE_CODE__}}' !== constant( 'WP_DEFENDER_TOTP_KEY' ) ) {
|
222 |
+
return WP_DEFENDER_TOTP_KEY;
|
223 |
+
} else {
|
224 |
+
return new WP_Error( Error_Code::INVALID, __( 'The Defender file with the random key is incorrect.', 'wpdef' ) );
|
225 |
+
}
|
226 |
+
}
|
227 |
+
|
228 |
+
/**
|
229 |
+
* Generate a random key.
|
230 |
+
*
|
231 |
* @return string
|
232 |
*/
|
233 |
+
protected function generate_random_key(): string {
|
234 |
+
return base64_encode( sodium_crypto_secretbox_keygen() );
|
235 |
+
}
|
236 |
+
|
237 |
+
/**
|
238 |
+
* Create a file with a random key.
|
239 |
+
*
|
240 |
+
* @return bool
|
241 |
+
*/
|
242 |
+
public function create_key_file(): bool {
|
243 |
+
$to = self::get_path_to_key_file();
|
244 |
+
if ( ! file_exists( $to ) ) {
|
245 |
+
// Move a template file to WP_CONTENT and replace the file content.
|
246 |
+
$template_file = WP_DEFENDER_DIR . 'src' . DIRECTORY_SEPARATOR . 'component' . DIRECTORY_SEPARATOR
|
247 |
+
. 'wp-defender-sample.php';
|
248 |
+
if ( copy( $template_file, $to ) ) {
|
249 |
+
$content = file_get_contents( $to );
|
250 |
+
if ( false !== strpos( $content, '{{__REPLACE_CODE__}}' ) ) {
|
251 |
+
$new_content = str_replace( '{{__REPLACE_CODE__}}', $this->generate_random_key(), $content );
|
252 |
|
253 |
+
return (bool) file_put_contents( $to, $new_content, LOCK_EX );
|
254 |
+
}
|
255 |
+
}
|
256 |
+
// The file was not copied.
|
257 |
+
return false;
|
258 |
+
}
|
259 |
+
// Everything is fine. The file exists.
|
260 |
+
return true;
|
261 |
}
|
262 |
}
|
src/component/error-code.php
CHANGED
@@ -6,14 +6,15 @@
|
|
6 |
namespace WP_Defender\Component;
|
7 |
|
8 |
class Error_Code {
|
9 |
-
public const NOT_WRITEABLE
|
10 |
public const WPDEBUG_NOT_FOUND = 2;
|
11 |
-
public const UNKNOWN_WPCONFIG
|
12 |
-
public const IS_EMPTY
|
13 |
-
public const VALIDATE
|
14 |
-
public const SQL_ERROR
|
15 |
-
public const DB_ERROR
|
16 |
-
public const INVALID
|
17 |
-
public const SCAN_ERROR
|
18 |
-
public const API_ERROR
|
|
|
19 |
}
|
6 |
namespace WP_Defender\Component;
|
7 |
|
8 |
class Error_Code {
|
9 |
+
public const NOT_WRITEABLE = 1;
|
10 |
public const WPDEBUG_NOT_FOUND = 2;
|
11 |
+
public const UNKNOWN_WPCONFIG = 3;
|
12 |
+
public const IS_EMPTY = 4;
|
13 |
+
public const VALIDATE = 5;
|
14 |
+
public const SQL_ERROR = 6;
|
15 |
+
public const DB_ERROR = 7;
|
16 |
+
public const INVALID = 8;
|
17 |
+
public const SCAN_ERROR = 9;
|
18 |
+
public const API_ERROR = 10;
|
19 |
+
public const TFA_DECRYPT_ERROR = 11;
|
20 |
}
|
src/component/legacy-versions.php
CHANGED
@@ -334,4 +334,40 @@ class Legacy_Versions extends Component {
|
|
334 |
public function change_onboarding_status() {
|
335 |
update_site_option( 'wp_defender_shown_activator', true );
|
336 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
337 |
}
|
334 |
public function change_onboarding_status() {
|
335 |
update_site_option( 'wp_defender_shown_activator', true );
|
336 |
}
|
337 |
+
|
338 |
+
/**
|
339 |
+
* @param string $encrypt_data
|
340 |
+
* @param string $key
|
341 |
+
*
|
342 |
+
* @return bool|string
|
343 |
+
*/
|
344 |
+
private static function decrypt_data_with_pub_key( $encrypt_data, $key ) {
|
345 |
+
$str = base64_decode( $encrypt_data );
|
346 |
+
if ( ! $str ) {
|
347 |
+
return false;
|
348 |
+
}
|
349 |
+
$cipher = 'aes-256-cbc';
|
350 |
+
$iv_len = openssl_cipher_iv_length( $cipher );
|
351 |
+
$iv = substr( $str, 0, $iv_len );
|
352 |
+
$ciphertext_raw = substr( $str, $iv_len + 32 );
|
353 |
+
|
354 |
+
return openssl_decrypt( $ciphertext_raw, $cipher, $key, OPENSSL_RAW_DATA, $iv );
|
355 |
+
}
|
356 |
+
|
357 |
+
/**
|
358 |
+
* Backward compatible for decryption with pub key file.
|
359 |
+
*
|
360 |
+
* @param string $data
|
361 |
+
*
|
362 |
+
* @return bool|string
|
363 |
+
*/
|
364 |
+
public static function get_decrypted_data_with_pub_key( $data ) {
|
365 |
+
$path_to_pub_key = __DIR__ . '/def.key';
|
366 |
+
if ( ! file_exists( $path_to_pub_key ) ) {
|
367 |
+
return false;
|
368 |
+
}
|
369 |
+
$key = file_get_contents( $path_to_pub_key );
|
370 |
+
|
371 |
+
return false !== $key ? self::decrypt_data_with_pub_key( $data, $key ) : '';
|
372 |
+
}
|
373 |
}
|
src/component/two-fa.php
CHANGED
@@ -4,6 +4,7 @@ namespace WP_Defender\Component;
|
|
4 |
|
5 |
use Calotes\Base\Component;
|
6 |
use Calotes\Helper\Array_Cache;
|
|
|
7 |
use WP_Defender\Component\Crypt;
|
8 |
use WP_Defender\Model\Setting\Two_Fa as Two_Fa_Model;
|
9 |
use WP_Defender\Component\Two_Factor\Providers\Totp;
|
@@ -119,15 +120,18 @@ class Two_Fa extends Component {
|
|
119 |
* @param string $user_code
|
120 |
* @param WP_User|null $user
|
121 |
*
|
122 |
-
* @return bool
|
123 |
*/
|
124 |
-
public function verify_otp( string $user_code, $user = null )
|
125 |
if ( strlen( $user_code ) < Totp::TOTP_DIGIT_COUNT ) {
|
126 |
return false;
|
127 |
}
|
128 |
for ( $i = - 30; $i <= Totp::TOTP_TIME_STEP_SEC; $i ++ ) {
|
129 |
$counter = 0 === $i ? null : $i * Totp::TOTP_TIME_STEP_SEC + time();
|
130 |
$code = Totp::generate_otp( $counter, $user );
|
|
|
|
|
|
|
131 |
if ( Crypt::compare_lines( $user_code, $code ) ) {
|
132 |
return true;
|
133 |
}
|
@@ -568,6 +572,8 @@ class Two_Fa extends Component {
|
|
568 |
// If the time difference between attempts is greater than the limit, clear the attempt counter.
|
569 |
if ( $end_time - $start_time >= $time_limit ) {
|
570 |
delete_user_meta( $user_id, 'wd_2fa_attempt_' . $slug );
|
|
|
|
|
571 |
}
|
572 |
|
573 |
$count = (int) $count -1;
|
@@ -599,4 +605,52 @@ class Two_Fa extends Component {
|
|
599 |
|
600 |
return $lockout_message;
|
601 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
602 |
}
|
4 |
|
5 |
use Calotes\Base\Component;
|
6 |
use Calotes\Helper\Array_Cache;
|
7 |
+
use WP_Defender\Component\Legacy_Versions;
|
8 |
use WP_Defender\Component\Crypt;
|
9 |
use WP_Defender\Model\Setting\Two_Fa as Two_Fa_Model;
|
10 |
use WP_Defender\Component\Two_Factor\Providers\Totp;
|
120 |
* @param string $user_code
|
121 |
* @param WP_User|null $user
|
122 |
*
|
123 |
+
* @return bool|WP_Error
|
124 |
*/
|
125 |
+
public function verify_otp( string $user_code, $user = null ) {
|
126 |
if ( strlen( $user_code ) < Totp::TOTP_DIGIT_COUNT ) {
|
127 |
return false;
|
128 |
}
|
129 |
for ( $i = - 30; $i <= Totp::TOTP_TIME_STEP_SEC; $i ++ ) {
|
130 |
$counter = 0 === $i ? null : $i * Totp::TOTP_TIME_STEP_SEC + time();
|
131 |
$code = Totp::generate_otp( $counter, $user );
|
132 |
+
if ( is_wp_error( $code ) ) {
|
133 |
+
return $code;
|
134 |
+
}
|
135 |
if ( Crypt::compare_lines( $user_code, $code ) ) {
|
136 |
return true;
|
137 |
}
|
572 |
// If the time difference between attempts is greater than the limit, clear the attempt counter.
|
573 |
if ( $end_time - $start_time >= $time_limit ) {
|
574 |
delete_user_meta( $user_id, 'wd_2fa_attempt_' . $slug );
|
575 |
+
$count = $this->get_attempt_limit();
|
576 |
+
$start_time = $end_time;
|
577 |
}
|
578 |
|
579 |
$count = (int) $count -1;
|
605 |
|
606 |
return $lockout_message;
|
607 |
}
|
608 |
+
|
609 |
+
/**
|
610 |
+
* @param int $user_id User ID.
|
611 |
+
* @param string $plaintext Clear text.
|
612 |
+
* @param string $state Previous state.
|
613 |
+
*
|
614 |
+
* @return bool
|
615 |
+
*/
|
616 |
+
protected function reencrypt_data( $user_id, $plaintext, $state = 'plaintext' ) {
|
617 |
+
$new_key = Crypt::get_encrypted_data( $plaintext );
|
618 |
+
if ( ! is_wp_error( $new_key ) ) {
|
619 |
+
// If everything is successful, remove an old key.
|
620 |
+
delete_user_meta( $user_id, TOTP::TOTP_SECRET_KEY );
|
621 |
+
// Update the value with a new key.
|
622 |
+
update_user_meta( $user_id, TOTP::TOTP_SODIUM_SECRET_KEY, $new_key );
|
623 |
+
// Logging.
|
624 |
+
$this->log( 'Update UID: ' . $user_id . '. Previous state: ' . $state, 'internal' );
|
625 |
+
|
626 |
+
return true;
|
627 |
+
}
|
628 |
+
$this->log( 'Encryption error for UID: ' . $user_id . '. State: ' . $state, 'internal' );
|
629 |
+
|
630 |
+
return false;
|
631 |
+
}
|
632 |
+
|
633 |
+
/**
|
634 |
+
* Old states with plaintext or pub key are exist?
|
635 |
+
*
|
636 |
+
* @param int $user_id
|
637 |
+
*
|
638 |
+
* @return bool
|
639 |
+
*/
|
640 |
+
public function maybe_update( $user_id ) {
|
641 |
+
$old_key = get_user_meta( $user_id, Totp::TOTP_SECRET_KEY, true );
|
642 |
+
if ( ! empty( $old_key ) && is_string( $old_key ) ) {
|
643 |
+
// Is it a plaintext? It was before v3.3.1.
|
644 |
+
if ( TOTP::TOTP_LENGTH === mb_strlen( $old_key, '8bit' ) ) {
|
645 |
+
return $this->reencrypt_data( $user_id, $old_key );
|
646 |
+
}
|
647 |
+
// Is it encrypted via a pub key? It was before v3.4.0.
|
648 |
+
$decrypted_data = Legacy_Versions::get_decrypted_data_with_pub_key( $old_key );
|
649 |
+
if ( false !== $decrypted_data ) {
|
650 |
+
return $this->reencrypt_data( $user_id, $decrypted_data, 'pub-key' );
|
651 |
+
}
|
652 |
+
}
|
653 |
+
|
654 |
+
return false;
|
655 |
+
}
|
656 |
}
|
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\Crypt;
|
8 |
use WP_Defender\Component\Two_Factor\Two_Factor_Provider;
|
9 |
use WP_Defender\Extra\Base2n;
|
@@ -34,10 +35,19 @@ class Totp extends Two_Factor_Provider {
|
|
34 |
public const TOTP_AUTH_KEY = 'defenderAuthOn';
|
35 |
|
36 |
/**
|
|
|
|
|
37 |
* @type string
|
38 |
*/
|
39 |
public const TOTP_SECRET_KEY = 'defenderAuthSecret';
|
40 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
41 |
/**
|
42 |
* @type string
|
43 |
*/
|
@@ -168,6 +178,20 @@ class Totp extends Two_Factor_Provider {
|
|
168 |
]
|
169 |
);
|
170 |
} else {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
171 |
$this->get_controller()->render_partial(
|
172 |
'two-fa/providers/totp-disabled',
|
173 |
[
|
@@ -175,8 +199,9 @@ class Totp extends Two_Factor_Provider {
|
|
175 |
'default_message' => $default_values['message'],
|
176 |
'auth_apps' => $this->get_auth_apps(),
|
177 |
'user' => $user,
|
178 |
-
'secret_key' =>
|
179 |
'class' => $service->is_checked_enabled_provider_by_slug( $user, self::$slug ) ? '' : 'hidden',
|
|
|
180 |
]
|
181 |
);
|
182 |
}
|
@@ -232,24 +257,36 @@ class Totp extends Two_Factor_Provider {
|
|
232 |
/**
|
233 |
* @param WP_User|null $user
|
234 |
*
|
235 |
-
* @return
|
236 |
*/
|
237 |
-
|
238 |
// This should only use in testing.
|
239 |
if ( is_object( $user ) ) {
|
240 |
$user_id = $user->ID;
|
241 |
} else {
|
242 |
$user_id = get_current_user_id();
|
243 |
}
|
244 |
-
|
245 |
-
$data = get_user_meta( $user_id, self::
|
246 |
if ( ! empty( $data ) ) {
|
247 |
-
return Crypt::
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
248 |
}
|
249 |
-
//
|
250 |
$plaintext = defender_generate_random_string( self::TOTP_LENGTH, self::TOTP_CHARACTERS );
|
251 |
-
$secret = Crypt::
|
252 |
-
|
|
|
|
|
|
|
|
|
253 |
|
254 |
return $plaintext;
|
255 |
}
|
@@ -260,12 +297,16 @@ class Totp extends Two_Factor_Provider {
|
|
260 |
* @param int|null $counter
|
261 |
* @param WP_User|null $user
|
262 |
*
|
263 |
-
* @return string
|
264 |
*/
|
265 |
public static function generate_otp( $counter = null, $user = null ) {
|
|
|
|
|
|
|
|
|
266 |
include_once defender_path( 'src/extra/binary-to-text-php/Base2n.php' );
|
267 |
$base32 = new Base2n( 5, self::TOTP_CHARACTERS, false, true, true );
|
268 |
-
$secret = $base32->decode(
|
269 |
if ( is_null( $counter ) ) {
|
270 |
$counter = time();
|
271 |
}
|
4 |
namespace WP_Defender\Component\Two_Factor\Providers;
|
5 |
|
6 |
use Calotes\Helper\HTTP;
|
7 |
+
use WP_Defender\Component\Two_Fa as Two_Fa_Component;
|
8 |
use WP_Defender\Component\Crypt;
|
9 |
use WP_Defender\Component\Two_Factor\Two_Factor_Provider;
|
10 |
use WP_Defender\Extra\Base2n;
|
35 |
public const TOTP_AUTH_KEY = 'defenderAuthOn';
|
36 |
|
37 |
/**
|
38 |
+
* Used def.key before v3.4.0.
|
39 |
+
*
|
40 |
* @type string
|
41 |
*/
|
42 |
public const TOTP_SECRET_KEY = 'defenderAuthSecret';
|
43 |
|
44 |
+
/**
|
45 |
+
* Use Sodium library since v3.4.0.
|
46 |
+
*
|
47 |
+
* @type string
|
48 |
+
*/
|
49 |
+
public const TOTP_SODIUM_SECRET_KEY = 'defenderAuthSodiumSecret';
|
50 |
+
|
51 |
/**
|
52 |
* @type string
|
53 |
*/
|
178 |
]
|
179 |
);
|
180 |
} else {
|
181 |
+
$is_success = true;
|
182 |
+
$result = self::get_user_secret();
|
183 |
+
if ( is_wp_error( $result ) ) {
|
184 |
+
$secret = $result->get_error_message();
|
185 |
+
$is_success = false;
|
186 |
+
} elseif ( is_bool( $result ) ) {
|
187 |
+
// Sometimes we can get a boolean value due to errors with writing to the database. In this case, we need to reset the value.
|
188 |
+
delete_user_meta( $user->ID, self::TOTP_SECRET_KEY );
|
189 |
+
// Also for new key.
|
190 |
+
delete_user_meta( $user->ID, self::TOTP_SODIUM_SECRET_KEY );
|
191 |
+
$secret = self::get_user_secret();
|
192 |
+
} else {
|
193 |
+
$secret = $result;
|
194 |
+
}
|
195 |
$this->get_controller()->render_partial(
|
196 |
'two-fa/providers/totp-disabled',
|
197 |
[
|
199 |
'default_message' => $default_values['message'],
|
200 |
'auth_apps' => $this->get_auth_apps(),
|
201 |
'user' => $user,
|
202 |
+
'secret_key' => $secret,
|
203 |
'class' => $service->is_checked_enabled_provider_by_slug( $user, self::$slug ) ? '' : 'hidden',
|
204 |
+
'is_success' => $is_success,
|
205 |
]
|
206 |
);
|
207 |
}
|
257 |
/**
|
258 |
* @param WP_User|null $user
|
259 |
*
|
260 |
+
* @return string|WP_Error|bool
|
261 |
*/
|
262 |
+
private static function get_user_secret( $user = null ) {
|
263 |
// This should only use in testing.
|
264 |
if ( is_object( $user ) ) {
|
265 |
$user_id = $user->ID;
|
266 |
} else {
|
267 |
$user_id = get_current_user_id();
|
268 |
}
|
269 |
+
// First, we check the new 'TOTP_SODIUM_SECRET_KEY' key.
|
270 |
+
$data = get_user_meta( $user_id, self::TOTP_SODIUM_SECRET_KEY, true );
|
271 |
if ( ! empty( $data ) ) {
|
272 |
+
return Crypt::get_decrypted_data( $data );
|
273 |
+
}
|
274 |
+
// Then check the old 'TOTP_SECRET_KEY' key.
|
275 |
+
if ( ( new Two_Fa_Component() )->maybe_update( $user_id ) ) {
|
276 |
+
// Check a new key again.
|
277 |
+
$data = get_user_meta( $user_id, self::TOTP_SODIUM_SECRET_KEY, true );
|
278 |
+
if ( ! empty( $data ) && is_string( $data ) ) {
|
279 |
+
return Crypt::get_decrypted_data( $data );
|
280 |
+
}
|
281 |
}
|
282 |
+
// Finally, add a new one.
|
283 |
$plaintext = defender_generate_random_string( self::TOTP_LENGTH, self::TOTP_CHARACTERS );
|
284 |
+
$secret = Crypt::get_encrypted_data( $plaintext );
|
285 |
+
if ( is_wp_error( $secret ) ) {
|
286 |
+
return $secret;
|
287 |
+
}
|
288 |
+
// Todo: Maybe save token only when we verify it?
|
289 |
+
update_user_meta( $user_id, self::TOTP_SODIUM_SECRET_KEY, $secret );
|
290 |
|
291 |
return $plaintext;
|
292 |
}
|
297 |
* @param int|null $counter
|
298 |
* @param WP_User|null $user
|
299 |
*
|
300 |
+
* @return string|WP_Error
|
301 |
*/
|
302 |
public static function generate_otp( $counter = null, $user = null ) {
|
303 |
+
$result = self::get_user_secret( $user );
|
304 |
+
if ( is_wp_error( $result ) ) {
|
305 |
+
return $result;
|
306 |
+
}
|
307 |
include_once defender_path( 'src/extra/binary-to-text-php/Base2n.php' );
|
308 |
$base32 = new Base2n( 5, self::TOTP_CHARACTERS, false, true, true );
|
309 |
+
$secret = $base32->decode( $result );
|
310 |
if ( is_null( $counter ) ) {
|
311 |
$counter = time();
|
312 |
}
|
src/component/wp-defender-sample.php
ADDED
@@ -0,0 +1,8 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
// The file is used to generate and validate secret keys. Deleting this file or manually editing the content will permanently break 2fa TOTP method for all users.
|
3 |
+
if ( ! defined( 'WPINC' ) ) {
|
4 |
+
die;
|
5 |
+
}
|
6 |
+
// WP Defender - Start
|
7 |
+
define( 'WP_DEFENDER_TOTP_KEY', '{{__REPLACE_CODE__}}' );
|
8 |
+
// WP Defender - End
|
src/controller/two-factor.php
CHANGED
@@ -477,7 +477,7 @@ class Two_Factor extends Controller {
|
|
477 |
$params['error'] = null;
|
478 |
}
|
479 |
// If this goes here then the current user is ok, need to show the 2 auth.
|
480 |
-
$this->attach_behavior(
|
481 |
$custom_graphic = '';
|
482 |
$custom_graphic_type = '';
|
483 |
$settings = new Two_Fa();
|
@@ -598,8 +598,10 @@ class Two_Factor extends Controller {
|
|
598 |
public function disable_totp() {
|
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 ) ) {
|
@@ -613,6 +615,11 @@ class Two_Factor extends Controller {
|
|
613 |
$enabled_providers = '';
|
614 |
}
|
615 |
update_user_meta( $user_id, Two_Fa_Component::ENABLED_PROVIDERS_USER_KEY, $enabled_providers );
|
|
|
|
|
|
|
|
|
|
|
616 |
|
617 |
return new Response( true, [] );
|
618 |
}
|
@@ -639,7 +646,15 @@ class Two_Factor extends Controller {
|
|
639 |
);
|
640 |
}
|
641 |
//Todo: maybe new validate_code() method from TOTP provider class.
|
642 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
643 |
$user_id = get_current_user_id();
|
644 |
$this->service->enable_otp( $user_id );
|
645 |
$totp_slug = Totp::$slug;
|
@@ -1030,8 +1045,9 @@ class Two_Factor extends Controller {
|
|
1030 |
// From Totp.
|
1031 |
'wd_2fa_attempt_' . TOTP::$slug,
|
1032 |
TOTP::TOTP_AUTH_KEY,
|
1033 |
-
//
|
1034 |
TOTP::TOTP_SECRET_KEY,
|
|
|
1035 |
TOTP::TOTP_FORCE_KEY,
|
1036 |
// From Backup_Codes.
|
1037 |
'wd_2fa_attempt_' . Backup_Codes::$slug,
|
@@ -1053,6 +1069,11 @@ class Two_Factor extends Controller {
|
|
1053 |
// Delete 2fa file. It's actual for prev v3.3.1.
|
1054 |
@unlink( $file );
|
1055 |
}
|
|
|
|
|
|
|
|
|
|
|
1056 |
}
|
1057 |
|
1058 |
/**
|
477 |
$params['error'] = null;
|
478 |
}
|
479 |
// If this goes here then the current user is ok, need to show the 2 auth.
|
480 |
+
$this->attach_behavior( WPMUDEV::class, WPMUDEV::class );
|
481 |
$custom_graphic = '';
|
482 |
$custom_graphic_type = '';
|
483 |
$settings = new Two_Fa();
|
598 |
public function disable_totp() {
|
599 |
$user_id = get_current_user_id();
|
600 |
update_user_meta( $user_id, Totp::TOTP_AUTH_KEY, 0 );
|
601 |
+
// Remove old secret key.
|
602 |
delete_user_meta( $user_id, Totp::TOTP_SECRET_KEY );
|
603 |
+
// Remove new secret key.
|
604 |
+
delete_user_meta( $user_id, Totp::TOTP_SODIUM_SECRET_KEY );
|
605 |
// Remove TOTP from enabled providers.
|
606 |
$enabled_providers = get_user_meta( $user_id, Two_Fa_Component::ENABLED_PROVIDERS_USER_KEY, true );
|
607 |
if ( isset( $enabled_providers ) && ! empty( $enabled_providers ) ) {
|
615 |
$enabled_providers = '';
|
616 |
}
|
617 |
update_user_meta( $user_id, Two_Fa_Component::ENABLED_PROVIDERS_USER_KEY, $enabled_providers );
|
618 |
+
// Check the default provider. If it's TOTP then clear the value.
|
619 |
+
$default_provider = get_user_meta( $user_id, Two_Fa_Component::DEFAULT_PROVIDER_USER_KEY, true );
|
620 |
+
if ( ! empty( $default_provider ) && $default_provider === Totp::$slug ) {
|
621 |
+
update_user_meta( $user_id, Two_Fa_Component::DEFAULT_PROVIDER_USER_KEY, '' );
|
622 |
+
}
|
623 |
|
624 |
return new Response( true, [] );
|
625 |
}
|
646 |
);
|
647 |
}
|
648 |
//Todo: maybe new validate_code() method from TOTP provider class.
|
649 |
+
$result = $this->service->verify_otp( $otp );
|
650 |
+
// OTP result can be a boolean value or WP error.
|
651 |
+
if ( is_wp_error( $result ) ) {
|
652 |
+
return new Response(
|
653 |
+
false,
|
654 |
+
[ 'message' => $result->get_error_message() ]
|
655 |
+
);
|
656 |
+
}
|
657 |
+
if ( $result ) {
|
658 |
$user_id = get_current_user_id();
|
659 |
$this->service->enable_otp( $user_id );
|
660 |
$totp_slug = Totp::$slug;
|
1045 |
// From Totp.
|
1046 |
'wd_2fa_attempt_' . TOTP::$slug,
|
1047 |
TOTP::TOTP_AUTH_KEY,
|
1048 |
+
// For backward compatible with the def.key file. We'll remove this key in future versions and use the key for Sodium.
|
1049 |
TOTP::TOTP_SECRET_KEY,
|
1050 |
+
TOTP::TOTP_SODIUM_SECRET_KEY,
|
1051 |
TOTP::TOTP_FORCE_KEY,
|
1052 |
// From Backup_Codes.
|
1053 |
'wd_2fa_attempt_' . Backup_Codes::$slug,
|
1069 |
// Delete 2fa file. It's actual for prev v3.3.1.
|
1070 |
@unlink( $file );
|
1071 |
}
|
1072 |
+
// Check if the file with a random key exists.
|
1073 |
+
$file = Crypt::get_path_to_key_file();
|
1074 |
+
if ( is_file( $file ) && is_readable( $file ) ) {
|
1075 |
+
@unlink( $file );
|
1076 |
+
}
|
1077 |
}
|
1078 |
|
1079 |
/**
|
src/upgrader.php
CHANGED
@@ -3,6 +3,7 @@ declare( strict_types=1 );
|
|
3 |
|
4 |
namespace WP_Defender;
|
5 |
|
|
|
6 |
use WP_Defender\Component\Feature_Modal;
|
7 |
use WP_Defender\Component\Two_Factor\Providers\Fallback_Email;
|
8 |
use WP_Defender\Component\Two_Factor\Providers\Totp;
|
@@ -321,8 +322,8 @@ class Upgrader {
|
|
321 |
if ( version_compare( $db_version, '3.3.1', '<' ) ) {
|
322 |
$this->upgrade_3_3_1();
|
323 |
}
|
324 |
-
if ( version_compare( $db_version, '3.3.
|
325 |
-
$this->
|
326 |
}
|
327 |
|
328 |
defender_no_fresh_install();
|
@@ -1098,101 +1099,40 @@ Your temporary password is {{passcode}}. To finish logging in, copy and paste th
|
|
1098 |
}
|
1099 |
|
1100 |
/**
|
1101 |
-
*
|
1102 |
-
* @param array $arr_user_ids
|
1103 |
*
|
1104 |
-
* @
|
|
|
|
|
1105 |
*/
|
1106 |
-
private function
|
1107 |
-
|
1108 |
-
|
1109 |
-
|
1110 |
-
|
1111 |
-
|
1112 |
-
|
1113 |
-
|
1114 |
-
|
1115 |
-
|
1116 |
-
|
1117 |
-
|
1118 |
-
|
1119 |
-
|
1120 |
-
|
1121 |
-
|
1122 |
-
|
1123 |
-
|
1124 |
-
|
1125 |
-
|
1126 |
-
|
1127 |
-
|
1128 |
-
// Update
|
1129 |
-
update_user_meta( $user_id,
|
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,
|
1178 |
-
'meta_key' => Totp::TOTP_SECRET_KEY,
|
1179 |
-
'fields' => 'ID',
|
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 |
}
|
1197 |
}
|
1198 |
}
|
3 |
|
4 |
namespace WP_Defender;
|
5 |
|
6 |
+
use Safe\Exceptions\SodiumException;
|
7 |
use WP_Defender\Component\Feature_Modal;
|
8 |
use WP_Defender\Component\Two_Factor\Providers\Fallback_Email;
|
9 |
use WP_Defender\Component\Two_Factor\Providers\Totp;
|
322 |
if ( version_compare( $db_version, '3.3.1', '<' ) ) {
|
323 |
$this->upgrade_3_3_1();
|
324 |
}
|
325 |
+
if ( version_compare( $db_version, '3.3.3', '<' ) ) {
|
326 |
+
$this->upgrade_3_3_3();
|
327 |
}
|
328 |
|
329 |
defender_no_fresh_install();
|
1099 |
}
|
1100 |
|
1101 |
/**
|
1102 |
+
* Upgrade to 3.3.3: update 2FA flow for secret keys.
|
|
|
1103 |
*
|
1104 |
+
* @since 3.3.3
|
1105 |
+
* @return void
|
1106 |
+
* @throws SodiumException
|
1107 |
*/
|
1108 |
+
private function upgrade_3_3_3(): void {
|
1109 |
+
// Create a file with a random key if it doesn't exist.
|
1110 |
+
if ( ( new Crypt() )->create_key_file() ) {
|
1111 |
+
// Get user data.
|
1112 |
+
$query = new \WP_User_Query(
|
1113 |
+
[
|
1114 |
+
'blog_id' => 0,
|
1115 |
+
'meta_key' => Totp::TOTP_SECRET_KEY,
|
1116 |
+
'fields' => 'ID',
|
1117 |
+
]
|
1118 |
+
);
|
1119 |
+
if ( $query->get_total() > 0 ) {
|
1120 |
+
$service = wd_di()->get( Two_Fa_Component::class );
|
1121 |
+
foreach ( $query->get_results() as $user_id ) {
|
1122 |
+
// If we have the old states (cleartext, pub key) then re-encrypt via Sodium and save it.
|
1123 |
+
if ( ! $service->maybe_update( $user_id ) ) {
|
1124 |
+
// Otherwise just encrypt it via Sodium.
|
1125 |
+
$plaintext = defender_generate_random_string( TOTP::TOTP_LENGTH, TOTP::TOTP_CHARACTERS );
|
1126 |
+
$new_key = Crypt::get_encrypted_data( $plaintext );
|
1127 |
+
if ( ! is_wp_error( $new_key ) ) {
|
1128 |
+
// Remove an old key.
|
1129 |
+
delete_user_meta( $user_id, TOTP::TOTP_SECRET_KEY );
|
1130 |
+
// Update a new one.
|
1131 |
+
update_user_meta( $user_id, TOTP::TOTP_SODIUM_SECRET_KEY, $new_key );
|
|
|
1132 |
}
|
1133 |
}
|
1134 |
}
|
1135 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1136 |
}
|
1137 |
}
|
1138 |
}
|
src/view/two-fa/providers/totp-disabled.php
CHANGED
@@ -25,24 +25,28 @@
|
|
25 |
<strong>
|
26 |
<?php _e( '2. Scan the QR code or enter the key', 'wpdef' ); ?>
|
27 |
</strong>
|
28 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
29 |
<?php
|
30 |
-
|
31 |
-
'Open the authenticator app, and scan the QR code below or manually enter the setup key to add your new site.',
|
32 |
-
'wpdef'
|
33 |
-
)
|
34 |
?>
|
35 |
-
|
36 |
-
|
37 |
-
|
38 |
-
|
39 |
-
|
40 |
-
|
41 |
-
|
42 |
-
|
43 |
-
|
44 |
-
|
45 |
-
</p>
|
46 |
<div class="line"></div>
|
47 |
<strong>
|
48 |
<?php _e( '3. Enter passcode', 'wpdef' ); ?>
|
@@ -59,7 +63,7 @@
|
|
59 |
<p class="error"></p>
|
60 |
<input type="text" id="otp-code" class="def-small-text"
|
61 |
placeholder="<?php _e( 'Enter passcode', 'wpdef' ); ?>" />
|
62 |
-
<button type="button" class="button button-primary" id="verify-otp"
|
63 |
<?php _e( 'Verify', 'wpdef' ); ?>
|
64 |
</button>
|
65 |
</div>
|
25 |
<strong>
|
26 |
<?php _e( '2. Scan the QR code or enter the key', 'wpdef' ); ?>
|
27 |
</strong>
|
28 |
+
<?php if ( $is_success ) { ?>
|
29 |
+
<p class="wd_text_wrap">
|
30 |
+
<?php
|
31 |
+
_e(
|
32 |
+
'Open the authenticator app, and scan the QR code below or manually enter the setup key to add your new site.',
|
33 |
+
'wpdef'
|
34 |
+
)
|
35 |
+
?>
|
36 |
+
</p>
|
37 |
<?php
|
38 |
+
WP_Defender\Component\Two_Factor\Providers\Totp::generate_qr_code( $secret_key );
|
|
|
|
|
|
|
39 |
?>
|
40 |
+
<p class="wd_code_wrap">
|
41 |
+
<code id="wd_clipboard"><?php echo esc_html( $secret_key ); ?></code>
|
42 |
+
<button type="button" class="button" id="wd_copy_2fa_key"
|
43 |
+
data-clipborad-action="copy" data-clipboard-target="#wd_clipboard">
|
44 |
+
<?php _e( 'Copy', 'wpdef' ); ?>
|
45 |
+
</button>
|
46 |
+
</p>
|
47 |
+
<?php } else { ?>
|
48 |
+
<p class="error_process"><?php echo esc_html( $secret_key ); ?></p>
|
49 |
+
<?php } ?>
|
|
|
50 |
<div class="line"></div>
|
51 |
<strong>
|
52 |
<?php _e( '3. Enter passcode', 'wpdef' ); ?>
|
63 |
<p class="error"></p>
|
64 |
<input type="text" id="otp-code" class="def-small-text"
|
65 |
placeholder="<?php _e( 'Enter passcode', 'wpdef' ); ?>" />
|
66 |
+
<button type="button" class="button button-primary" <?php echo $is_success ? 'id="verify-otp"' : 'disabled'; ?>>
|
67 |
<?php _e( 'Verify', 'wpdef' ); ?>
|
68 |
</button>
|
69 |
</div>
|
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.
|
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.
|
37 |
}
|
38 |
if ( ! defined( 'DEFENDER_DB_VERSION' ) ) {
|
39 |
-
define( 'DEFENDER_DB_VERSION', '3.3.
|
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.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', '3.3.3' );
|
37 |
}
|
38 |
if ( ! defined( 'DEFENDER_DB_VERSION' ) ) {
|
39 |
+
define( 'DEFENDER_DB_VERSION', '3.3.3' );
|
40 |
}
|
41 |
if ( ! defined( 'DEFENDER_SUI' ) ) {
|
42 |
define( 'DEFENDER_SUI', '2-12-8' );
|