Shield Security for WordPress - Version 13.0.5

Version Description

Download this release

Release Info

Developer paultgoodchild
Plugin Icon 128x128 Shield Security for WordPress
Version 13.0.5
Comparing to
See all releases

Code changes from version 13.0.4 to 13.0.5

Files changed (91) hide show
  1. cl.json +36 -0
  2. config/deprecated/hack_protect.php +3 -3
  3. config/deprecated/login_protect.php +1 -43
  4. config/deprecated/plugin.php +1 -6
  5. config/login_protect.json +1 -43
  6. icwp-wpsf.php +2 -2
  7. plugin-spec.php +28 -24
  8. plugin.json +28 -24
  9. readme.txt +1 -1
  10. resources/css/shield/userprofile.css +15 -0
  11. resources/js/shield/notbot.js +42 -45
  12. src/lib/src/Controller/Controller.php +6 -14
  13. src/lib/src/Modules/Autoupdates/AjaxHandler.php +0 -9
  14. src/lib/src/Modules/Base/AdminNotices.php +35 -53
  15. src/lib/src/Modules/Base/Options.php +3 -7
  16. src/lib/src/Modules/Data/DB/IPs/Ops/Insert.php +0 -1
  17. src/lib/src/Modules/IPs/Lib/Bots/NotBot/InsertNotBotJs.php +12 -9
  18. src/lib/src/Modules/Integrations/Lib/Bots/Common/BaseBotDetectionController.php +18 -19
  19. src/lib/src/Modules/Integrations/Lib/Bots/Common/BaseHandler.php +41 -19
  20. src/lib/src/Modules/Integrations/Lib/Bots/Spam/Handlers/Base.php +8 -12
  21. src/lib/src/Modules/Integrations/Lib/Bots/Spam/Handlers/ContactForm7.php +0 -4
  22. src/lib/src/Modules/Integrations/Lib/Bots/Spam/Handlers/ElementorPro.php +0 -4
  23. src/lib/src/Modules/Integrations/Lib/Bots/Spam/Handlers/FluentForms.php +15 -14
  24. src/lib/src/Modules/Integrations/Lib/Bots/Spam/Handlers/FormidableForms.php +0 -4
  25. src/lib/src/Modules/Integrations/Lib/Bots/Spam/Handlers/Forminator.php +0 -4
  26. src/lib/src/Modules/Integrations/Lib/Bots/Spam/Handlers/GravityForms.php +0 -4
  27. src/lib/src/Modules/Integrations/Lib/Bots/Spam/Handlers/Groundhogg.php +1 -6
  28. src/lib/src/Modules/Integrations/Lib/Bots/Spam/Handlers/KaliForms.php +0 -4
  29. src/lib/src/Modules/Integrations/Lib/Bots/Spam/Handlers/NinjaForms.php +0 -4
  30. src/lib/src/Modules/Integrations/Lib/Bots/Spam/Handlers/SuperForms.php +0 -4
  31. src/lib/src/Modules/Integrations/Lib/Bots/Spam/Handlers/SupportCandy.php +0 -4
  32. src/lib/src/Modules/Integrations/Lib/Bots/Spam/Handlers/WPForms.php +0 -4
  33. src/lib/src/Modules/Integrations/Lib/Bots/Spam/Handlers/WpForo.php +10 -11
  34. src/lib/src/Modules/Integrations/Lib/Bots/Spam/SpamController.php +16 -16
  35. src/lib/src/Modules/Integrations/Lib/Bots/UserForms/Handlers/Base.php +8 -7
  36. src/lib/src/Modules/Integrations/Lib/Bots/UserForms/Handlers/Buddyboss.php +0 -4
  37. src/lib/src/Modules/Integrations/Lib/Bots/UserForms/Handlers/Buddypress.php +0 -4
  38. src/lib/src/Modules/Integrations/Lib/Bots/UserForms/Handlers/EasyDigitalDownloads.php +0 -4
  39. src/lib/src/Modules/Integrations/Lib/Bots/UserForms/Handlers/LearnPress.php +0 -4
  40. src/lib/src/Modules/Integrations/Lib/Bots/UserForms/Handlers/LifterLMS.php +0 -4
  41. src/lib/src/Modules/Integrations/Lib/Bots/UserForms/Handlers/MemberPress.php +0 -4
  42. src/lib/src/Modules/Integrations/Lib/Bots/UserForms/Handlers/PaidMemberSubscriptions.php +0 -4
  43. src/lib/src/Modules/Integrations/Lib/Bots/UserForms/Handlers/ProfileBuilder.php +0 -4
  44. src/lib/src/Modules/Integrations/Lib/Bots/UserForms/Handlers/UltimateMember.php +0 -4
  45. src/lib/src/Modules/Integrations/Lib/Bots/UserForms/Handlers/WPMembers.php +0 -4
  46. src/lib/src/Modules/Integrations/Lib/Bots/UserForms/Handlers/WooCommerce.php +0 -4
  47. src/lib/src/Modules/Integrations/Lib/Bots/UserForms/Handlers/WordPress.php +0 -4
  48. src/lib/src/Modules/Integrations/Lib/Bots/UserForms/UserFormsController.php +15 -17
  49. src/lib/src/Modules/Integrations/ModCon.php +14 -3
  50. src/lib/src/Modules/Integrations/Options.php +3 -3
  51. src/lib/src/Modules/Integrations/Processor.php +1 -3
  52. src/lib/src/Modules/Integrations/Strings.php +3 -7
  53. src/lib/src/Modules/Integrations/UI.php +34 -3
  54. src/lib/src/Modules/Integrations/Upgrade.php +0 -16
  55. src/lib/src/Modules/License/AjaxHandler.php +6 -6
  56. src/lib/src/Modules/License/Lib/LicenseHandler.php +30 -20
  57. src/lib/src/Modules/License/WpCli/License.php +6 -6
  58. src/lib/src/Modules/LoginGuard/Lib/AntiBot/AntibotSetup.php +3 -1
  59. src/lib/src/Modules/LoginGuard/Lib/TwoFactor/LoginIntentPage.php +6 -9
  60. src/lib/src/Modules/LoginGuard/Lib/TwoFactor/MfaController.php +11 -18
  61. src/lib/src/Modules/LoginGuard/Lib/TwoFactor/MfaProfilesController.php +80 -14
  62. src/lib/src/Modules/LoginGuard/Lib/TwoFactor/MfaSkip.php +30 -35
  63. src/lib/src/Modules/LoginGuard/Lib/TwoFactor/Profiles/RenderCustomForms.php +16 -9
  64. src/lib/src/Modules/LoginGuard/Lib/TwoFactor/Provider/BaseProvider.php +0 -9
  65. src/lib/src/Modules/LoginGuard/Lib/TwoFactor/UserProfile.php +6 -71
  66. src/lib/src/Modules/LoginGuard/Lib/TwoFactor/ValidateLoginIntentRequest.php +0 -1
  67. src/lib/src/Modules/LoginGuard/ModCon.php +7 -17
  68. src/lib/src/Modules/LoginGuard/Options.php +9 -11
  69. src/lib/src/Modules/LoginGuard/Processor.php +19 -10
  70. src/lib/src/Modules/LoginGuard/Strings.php +8 -2
  71. src/lib/src/Modules/LoginGuard/UI.php +40 -16
  72. src/lib/src/Modules/ModConsumer.php +0 -4
  73. src/lib/src/Modules/OptsConsumer.php +0 -4
  74. src/lib/src/Modules/Plugin/AdminNotices.php +2 -12
  75. src/lib/src/Modules/Plugin/Processor.php +3 -0
  76. src/lib/src/Scans/Afs/ResultItem.php +1 -1
  77. src/lib/src/ShieldNetApi/HandshakingNonce.php +2 -4
  78. src/lib/src/ShieldNetApi/ShieldNetApiController.php +0 -2
  79. src/lib/src/ShieldNetApi/ShieldNetApiDataVO.php +0 -2
  80. src/lib/vendor/composer/ClassLoader.php +14 -109
  81. src/lib/vendor/fernleafsystems/wordpress-services/src/Utilities/Email.php +0 -2
  82. src/lib/vendor/fernleafsystems/wordpress-services/src/Utilities/GeoIp.php +0 -4
  83. src/lib/vendor/fernleafsystems/wordpress-services/src/Utilities/Html.php +0 -4
  84. src/lib/vendor/fernleafsystems/wordpress-services/src/Utilities/Licenses/EddLicenseVO.php +1 -2
  85. src/lib/vendor/fernleafsystems/wordpress-services/src/Utilities/Obfuscate.php +0 -4
  86. src/lib/vendor/fernleafsystems/wordpress-services/src/Utilities/ServiceProviders.php +0 -4
  87. templates/twig/admin/user/profile/mfa/mfa_container.twig +0 -12
  88. templates/twig/admin/user/profile/mfa/mfa_email.twig +1 -1
  89. templates/twig/components/options_form/main.twig +1 -1
  90. templates/twig/notices/plugin-mailing-list-signup.twig +2 -6
  91. templates/twig/user/profile/mfa/main.twig +6 -1
cl.json CHANGED
@@ -129,6 +129,42 @@
129
  "title": "Error with MainWP loading in certain cases.",
130
  "description": [],
131
  "patch": "13.0.4"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
132
  }
133
  ]
134
  },
129
  "title": "Error with MainWP loading in certain cases.",
130
  "description": [],
131
  "patch": "13.0.4"
132
+ },
133
+ {
134
+ "type": "improved",
135
+ "title": "Options to provide custom roles for Email 2FA enforcement is now free-form.",
136
+ "description": [],
137
+ "patch": "13.0.5"
138
+ },
139
+ {
140
+ "type": "improved",
141
+ "title": "Multi-factor authentication settings are available even when your IP is on the bypass lists.",
142
+ "description": [],
143
+ "patch": "13.0.5"
144
+ },
145
+ {
146
+ "type": "improved",
147
+ "title": "ShieldPRO license lookups when using separate domains for multilingual site versions.",
148
+ "description": [],
149
+ "patch": "13.0.5"
150
+ },
151
+ {
152
+ "type": "improved",
153
+ "title": "FluentForms integration wasn't always loading and so SPAM submissions could still come through.",
154
+ "description": [],
155
+ "patch": "13.0.5"
156
+ },
157
+ {
158
+ "type": "improved",
159
+ "title": "NotBot Javascript is improved to better handle server timeouts and work around Page Caching limitations.",
160
+ "description": [],
161
+ "patch": "13.0.5"
162
+ },
163
+ {
164
+ "type": "fixed",
165
+ "title": "Prevent some fatal errors when integrating with 3rd parties and their data isn't as expected.",
166
+ "description": [],
167
+ "patch": "13.0.5"
168
  }
169
  ]
170
  },
config/deprecated/hack_protect.php CHANGED
@@ -98,7 +98,7 @@
98
  "default": "Y",
99
  "type": "checkbox",
100
  "link_info": "https://shsec.io/wpsf38",
101
- "link_blog": "https://shsec.io/9x",
102
  "beacon_id": 217,
103
  "name": "Enable Hack Guard",
104
  "summary": "Enable (or Disable) The Hack Guard Module",
@@ -111,7 +111,7 @@
111
  "type": "checkbox",
112
  "link_info": "https://shsec.io/hd",
113
  "link_blog": "https://shsec.io/wpsf37",
114
- "beacon_id": 224,
115
  "name": "WP Core File Scanner",
116
  "summary": "Automatically Scans WordPress Core Files For Alterations",
117
  "description": "Compares all WordPress core files on your site against the official WordPress files. WordPress Core files should never be altered for any reason."
@@ -203,7 +203,7 @@
203
  "default": "Y",
204
  "link_info": "https://shsec.io/du",
205
  "link_blog": "https://shsec.io/ah",
206
- "beacon_id": 137,
207
  "name": "Vulnerability Scanner",
208
  "summary": "Enable The Vulnerability Scanner",
209
  "description": "Scan all your WordPress assets for known security vulnerabilities."
98
  "default": "Y",
99
  "type": "checkbox",
100
  "link_info": "https://shsec.io/wpsf38",
101
+ "link_blog": "",
102
  "beacon_id": 217,
103
  "name": "Enable Hack Guard",
104
  "summary": "Enable (or Disable) The Hack Guard Module",
111
  "type": "checkbox",
112
  "link_info": "https://shsec.io/hd",
113
  "link_blog": "https://shsec.io/wpsf37",
114
+ "beacon_id": 454,
115
  "name": "WP Core File Scanner",
116
  "summary": "Automatically Scans WordPress Core Files For Alterations",
117
  "description": "Compares all WordPress core files on your site against the official WordPress files. WordPress Core files should never be altered for any reason."
203
  "default": "Y",
204
  "link_info": "https://shsec.io/du",
205
  "link_blog": "https://shsec.io/ah",
206
+ "beacon_id": 134,
207
  "name": "Vulnerability Scanner",
208
  "summary": "Enable The Vulnerability Scanner",
209
  "description": "Scan all your WordPress assets for known security vulnerabilities."
config/deprecated/login_protect.php CHANGED
@@ -213,55 +213,13 @@
213
  "key": "two_factor_auth_user_roles",
214
  "section": "section_2fa_email",
215
  "advanced": true,
216
- "type": "multiple_select",
217
  "default": [
218
  "contributor",
219
  "author",
220
  "editor",
221
  "administrator"
222
  ],
223
- "value_options": [
224
- {
225
- "value_key": "subscriber",
226
- "text": "Subscribers"
227
- },
228
- {
229
- "value_key": "contributor",
230
- "text": "Contributors"
231
- },
232
- {
233
- "value_key": "author",
234
- "text": "Authors"
235
- },
236
- {
237
- "value_key": "editor",
238
- "text": "Editors"
239
- },
240
- {
241
- "value_key": "administrator",
242
- "text": "Administrators"
243
- },
244
- {
245
- "value_key": "customer",
246
- "text": "[Woo] Customer"
247
- },
248
- {
249
- "value_key": "shop_manager",
250
- "text": "[Woo/EDD] Shop Manager"
251
- },
252
- {
253
- "value_key": "shop_accountant",
254
- "text": "[EDD] Shop Accountant"
255
- },
256
- {
257
- "value_key": "shop_worker",
258
- "text": "[EDD] Shop Worker"
259
- },
260
- {
261
- "value_key": "edd_subscriber",
262
- "text": "[EDD] Customer"
263
- }
264
- ],
265
  "link_info": "https://shsec.io/4v",
266
  "link_blog": "",
267
  "beacon_id": 243,
213
  "key": "two_factor_auth_user_roles",
214
  "section": "section_2fa_email",
215
  "advanced": true,
216
+ "type": "array",
217
  "default": [
218
  "contributor",
219
  "author",
220
  "editor",
221
  "administrator"
222
  ],
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
223
  "link_info": "https://shsec.io/4v",
224
  "link_blog": "",
225
  "beacon_id": 243,
config/deprecated/plugin.php CHANGED
@@ -107,11 +107,6 @@
107
  "title_short": "Import / Export",
108
  "beacon_id": 129
109
  },
110
- {
111
- "slug": "section_integrations",
112
- "title": "Integrations",
113
- "title_short": "Integrations"
114
- },
115
  {
116
  "slug": "section_global_security_options",
117
  "title": "Global Plugin Security Options",
@@ -397,7 +392,7 @@
397
  ],
398
  "link_info": "https://shsec.io/dq",
399
  "link_blog": "",
400
- "beacon_id": 269,
401
  "name": "CAPTCHA Provider",
402
  "summary": "Which CAPTCHA Provider To Use Throughout",
403
  "description": "You can choose the CAPTCHA provider depending on your preferences."
107
  "title_short": "Import / Export",
108
  "beacon_id": 129
109
  },
 
 
 
 
 
110
  {
111
  "slug": "section_global_security_options",
112
  "title": "Global Plugin Security Options",
392
  ],
393
  "link_info": "https://shsec.io/dq",
394
  "link_blog": "",
395
+ "beacon_id": 390,
396
  "name": "CAPTCHA Provider",
397
  "summary": "Which CAPTCHA Provider To Use Throughout",
398
  "description": "You can choose the CAPTCHA provider depending on your preferences."
config/login_protect.json CHANGED
@@ -213,55 +213,13 @@
213
  "key": "two_factor_auth_user_roles",
214
  "section": "section_2fa_email",
215
  "advanced": true,
216
- "type": "multiple_select",
217
  "default": [
218
  "contributor",
219
  "author",
220
  "editor",
221
  "administrator"
222
  ],
223
- "value_options": [
224
- {
225
- "value_key": "subscriber",
226
- "text": "Subscribers"
227
- },
228
- {
229
- "value_key": "contributor",
230
- "text": "Contributors"
231
- },
232
- {
233
- "value_key": "author",
234
- "text": "Authors"
235
- },
236
- {
237
- "value_key": "editor",
238
- "text": "Editors"
239
- },
240
- {
241
- "value_key": "administrator",
242
- "text": "Administrators"
243
- },
244
- {
245
- "value_key": "customer",
246
- "text": "[Woo] Customer"
247
- },
248
- {
249
- "value_key": "shop_manager",
250
- "text": "[Woo/EDD] Shop Manager"
251
- },
252
- {
253
- "value_key": "shop_accountant",
254
- "text": "[EDD] Shop Accountant"
255
- },
256
- {
257
- "value_key": "shop_worker",
258
- "text": "[EDD] Shop Worker"
259
- },
260
- {
261
- "value_key": "edd_subscriber",
262
- "text": "[EDD] Customer"
263
- }
264
- ],
265
  "link_info": "https://shsec.io/4v",
266
  "link_blog": "",
267
  "beacon_id": 243,
213
  "key": "two_factor_auth_user_roles",
214
  "section": "section_2fa_email",
215
  "advanced": true,
216
+ "type": "array",
217
  "default": [
218
  "contributor",
219
  "author",
220
  "editor",
221
  "administrator"
222
  ],
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
223
  "link_info": "https://shsec.io/4v",
224
  "link_blog": "",
225
  "beacon_id": 243,
icwp-wpsf.php CHANGED
@@ -3,7 +3,7 @@
3
  * Plugin Name: Shield Security
4
  * Plugin URI: https://shsec.io/2f
5
  * Description: Powerful, Easy-To-Use #1 Rated WordPress Security System
6
- * Version: 13.0.4
7
  * Text Domain: wp-simple-firewall
8
  * Domain Path: /languages
9
  * Author: Shield Security
@@ -11,7 +11,7 @@
11
  */
12
 
13
  /**
14
- * Copyright (c) 2021 Shield Security <support@getshieldsecurity.com>
15
  * All rights reserved.
16
  * "Shield" (formerly WordPress Simple Firewall) is distributed under the GNU
17
  * General Public License, Version 2, June 1991. Copyright (C) 1989, 1991 Free
3
  * Plugin Name: Shield Security
4
  * Plugin URI: https://shsec.io/2f
5
  * Description: Powerful, Easy-To-Use #1 Rated WordPress Security System
6
+ * Version: 13.0.5
7
  * Text Domain: wp-simple-firewall
8
  * Domain Path: /languages
9
  * Author: Shield Security
11
  */
12
 
13
  /**
14
+ * Copyright (c) 2022 Shield Security <support@getshieldsecurity.com>
15
  * All rights reserved.
16
  * "Shield" (formerly WordPress Simple Firewall) is distributed under the GNU
17
  * General Public License, Version 2, June 1991. Copyright (C) 1989, 1991 Free
plugin-spec.php CHANGED
@@ -1,8 +1,8 @@
1
  {
2
  "properties": {
3
- "version": "13.0.4",
4
- "release_timestamp": 1640169200,
5
- "build": "202112.2201",
6
  "slug_parent": "icwp",
7
  "slug_plugin": "wpsf",
8
  "human_name": "Shield Security",
@@ -83,91 +83,95 @@
83
  },
84
  "register": {
85
  "css": {
86
- "bootstrap": {
87
  "url": "https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.6.1/css/bootstrap.min.css"
88
  },
89
- "bootstrap-datepicker": {
90
  "url": "https://cdnjs.cloudflare.com/ajax/libs/bootstrap-datepicker/1.8.0/css/bootstrap-datepicker.min.css",
91
  "deps": [
92
  "bootstrap"
93
  ]
94
  },
95
- "bootstrap-select": {
96
  "url": "https://cdnjs.cloudflare.com/ajax/libs/bootstrap-select/1.13.18/css/bootstrap-select.min.css",
97
  "deps": [
98
  "bootstrap"
99
  ]
100
  },
101
- "select2": {
102
  "url": "https://cdnjs.cloudflare.com/ajax/libs/select2/4.0.13/css/select2.min.css",
103
  "deps": [
104
  "plugin"
105
  ]
106
  },
107
- "datatables-bootstrap": {
108
  "url": "https://cdn.datatables.net/1.11.3/css/dataTables.bootstrap4.min.css",
109
  "deps": [
110
  "bootstrap"
111
  ]
112
  },
113
- "datatables-searchpanes": {
114
  "url": "https://cdn.datatables.net/searchpanes/1.4.0/css/searchPanes.dataTables.min.css",
115
  "deps": [
116
  "datatables-bootstrap"
117
  ]
118
  },
119
- "datatables-select": {
120
  "url": "https://cdn.datatables.net/select/1.3.3/css/select.dataTables.min.css",
121
  "deps": [
122
  "datatables-bootstrap"
123
  ]
124
  },
125
- "datatables-buttons": {
126
  "url": "https://cdn.datatables.net/buttons/1.7.1/css/buttons.dataTables.min.css",
127
  "deps": [
128
  "datatables-bootstrap"
129
  ]
130
  },
131
- "global-plugin": {},
132
- "plugin": {
133
  "deps": [
134
  "bootstrap",
135
  "global-plugin"
136
  ]
137
  },
138
- "shield/wizard": {
139
  "deps": [
140
  "bootstrap",
141
  "global-plugin"
142
  ]
143
  },
144
- "jquery/featherlight": {
145
  "url": "https://cdnjs.cloudflare.com/ajax/libs/featherlight/1.7.13/featherlight.min.css"
146
  },
147
- "chartist": {
148
  "url": "https://cdnjs.cloudflare.com/ajax/libs/chartist/0.11.4/chartist.min.css"
149
  },
150
- "chartist-plugin-legend": {
151
  "deps": [
152
  "chartist"
153
  ]
154
  },
155
- "introjs": {
156
  "url": "https://cdnjs.cloudflare.com/ajax/libs/intro.js/3.3.1/introjs.min.css"
157
  },
158
- "shield/charts": {
 
 
 
 
159
  "deps": [
160
  "plugin"
161
  ]
162
  },
163
- "shield/dialog": {
164
  "deps": [
165
  "wp-wp-jquery-ui-dialog"
166
  ],
167
  "footer": true
168
  },
169
- "shield/mainwp": {},
170
- "shield/datatables": {
171
  "deps": [
172
  "datatables-select",
173
  "datatables-buttons",
@@ -176,7 +180,7 @@
176
  "tp/highlightjs"
177
  ]
178
  },
179
- "shield/scanners": {
180
  "deps": [
181
  "datatables-select",
182
  "datatables-buttons",
@@ -184,7 +188,7 @@
184
  "tp/highlightjs"
185
  ]
186
  },
187
- "tp/highlightjs": {
188
  "url": "https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.1.0/styles/default.min.css"
189
  }
190
  },
1
  {
2
  "properties": {
3
+ "version": "13.0.5",
4
+ "release_timestamp": 1641981192,
5
+ "build": "202201.1201",
6
  "slug_parent": "icwp",
7
  "slug_plugin": "wpsf",
8
  "human_name": "Shield Security",
83
  },
84
  "register": {
85
  "css": {
86
+ "bootstrap": {
87
  "url": "https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.6.1/css/bootstrap.min.css"
88
  },
89
+ "bootstrap-datepicker": {
90
  "url": "https://cdnjs.cloudflare.com/ajax/libs/bootstrap-datepicker/1.8.0/css/bootstrap-datepicker.min.css",
91
  "deps": [
92
  "bootstrap"
93
  ]
94
  },
95
+ "bootstrap-select": {
96
  "url": "https://cdnjs.cloudflare.com/ajax/libs/bootstrap-select/1.13.18/css/bootstrap-select.min.css",
97
  "deps": [
98
  "bootstrap"
99
  ]
100
  },
101
+ "select2": {
102
  "url": "https://cdnjs.cloudflare.com/ajax/libs/select2/4.0.13/css/select2.min.css",
103
  "deps": [
104
  "plugin"
105
  ]
106
  },
107
+ "datatables-bootstrap": {
108
  "url": "https://cdn.datatables.net/1.11.3/css/dataTables.bootstrap4.min.css",
109
  "deps": [
110
  "bootstrap"
111
  ]
112
  },
113
+ "datatables-searchpanes": {
114
  "url": "https://cdn.datatables.net/searchpanes/1.4.0/css/searchPanes.dataTables.min.css",
115
  "deps": [
116
  "datatables-bootstrap"
117
  ]
118
  },
119
+ "datatables-select": {
120
  "url": "https://cdn.datatables.net/select/1.3.3/css/select.dataTables.min.css",
121
  "deps": [
122
  "datatables-bootstrap"
123
  ]
124
  },
125
+ "datatables-buttons": {
126
  "url": "https://cdn.datatables.net/buttons/1.7.1/css/buttons.dataTables.min.css",
127
  "deps": [
128
  "datatables-bootstrap"
129
  ]
130
  },
131
+ "global-plugin": {},
132
+ "plugin": {
133
  "deps": [
134
  "bootstrap",
135
  "global-plugin"
136
  ]
137
  },
138
+ "shield/wizard": {
139
  "deps": [
140
  "bootstrap",
141
  "global-plugin"
142
  ]
143
  },
144
+ "jquery/featherlight": {
145
  "url": "https://cdnjs.cloudflare.com/ajax/libs/featherlight/1.7.13/featherlight.min.css"
146
  },
147
+ "chartist": {
148
  "url": "https://cdnjs.cloudflare.com/ajax/libs/chartist/0.11.4/chartist.min.css"
149
  },
150
+ "chartist-plugin-legend": {
151
  "deps": [
152
  "chartist"
153
  ]
154
  },
155
+ "introjs": {
156
  "url": "https://cdnjs.cloudflare.com/ajax/libs/intro.js/3.3.1/introjs.min.css"
157
  },
158
+ "shield/userprofile": {
159
+ "deps": [],
160
+ "footer": true
161
+ },
162
+ "shield/charts": {
163
  "deps": [
164
  "plugin"
165
  ]
166
  },
167
+ "shield/dialog": {
168
  "deps": [
169
  "wp-wp-jquery-ui-dialog"
170
  ],
171
  "footer": true
172
  },
173
+ "shield/mainwp": {},
174
+ "shield/datatables": {
175
  "deps": [
176
  "datatables-select",
177
  "datatables-buttons",
180
  "tp/highlightjs"
181
  ]
182
  },
183
+ "shield/scanners": {
184
  "deps": [
185
  "datatables-select",
186
  "datatables-buttons",
188
  "tp/highlightjs"
189
  ]
190
  },
191
+ "tp/highlightjs": {
192
  "url": "https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.1.0/styles/default.min.css"
193
  }
194
  },
plugin.json CHANGED
@@ -1,8 +1,8 @@
1
  {
2
  "properties": {
3
- "version": "13.0.4",
4
- "release_timestamp": 1640169200,
5
- "build": "202112.2201",
6
  "slug_parent": "icwp",
7
  "slug_plugin": "wpsf",
8
  "human_name": "Shield Security",
@@ -83,91 +83,95 @@
83
  },
84
  "register": {
85
  "css": {
86
- "bootstrap": {
87
  "url": "https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.6.1/css/bootstrap.min.css"
88
  },
89
- "bootstrap-datepicker": {
90
  "url": "https://cdnjs.cloudflare.com/ajax/libs/bootstrap-datepicker/1.8.0/css/bootstrap-datepicker.min.css",
91
  "deps": [
92
  "bootstrap"
93
  ]
94
  },
95
- "bootstrap-select": {
96
  "url": "https://cdnjs.cloudflare.com/ajax/libs/bootstrap-select/1.13.18/css/bootstrap-select.min.css",
97
  "deps": [
98
  "bootstrap"
99
  ]
100
  },
101
- "select2": {
102
  "url": "https://cdnjs.cloudflare.com/ajax/libs/select2/4.0.13/css/select2.min.css",
103
  "deps": [
104
  "plugin"
105
  ]
106
  },
107
- "datatables-bootstrap": {
108
  "url": "https://cdn.datatables.net/1.11.3/css/dataTables.bootstrap4.min.css",
109
  "deps": [
110
  "bootstrap"
111
  ]
112
  },
113
- "datatables-searchpanes": {
114
  "url": "https://cdn.datatables.net/searchpanes/1.4.0/css/searchPanes.dataTables.min.css",
115
  "deps": [
116
  "datatables-bootstrap"
117
  ]
118
  },
119
- "datatables-select": {
120
  "url": "https://cdn.datatables.net/select/1.3.3/css/select.dataTables.min.css",
121
  "deps": [
122
  "datatables-bootstrap"
123
  ]
124
  },
125
- "datatables-buttons": {
126
  "url": "https://cdn.datatables.net/buttons/1.7.1/css/buttons.dataTables.min.css",
127
  "deps": [
128
  "datatables-bootstrap"
129
  ]
130
  },
131
- "global-plugin": {},
132
- "plugin": {
133
  "deps": [
134
  "bootstrap",
135
  "global-plugin"
136
  ]
137
  },
138
- "shield/wizard": {
139
  "deps": [
140
  "bootstrap",
141
  "global-plugin"
142
  ]
143
  },
144
- "jquery/featherlight": {
145
  "url": "https://cdnjs.cloudflare.com/ajax/libs/featherlight/1.7.13/featherlight.min.css"
146
  },
147
- "chartist": {
148
  "url": "https://cdnjs.cloudflare.com/ajax/libs/chartist/0.11.4/chartist.min.css"
149
  },
150
- "chartist-plugin-legend": {
151
  "deps": [
152
  "chartist"
153
  ]
154
  },
155
- "introjs": {
156
  "url": "https://cdnjs.cloudflare.com/ajax/libs/intro.js/3.3.1/introjs.min.css"
157
  },
158
- "shield/charts": {
 
 
 
 
159
  "deps": [
160
  "plugin"
161
  ]
162
  },
163
- "shield/dialog": {
164
  "deps": [
165
  "wp-wp-jquery-ui-dialog"
166
  ],
167
  "footer": true
168
  },
169
- "shield/mainwp": {},
170
- "shield/datatables": {
171
  "deps": [
172
  "datatables-select",
173
  "datatables-buttons",
@@ -176,7 +180,7 @@
176
  "tp/highlightjs"
177
  ]
178
  },
179
- "shield/scanners": {
180
  "deps": [
181
  "datatables-select",
182
  "datatables-buttons",
@@ -184,7 +188,7 @@
184
  "tp/highlightjs"
185
  ]
186
  },
187
- "tp/highlightjs": {
188
  "url": "https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.1.0/styles/default.min.css"
189
  }
190
  },
1
  {
2
  "properties": {
3
+ "version": "13.0.5",
4
+ "release_timestamp": 1641981192,
5
+ "build": "202201.1201",
6
  "slug_parent": "icwp",
7
  "slug_plugin": "wpsf",
8
  "human_name": "Shield Security",
83
  },
84
  "register": {
85
  "css": {
86
+ "bootstrap": {
87
  "url": "https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.6.1/css/bootstrap.min.css"
88
  },
89
+ "bootstrap-datepicker": {
90
  "url": "https://cdnjs.cloudflare.com/ajax/libs/bootstrap-datepicker/1.8.0/css/bootstrap-datepicker.min.css",
91
  "deps": [
92
  "bootstrap"
93
  ]
94
  },
95
+ "bootstrap-select": {
96
  "url": "https://cdnjs.cloudflare.com/ajax/libs/bootstrap-select/1.13.18/css/bootstrap-select.min.css",
97
  "deps": [
98
  "bootstrap"
99
  ]
100
  },
101
+ "select2": {
102
  "url": "https://cdnjs.cloudflare.com/ajax/libs/select2/4.0.13/css/select2.min.css",
103
  "deps": [
104
  "plugin"
105
  ]
106
  },
107
+ "datatables-bootstrap": {
108
  "url": "https://cdn.datatables.net/1.11.3/css/dataTables.bootstrap4.min.css",
109
  "deps": [
110
  "bootstrap"
111
  ]
112
  },
113
+ "datatables-searchpanes": {
114
  "url": "https://cdn.datatables.net/searchpanes/1.4.0/css/searchPanes.dataTables.min.css",
115
  "deps": [
116
  "datatables-bootstrap"
117
  ]
118
  },
119
+ "datatables-select": {
120
  "url": "https://cdn.datatables.net/select/1.3.3/css/select.dataTables.min.css",
121
  "deps": [
122
  "datatables-bootstrap"
123
  ]
124
  },
125
+ "datatables-buttons": {
126
  "url": "https://cdn.datatables.net/buttons/1.7.1/css/buttons.dataTables.min.css",
127
  "deps": [
128
  "datatables-bootstrap"
129
  ]
130
  },
131
+ "global-plugin": {},
132
+ "plugin": {
133
  "deps": [
134
  "bootstrap",
135
  "global-plugin"
136
  ]
137
  },
138
+ "shield/wizard": {
139
  "deps": [
140
  "bootstrap",
141
  "global-plugin"
142
  ]
143
  },
144
+ "jquery/featherlight": {
145
  "url": "https://cdnjs.cloudflare.com/ajax/libs/featherlight/1.7.13/featherlight.min.css"
146
  },
147
+ "chartist": {
148
  "url": "https://cdnjs.cloudflare.com/ajax/libs/chartist/0.11.4/chartist.min.css"
149
  },
150
+ "chartist-plugin-legend": {
151
  "deps": [
152
  "chartist"
153
  ]
154
  },
155
+ "introjs": {
156
  "url": "https://cdnjs.cloudflare.com/ajax/libs/intro.js/3.3.1/introjs.min.css"
157
  },
158
+ "shield/userprofile": {
159
+ "deps": [],
160
+ "footer": true
161
+ },
162
+ "shield/charts": {
163
  "deps": [
164
  "plugin"
165
  ]
166
  },
167
+ "shield/dialog": {
168
  "deps": [
169
  "wp-wp-jquery-ui-dialog"
170
  ],
171
  "footer": true
172
  },
173
+ "shield/mainwp": {},
174
+ "shield/datatables": {
175
  "deps": [
176
  "datatables-select",
177
  "datatables-buttons",
180
  "tp/highlightjs"
181
  ]
182
  },
183
+ "shield/scanners": {
184
  "deps": [
185
  "datatables-select",
186
  "datatables-buttons",
188
  "tp/highlightjs"
189
  ]
190
  },
191
+ "tp/highlightjs": {
192
  "url": "https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.1.0/styles/default.min.css"
193
  }
194
  },
readme.txt CHANGED
@@ -7,7 +7,7 @@ Tags: scan, malware, firewall, two factor authentication, login protection
7
  Requires at least: 3.7
8
  Requires PHP: 7.0
9
  Recommended PHP: 7.4
10
- Tested up to: 5.8
11
  Stable tag: 13.0.4
12
 
13
  No-Nonsense Security Hardening that protects WordPress against hackers, malicious bots, and spammers (no captchas!). Now with exclusive ShieldNET Technology.
7
  Requires at least: 3.7
8
  Requires PHP: 7.0
9
  Recommended PHP: 7.4
10
+ Tested up to: 5.9
11
  Stable tag: 13.0.4
12
 
13
  No-Nonsense Security Hardening that protects WordPress against hackers, malicious bots, and spammers (no captchas!). Now with exclusive ShieldNET Technology.
resources/css/shield/userprofile.css ADDED
@@ -0,0 +1,15 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #ShieldUserProfileMFA {
2
+ margin-top: 1em;
3
+ }
4
+ #ShieldUserProfileMFA th {
5
+ text-align: left;
6
+ vertical-align: top;
7
+ padding: 20px 10px 20px 0;
8
+ width: 200px;
9
+ line-height: 1.3;
10
+ font-weight: 600;
11
+ }
12
+ #ShieldUserProfileMFA td {
13
+ padding: 20px 0;
14
+ vertical-align: top;
15
+ }
resources/js/shield/notbot.js CHANGED
@@ -1,85 +1,82 @@
 
 
 
1
  if ( typeof Shield_Antibot === typeof undefined && typeof shield_vars_notbotjs !== typeof undefined ) {
2
-
3
- var Shield_Antibot = new function () {
4
 
5
  let request_count = 0;
6
- let can_continue = true;
7
-
8
- var domReady = function ( fn ) {
9
- if ( document.readyState !== 'loading' ) {
10
- fn();
11
- }
12
- else if ( document.addEventListener ) {
13
- document.addEventListener( 'DOMContentLoaded', fn );
14
- }
15
- else {
16
- document.attachEvent( 'onreadystatechange', function () {
17
- if ( document.readyState !== 'loading' )
18
- fn();
19
- } );
20
- }
21
- }
22
 
23
  this.initialise = function () {
24
  /**
25
  * @since 11.2 we no longer wait until DOM is ready.
26
  * @since 12.0.10 we return to using cookies to optimise whether the AJAX request is sent.
27
- * This is mainly AJAX so it's asynchronous and wont hold up any other part of the page load.
28
  * Early execution also helps mitigate the case where login requests are
29
  * sent quickly, before browser has fired NotBot request.
30
  */
 
 
 
 
 
 
31
  if ( shield_vars_notbotjs.flags.run ) {
32
  fire();
33
  }
34
- /**
35
- * @since 11.2 this script is only loaded if a not bot signal doesn't exist for this IP.
36
- */
37
- domReady( function () {
38
- // fire();
39
- } );
40
  };
41
 
42
  /**
43
  * @since 12.0.10 - rather than auto send request every page load, check for cookie repeatedly and send if
44
  * absent.
45
  */
46
- var fire = function () {
47
- let current = getCookie( 'icwp-wpsf-notbot' );
48
- if ( current === undefined || typeof (current) === 'undefined' ) {
49
- sendReq();
50
- }
51
- if ( can_continue && request_count < 10 ) {
52
- window.setTimeout( fire, 10000 );
53
  }
 
54
  };
55
 
56
- var sendReq = function ( name ) {
 
 
 
57
  request_count++;
58
 
59
  let xhr = new XMLHttpRequest();
 
 
60
 
61
  /**
62
- * Ensures that if there's an error with the AJAX, we don't continue
63
- * to keep trying the requests.
64
  */
65
  xhr.onreadystatechange = function () {
66
  if ( xhr.readyState === 4 ) {
67
- let resp = JSON.parse( xhr.response );
68
- can_continue = resp && resp.success;
69
- if ( !can_continue ) {
70
- console.log( xhr.response );
 
 
 
71
  }
72
  }
 
 
 
73
  }
74
 
75
- xhr.open( "POST", shield_vars_notbotjs.hrefs.ajax, true );
76
- xhr.setRequestHeader( 'Content-Type', 'application/x-www-form-urlencoded;' );
77
- xhr.send( shield_vars_notbotjs.ajax.not_bot );
78
  };
79
 
80
- var getCookie = function ( name ) {
81
- var value = "; " + document.cookie;
82
- var parts = value.split( "; " + name + "=" );
83
  if ( parts.length === 2 ) return parts.pop().split( ";" ).shift();
84
  };
85
  }();
1
+ /**
2
+ * @var shield_vars_notbotjs object
3
+ */
4
  if ( typeof Shield_Antibot === typeof undefined && typeof shield_vars_notbotjs !== typeof undefined ) {
5
+ let Shield_Antibot = new function () {
 
6
 
7
  let request_count = 0;
8
+ let can_send_request = true;
9
+ let nonce_cook = '';
10
+ let ajaxurl = shield_vars_notbotjs.ajax.not_bot.ajaxurl;
 
 
 
 
 
 
 
 
 
 
 
 
 
11
 
12
  this.initialise = function () {
13
  /**
14
  * @since 11.2 we no longer wait until DOM is ready.
15
  * @since 12.0.10 we return to using cookies to optimise whether the AJAX request is sent.
16
+ * This is mainly AJAX so it's asynchronous and won't hold up any other part of the page load.
17
  * Early execution also helps mitigate the case where login requests are
18
  * sent quickly, before browser has fired NotBot request.
19
  */
20
+ delete shield_vars_notbotjs.ajax.not_bot.ajaxurl;
21
+ nonce_cook = getCookie( 'shield-notbot-nonce' );
22
+ if ( typeof nonce_cook !== typeof undefined && nonce_cook.length > 0 ) {
23
+ /** Overcome limitations of page caching by passing nonce via cookie **/
24
+ shield_vars_notbotjs.ajax.not_bot.exec_nonce = nonce_cook;
25
+ }
26
  if ( shield_vars_notbotjs.flags.run ) {
27
  fire();
28
  }
 
 
 
 
 
 
29
  };
30
 
31
  /**
32
  * @since 12.0.10 - rather than auto send request every page load, check for cookie repeatedly and send if
33
  * absent.
34
  */
35
+ let fire = function () {
36
+ if ( can_send_request && request_count < 10 ) {
37
+ let current = getCookie( 'icwp-wpsf-notbot' );
38
+ if ( current === undefined || typeof (current) === 'undefined' ) {
39
+ sendReq();
40
+ }
 
41
  }
42
+ window.setTimeout( fire, 30000 );
43
  };
44
 
45
+ /**
46
+ * We use the cookie to help ensure we don't send unnecessary requests and keep checking
47
+ */
48
+ let sendReq = function () {
49
  request_count++;
50
 
51
  let xhr = new XMLHttpRequest();
52
+ xhr.open( "POST", ajaxurl, true );
53
+ xhr.setRequestHeader( 'Content-Type', 'application/x-www-form-urlencoded;' );
54
 
55
  /**
56
+ * Ensures that if there's an error with the AJAX, we don't keep retrying the requests.
 
57
  */
58
  xhr.onreadystatechange = function () {
59
  if ( xhr.readyState === 4 ) {
60
+ let rawResp = xhr.response;
61
+ if ( rawResp != null && rawResp !== '' && rawResp.charAt( 0 ) === '{' ) {
62
+ let resp = JSON.parse( rawResp )
63
+ can_send_request = resp && resp.success;
64
+ if ( !can_send_request ) {
65
+ console.log( xhr.response );
66
+ }
67
  }
68
  }
69
+ else {
70
+ can_send_request = false;
71
+ }
72
  }
73
 
74
+ xhr.send( (new URLSearchParams( shield_vars_notbotjs.ajax.not_bot )).toString() );
 
 
75
  };
76
 
77
+ let getCookie = function ( name ) {
78
+ let value = "; " + document.cookie;
79
+ let parts = value.split( "; " + name + "=" );
80
  if ( parts.length === 2 ) return parts.pop().split( ";" ).shift();
81
  };
82
  }();
src/lib/src/Controller/Controller.php CHANGED
@@ -545,8 +545,6 @@ class Controller extends DynPropertiesClass {
545
  }
546
 
547
  /**
548
- * @param string $action
549
- * @return array
550
  * @throws \Exception
551
  */
552
  public function getNonceActionData( string $action = '' ) :array {
@@ -754,24 +752,24 @@ class Controller extends DynPropertiesClass {
754
  }
755
 
756
  /**
757
- * @param array $aPlugins
758
  * @return array
759
  */
760
- public function doPluginLabels( $aPlugins ) {
761
  $labels = $this->getLabels();
762
  if ( empty( $labels ) ) {
763
- return $aPlugins;
764
  }
765
 
766
  $file = $this->base_file;
767
  // For this plugin, overwrite any specified settings
768
- if ( array_key_exists( $file, $aPlugins ) ) {
769
  foreach ( $labels as $sLabelKey => $sLabel ) {
770
- $aPlugins[ $file ][ $sLabelKey ] = $sLabel;
771
  }
772
  }
773
 
774
- return $aPlugins;
775
  }
776
 
777
  public function getLabels() :array {
@@ -863,7 +861,6 @@ class Controller extends DynPropertiesClass {
863
  }
864
 
865
  /**
866
- * @return Config\ConfigVO
867
  * @throws \Exception
868
  */
869
  private function loadConfig() :Config\ConfigVO {
@@ -882,7 +879,6 @@ class Controller extends DynPropertiesClass {
882
  }
883
 
884
  /**
885
- * @param string $key
886
  * @return string|null
887
  */
888
  public function getPluginSpec_Path( string $key ) {
@@ -890,7 +886,6 @@ class Controller extends DynPropertiesClass {
890
  }
891
 
892
  /**
893
- * @param string $key
894
  * @return mixed|null
895
  */
896
  protected function getCfgProperty( string $key ) {
@@ -1165,7 +1160,6 @@ class Controller extends DynPropertiesClass {
1165
  }
1166
 
1167
  /**
1168
- * @return bool
1169
  * @throws \Exception
1170
  */
1171
  public function loadAllFeatures() :bool {
@@ -1195,7 +1189,6 @@ class Controller extends DynPropertiesClass {
1195
  }
1196
 
1197
  /**
1198
- * @param string $slug
1199
  * @return Shield\Modules\Base\ModCon|null|mixed
1200
  */
1201
  public function getModule( string $slug ) {
@@ -1294,7 +1287,6 @@ class Controller extends DynPropertiesClass {
1294
  }
1295
 
1296
  /**
1297
- * @param array $modProps
1298
  * @return Shield\Modules\Base\ModCon|mixed
1299
  * @throws \Exception
1300
  */
545
  }
546
 
547
  /**
 
 
548
  * @throws \Exception
549
  */
550
  public function getNonceActionData( string $action = '' ) :array {
752
  }
753
 
754
  /**
755
+ * @param array $plugins
756
  * @return array
757
  */
758
+ public function doPluginLabels( $plugins ) {
759
  $labels = $this->getLabels();
760
  if ( empty( $labels ) ) {
761
+ return $plugins;
762
  }
763
 
764
  $file = $this->base_file;
765
  // For this plugin, overwrite any specified settings
766
+ if ( array_key_exists( $file, $plugins ) ) {
767
  foreach ( $labels as $sLabelKey => $sLabel ) {
768
+ $plugins[ $file ][ $sLabelKey ] = $sLabel;
769
  }
770
  }
771
 
772
+ return $plugins;
773
  }
774
 
775
  public function getLabels() :array {
861
  }
862
 
863
  /**
 
864
  * @throws \Exception
865
  */
866
  private function loadConfig() :Config\ConfigVO {
879
  }
880
 
881
  /**
 
882
  * @return string|null
883
  */
884
  public function getPluginSpec_Path( string $key ) {
886
  }
887
 
888
  /**
 
889
  * @return mixed|null
890
  */
891
  protected function getCfgProperty( string $key ) {
1160
  }
1161
 
1162
  /**
 
1163
  * @throws \Exception
1164
  */
1165
  public function loadAllFeatures() :bool {
1189
  }
1190
 
1191
  /**
 
1192
  * @return Shield\Modules\Base\ModCon|null|mixed
1193
  */
1194
  public function getModule( string $slug ) {
1287
  }
1288
 
1289
  /**
 
1290
  * @return Shield\Modules\Base\ModCon|mixed
1291
  * @throws \Exception
1292
  */
src/lib/src/Modules/Autoupdates/AjaxHandler.php DELETED
@@ -1,9 +0,0 @@
1
- <?php declare( strict_types=1 );
2
-
3
- namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\Autoupdates;
4
-
5
- use FernleafSystems\Wordpress\Plugin\Shield;
6
-
7
- class AjaxHandler extends Shield\Modules\BaseShield\AjaxHandler {
8
-
9
- }
 
 
 
 
 
 
 
 
 
src/lib/src/Modules/Base/AdminNotices.php CHANGED
@@ -26,14 +26,14 @@ class AdminNotices {
26
  }
27
 
28
  protected function ajaxExec_DismissAdminNotice() :array {
29
- $aAjaxResponse = [];
30
 
31
- $sNoticeId = sanitize_key( Services::Request()->query( 'notice_id', '' ) );
32
 
33
  foreach ( $this->getAdminNotices() as $notice ) {
34
- if ( $sNoticeId == $notice->id ) {
35
  $this->setNoticeDismissed( $notice );
36
- $aAjaxResponse = [
37
  'success' => true,
38
  'message' => 'Admin notice dismissed', //not currently seen
39
  'notice_id' => $notice->id,
@@ -43,22 +43,22 @@ class AdminNotices {
43
  }
44
 
45
  // leave response empty if it doesn't apply here, so other modules can process it.
46
- return $aAjaxResponse;
47
  }
48
 
49
  /**
50
- * @param Shield\Utilities\AdminNotices\NoticeVO[] $aNotices
51
  * @return Shield\Utilities\AdminNotices\NoticeVO[]
52
  */
53
- public function addNotices( $aNotices ) {
54
- return array_merge( $aNotices, $this->buildNotices() );
55
  }
56
 
57
  /**
58
  * @return Shield\Utilities\AdminNotices\NoticeVO[]
59
  */
60
- protected function buildNotices() {
61
- $aNotices = [];
62
 
63
  foreach ( $this->getAdminNotices() as $notice ) {
64
  $this->preProcessNotice( $notice );
@@ -66,7 +66,7 @@ class AdminNotices {
66
  try {
67
  $this->processNotice( $notice );
68
  if ( $notice->display ) {
69
- $aNotices[] = $notice;
70
  }
71
  }
72
  catch ( \Exception $e ) {
@@ -74,7 +74,7 @@ class AdminNotices {
74
  }
75
  }
76
 
77
- return $aNotices;
78
  }
79
 
80
  /**
@@ -145,21 +145,17 @@ class AdminNotices {
145
  $notice->template = '/notices/'.$notice->id;
146
  }
147
 
148
- /**
149
- * @param NoticeVO $notice
150
- * @return bool
151
- */
152
- protected function isNoticeDismissed( $notice ) {
153
- $bDismissedUser = $this->isNoticeDismissedForCurrentUser( $notice );
154
 
155
- $aDisd = $this->getMod()->getDismissedNotices();
156
- $bDismissedMod = isset( $aDisd[ $notice->id ] ) && $aDisd[ $notice->id ] > 0;
157
 
158
- if ( !$notice->per_user && $bDismissedUser && !$bDismissedMod ) {
159
  $this->setNoticeDismissed( $notice );
160
  }
161
 
162
- return $bDismissedUser || $bDismissedMod;
163
  }
164
 
165
  /**
@@ -170,72 +166,58 @@ class AdminNotices {
170
  return true;
171
  }
172
 
173
- /**
174
- * @param NoticeVO $notice
175
- * @return bool
176
- */
177
- protected function isNoticeDismissedForCurrentUser( $notice ) {
178
- $bDismissed = false;
179
 
180
  $meta = $this->getCon()->getCurrentUserMeta();
181
  if ( $meta instanceof PluginUserMeta ) {
182
- $sNoticeMetaKey = $this->getNoticeMetaKey( $notice );
183
 
184
- if ( isset( $meta->{$sNoticeMetaKey} ) ) {
185
- $bDismissed = true;
186
 
187
  // migrate from old-style array storage to plain Timestamp
188
- if ( is_array( $meta->{$sNoticeMetaKey} ) ) {
189
- $meta->{$sNoticeMetaKey} = $meta->{$sNoticeMetaKey}[ 'time' ];
190
  }
191
  }
192
  }
193
 
194
- return $bDismissed;
195
  }
196
 
197
  /**
198
- * @param NoticeVO $notice
199
  * @throws \Exception
200
  */
201
  protected function processNotice( NoticeVO $notice ) {
202
  throw new \Exception( 'Unsupported Notice ID: '.$notice->id );
203
  }
204
 
205
- /**
206
- * @param NoticeVO $notice
207
- * @return $this
208
- */
209
- protected function setNoticeDismissed( $notice ) {
210
- $nTs = Services::Request()->ts();
211
 
212
  $meta = $this->getCon()->getCurrentUserMeta();
213
- $sNoticeMetaKey = $this->getNoticeMetaKey( $notice );
214
 
215
  if ( $notice->per_user ) {
216
  if ( $meta instanceof PluginUserMeta ) {
217
- $meta->{$sNoticeMetaKey} = $nTs;
218
  }
219
  }
220
  else {
221
  $mod = $this->getMod();
222
- $aDismissed = $mod->getDismissedNotices();
223
- $aDismissed[ $notice->id ] = $nTs;
224
- $mod->setDismissedNotices( $aDismissed );
225
 
226
  // Clear out any old
227
  if ( $meta instanceof PluginUserMeta ) {
228
- unset( $meta->{$sNoticeMetaKey} );
229
  }
230
  }
231
- return $this;
232
  }
233
 
234
- /**
235
- * @param NoticeVO $notice
236
- * @return string
237
- */
238
- private function getNoticeMetaKey( $notice ) {
239
  return 'notice_'.str_replace( [ '-', '_' ], '', $notice->id );
240
  }
241
  }
26
  }
27
 
28
  protected function ajaxExec_DismissAdminNotice() :array {
29
+ $ajaxResponse = [];
30
 
31
+ $noticeID = sanitize_key( Services::Request()->query( 'notice_id', '' ) );
32
 
33
  foreach ( $this->getAdminNotices() as $notice ) {
34
+ if ( $noticeID == $notice->id ) {
35
  $this->setNoticeDismissed( $notice );
36
+ $ajaxResponse = [
37
  'success' => true,
38
  'message' => 'Admin notice dismissed', //not currently seen
39
  'notice_id' => $notice->id,
43
  }
44
 
45
  // leave response empty if it doesn't apply here, so other modules can process it.
46
+ return $ajaxResponse;
47
  }
48
 
49
  /**
50
+ * @param Shield\Utilities\AdminNotices\NoticeVO[] $notices
51
  * @return Shield\Utilities\AdminNotices\NoticeVO[]
52
  */
53
+ public function addNotices( $notices ) {
54
+ return array_merge( $notices, $this->buildNotices() );
55
  }
56
 
57
  /**
58
  * @return Shield\Utilities\AdminNotices\NoticeVO[]
59
  */
60
+ protected function buildNotices() :array {
61
+ $notices = [];
62
 
63
  foreach ( $this->getAdminNotices() as $notice ) {
64
  $this->preProcessNotice( $notice );
66
  try {
67
  $this->processNotice( $notice );
68
  if ( $notice->display ) {
69
+ $notices[] = $notice;
70
  }
71
  }
72
  catch ( \Exception $e ) {
74
  }
75
  }
76
 
77
+ return $notices;
78
  }
79
 
80
  /**
145
  $notice->template = '/notices/'.$notice->id;
146
  }
147
 
148
+ protected function isNoticeDismissed( NoticeVO $notice ) :bool {
149
+ $dismissedUser = $this->isNoticeDismissedForCurrentUser( $notice );
 
 
 
 
150
 
151
+ $allDisd = $this->getMod()->getDismissedNotices();
152
+ $dismissedMod = isset( $allDisd[ $notice->id ] ) && $allDisd[ $notice->id ] > 0;
153
 
154
+ if ( !$notice->per_user && $dismissedUser && !$dismissedMod ) {
155
  $this->setNoticeDismissed( $notice );
156
  }
157
 
158
+ return $dismissedUser || $dismissedMod;
159
  }
160
 
161
  /**
166
  return true;
167
  }
168
 
169
+ protected function isNoticeDismissedForCurrentUser( NoticeVO $notice ) :bool {
170
+ $dismissed = false;
 
 
 
 
171
 
172
  $meta = $this->getCon()->getCurrentUserMeta();
173
  if ( $meta instanceof PluginUserMeta ) {
174
+ $noticeMetaKey = $this->getNoticeMetaKey( $notice );
175
 
176
+ if ( isset( $meta->{$noticeMetaKey} ) ) {
177
+ $dismissed = true;
178
 
179
  // migrate from old-style array storage to plain Timestamp
180
+ if ( is_array( $meta->{$noticeMetaKey} ) ) {
181
+ $meta->{$noticeMetaKey} = $meta->{$noticeMetaKey}[ 'time' ];
182
  }
183
  }
184
  }
185
 
186
+ return $dismissed;
187
  }
188
 
189
  /**
 
190
  * @throws \Exception
191
  */
192
  protected function processNotice( NoticeVO $notice ) {
193
  throw new \Exception( 'Unsupported Notice ID: '.$notice->id );
194
  }
195
 
196
+ protected function setNoticeDismissed( NoticeVO $notice ) {
197
+ $ts = Services::Request()->ts();
 
 
 
 
198
 
199
  $meta = $this->getCon()->getCurrentUserMeta();
200
+ $noticeMetaKey = $this->getNoticeMetaKey( $notice );
201
 
202
  if ( $notice->per_user ) {
203
  if ( $meta instanceof PluginUserMeta ) {
204
+ $meta->{$noticeMetaKey} = $ts;
205
  }
206
  }
207
  else {
208
  $mod = $this->getMod();
209
+ $allDismissed = $mod->getDismissedNotices();
210
+ $allDismissed[ $notice->id ] = $ts;
211
+ $mod->setDismissedNotices( $allDismissed );
212
 
213
  // Clear out any old
214
  if ( $meta instanceof PluginUserMeta ) {
215
+ unset( $meta->{$noticeMetaKey} );
216
  }
217
  }
 
218
  }
219
 
220
+ private function getNoticeMetaKey( NoticeVO $notice ) :string {
 
 
 
 
221
  return 'notice_'.str_replace( [ '-', '_' ], '', $notice->id );
222
  }
223
  }
src/lib/src/Modules/Base/Options.php CHANGED
@@ -202,6 +202,7 @@ class Options {
202
  public function isValidOptionValueType( string $key, $value ) :bool {
203
  switch ( $this->getOptionType( $key ) ) {
204
  case 'array':
 
205
  $valid = is_array( $value );
206
  break;
207
  default:
@@ -398,8 +399,7 @@ class Options {
398
  }
399
 
400
  /**
401
- * @param string $key
402
- * @param mixed $mDefault
403
  * @return mixed
404
  */
405
  public function getOpt( string $key, $mDefault = false ) {
@@ -413,7 +413,6 @@ class Options {
413
  }
414
 
415
  /**
416
- * @param string $key
417
  * @param mixed $mDefault
418
  * @return mixed|null
419
  */
@@ -427,20 +426,17 @@ class Options {
427
  }
428
 
429
  /**
430
- * @param string $key
431
  * @param mixed $mValueToTest
432
  * @param bool $strict
433
- * @return bool
434
  */
435
  public function isOpt( string $key, $mValueToTest, $strict = false ) :bool {
436
  return $strict ? $this->getOpt( $key ) === $mValueToTest : $this->getOpt( $key ) == $mValueToTest;
437
  }
438
 
439
  /**
440
- * @param string $key
441
  * @return string|null
442
  */
443
- public function getOptionType( $key ) {
444
  return $this->getOptDefinition( $key )[ 'type' ] ?? null;
445
  }
446
 
202
  public function isValidOptionValueType( string $key, $value ) :bool {
203
  switch ( $this->getOptionType( $key ) ) {
204
  case 'array':
205
+ case 'multiple_select':
206
  $valid = is_array( $value );
207
  break;
208
  default:
399
  }
400
 
401
  /**
402
+ * @param mixed $mDefault
 
403
  * @return mixed
404
  */
405
  public function getOpt( string $key, $mDefault = false ) {
413
  }
414
 
415
  /**
 
416
  * @param mixed $mDefault
417
  * @return mixed|null
418
  */
426
  }
427
 
428
  /**
 
429
  * @param mixed $mValueToTest
430
  * @param bool $strict
 
431
  */
432
  public function isOpt( string $key, $mValueToTest, $strict = false ) :bool {
433
  return $strict ? $this->getOpt( $key ) === $mValueToTest : $this->getOpt( $key ) == $mValueToTest;
434
  }
435
 
436
  /**
 
437
  * @return string|null
438
  */
439
+ public function getOptionType( string $key ) {
440
  return $this->getOptDefinition( $key )[ 'type' ] ?? null;
441
  }
442
 
src/lib/src/Modules/Data/DB/IPs/Ops/Insert.php CHANGED
@@ -9,7 +9,6 @@ class Insert extends Base\Insert {
9
 
10
  /**
11
  * @param Record $record
12
- * @return bool
13
  */
14
  public function insert( $record ) :bool {
15
  return (bool)Services::WpDb()->doSql( sprintf(
9
 
10
  /**
11
  * @param Record $record
 
12
  */
13
  public function insert( $record ) :bool {
14
  return (bool)Services::WpDb()->doSql( sprintf(
src/lib/src/Modules/IPs/Lib/Bots/NotBot/InsertNotBotJs.php CHANGED
@@ -42,10 +42,21 @@ class InsertNotBotJs extends ExecOnceModConsumer {
42
  }
43
 
44
  protected function run() {
 
45
  $this->enqueueJS();
46
  $this->nonceJs();
47
  }
48
 
 
 
 
 
 
 
 
 
 
 
49
  protected function enqueueJS() {
50
  add_filter( 'shield/custom_enqueues', function ( array $enqueues ) {
51
  $enqueues[ Enqueue::JS ][] = 'shield/notbot';
@@ -58,20 +69,12 @@ class InsertNotBotJs extends ExecOnceModConsumer {
58
  */
59
  private function nonceJs() {
60
  add_filter( 'shield/custom_localisations', function ( array $localz ) {
61
-
62
- $ajaxData = $this->getMod()->getAjaxActionData( 'not_bot' );
63
- $ajaxHref = $ajaxData[ 'ajaxurl' ];
64
- unset( $ajaxData[ 'ajaxurl' ] );
65
-
66
  $localz[] = [
67
  'shield/notbot',
68
  'shield_vars_notbotjs',
69
  apply_filters( 'shield/notbot_data_js', [
70
  'ajax' => [
71
- 'not_bot' => http_build_query( $ajaxData )
72
- ],
73
- 'hrefs' => [
74
- 'ajax' => $ajaxHref
75
  ],
76
  'flags' => [
77
  'run' => !in_array( Services::IP()->getIpDetector()->getIPIdentity(), [ 'gtmetrix' ] ),
42
  }
43
 
44
  protected function run() {
45
+ $this->sendNonceCookie();
46
  $this->enqueueJS();
47
  $this->nonceJs();
48
  }
49
 
50
+ protected function sendNonceCookie() {
51
+ if ( $this->isForcedForOptimisationPlugins() ) {
52
+ Services::Response()->cookieSet(
53
+ 'shield-notbot-nonce',
54
+ $this->getMod()->getAjaxActionData( 'not_bot' )[ 'exec_nonce' ],
55
+ 10
56
+ );
57
+ }
58
+ }
59
+
60
  protected function enqueueJS() {
61
  add_filter( 'shield/custom_enqueues', function ( array $enqueues ) {
62
  $enqueues[ Enqueue::JS ][] = 'shield/notbot';
69
  */
70
  private function nonceJs() {
71
  add_filter( 'shield/custom_localisations', function ( array $localz ) {
 
 
 
 
 
72
  $localz[] = [
73
  'shield/notbot',
74
  'shield_vars_notbotjs',
75
  apply_filters( 'shield/notbot_data_js', [
76
  'ajax' => [
77
+ 'not_bot' => $this->getMod()->getAjaxActionData( 'not_bot' )
 
 
 
78
  ],
79
  'flags' => [
80
  'run' => !in_array( Services::IP()->getIpDetector()->getIPIdentity(), [ 'gtmetrix' ] ),
src/lib/src/Modules/Integrations/Lib/Bots/Common/BaseBotDetectionController.php CHANGED
@@ -15,39 +15,38 @@ abstract class BaseBotDetectionController extends ExecOnceModConsumer {
15
 
16
  protected function run() {
17
  array_map(
18
- function ( $provider ) {
19
- $provider->execute();
20
- },
21
- $this->getInstalledProviders()
22
- );
23
- }
24
-
25
- /**
26
- * Inserts the ModCon;
27
- * @return BaseHandler[]
28
- */
29
- public function getInstalledProviders() :array {
30
- return array_map(
31
- function ( $provider ) {
32
- return $provider->setMod( $this->getMod() );
33
  },
34
  array_filter(
35
- $this->enumProviders(),
 
 
 
36
  function ( $provider ) {
37
- return $provider::IsProviderInstalled();
38
  }
39
  )
40
  );
41
  }
42
 
43
  /**
44
- * @return BaseHandler[]
 
 
 
 
 
 
 
 
 
45
  */
46
  public function enumProviders() :array {
47
  return [];
48
  }
49
 
50
  protected function isEnabled() :bool {
51
- return false;
52
  }
53
  }
15
 
16
  protected function run() {
17
  array_map(
18
+ function ( $providerClass ) {
19
+ ( new $providerClass() )->setMod( $this->getMod() )->execute();
 
 
 
 
 
 
 
 
 
 
 
 
 
20
  },
21
  array_filter(
22
+ array_intersect_key(
23
+ $this->enumProviders(),
24
+ array_flip( $this->getSelectedProviders() )
25
+ ),
26
  function ( $provider ) {
27
+ return call_user_func( $provider.'::IsProviderInstalled' );
28
  }
29
  )
30
  );
31
  }
32
 
33
  /**
34
+ * @return string[]
35
+ */
36
+ public function getSelectedProviders() :array {
37
+ return $this->getOptions()->getOpt( $this->getSelectedProvidersOptKey(), [] );
38
+ }
39
+
40
+ abstract public function getSelectedProvidersOptKey() :string;
41
+
42
+ /**
43
+ * @return string[]
44
  */
45
  public function enumProviders() :array {
46
  return [];
47
  }
48
 
49
  protected function isEnabled() :bool {
50
+ return !empty( $this->getSelectedProviders() );
51
  }
52
  }
src/lib/src/Modules/Integrations/Lib/Bots/Common/BaseHandler.php CHANGED
@@ -7,11 +7,43 @@ use FernleafSystems\Wordpress\Services\Services;
7
 
8
  abstract class BaseHandler extends ExecOnceModConsumer {
9
 
10
- const SLUG = '';
11
-
12
  protected function canRun() :bool {
13
- return ( $this->getCon()->isPremiumActive() || !$this->isProOnly() )
14
- && $this->isEnabled() && static::IsProviderInstalled();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
15
  }
16
 
17
  protected function isBot() :bool {
@@ -21,26 +53,16 @@ abstract class BaseHandler extends ExecOnceModConsumer {
21
  ->isBot( Services::IP()->getRequestIp() );
22
  }
23
 
24
- public function isEnabled() :bool {
25
- return false;
26
- }
27
-
28
- public static function IsProviderInstalled() :bool {
29
  return false;
30
  }
31
 
32
- protected function getProviderName() :string {
33
- return '';
34
  }
35
 
36
- public function getHandlerSlug() :string {
37
- try {
38
- $slug = strtolower( ( new \ReflectionClass( $this ) )->getShortName() );
39
- }
40
- catch ( \Exception $e ) {
41
- $slug = '';
42
- }
43
- return $slug;
44
  }
45
 
46
  protected function isProOnly() :bool {
7
 
8
  abstract class BaseHandler extends ExecOnceModConsumer {
9
 
 
 
10
  protected function canRun() :bool {
11
+ return static::IsProviderInstalled()
12
+ && $this->isEnabled()
13
+ && ( $this->getCon()->isPremiumActive() || !$this->isProOnly() );
14
+ }
15
+
16
+ /**
17
+ * @return BaseBotDetectionController|mixed
18
+ */
19
+ abstract public function getHandlerController();
20
+
21
+ public function getHandlerSlug() :string {
22
+ try {
23
+ $slug = strtolower( ( new \ReflectionClass( $this ) )->getShortName() );
24
+ }
25
+ catch ( \Exception $e ) {
26
+ $slug = '';
27
+ }
28
+ return $slug;
29
+ }
30
+
31
+ public function getHandlerName() :string {
32
+ $name = 'Undefined Name';
33
+ $slug = $this->getHandlerSlug();
34
+
35
+ $valueOptions = $this->getOptions()
36
+ ->getOptDefinition(
37
+ $this->getHandlerController()->getSelectedProvidersOptKey()
38
+ )[ 'value_options' ];
39
+
40
+ foreach ( $valueOptions as $valueOption ) {
41
+ if ( $valueOption[ 'value_key' ] === $slug ) {
42
+ $name = __( $valueOption[ 'text' ], 'wp-simple-firewall' );
43
+ break;
44
+ }
45
+ }
46
+ return $name;
47
  }
48
 
49
  protected function isBot() :bool {
53
  ->isBot( Services::IP()->getRequestIp() );
54
  }
55
 
56
+ protected function isSpam_Human() :bool {
 
 
 
 
57
  return false;
58
  }
59
 
60
+ public function isEnabled() :bool {
61
+ return in_array( $this->getHandlerSlug(), $this->getHandlerController()->getSelectedProviders() );
62
  }
63
 
64
+ public static function IsProviderInstalled() :bool {
65
+ return false;
 
 
 
 
 
 
66
  }
67
 
68
  protected function isProOnly() :bool {
src/lib/src/Modules/Integrations/Lib/Bots/Spam/Handlers/Base.php CHANGED
@@ -2,31 +2,27 @@
2
 
3
  namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\Integrations\Lib\Bots\Spam\Handlers;
4
 
5
- use FernleafSystems\Utilities\Logic\ExecOnce;
6
  use FernleafSystems\Wordpress\Plugin\Shield\Modules\Integrations\Lib\Bots\Common\BaseHandler;
7
- use FernleafSystems\Wordpress\Plugin\Shield\Modules\ModConsumer;
8
- use FernleafSystems\Wordpress\Services\Services;
9
 
10
  abstract class Base extends BaseHandler {
11
 
 
 
 
 
 
 
12
  public function isSpam() :bool {
13
  $isSpam = $this->isBot();
14
  $this->getCon()->fireEvent(
15
  sprintf( 'spam_form_%s', $isSpam ? 'fail' : 'pass' ),
16
  [
17
  'audit_params' => [
18
- 'form_provider' => $this->getProviderName(),
19
  ]
20
  ]
21
  );
22
  return $isSpam;
23
  }
24
-
25
- protected function isSpam_Human() :bool {
26
- return false;
27
- }
28
-
29
- public function isEnabled() :bool {
30
- return in_array( $this->getHandlerSlug(), $this->getOptions()->getOpt( 'form_spam_providers', [] ) );
31
- }
32
  }
2
 
3
  namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\Integrations\Lib\Bots\Spam\Handlers;
4
 
 
5
  use FernleafSystems\Wordpress\Plugin\Shield\Modules\Integrations\Lib\Bots\Common\BaseHandler;
6
+ use FernleafSystems\Wordpress\Plugin\Shield\Modules\Integrations\ModCon;
 
7
 
8
  abstract class Base extends BaseHandler {
9
 
10
+ public function getHandlerController() {
11
+ /** @var ModCon $mod */
12
+ $mod = $this->getMod();
13
+ return $mod->getController_SpamForms();
14
+ }
15
+
16
  public function isSpam() :bool {
17
  $isSpam = $this->isBot();
18
  $this->getCon()->fireEvent(
19
  sprintf( 'spam_form_%s', $isSpam ? 'fail' : 'pass' ),
20
  [
21
  'audit_params' => [
22
+ 'form_provider' => $this->getHandlerName(),
23
  ]
24
  ]
25
  );
26
  return $isSpam;
27
  }
 
 
 
 
 
 
 
 
28
  }
src/lib/src/Modules/Integrations/Lib/Bots/Spam/Handlers/ContactForm7.php CHANGED
@@ -10,10 +10,6 @@ class ContactForm7 extends Base {
10
  }, 1000, 2 );
11
  }
12
 
13
- protected function getProviderName() :string {
14
- return 'Contact Form 7';
15
- }
16
-
17
  public static function IsProviderInstalled() :bool {
18
  return defined( 'WPCF7_TEXT_DOMAIN' ) && WPCF7_TEXT_DOMAIN === 'contact-form-7';
19
  }
10
  }, 1000, 2 );
11
  }
12
 
 
 
 
 
13
  public static function IsProviderInstalled() :bool {
14
  return defined( 'WPCF7_TEXT_DOMAIN' ) && WPCF7_TEXT_DOMAIN === 'contact-form-7';
15
  }
src/lib/src/Modules/Integrations/Lib/Bots/Spam/Handlers/ElementorPro.php CHANGED
@@ -16,10 +16,6 @@ class ElementorPro extends Base {
16
  }, 1000, 2 );
17
  }
18
 
19
- protected function getProviderName() :string {
20
- return 'Elementor Pro';
21
- }
22
-
23
  public static function IsProviderInstalled() :bool {
24
  return defined( 'ELEMENTOR_PRO_VERSION' ) && @function_exists( 'elementor_pro_load_plugin' );
25
  }
16
  }, 1000, 2 );
17
  }
18
 
 
 
 
 
19
  public static function IsProviderInstalled() :bool {
20
  return defined( 'ELEMENTOR_PRO_VERSION' ) && @function_exists( 'elementor_pro_load_plugin' );
21
  }
src/lib/src/Modules/Integrations/Lib/Bots/Spam/Handlers/FluentForms.php CHANGED
@@ -3,26 +3,27 @@
3
  namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\Integrations\Lib\Bots\Spam\Handlers;
4
 
5
  /**
6
- * This form only provides a filter on the "Akismet" spam result, not a general spam result.
7
- *
8
- * Luckily the error message within the plugin is non-Akismet specific.
9
- *
10
- * Class FluentForms
11
- * @package FernleafSystems\Wordpress\Plugin\Shield\Modules\Integrations\Lib\Bots\Spam\Handlers
12
  */
13
  class FluentForms extends Base {
14
 
15
  protected function run() {
16
- add_filter( 'fluentform_akismet_spam_result', function ( $wasSpam ) {
17
- return $wasSpam || $this->isSpam();
18
- }, 1000 );
19
- }
20
-
21
- protected function getProviderName() :string {
22
- return 'Fluent Forms';
 
 
23
  }
24
 
25
  public static function IsProviderInstalled() :bool {
26
- return defined( 'FLUENTFORM' ) && @class_exists( '\FluentForm\Framework\Foundation\Bootstrap' );
 
 
 
27
  }
28
  }
3
  namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\Integrations\Lib\Bots\Spam\Handlers;
4
 
5
  /**
6
+ * It's a little convoluted, but we use the same approach as they use for their own HoneyPot.
7
+ * See Hooks/Ajax.php in their plugin.
 
 
 
 
8
  */
9
  class FluentForms extends Base {
10
 
11
  protected function run() {
12
+ \FluentForm\App::getApplication()->addAction( 'fluentform_before_insert_submission',
13
+ function () {
14
+ if ( $this->isSpam() ) {
15
+ wp_send_json( [
16
+ 'errors' => sprintf( __( "This appears to be spam - failed %s AntiBot protection checks.", 'wp-simple-firewall' ),
17
+ $this->getCon()->getHumanName() )
18
+ ], 422 );
19
+ }
20
+ }, 9, 0 );
21
  }
22
 
23
  public static function IsProviderInstalled() :bool {
24
+ return defined( 'FLUENTFORM' )
25
+ && @class_exists( '\FluentForm\App' )
26
+ && @method_exists( '\FluentForm\App', 'getApplication' )
27
+ && @method_exists( \FluentForm\App::getApplication(), 'addPublicAjaxAction' );
28
  }
29
  }
src/lib/src/Modules/Integrations/Lib/Bots/Spam/Handlers/FormidableForms.php CHANGED
@@ -19,10 +19,6 @@ class FormidableForms extends Base {
19
  }, 1000 );
20
  }
21
 
22
- protected function getProviderName() :string {
23
- return 'Formidable Forms';
24
- }
25
-
26
  public static function IsProviderInstalled() :bool {
27
  return function_exists( 'load_formidable_forms' ) && @class_exists( '\FrmHooksController' );
28
  }
19
  }, 1000 );
20
  }
21
 
 
 
 
 
22
  public static function IsProviderInstalled() :bool {
23
  return function_exists( 'load_formidable_forms' ) && @class_exists( '\FrmHooksController' );
24
  }
src/lib/src/Modules/Integrations/Lib/Bots/Spam/Handlers/Forminator.php CHANGED
@@ -10,10 +10,6 @@ class Forminator extends Base {
10
  }, 1000 );
11
  }
12
 
13
- protected function getProviderName() :string {
14
- return 'Forminator';
15
- }
16
-
17
  public static function IsProviderInstalled() :bool {
18
  return defined( 'FORMINATOR_VERSION' ) && @class_exists( '\Forminator' );
19
  }
10
  }, 1000 );
11
  }
12
 
 
 
 
 
13
  public static function IsProviderInstalled() :bool {
14
  return defined( 'FORMINATOR_VERSION' ) && @class_exists( '\Forminator' );
15
  }
src/lib/src/Modules/Integrations/Lib/Bots/Spam/Handlers/GravityForms.php CHANGED
@@ -10,10 +10,6 @@ class GravityForms extends Base {
10
  }, 1000 );
11
  }
12
 
13
- protected function getProviderName() :string {
14
- return 'Gravity Forms';
15
- }
16
-
17
  public static function IsProviderInstalled() :bool {
18
  return @class_exists( '\GFForms' )
19
  && isset( \GFForms::$version )
10
  }, 1000 );
11
  }
12
 
 
 
 
 
13
  public static function IsProviderInstalled() :bool {
14
  return @class_exists( '\GFForms' )
15
  && isset( \GFForms::$version )
src/lib/src/Modules/Integrations/Lib/Bots/Spam/Handlers/Groundhogg.php CHANGED
@@ -10,12 +10,7 @@ class Groundhogg extends Base {
10
  }, 1000 );
11
  }
12
 
13
- protected function getProviderName() :string {
14
- return 'Groundhogg';
15
- }
16
-
17
  public static function IsProviderInstalled() :bool {
18
- return defined( 'GROUNDHOGG_TEXT_DOMAIN' ) && defined( 'GROUNDHOGG_VERSION' )
19
- && version_compare( GROUNDHOGG_VERSION, '2.4.5.5', '>=' );
20
  }
21
  }
10
  }, 1000 );
11
  }
12
 
 
 
 
 
13
  public static function IsProviderInstalled() :bool {
14
+ return defined( 'GROUNDHOGG_VERSION' ) && version_compare( GROUNDHOGG_VERSION, '2.4.5.5', '>=' );
 
15
  }
16
  }
src/lib/src/Modules/Integrations/Lib/Bots/Spam/Handlers/KaliForms.php CHANGED
@@ -17,10 +17,6 @@ class KaliForms extends Base {
17
  }, 1000 );
18
  }
19
 
20
- protected function getProviderName() :string {
21
- return 'Kali Forms';
22
- }
23
-
24
  public static function IsProviderInstalled() :bool {
25
  return defined( 'KALIFORMS_PLUGIN_FILE' ) && @class_exists( '\KaliForms\Inc\KaliForms' );
26
  }
17
  }, 1000 );
18
  }
19
 
 
 
 
 
20
  public static function IsProviderInstalled() :bool {
21
  return defined( 'KALIFORMS_PLUGIN_FILE' ) && @class_exists( '\KaliForms\Inc\KaliForms' );
22
  }
src/lib/src/Modules/Integrations/Lib/Bots/Spam/Handlers/NinjaForms.php CHANGED
@@ -38,10 +38,6 @@ class NinjaForms extends Base {
38
  }, 1000 );
39
  }
40
 
41
- protected function getProviderName() :string {
42
- return 'Ninja Forms';
43
- }
44
-
45
  public static function IsProviderInstalled() :bool {
46
  return @class_exists( '\Ninja_Forms' );
47
  }
38
  }, 1000 );
39
  }
40
 
 
 
 
 
41
  public static function IsProviderInstalled() :bool {
42
  return @class_exists( '\Ninja_Forms' );
43
  }
src/lib/src/Modules/Integrations/Lib/Bots/Spam/Handlers/SuperForms.php CHANGED
@@ -12,10 +12,6 @@ class SuperForms extends Base {
12
  }, 1000 );
13
  }
14
 
15
- protected function getProviderName() :string {
16
- return 'Super Forms';
17
- }
18
-
19
  public static function IsProviderInstalled() :bool {
20
  return @class_exists( '\SUPER_Forms' )
21
  && isset( \SUPER_Forms::$version )
12
  }, 1000 );
13
  }
14
 
 
 
 
 
15
  public static function IsProviderInstalled() :bool {
16
  return @class_exists( '\SUPER_Forms' )
17
  && isset( \SUPER_Forms::$version )
src/lib/src/Modules/Integrations/Lib/Bots/Spam/Handlers/SupportCandy.php CHANGED
@@ -16,10 +16,6 @@ class SupportCandy extends Base {
16
  }, 1000 );
17
  }
18
 
19
- protected function getProviderName() :string {
20
- return 'SupportCandy';
21
- }
22
-
23
  public static function IsProviderInstalled() :bool {
24
  return @class_exists( 'Support_Candy' )
25
  && defined( 'WPSC_VERSION' ) && version_compare( WPSC_VERSION, '2.2.3', '>=' );
16
  }, 1000 );
17
  }
18
 
 
 
 
 
19
  public static function IsProviderInstalled() :bool {
20
  return @class_exists( 'Support_Candy' )
21
  && defined( 'WPSC_VERSION' ) && version_compare( WPSC_VERSION, '2.2.3', '>=' );
src/lib/src/Modules/Integrations/Lib/Bots/Spam/Handlers/WPForms.php CHANGED
@@ -27,10 +27,6 @@ class WPForms extends Base {
27
  }, 1000, 2 );
28
  }
29
 
30
- protected function getProviderName() :string {
31
- return 'WP Forms';
32
- }
33
-
34
  public static function IsProviderInstalled() :bool {
35
  return defined( 'WPFORMS_VERSION' ) && function_exists( 'wpforms' );
36
  }
27
  }, 1000, 2 );
28
  }
29
 
 
 
 
 
30
  public static function IsProviderInstalled() :bool {
31
  return defined( 'WPFORMS_VERSION' ) && function_exists( 'wpforms' );
32
  }
src/lib/src/Modules/Integrations/Lib/Bots/Spam/Handlers/WpForo.php CHANGED
@@ -6,14 +6,17 @@ class WpForo extends Base {
6
 
7
  protected function run() {
8
  foreach ( $this->getFiltersToMonitor() as $filter ) {
9
- add_filter( $filter, function ( array $args = [] ) {
10
-
11
- $status = $args[ 'status' ] ?? null;
12
- if ( $status !== 1 && $this->isSpam() ) {
13
- if ( !empty( WPF()->current_userid ) ) {
14
- WPF()->moderation->ban_for_spam( WPF()->current_userid );
 
 
 
 
15
  }
16
- $args[ 'status' ] = 1; // 1 signifies not approved
17
  }
18
 
19
  return $args;
@@ -30,10 +33,6 @@ class WpForo extends Base {
30
  ];
31
  }
32
 
33
- protected function getProviderName() :string {
34
- return 'wpForo';
35
- }
36
-
37
  public static function IsProviderInstalled() :bool {
38
  return function_exists( 'WPF' ) && @class_exists( 'wpForo' ) && !empty( WPF()->tools_antispam[ 'spam_filter' ] );
39
  }
6
 
7
  protected function run() {
8
  foreach ( $this->getFiltersToMonitor() as $filter ) {
9
+ add_filter( $filter, function ( $args = [] ) {
10
+
11
+ // It should be an array, but customer reported fatal error with a boolean passed
12
+ if ( is_array( $args ) ) {
13
+ $status = $args[ 'status' ] ?? null;
14
+ if ( $status !== 1 && $this->isSpam() ) {
15
+ if ( !empty( WPF()->current_userid ) ) {
16
+ WPF()->moderation->ban_for_spam( WPF()->current_userid );
17
+ }
18
+ $args[ 'status' ] = 1; // 1 signifies not approved
19
  }
 
20
  }
21
 
22
  return $args;
33
  ];
34
  }
35
 
 
 
 
 
36
  public static function IsProviderInstalled() :bool {
37
  return function_exists( 'WPF' ) && @class_exists( 'wpForo' ) && !empty( WPF()->tools_antispam[ 'spam_filter' ] );
38
  }
src/lib/src/Modules/Integrations/Lib/Bots/Spam/SpamController.php CHANGED
@@ -6,28 +6,28 @@ use FernleafSystems\Wordpress\Plugin\Shield\Modules\Integrations\Lib\Bots\Common
6
 
7
  class SpamController extends BaseBotDetectionController {
8
 
9
- protected function isEnabled() :bool {
10
- return !empty( $this->getOptions()->getOpt( 'form_spam_providers' ) );
11
  }
12
 
13
  /**
14
- * @return Handlers\Base[]
15
  */
16
  public function enumProviders() :array {
17
  return [
18
- new Handlers\ContactForm7(),
19
- new Handlers\ElementorPro(),
20
- new Handlers\FormidableForms(),
21
- new Handlers\FluentForms(),
22
- new Handlers\Forminator(),
23
- new Handlers\Groundhogg(),
24
- new Handlers\GravityForms(),
25
- new Handlers\KaliForms(),
26
- new Handlers\NinjaForms(),
27
- new Handlers\SuperForms(),
28
- new Handlers\SupportCandy(),
29
- new Handlers\WPForms(),
30
- new Handlers\WpForo(),
31
  ];
32
  }
33
  }
6
 
7
  class SpamController extends BaseBotDetectionController {
8
 
9
+ public function getSelectedProvidersOptKey() :string {
10
+ return 'form_spam_providers';
11
  }
12
 
13
  /**
14
+ * @inheritDoc
15
  */
16
  public function enumProviders() :array {
17
  return [
18
+ 'contactform7' => Handlers\ContactForm7::class,
19
+ 'elementorpro' => Handlers\ElementorPro::class,
20
+ 'fluentforms' => Handlers\FluentForms::class,
21
+ 'formidableforms' => Handlers\FormidableForms::class,
22
+ 'forminator' => Handlers\Forminator::class,
23
+ 'gravityforms' => Handlers\GravityForms::class,
24
+ 'groundhogg' => Handlers\Groundhogg::class,
25
+ 'kaliforms' => Handlers\KaliForms::class,
26
+ 'ninjaforms' => Handlers\NinjaForms::class,
27
+ 'superforms' => Handlers\SuperForms::class,
28
+ 'supportcandy' => Handlers\SupportCandy::class,
29
+ 'wpforms' => Handlers\WPForms::class,
30
+ 'wpforo' => Handlers\WpForo::class,
31
  ];
32
  }
33
  }
src/lib/src/Modules/Integrations/Lib/Bots/UserForms/Handlers/Base.php CHANGED
@@ -3,6 +3,7 @@
3
  namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\Integrations\Lib\Bots\UserForms\Handlers;
4
 
5
  use FernleafSystems\Wordpress\Plugin\Shield\Modules\Integrations;
 
6
  use FernleafSystems\Wordpress\Plugin\Shield\Modules\LoginGuard;
7
 
8
  abstract class Base extends Integrations\Lib\Bots\Common\BaseHandler {
@@ -54,6 +55,12 @@ abstract class Base extends Integrations\Lib\Bots\Common\BaseHandler {
54
  return empty( $this->auditUser ) ? 'unknown' : $this->auditUser;
55
  }
56
 
 
 
 
 
 
 
57
  /**
58
  * @param string $action
59
  * @return $this
@@ -79,7 +86,7 @@ abstract class Base extends Integrations\Lib\Bots\Common\BaseHandler {
79
  sprintf( 'user_form_bot_%s', self::$isBot ? 'fail' : 'pass' ),
80
  [
81
  'audit_params' => [
82
- 'form_provider' => $this->getProviderName(),
83
  'action' => $this->getAuditAction(),
84
  'username' => $this->getAuditUser(),
85
  ]
@@ -89,12 +96,6 @@ abstract class Base extends Integrations\Lib\Bots\Common\BaseHandler {
89
  return self::$isBot;
90
  }
91
 
92
- public function isEnabled() :bool {
93
- /** @var Integrations\Options $opts */
94
- $opts = $this->getOptions();
95
- return in_array( $this->getHandlerSlug(), $opts->getUserFormProviders() );
96
- }
97
-
98
  protected function getErrorMessage() :string {
99
  return sprintf( __( '%s Bot Check Failed.', 'wp-simple-firewall' ), $this->getCon()->getHumanName() );
100
  }
3
  namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\Integrations\Lib\Bots\UserForms\Handlers;
4
 
5
  use FernleafSystems\Wordpress\Plugin\Shield\Modules\Integrations;
6
+ use FernleafSystems\Wordpress\Plugin\Shield\Modules\Integrations\ModCon;
7
  use FernleafSystems\Wordpress\Plugin\Shield\Modules\LoginGuard;
8
 
9
  abstract class Base extends Integrations\Lib\Bots\Common\BaseHandler {
55
  return empty( $this->auditUser ) ? 'unknown' : $this->auditUser;
56
  }
57
 
58
+ public function getHandlerController() {
59
+ /** @var ModCon $mod */
60
+ $mod = $this->getMod();
61
+ return $mod->getController_UserForms();
62
+ }
63
+
64
  /**
65
  * @param string $action
66
  * @return $this
86
  sprintf( 'user_form_bot_%s', self::$isBot ? 'fail' : 'pass' ),
87
  [
88
  'audit_params' => [
89
+ 'form_provider' => $this->getHandlerName(),
90
  'action' => $this->getAuditAction(),
91
  'username' => $this->getAuditUser(),
92
  ]
96
  return self::$isBot;
97
  }
98
 
 
 
 
 
 
 
99
  protected function getErrorMessage() :string {
100
  return sprintf( __( '%s Bot Check Failed.', 'wp-simple-firewall' ), $this->getCon()->getHumanName() );
101
  }
src/lib/src/Modules/Integrations/Lib/Bots/UserForms/Handlers/Buddyboss.php CHANGED
@@ -17,10 +17,6 @@ class Buddyboss extends Base {
17
  }
18
  }
19
 
20
- protected function getProviderName() :string {
21
- return 'BuddyBoss';
22
- }
23
-
24
  public static function IsProviderInstalled() :bool {
25
  return @class_exists( '\BuddyPress' )
26
  && method_exists( '\BuddyPress', 'instance' )
17
  }
18
  }
19
 
 
 
 
 
20
  public static function IsProviderInstalled() :bool {
21
  return @class_exists( '\BuddyPress' )
22
  && method_exists( '\BuddyPress', 'instance' )
src/lib/src/Modules/Integrations/Lib/Bots/UserForms/Handlers/Buddypress.php CHANGED
@@ -14,10 +14,6 @@ class Buddypress extends Base {
14
  }
15
  }
16
 
17
- protected function getProviderName() :string {
18
- return 'BuddyPress';
19
- }
20
-
21
  public static function IsProviderInstalled() :bool {
22
  return @class_exists( '\BuddyPress' );
23
  }
14
  }
15
  }
16
 
 
 
 
 
17
  public static function IsProviderInstalled() :bool {
18
  return @class_exists( '\BuddyPress' );
19
  }
src/lib/src/Modules/Integrations/Lib/Bots/UserForms/Handlers/EasyDigitalDownloads.php CHANGED
@@ -14,10 +14,6 @@ class EasyDigitalDownloads extends Base {
14
  }
15
  }
16
 
17
- protected function getProviderName() :string {
18
- return 'Easy Digital Downloads';
19
- }
20
-
21
  public static function IsProviderInstalled() :bool {
22
  return function_exists( 'edd_set_error' ) && @class_exists( 'Easy_Digital_Downloads' );
23
  }
14
  }
15
  }
16
 
 
 
 
 
17
  public static function IsProviderInstalled() :bool {
18
  return function_exists( 'edd_set_error' ) && @class_exists( 'Easy_Digital_Downloads' );
19
  }
src/lib/src/Modules/Integrations/Lib/Bots/UserForms/Handlers/LearnPress.php CHANGED
@@ -34,10 +34,6 @@ class LearnPress extends Base {
34
  return $maybeError;
35
  }
36
 
37
- protected function getProviderName() :string {
38
- return 'LearnPress';
39
- }
40
-
41
  public static function IsProviderInstalled() :bool {
42
  return @class_exists( 'LearnPress' );
43
  }
34
  return $maybeError;
35
  }
36
 
 
 
 
 
37
  public static function IsProviderInstalled() :bool {
38
  return @class_exists( 'LearnPress' );
39
  }
src/lib/src/Modules/Integrations/Lib/Bots/UserForms/Handlers/LifterLMS.php CHANGED
@@ -37,10 +37,6 @@ class LifterLMS extends Base {
37
  return $valid;
38
  }
39
 
40
- protected function getProviderName() :string {
41
- return 'LifterLMS';
42
- }
43
-
44
  public static function IsProviderInstalled() :bool {
45
  return defined( 'LLMS_PLUGIN_FILE' ) && @class_exists( 'LifterLMS' )
46
  && defined( 'LLMS_VERSION' ) && version_compare( LLMS_VERSION, '4.20', '>' );
37
  return $valid;
38
  }
39
 
 
 
 
 
40
  public static function IsProviderInstalled() :bool {
41
  return defined( 'LLMS_PLUGIN_FILE' ) && @class_exists( 'LifterLMS' )
42
  && defined( 'LLMS_VERSION' ) && version_compare( LLMS_VERSION, '4.20', '>' );
src/lib/src/Modules/Integrations/Lib/Bots/UserForms/Handlers/MemberPress.php CHANGED
@@ -61,10 +61,6 @@ class MemberPress extends Base {
61
  return $errors;
62
  }
63
 
64
- protected function getProviderName() :string {
65
- return 'MemberPress';
66
- }
67
-
68
  public static function IsProviderInstalled() :bool {
69
  return function_exists( 'mepr_autoloader' ) || @class_exists( '\MeprAccountCtrl' );
70
  }
61
  return $errors;
62
  }
63
 
 
 
 
 
64
  public static function IsProviderInstalled() :bool {
65
  return function_exists( 'mepr_autoloader' ) || @class_exists( '\MeprAccountCtrl' );
66
  }
src/lib/src/Modules/Integrations/Lib/Bots/UserForms/Handlers/PaidMemberSubscriptions.php CHANGED
@@ -14,10 +14,6 @@ class PaidMemberSubscriptions extends Base {
14
  }
15
  }
16
 
17
- protected function getProviderName() :string {
18
- return 'Paid Member Subscriptions';
19
- }
20
-
21
  public static function IsProviderInstalled() :bool {
22
  return @class_exists( 'Paid_Member_Subscriptions' ) && function_exists( 'pms_errors' );
23
  }
14
  }
15
  }
16
 
 
 
 
 
17
  public static function IsProviderInstalled() :bool {
18
  return @class_exists( 'Paid_Member_Subscriptions' ) && function_exists( 'pms_errors' );
19
  }
src/lib/src/Modules/Integrations/Lib/Bots/UserForms/Handlers/ProfileBuilder.php CHANGED
@@ -22,10 +22,6 @@ class ProfileBuilder extends Base {
22
  return $errors;
23
  }
24
 
25
- protected function getProviderName() :string {
26
- return 'Profile Builder';
27
- }
28
-
29
  public static function IsProviderInstalled() :bool {
30
  return defined( 'PROFILE_BUILDER_VERSION' );
31
  }
22
  return $errors;
23
  }
24
 
 
 
 
 
25
  public static function IsProviderInstalled() :bool {
26
  return defined( 'PROFILE_BUILDER_VERSION' );
27
  }
src/lib/src/Modules/Integrations/Lib/Bots/UserForms/Handlers/UltimateMember.php CHANGED
@@ -37,10 +37,6 @@ class UltimateMember extends Base {
37
  }
38
  }
39
 
40
- protected function getProviderName() :string {
41
- return 'Ultimate Member';
42
- }
43
-
44
  public static function IsProviderInstalled() :bool {
45
  return function_exists( '\UM' ) && @class_exists( '\UM' ) && method_exists( '\UM', 'form' );
46
  }
37
  }
38
  }
39
 
 
 
 
 
40
  public static function IsProviderInstalled() :bool {
41
  return function_exists( '\UM' ) && @class_exists( '\UM' ) && method_exists( '\UM', 'form' );
42
  }
src/lib/src/Modules/Integrations/Lib/Bots/UserForms/Handlers/WPMembers.php CHANGED
@@ -39,10 +39,6 @@ class WPMembers extends Base {
39
  }
40
  }
41
 
42
- protected function getProviderName() :string {
43
- return 'WP Members';
44
- }
45
-
46
  public static function IsProviderInstalled() :bool {
47
  return defined( 'WPMEM_VERSION' ) && function_exists( 'wpmem_init' );
48
  }
39
  }
40
  }
41
 
 
 
 
 
42
  public static function IsProviderInstalled() :bool {
43
  return defined( 'WPMEM_VERSION' ) && function_exists( 'wpmem_init' );
44
  }
src/lib/src/Modules/Integrations/Lib/Bots/UserForms/Handlers/WooCommerce.php CHANGED
@@ -52,10 +52,6 @@ class WooCommerce extends Base {
52
  return $wpError;
53
  }
54
 
55
- protected function getProviderName() :string {
56
- return 'WooCommerce';
57
- }
58
-
59
  public static function IsProviderInstalled() :bool {
60
  return @class_exists( 'WooCommerce' );
61
  }
52
  return $wpError;
53
  }
54
 
 
 
 
 
55
  public static function IsProviderInstalled() :bool {
56
  return @class_exists( 'WooCommerce' );
57
  }
src/lib/src/Modules/Integrations/Lib/Bots/UserForms/Handlers/WordPress.php CHANGED
@@ -74,10 +74,6 @@ class WordPress extends Base {
74
  return $wpError;
75
  }
76
 
77
- protected function getProviderName() :string {
78
- return 'WordPress';
79
- }
80
-
81
  public static function IsProviderInstalled() :bool {
82
  return true;
83
  }
74
  return $wpError;
75
  }
76
 
 
 
 
 
77
  public static function IsProviderInstalled() :bool {
78
  return true;
79
  }
src/lib/src/Modules/Integrations/Lib/Bots/UserForms/UserFormsController.php CHANGED
@@ -16,29 +16,27 @@ class UserFormsController extends Integrations\Lib\Bots\Common\BaseBotDetectionC
16
  && $loginOpts->isEnabledAntiBot();
17
  }
18
 
19
- protected function isEnabled() :bool {
20
- /** @var Integrations\Options $opts */
21
- $opts = $this->getOptions();
22
- return !empty( $opts->getUserFormProviders() );
23
  }
24
 
25
  /**
26
- * @return Handlers\Base[]
27
  */
28
  public function enumProviders() :array {
29
  return [
30
- new Handlers\Buddyboss(),
31
- new Handlers\Buddypress(),
32
- new Handlers\EasyDigitalDownloads(),
33
- new Handlers\LearnPress(),
34
- new Handlers\LifterLMS(),
35
- new Handlers\MemberPress(),
36
- new Handlers\PaidMemberSubscriptions(),
37
- new Handlers\ProfileBuilder(),
38
- new Handlers\UltimateMember(),
39
- new Handlers\WooCommerce(),
40
- new Handlers\WordPress(),
41
- new Handlers\WPMembers(),
42
  ];
43
  }
44
  }
16
  && $loginOpts->isEnabledAntiBot();
17
  }
18
 
19
+ public function getSelectedProvidersOptKey() :string {
20
+ return 'user_form_providers';
 
 
21
  }
22
 
23
  /**
24
+ * @inheritDoc
25
  */
26
  public function enumProviders() :array {
27
  return [
28
+ 'buddyboss' => Handlers\Buddyboss::class,
29
+ 'buddypress' => Handlers\Buddypress::class,
30
+ 'easydigitaldownloads' => Handlers\EasyDigitalDownloads::class,
31
+ 'learnpress' => Handlers\LearnPress::class,
32
+ 'lifterlms' => Handlers\LifterLMS::class,
33
+ 'memberpress' => Handlers\MemberPress::class,
34
+ 'paidmembersubscriptions' => Handlers\PaidMemberSubscriptions::class,
35
+ 'profilebuilder' => Handlers\ProfileBuilder::class,
36
+ 'ultimatemember' => Handlers\UltimateMember::class,
37
+ 'woocommerce' => Handlers\WooCommerce::class,
38
+ 'wordpress' => Handlers\WordPress::class,
39
+ 'wpmembers' => Handlers\WPMembers::class,
40
  ];
41
  }
42
  }
src/lib/src/Modules/Integrations/ModCon.php CHANGED
@@ -17,6 +17,11 @@ class ModCon extends BaseShield\ModCon {
17
  */
18
  private $userFormsCon;
19
 
 
 
 
 
 
20
  public function getControllerMWP() :Lib\MainWP\Controller {
21
  if ( empty( $this->mwp ) ) {
22
  $this->mwp = ( new Lib\MainWP\Controller() )
@@ -25,10 +30,16 @@ class ModCon extends BaseShield\ModCon {
25
  return $this->mwp;
26
  }
27
 
 
 
 
 
 
 
 
28
  public function getController_UserForms() :Lib\Bots\UserForms\UserFormsController {
29
- if ( !$this->userFormsCon instanceof Lib\Bots\UserForms\UserFormsController ) {
30
- $this->userFormsCon = ( new Lib\Bots\UserForms\UserFormsController() )
31
- ->setMod( $this );
32
  }
33
  return $this->userFormsCon;
34
  }
17
  */
18
  private $userFormsCon;
19
 
20
+ /**
21
+ * @var Lib\Bots\Spam\SpamController
22
+ */
23
+ private $spamFormsCon;
24
+
25
  public function getControllerMWP() :Lib\MainWP\Controller {
26
  if ( empty( $this->mwp ) ) {
27
  $this->mwp = ( new Lib\MainWP\Controller() )
30
  return $this->mwp;
31
  }
32
 
33
+ public function getController_SpamForms() :Lib\Bots\Spam\SpamController {
34
+ if ( empty( $this->spamFormsCon ) ) {
35
+ $this->spamFormsCon = ( new Lib\Bots\Spam\SpamController() )->setMod( $this );
36
+ }
37
+ return $this->spamFormsCon;
38
+ }
39
+
40
  public function getController_UserForms() :Lib\Bots\UserForms\UserFormsController {
41
+ if ( empty( $this->userFormsCon ) ) {
42
+ $this->userFormsCon = ( new Lib\Bots\UserForms\UserFormsController() )->setMod( $this );
 
43
  }
44
  return $this->userFormsCon;
45
  }
src/lib/src/Modules/Integrations/Options.php CHANGED
@@ -10,11 +10,11 @@ class Options extends BaseShield\Options {
10
  return $this->isOpt( 'enable_mainwp', 'Y' );
11
  }
12
 
 
 
 
13
  public function getUserFormProviders() :array {
14
  $userForms = $this->getOpt( 'user_form_providers' );
15
- if ( !is_array( $userForms ) ) {
16
- $userForms = [];
17
- }
18
  if ( !in_array( 'wordpress', $userForms ) ) {
19
  $userForms[] = 'wordpress';
20
  $this->setOpt( 'user_form_providers', $userForms );
10
  return $this->isOpt( 'enable_mainwp', 'Y' );
11
  }
12
 
13
+ /**
14
+ * @deprecated 13.0.5
15
+ */
16
  public function getUserFormProviders() :array {
17
  $userForms = $this->getOpt( 'user_form_providers' );
 
 
 
18
  if ( !in_array( 'wordpress', $userForms ) ) {
19
  $userForms[] = 'wordpress';
20
  $this->setOpt( 'user_form_providers', $userForms );
src/lib/src/Modules/Integrations/Processor.php CHANGED
@@ -13,9 +13,7 @@ class Processor extends BaseShield\Processor {
13
  $mod->getControllerMWP()->execute();
14
 
15
  if ( !empty( Services::IP()->getRequestIp() ) ) {
16
- ( new Lib\Bots\Spam\SpamController() )
17
- ->setMod( $this->getMod() )
18
- ->execute();
19
 
20
  add_action( 'init', function () use ( $mod ) {
21
  $mod->getController_UserForms()->execute();
13
  $mod->getControllerMWP()->execute();
14
 
15
  if ( !empty( Services::IP()->getRequestIp() ) ) {
16
+ $mod->getController_SpamForms()->execute();
 
 
17
 
18
  add_action( 'init', function () use ( $mod ) {
19
  $mod->getController_UserForms()->execute();
src/lib/src/Modules/Integrations/Strings.php CHANGED
@@ -39,9 +39,7 @@ class Strings extends Base\Strings {
39
  }
40
 
41
  /**
42
- * @param string $section
43
- * @return array
44
- * @throws \Exception
45
  */
46
  public function getSectionStrings( string $section ) :array {
47
 
@@ -80,14 +78,12 @@ class Strings extends Base\Strings {
80
  return [
81
  'title' => $title,
82
  'title_short' => $titleShort,
83
- 'summary' => is_array( $summary ) ? $summary : [],
84
  ];
85
  }
86
 
87
  /**
88
- * @param string $key
89
- * @return array
90
- * @throws \Exception
91
  */
92
  public function getOptionStrings( string $key ) :array {
93
  $con = $this->getCon();
39
  }
40
 
41
  /**
42
+ * @inheritDoc
 
 
43
  */
44
  public function getSectionStrings( string $section ) :array {
45
 
78
  return [
79
  'title' => $title,
80
  'title_short' => $titleShort,
81
+ 'summary' => $summary,
82
  ];
83
  }
84
 
85
  /**
86
+ * @inheritDoc
 
 
87
  */
88
  public function getOptionStrings( string $key ) :array {
89
  $con = $this->getCon();
src/lib/src/Modules/Integrations/UI.php CHANGED
@@ -3,6 +3,7 @@
3
  namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\Integrations;
4
 
5
  use FernleafSystems\Wordpress\Plugin\Shield\Modules;
 
6
 
7
  class UI extends Modules\BaseShield\UI {
8
 
@@ -32,7 +33,7 @@ class UI extends Modules\BaseShield\UI {
32
  if ( $loginGuardOpts->isEnabledAntiBot() ) {
33
  $notices[] = sprintf( '%s: %s %s', __( 'Note', 'wp-simple-firewall' ),
34
  sprintf(
35
- __( "The following forms are protected by AntiBot Detection: %s.", 'wp-simple-firewall' ),
36
  $locations
37
  ),
38
  sprintf( '<a href="%s" target="_blank">%s</a>',
@@ -48,9 +49,10 @@ class UI extends Modules\BaseShield\UI {
48
 
49
  protected function getSectionWarnings( string $section ) :array {
50
  $warnings = [];
 
51
 
52
  /** @var Modules\LoginGuard\Options $loginGuardOpts */
53
- $loginGuardOpts = $this->getCon()->getModule_LoginGuard()->getOptions();
54
 
55
  switch ( $section ) {
56
 
@@ -59,11 +61,40 @@ class UI extends Modules\BaseShield\UI {
59
  $warnings[] = sprintf( '%s: %s %s', __( 'Important', 'wp-simple-firewall' ),
60
  __( "Use of the AntiBot Detection Engine for user forms isn't turned on in the Login Guard module.", 'wp-simple-firewall' ),
61
  sprintf( '<a href="%s" target="_blank">%s</a>',
62
- $this->getCon()->getModule_LoginGuard()->getUrl_AdminPage(),
63
  __( 'Click here to review those settings.', 'wp-simple-firewall' ) )
64
  );
65
  }
66
  break;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
67
  }
68
 
69
  return $warnings;
3
  namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\Integrations;
4
 
5
  use FernleafSystems\Wordpress\Plugin\Shield\Modules;
6
+ use FernleafSystems\Wordpress\Plugin\Shield\Modules\Integrations\Lib\Bots\Common\BaseHandler;
7
 
8
  class UI extends Modules\BaseShield\UI {
9
 
33
  if ( $loginGuardOpts->isEnabledAntiBot() ) {
34
  $notices[] = sprintf( '%s: %s %s', __( 'Note', 'wp-simple-firewall' ),
35
  sprintf(
36
+ __( "The following types of user forms are protected by AntiBot Detection: %s.", 'wp-simple-firewall' ),
37
  $locations
38
  ),
39
  sprintf( '<a href="%s" target="_blank">%s</a>',
49
 
50
  protected function getSectionWarnings( string $section ) :array {
51
  $warnings = [];
52
+ $con = $this->getCon();
53
 
54
  /** @var Modules\LoginGuard\Options $loginGuardOpts */
55
+ $loginGuardOpts = $con->getModule_LoginGuard()->getOptions();
56
 
57
  switch ( $section ) {
58
 
61
  $warnings[] = sprintf( '%s: %s %s', __( 'Important', 'wp-simple-firewall' ),
62
  __( "Use of the AntiBot Detection Engine for user forms isn't turned on in the Login Guard module.", 'wp-simple-firewall' ),
63
  sprintf( '<a href="%s" target="_blank">%s</a>',
64
+ $con->getModule_LoginGuard()->getUrl_AdminPage(),
65
  __( 'Click here to review those settings.', 'wp-simple-firewall' ) )
66
  );
67
  }
68
  break;
69
+
70
+ case 'section_spam':
71
+ /** @var ModCon $mod */
72
+ $mod = $this->getMod();
73
+ /** @var BaseHandler[] $installedButNotEnabledProviders */
74
+ $installedButNotEnabledProviders = array_filter(
75
+ array_map(
76
+ function ( $providerClass ) {
77
+ return ( new $providerClass() )->setMod( $this->getMod() );
78
+ },
79
+ $mod->getController_SpamForms()->enumProviders()
80
+ ),
81
+ function ( $provider ) {
82
+ /** @var BaseHandler $provider */
83
+ return !$provider->isEnabled() && $provider::IsProviderInstalled();
84
+ }
85
+ );
86
+
87
+ if ( !empty( $installedButNotEnabledProviders ) ) {
88
+ $warnings[] = sprintf( __( "%s has an integration available to protect the forms of a 3rd party plugin you're using: %s", 'wp-simple-firewall' ),
89
+ $con->getHumanName(),
90
+ implode( ', ', array_map(
91
+ function ( $provider ) {
92
+ return $provider->getHandlerName();
93
+ }, $installedButNotEnabledProviders
94
+ ) )
95
+ );
96
+ }
97
+ break;
98
  }
99
 
100
  return $warnings;
src/lib/src/Modules/Integrations/Upgrade.php CHANGED
@@ -3,23 +3,7 @@
3
  namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\Integrations;
4
 
5
  use FernleafSystems\Wordpress\Plugin\Shield\Modules\Base;
6
- use FernleafSystems\Wordpress\Plugin\Shield\Modules\Integrations\Lib\Bots\UserForms\UserFormsController;
7
 
8
  class Upgrade extends Base\Upgrade {
9
 
10
- protected function upgrade_1120() {
11
- /** @var Options $opts */
12
- $opts = $this->getOptions();
13
- $providers = ( new UserFormsController() )
14
- ->setMod( $this->getMod() )
15
- ->enumProviders();
16
-
17
- $enabledProviders = $opts->getUserFormProviders();
18
- foreach ( $providers as $provider ) {
19
- if ( $provider::IsProviderInstalled() ) {
20
- $enabledProviders[] = $provider->getHandlerSlug();
21
- }
22
- }
23
- $opts->setOpt( 'user_form_providers', array_unique( $enabledProviders ) );
24
- }
25
  }
3
  namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\Integrations;
4
 
5
  use FernleafSystems\Wordpress\Plugin\Shield\Modules\Base;
 
6
 
7
  class Upgrade extends Base\Upgrade {
8
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
9
  }
src/lib/src/Modules/License/AjaxHandler.php CHANGED
@@ -58,7 +58,7 @@ class AjaxHandler extends Shield\Modules\BaseShield\AjaxHandler {
58
  private function ajaxExec_LicenseHandling() {
59
  /** @var ModCon $mod */
60
  $mod = $this->getMod();
61
- $sHandler = $mod->getLicenseHandler();
62
 
63
  $success = false;
64
  $msg = 'Unsupported license action';
@@ -67,14 +67,14 @@ class AjaxHandler extends Shield\Modules\BaseShield\AjaxHandler {
67
 
68
  if ( $sLicenseAction == 'clear' ) {
69
  $success = true;
70
- $sHandler->deactivate( false );
71
- $sHandler->clearLicense();
72
  $msg = __( 'Success', 'wp-simple-firewall' ).'! '
73
  .__( 'Reloading page', 'wp-simple-firewall' ).'...';
74
  }
75
  elseif ( $sLicenseAction == 'check' ) {
76
 
77
- $nCheckInterval = $sHandler->getLicenseNotCheckedForInterval();
78
  if ( $nCheckInterval < 20 ) {
79
  $nWait = 20 - $nCheckInterval;
80
  $msg = sprintf(
@@ -84,8 +84,8 @@ class AjaxHandler extends Shield\Modules\BaseShield\AjaxHandler {
84
  }
85
  else {
86
  try {
87
- $success = $sHandler->verify( true )
88
- ->hasValidWorkingLicense();
89
  $msg = $success ? __( 'Valid license found.', 'wp-simple-firewall' ) : __( "Valid license couldn't be found.", 'wp-simple-firewall' );
90
  }
91
  catch ( \Exception $e ) {
58
  private function ajaxExec_LicenseHandling() {
59
  /** @var ModCon $mod */
60
  $mod = $this->getMod();
61
+ $licHandler = $mod->getLicenseHandler();
62
 
63
  $success = false;
64
  $msg = 'Unsupported license action';
67
 
68
  if ( $sLicenseAction == 'clear' ) {
69
  $success = true;
70
+ $licHandler->deactivate( false );
71
+ $licHandler->clearLicense();
72
  $msg = __( 'Success', 'wp-simple-firewall' ).'! '
73
  .__( 'Reloading page', 'wp-simple-firewall' ).'...';
74
  }
75
  elseif ( $sLicenseAction == 'check' ) {
76
 
77
+ $nCheckInterval = $licHandler->getLicenseNotCheckedForInterval();
78
  if ( $nCheckInterval < 20 ) {
79
  $nWait = 20 - $nCheckInterval;
80
  $msg = sprintf(
84
  }
85
  else {
86
  try {
87
+ $success = $licHandler->verify( true )
88
+ ->hasValidWorkingLicense();
89
  $msg = $success ? __( 'Valid license found.', 'wp-simple-firewall' ) : __( "Valid license couldn't be found.", 'wp-simple-firewall' );
90
  }
91
  catch ( \Exception $e ) {
src/lib/src/Modules/License/Lib/LicenseHandler.php CHANGED
@@ -2,17 +2,13 @@
2
 
3
  namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\License\Lib;
4
 
5
- use FernleafSystems\Utilities\Logic\ExecOnce;
6
  use FernleafSystems\Wordpress\Plugin\Shield\License\EddLicenseVO;
7
  use FernleafSystems\Wordpress\Plugin\Shield\Modules;
8
  use FernleafSystems\Wordpress\Plugin\Shield\Modules\License\ModCon;
9
  use FernleafSystems\Wordpress\Plugin\Shield\ShieldNetApi\HandshakingNonce;
10
  use FernleafSystems\Wordpress\Services\Services;
11
 
12
- class LicenseHandler {
13
-
14
- use Modules\ModConsumer;
15
- use ExecOnce;
16
 
17
  protected function run() {
18
  add_action( $this->getCon()->prefix( 'shield_action' ), function ( $action ) {
@@ -44,14 +40,31 @@ class LicenseHandler {
44
 
45
  // performs the license check on-demand
46
  add_action( $this->getCon()->prefix( 'adhoc_cron_license_check' ), function () {
47
- /** @var ModCon $mod */
48
- $mod = $this->getMod();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
49
  try {
50
- $mod->getLicenseHandler()->verify( true );
51
  }
52
  catch ( \Exception $e ) {
53
  }
54
- } );
55
  }
56
 
57
  private function canCheck() :bool {
@@ -70,13 +83,13 @@ class LicenseHandler {
70
  }
71
 
72
  /**
73
- * @param bool $bSendEmail
74
  */
75
- public function deactivate( $bSendEmail = true ) {
76
  if ( $this->isActive() ) {
77
  $this->clearLicense();
78
  $this->getOptions()->setOptAt( 'license_deactivated_at' );
79
- if ( $bSendEmail ) {
80
  ( new LicenseEmails() )
81
  ->setMod( $this->getMod() )
82
  ->sendLicenseDeactivatedEmail();
@@ -134,11 +147,9 @@ class LicenseHandler {
134
  * 3) the license is marked as "active"
135
  * 4) the license hasn't expired
136
  * 5) the time since the last check hasn't expired
137
- * @return bool
138
  */
139
  public function hasValidWorkingLicense() :bool {
140
- $oLic = $this->getLicense();
141
- return $oLic->isValid() && $this->isActive();
142
  }
143
 
144
  public function isActive() :bool {
@@ -179,12 +190,11 @@ class LicenseHandler {
179
  }
180
 
181
  /**
182
- * @param bool $bForceCheck
183
  * @return $this
184
  * @throws \Exception
185
  */
186
- public function verify( $bForceCheck = true ) {
187
- if ( $bForceCheck || ( $this->isVerifyRequired() && $this->canCheck() ) ) {
188
  ( new Verify() )
189
  ->setMod( $this->getMod() )
190
  ->run();
@@ -197,9 +207,9 @@ class LicenseHandler {
197
  }
198
 
199
  private function canLicenseCheck_FileFlag() :bool {
200
- $nMtime = (int)Services::WpFs()->getModifiedTime(
201
  $this->getCon()->paths->forFlag( 'license_check' )
202
  );
203
- return ( Services::Request()->ts() - $nMtime ) > MINUTE_IN_SECONDS;
204
  }
205
  }
2
 
3
  namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\License\Lib;
4
 
 
5
  use FernleafSystems\Wordpress\Plugin\Shield\License\EddLicenseVO;
6
  use FernleafSystems\Wordpress\Plugin\Shield\Modules;
7
  use FernleafSystems\Wordpress\Plugin\Shield\Modules\License\ModCon;
8
  use FernleafSystems\Wordpress\Plugin\Shield\ShieldNetApi\HandshakingNonce;
9
  use FernleafSystems\Wordpress\Services\Services;
10
 
11
+ class LicenseHandler extends Modules\Base\Common\ExecOnceModConsumer {
 
 
 
12
 
13
  protected function run() {
14
  add_action( $this->getCon()->prefix( 'shield_action' ), function ( $action ) {
40
 
41
  // performs the license check on-demand
42
  add_action( $this->getCon()->prefix( 'adhoc_cron_license_check' ), function () {
43
+ $this->runAdhocLicenseCheck();
44
+ } );
45
+ }
46
+
47
+ /**
48
+ * Customer reported that they're using a multilingual system with different hostnames for each language.
49
+ * This meant that adhoc lookups that happen on the wrong hostname name request would fail and remove
50
+ * the license. So now we tie ad-hoc lookups to the hostname.
51
+ *
52
+ * This doesn't solve all problems since the ad-hoc lookup is cron-based, and the cron may get triggered
53
+ * on the wrong hostname.
54
+ */
55
+ private function runAdhocLicenseCheck() {
56
+ /** @var ModCon $mod */
57
+ $mod = $this->getMod();
58
+
59
+ $licHost = wp_parse_url( $this->getLicense()->url, PHP_URL_HOST );
60
+ $reqHost = Services::Request()->getHost();
61
+ if ( !$this->hasValidWorkingLicense() || empty( $licHost ) || empty( $reqHost ) || ( $licHost === $reqHost ) ) {
62
  try {
63
+ $mod->getLicenseHandler()->verify();
64
  }
65
  catch ( \Exception $e ) {
66
  }
67
+ }
68
  }
69
 
70
  private function canCheck() :bool {
83
  }
84
 
85
  /**
86
+ * @param bool $sendEmail
87
  */
88
+ public function deactivate( bool $sendEmail = true ) {
89
  if ( $this->isActive() ) {
90
  $this->clearLicense();
91
  $this->getOptions()->setOptAt( 'license_deactivated_at' );
92
+ if ( $sendEmail ) {
93
  ( new LicenseEmails() )
94
  ->setMod( $this->getMod() )
95
  ->sendLicenseDeactivatedEmail();
147
  * 3) the license is marked as "active"
148
  * 4) the license hasn't expired
149
  * 5) the time since the last check hasn't expired
 
150
  */
151
  public function hasValidWorkingLicense() :bool {
152
+ return $this->getLicense()->isValid() && $this->isActive();
 
153
  }
154
 
155
  public function isActive() :bool {
190
  }
191
 
192
  /**
 
193
  * @return $this
194
  * @throws \Exception
195
  */
196
+ public function verify( bool $force = true ) {
197
+ if ( $force || ( $this->isVerifyRequired() && $this->canCheck() ) ) {
198
  ( new Verify() )
199
  ->setMod( $this->getMod() )
200
  ->run();
207
  }
208
 
209
  private function canLicenseCheck_FileFlag() :bool {
210
+ $mtime = Services::WpFs()->getModifiedTime(
211
  $this->getCon()->paths->forFlag( 'license_check' )
212
  );
213
+ return ( Services::Request()->ts() - $mtime ) > MINUTE_IN_SECONDS;
214
  }
215
  }
src/lib/src/Modules/License/WpCli/License.php CHANGED
@@ -98,24 +98,24 @@ class License extends Base\WpCli\BaseWpCliCmd {
98
  if ( $this->getCon()->isPremiumActive() ) {
99
  WP_CLI::log( 'Premium license is already active. Re-checking...' );
100
  }
101
- $bSuccess = $mod
102
  ->getLicenseHandler()
103
  ->verify()
104
  ->hasValidWorkingLicense();
105
- $sMessage = $bSuccess ? __( 'Valid license found and installed.', 'wp-simple-firewall' ) : __( "Valid license couldn't be found.", 'wp-simple-firewall' );
 
106
  }
107
  catch ( \Exception $e ) {
108
- $bSuccess = false;
109
- $sMessage = $e->getMessage();
110
  }
111
 
112
- $bSuccess ? WP_CLI::success( $sMessage ) : WP_CLI::error( $sMessage );
113
  }
114
 
115
  /**
116
  * License checking WP-CLI cmds may be run if you're not premium,
117
  * or you're premium and you haven't switched it off (parent).
118
- * @inheritDoc
119
  */
120
  protected function canRun() :bool {
121
  return !$this->getCon()->isPremiumActive() || parent::canRun();
98
  if ( $this->getCon()->isPremiumActive() ) {
99
  WP_CLI::log( 'Premium license is already active. Re-checking...' );
100
  }
101
+ $success = $mod
102
  ->getLicenseHandler()
103
  ->verify()
104
  ->hasValidWorkingLicense();
105
+ $msg = $success ? __( 'Valid license found and installed.', 'wp-simple-firewall' )
106
+ : __( "Valid license couldn't be found.", 'wp-simple-firewall' );
107
  }
108
  catch ( \Exception $e ) {
109
+ $success = false;
110
+ $msg = $e->getMessage();
111
  }
112
 
113
+ $success ? WP_CLI::success( $msg ) : WP_CLI::error( $msg );
114
  }
115
 
116
  /**
117
  * License checking WP-CLI cmds may be run if you're not premium,
118
  * or you're premium and you haven't switched it off (parent).
 
119
  */
120
  protected function canRun() :bool {
121
  return !$this->getCon()->isPremiumActive() || parent::canRun();
src/lib/src/Modules/LoginGuard/Lib/AntiBot/AntibotSetup.php CHANGED
@@ -11,7 +11,9 @@ use FernleafSystems\Wordpress\Services\Services;
11
  class AntibotSetup extends ExecOnceModConsumer {
12
 
13
  protected function canRun() :bool {
14
- return !Services::WpUsers()->isUserLoggedIn();
 
 
15
  }
16
 
17
  protected function run() {
11
  class AntibotSetup extends ExecOnceModConsumer {
12
 
13
  protected function canRun() :bool {
14
+ /** @var LoginGuard\ModCon $mod */
15
+ $mod = $this->getMod();
16
+ return !$mod->isVisitorWhitelisted() && !Services::WpUsers()->isUserLoggedIn();
17
  }
18
 
19
  protected function run() {
src/lib/src/Modules/LoginGuard/Lib/TwoFactor/LoginIntentPage.php CHANGED
@@ -15,10 +15,7 @@ class LoginIntentPage {
15
  echo $this->renderPage();
16
  }
17
 
18
- /**
19
- * @return string
20
- */
21
- public function renderForm() {
22
  $mfaCon = $this->getMfaCon();
23
  /** @var LoginGuard\ModCon $mod */
24
  $mod = $mfaCon->getMod();
@@ -114,15 +111,15 @@ class LoginIntentPage {
114
  }
115
 
116
  private function renderPage() :string {
117
- $oIC = $this->getMfaCon();
118
  /** @var LoginGuard\ModCon $mod */
119
- $mod = $oIC->getMod();
120
- $con = $oIC->getCon();
121
  $req = Services::Request();
122
 
123
  $labels = $con->getLabels();
124
  $bannerURL = empty( $labels[ 'url_login2fa_logourl' ] ) ? $con->urls->forImage( 'shield/banner-2FA.png' ) : $labels[ 'url_login2fa_logourl' ];
125
- $timeRemaining = $oIC->getLoginIntentExpiresAt() - $req->ts();
126
 
127
  $data = [
128
  'strings' => [
@@ -144,7 +141,7 @@ class LoginIntentPage {
144
  ],
145
  'flags' => [
146
  'show_branded_links' => !$con->getModule_SecAdmin()->getWhiteLabelController()->isEnabled(),
147
- 'has_u2f' => isset( $oIC->getProvidersForUser(
148
  Services::WpUsers()->getCurrentWpUser(), true )[ LoginGuard\Lib\TwoFactor\Provider\U2F::SLUG ] )
149
  ],
150
  'content' => [
15
  echo $this->renderPage();
16
  }
17
 
18
+ public function renderForm() :string {
 
 
 
19
  $mfaCon = $this->getMfaCon();
20
  /** @var LoginGuard\ModCon $mod */
21
  $mod = $mfaCon->getMod();
111
  }
112
 
113
  private function renderPage() :string {
114
+ $IC = $this->getMfaCon();
115
  /** @var LoginGuard\ModCon $mod */
116
+ $mod = $IC->getMod();
117
+ $con = $IC->getCon();
118
  $req = Services::Request();
119
 
120
  $labels = $con->getLabels();
121
  $bannerURL = empty( $labels[ 'url_login2fa_logourl' ] ) ? $con->urls->forImage( 'shield/banner-2FA.png' ) : $labels[ 'url_login2fa_logourl' ];
122
+ $timeRemaining = $IC->getLoginIntentExpiresAt() - $req->ts();
123
 
124
  $data = [
125
  'strings' => [
141
  ],
142
  'flags' => [
143
  'show_branded_links' => !$con->getModule_SecAdmin()->getWhiteLabelController()->isEnabled(),
144
+ 'has_u2f' => isset( $IC->getProvidersForUser(
145
  Services::WpUsers()->getCurrentWpUser(), true )[ LoginGuard\Lib\TwoFactor\Provider\U2F::SLUG ] )
146
  ],
147
  'content' => [
src/lib/src/Modules/LoginGuard/Lib/TwoFactor/MfaController.php CHANGED
@@ -3,17 +3,14 @@
3
  namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\LoginGuard\Lib\TwoFactor;
4
 
5
  use FernleafSystems\Utilities\Data\Response\StdResponse;
6
- use FernleafSystems\Utilities\Logic\ExecOnce;
7
  use FernleafSystems\Wordpress\Plugin\Shield;
8
  use FernleafSystems\Wordpress\Plugin\Shield\Modules\LoginGuard;
9
  use FernleafSystems\Wordpress\Plugin\Shield\Modules\LoginGuard\Lib\TwoFactor\Provider;
10
  use FernleafSystems\Wordpress\Services\Services;
11
 
12
- class MfaController {
13
 
14
- use Shield\Modules\ModConsumer;
15
  use Shield\Utilities\Consumer\WpLoginCapture;
16
- use ExecOnce;
17
 
18
  /**
19
  * @var Provider\BaseProvider[]
@@ -23,7 +20,7 @@ class MfaController {
23
  /**
24
  * @var LoginIntentPage
25
  */
26
- private $oLoginIntentPageHandler;
27
 
28
  protected function run() {
29
  add_action( 'init', [ $this, 'onWpInit' ] );
@@ -40,11 +37,7 @@ class MfaController {
40
  }
41
 
42
  public function onWpLoaded() {
43
- ( new UserProfile() )
44
- ->setMfaController( $this )
45
- ->run();
46
  ( new MfaProfilesController() )->setMfaController( $this )->execute();
47
-
48
  add_shortcode( 'SHIELD_2FA_LOGIN', function () {
49
  return $this->getLoginIntentPageHandler()->renderForm();
50
  } );
@@ -143,10 +136,10 @@ class MfaController {
143
  }
144
 
145
  private function getLoginIntentPageHandler() :LoginIntentPage {
146
- if ( !isset( $this->oLoginIntentPageHandler ) ) {
147
- $this->oLoginIntentPageHandler = ( new LoginIntentPage() )->setMfaController( $this );
148
  }
149
- return $this->oLoginIntentPageHandler;
150
  }
151
 
152
  /**
@@ -172,16 +165,14 @@ class MfaController {
172
 
173
  /**
174
  * Ensures that BackupCode provider isn't supplied on its own, and the user profile is setup for each.
175
- * @param \WP_User $user
176
- * @param bool $onlyActiveProfiles
177
  * @return Provider\BaseProvider[]
178
  */
179
- public function getProvidersForUser( \WP_User $user, $onlyActiveProfiles = false ) :array {
180
  $Ps = array_filter( $this->getProviders(),
181
- function ( $provider ) use ( $user, $onlyActiveProfiles ) {
182
  /** @var Provider\BaseProvider $provider */
183
  return $provider->isProviderAvailableToUser( $user )
184
- && ( !$onlyActiveProfiles || $provider->isProfileActive( $user ) );
185
  }
186
  );
187
 
@@ -284,7 +275,9 @@ class MfaController {
284
  }
285
 
286
  public function isSubjectToLoginIntent( \WP_User $user ) :bool {
287
- return count( $this->getProvidersForUser( $user, true ) ) > 0;
 
 
288
  }
289
 
290
  public function removeAllFactorsForUser( int $userID ) :StdResponse {
3
  namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\LoginGuard\Lib\TwoFactor;
4
 
5
  use FernleafSystems\Utilities\Data\Response\StdResponse;
 
6
  use FernleafSystems\Wordpress\Plugin\Shield;
7
  use FernleafSystems\Wordpress\Plugin\Shield\Modules\LoginGuard;
8
  use FernleafSystems\Wordpress\Plugin\Shield\Modules\LoginGuard\Lib\TwoFactor\Provider;
9
  use FernleafSystems\Wordpress\Services\Services;
10
 
11
+ class MfaController extends Shield\Modules\Base\Common\ExecOnceModConsumer {
12
 
 
13
  use Shield\Utilities\Consumer\WpLoginCapture;
 
14
 
15
  /**
16
  * @var Provider\BaseProvider[]
20
  /**
21
  * @var LoginIntentPage
22
  */
23
+ private $loginIntentPageHandler;
24
 
25
  protected function run() {
26
  add_action( 'init', [ $this, 'onWpInit' ] );
37
  }
38
 
39
  public function onWpLoaded() {
 
 
 
40
  ( new MfaProfilesController() )->setMfaController( $this )->execute();
 
41
  add_shortcode( 'SHIELD_2FA_LOGIN', function () {
42
  return $this->getLoginIntentPageHandler()->renderForm();
43
  } );
136
  }
137
 
138
  private function getLoginIntentPageHandler() :LoginIntentPage {
139
+ if ( !isset( $this->loginIntentPageHandler ) ) {
140
+ $this->loginIntentPageHandler = ( new LoginIntentPage() )->setMfaController( $this );
141
  }
142
+ return $this->loginIntentPageHandler;
143
  }
144
 
145
  /**
165
 
166
  /**
167
  * Ensures that BackupCode provider isn't supplied on its own, and the user profile is setup for each.
 
 
168
  * @return Provider\BaseProvider[]
169
  */
170
+ public function getProvidersForUser( \WP_User $user, bool $onlyActive = false ) :array {
171
  $Ps = array_filter( $this->getProviders(),
172
+ function ( $provider ) use ( $user, $onlyActive ) {
173
  /** @var Provider\BaseProvider $provider */
174
  return $provider->isProviderAvailableToUser( $user )
175
+ && ( !$onlyActive || $provider->isProfileActive( $user ) );
176
  }
177
  );
178
 
275
  }
276
 
277
  public function isSubjectToLoginIntent( \WP_User $user ) :bool {
278
+ /** @var LoginGuard\ModCon $mod */
279
+ $mod = $this->getMod();
280
+ return !$mod->isVisitorWhitelisted() && count( $this->getProvidersForUser( $user, true ) ) > 0;
281
  }
282
 
283
  public function removeAllFactorsForUser( int $userID ) :StdResponse {
src/lib/src/Modules/LoginGuard/Lib/TwoFactor/MfaProfilesController.php CHANGED
@@ -17,7 +17,7 @@ class MfaProfilesController {
17
  private $isFrontend = false;
18
 
19
  protected function run() {
20
- $this->defineShortcodes();
21
  if ( Services::WpUsers()->isUserLoggedIn() ) {
22
  add_action( 'wp', function () {
23
  $this->enqueueAssets( true );
@@ -35,16 +35,16 @@ class MfaProfilesController {
35
  if ( $this->isFrontend || in_array( $hook, [ 'profile.php', 'user-edit.php' ] ) ) {
36
  $enqueues[ Enqueue::JS ][] = 'shield/userprofile';
37
  $enqueues[ Enqueue::CSS ][] = 'shield/dialog';
 
38
 
39
- if ( $this->isFrontend ) {
40
- add_filter( 'shield/custom_dequeues', function ( $assets ) {
41
- if ( !$this->rendered ) {
42
- $assets[ Enqueue::JS ][] = 'shield/userprofile';
43
- $assets[ Enqueue::CSS ][] = 'shield/dialog';
44
- }
45
- return $assets;
46
- } );
47
- }
48
 
49
  add_filter( 'shield/custom_localisations', function ( array $localz ) {
50
  $mfaCon = $this->getMfaCon();
@@ -75,19 +75,85 @@ class MfaProfilesController {
75
  }, 10, $this->isFrontend ? 1 : 2 );
76
  }
77
 
78
- private function loadUserProfileMFA( $attributes = [] ) :string {
79
  $this->rendered = true;
80
  return ( new Profiles\RenderCustomForms() )
81
  ->setMfaController( $this->getMfaCon() )
82
  ->setWpUser( Services::WpUsers()->getCurrentWpUser() )
83
- ->render( is_array( $attributes ) ? $attributes : [] );
84
  }
85
 
86
- private function defineShortcodes() {
 
 
87
  if ( $this->getMfaCon()->getCon()->isPremiumActive() ) {
88
  add_shortcode( 'SHIELD_USER_PROFILE_MFA', function ( $attributes ) {
89
- return $this->loadUserProfileMFA( $attributes );
90
  } );
91
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
92
  }
93
  }
17
  private $isFrontend = false;
18
 
19
  protected function run() {
20
+ $this->addHooks();
21
  if ( Services::WpUsers()->isUserLoggedIn() ) {
22
  add_action( 'wp', function () {
23
  $this->enqueueAssets( true );
35
  if ( $this->isFrontend || in_array( $hook, [ 'profile.php', 'user-edit.php' ] ) ) {
36
  $enqueues[ Enqueue::JS ][] = 'shield/userprofile';
37
  $enqueues[ Enqueue::CSS ][] = 'shield/dialog';
38
+ $enqueues[ Enqueue::CSS ][] = 'shield/userprofile';
39
 
40
+ add_filter( 'shield/custom_dequeues', function ( $assets ) {
41
+ if ( !$this->rendered ) {
42
+ $assets[ Enqueue::JS ][] = 'shield/userprofile';
43
+ $assets[ Enqueue::CSS ][] = 'shield/dialog';
44
+ $assets[ Enqueue::CSS ][] = 'shield/userprofile';
45
+ }
46
+ return $assets;
47
+ } );
 
48
 
49
  add_filter( 'shield/custom_localisations', function ( array $localz ) {
50
  $mfaCon = $this->getMfaCon();
75
  }, 10, $this->isFrontend ? 1 : 2 );
76
  }
77
 
78
+ private function loadUserProfileMFA( array $attributes = [] ) :string {
79
  $this->rendered = true;
80
  return ( new Profiles\RenderCustomForms() )
81
  ->setMfaController( $this->getMfaCon() )
82
  ->setWpUser( Services::WpUsers()->getCurrentWpUser() )
83
+ ->render( $attributes );
84
  }
85
 
86
+ private function addHooks() {
87
+
88
+ // shortcode for placing user authentication handling anywhere
89
  if ( $this->getMfaCon()->getCon()->isPremiumActive() ) {
90
  add_shortcode( 'SHIELD_USER_PROFILE_MFA', function ( $attributes ) {
91
+ return $this->loadUserProfileMFA( is_array( $attributes ) ? $attributes : [] );
92
  } );
93
  }
94
+
95
+ // Standard WordPress User Profile Editing
96
+ add_action( 'show_user_profile', function () {
97
+ $this->addOptionsToUserProfile();
98
+ }, 7, 0 );
99
+ add_action( 'edit_user_profile', function ( $user ) {
100
+ if ( $user instanceof \WP_User ) {
101
+ $this->addOptionsToUserEditProfile( $user );
102
+ }
103
+ } );
104
+ }
105
+
106
+ /**
107
+ * This MUST only ever be hooked into when the User is looking at their OWN profile, so we can use "current user"
108
+ * functions. Otherwise we need to be careful of mixing up users.
109
+ */
110
+ public function addOptionsToUserProfile() {
111
+ echo $this->loadUserProfileMFA( [
112
+ 'title'=>__( 'Multi-Factor Authentication', 'wp-simple-firewall' ),
113
+ 'subtitle' => sprintf( __( 'Provided by %s', 'wp-simple-firewall' ),
114
+ $this->getMfaCon()->getCon()->getHumanName() )
115
+ ] );
116
+ }
117
+
118
+ /**
119
+ * ONLY TO BE HOOKED TO USER PROFILE EDIT
120
+ */
121
+ public function addOptionsToUserEditProfile( \WP_User $user ) {
122
+ $mfaCon = $this->getMfaCon();
123
+ $con = $mfaCon->getCon();
124
+ $WPU = Services::WpUsers();
125
+ $pluginName = $con->getHumanName();
126
+
127
+ $providers = array_map(
128
+ function ( $provider ) {
129
+ return $provider->getProviderName();
130
+ },
131
+ $mfaCon->getProvidersForUser( $user, true )
132
+ );
133
+
134
+ echo $mfaCon->getMod()->renderTemplate( '/admin/user/profile/mfa/remove_for_other_user.twig', [
135
+ 'flags' => [
136
+ 'has_factors' => count( $providers ) > 0,
137
+ 'is_admin_profile' => $WPU->isUserAdmin( $user ),
138
+ 'can_remove' => $con->isPluginAdmin() || !$WPU->isUserAdmin( $user ),
139
+ ],
140
+ 'vars' => [
141
+ 'user_id' => $user->ID,
142
+ 'mfa_factor_names' => $providers,
143
+ ],
144
+ 'strings' => [
145
+ 'title' => __( 'Multi-Factor Authentication', 'wp-simple-firewall' ),
146
+ 'provided_by' => sprintf( __( 'Provided by %s', 'wp-simple-firewall' ), $pluginName ),
147
+ 'currently_active' => __( 'Currently active MFA Providers on this profile are' ),
148
+ 'remove_all' => __( 'Remove All MFA Providers' ),
149
+ 'remove_all_from' => __( 'Remove All MFA Providers From This User Profile' ),
150
+ 'remove_warning' => __( "Certain providers may not be removed if they're enforced." ),
151
+ 'no_providers' => __( 'There are no MFA providers active on this user account.' ),
152
+ 'only_secadmin' => sprintf( __( 'Only %s Security Admins may modify the MFA settings of another admin account.' ),
153
+ $pluginName ),
154
+ 'authenticate' => sprintf( __( 'You may authenticate with the %s Security Admin system and return here.' ),
155
+ $pluginName ),
156
+ ],
157
+ ] );
158
  }
159
  }
src/lib/src/Modules/LoginGuard/Lib/TwoFactor/MfaSkip.php CHANGED
@@ -10,58 +10,53 @@ class MfaSkip {
10
 
11
  use Shield\Modules\ModConsumer;
12
 
13
- /**
14
- * @param \WP_User $oUser
15
- */
16
- public function addMfaSkip( \WP_User $oUser ) {
17
- /** @var LoginGuard\Options $oOpts */
18
- $oOpts = $this->getOptions();
19
 
20
- $oMeta = $this->getCon()->getUserMeta( $oUser );
21
- $aHashes = is_array( $oMeta->hash_loginmfa ) ? $oMeta->hash_loginmfa : [];
22
- $aHashes[ $this->getAgentHash() ] = Services::Request()->ts();
23
 
24
- $nMaxExpires = $oOpts->getMfaSkip();
25
- if ( $nMaxExpires > 0 ) {
26
- $aHashes = array_filter( $aHashes,
27
- function ( $nTS ) use ( $nMaxExpires ) {
28
- return Services::Request()->ts() - $nTS < $nMaxExpires;
29
  }
30
  );
31
  }
32
 
33
- $oMeta->hash_loginmfa = $aHashes;
34
  }
35
 
36
- /**
37
- * @param \WP_User $oUser
38
- * @return bool
39
- */
40
- public function canMfaSkip( \WP_User $oUser ) {
41
  /** @var LoginGuard\Options $opts */
42
  $opts = $this->getOptions();
43
  $req = Services::Request();
44
 
45
- $bCanSkip = false;
46
 
47
  if ( $opts->isMfaSkip() ) {
48
- $sAgentHash = $this->getAgentHash();
49
- $oMeta = $this->getCon()->getUserMeta( $oUser );
50
- $aHashes = is_array( $oMeta->hash_loginmfa ) ? $oMeta->hash_loginmfa : [];
51
- $bCanSkip = isset( $aHashes[ $sAgentHash ] )
52
- && ( (int)$aHashes[ $sAgentHash ] + $opts->getMfaSkip() ) > $req->ts();
53
  }
54
 
55
- return $bCanSkip;
 
 
 
 
 
56
  }
57
 
58
- /**
59
- * @return string
60
- */
61
- private function getAgentHash() {
62
- return md5( serialize( [
63
- Services::IP()->getRequestIp(),
64
- Services::Request()->getUserAgent()
65
- ] ) );
66
  }
67
  }
10
 
11
  use Shield\Modules\ModConsumer;
12
 
13
+ public function addMfaSkip( \WP_User $user ) {
14
+ /** @var LoginGuard\Options $opts */
15
+ $opts = $this->getOptions();
 
 
 
16
 
17
+ $meta = $this->getCon()->getUserMeta( $user );
18
+ $hashes = is_array( $meta->hash_loginmfa ) ? $meta->hash_loginmfa : [];
19
+ $hashes[ $this->getAgentHash() ] = Services::Request()->ts();
20
 
21
+ $maxExpires = $opts->getMfaSkip();
22
+ if ( $maxExpires > 0 ) {
23
+ $hashes = array_filter( $hashes,
24
+ function ( $ts ) use ( $maxExpires ) {
25
+ return Services::Request()->ts() - $ts < $maxExpires;
26
  }
27
  );
28
  }
29
 
30
+ $meta->hash_loginmfa = $hashes;
31
  }
32
 
33
+ public function canMfaSkip( \WP_User $user ) :bool {
 
 
 
 
34
  /** @var LoginGuard\Options $opts */
35
  $opts = $this->getOptions();
36
  $req = Services::Request();
37
 
38
+ $canSkip = false;
39
 
40
  if ( $opts->isMfaSkip() ) {
41
+ $agentHash = $this->getAgentHash();
42
+ $meta = $this->getCon()->getUserMeta( $user );
43
+ $hashes = is_array( $meta->hash_loginmfa ) ? $meta->hash_loginmfa : [];
44
+ $canSkip = isset( $hashes[ $agentHash ] )
45
+ && ( (int)$hashes[ $agentHash ] + $opts->getMfaSkip() ) > $req->ts();
46
  }
47
 
48
+ return $canSkip;
49
+ }
50
+
51
+ private function getAgentHash() :string {
52
+ $hashData = apply_filters( 'shield/2fa_remember_me_params', $this->getDefaultHashParams() );
53
+ return md5( serialize( empty( $hashData ) ? $this->getDefaultHashParams() : $hashData ) );
54
  }
55
 
56
+ private function getDefaultHashParams() :array {
57
+ return [
58
+ 'ip' => Services::IP()->getRequestIp(),
59
+ 'user_agent' => Services::Request()->getUserAgent()
60
+ ];
 
 
 
61
  }
62
  }
src/lib/src/Modules/LoginGuard/Lib/TwoFactor/Profiles/RenderCustomForms.php CHANGED
@@ -13,17 +13,25 @@ class RenderCustomForms {
13
  private $attributes;
14
 
15
  public function render( array $attributes ) :string {
16
- $this->attributes = $attributes;
17
  return $this->getMfaCon()
18
  ->getMod()
19
  ->renderTemplate( '/user/profile/mfa/main.twig', $this->buildRenderData() );
20
  }
21
 
 
 
 
 
 
 
 
 
 
 
 
22
  private function buildRenderData() :array {
23
  $mfaCon = $this->getMfaCon();
24
- $con = $mfaCon->getCon();
25
- $pluginName = $con->getHumanName();
26
-
27
  $user = $this->getWpUser();
28
  $providers = $user instanceof \WP_User ? $mfaCon->getProvidersForUser( $user ) : [];
29
  $providerRenders = $user instanceof \WP_User ?
@@ -32,7 +40,7 @@ class RenderCustomForms {
32
  }, $providers )
33
  : [];
34
 
35
- $data = [
36
  'content' => [
37
  'providers' => $providerRenders,
38
  ],
@@ -41,15 +49,14 @@ class RenderCustomForms {
41
  'logged_in' => $user instanceof \WP_User,
42
  ],
43
  'strings' => [
44
- 'title' => sprintf( __( '%s MFA Options', 'wp-simple-firewall' ), $pluginName ),
 
45
  'not_logged_in' => __( 'Not currently logged-in.', 'wp-simple-firewall' ),
46
  'no_providers' => __( 'There are currently no 2FA providers available on your account.', 'wp-simple-firewall' ),
47
  ],
48
  'vars' => [
49
  'provider_data' => ''
50
  ],
51
- ];
52
-
53
- return apply_filters( 'shield/render_data_custom_profiles_mfa', $data );
54
  }
55
  }
13
  private $attributes;
14
 
15
  public function render( array $attributes ) :string {
16
+ $this->setAttributes( $attributes );
17
  return $this->getMfaCon()
18
  ->getMod()
19
  ->renderTemplate( '/user/profile/mfa/main.twig', $this->buildRenderData() );
20
  }
21
 
22
+ public function setAttributes( array $attributes ) {
23
+ $con = $this->getMfaCon()->getCon();
24
+ $this->attributes = shortcode_atts(
25
+ [
26
+ 'title' => sprintf( __( '%s MFA Options', 'wp-simple-firewall' ), $con->getHumanName() ),
27
+ 'subtitle' => '',
28
+ ],
29
+ $attributes
30
+ );
31
+ }
32
+
33
  private function buildRenderData() :array {
34
  $mfaCon = $this->getMfaCon();
 
 
 
35
  $user = $this->getWpUser();
36
  $providers = $user instanceof \WP_User ? $mfaCon->getProvidersForUser( $user ) : [];
37
  $providerRenders = $user instanceof \WP_User ?
40
  }, $providers )
41
  : [];
42
 
43
+ return apply_filters( 'shield/render_data_custom_profiles_mfa', [
44
  'content' => [
45
  'providers' => $providerRenders,
46
  ],
49
  'logged_in' => $user instanceof \WP_User,
50
  ],
51
  'strings' => [
52
+ 'title' => esc_html( $this->attributes[ 'title' ] ),
53
+ 'subtitle' => esc_html( $this->attributes[ 'subtitle' ] ),
54
  'not_logged_in' => __( 'Not currently logged-in.', 'wp-simple-firewall' ),
55
  'no_providers' => __( 'There are currently no 2FA providers available on your account.', 'wp-simple-firewall' ),
56
  ],
57
  'vars' => [
58
  'provider_data' => ''
59
  ],
60
+ ] );
 
 
61
  }
62
  }
src/lib/src/Modules/LoginGuard/Lib/TwoFactor/Provider/BaseProvider.php CHANGED
@@ -49,7 +49,6 @@ abstract class BaseProvider {
49
  }
50
 
51
  /**
52
- * @param \WP_User $user
53
  * @return string|array
54
  */
55
  protected function getSecret( \WP_User $user ) {
@@ -66,7 +65,6 @@ abstract class BaseProvider {
66
  }
67
 
68
  /**
69
- * @param \WP_User $user
70
  * @return bool
71
  */
72
  protected function hasValidSecret( \WP_User $user ) {
@@ -106,7 +104,6 @@ abstract class BaseProvider {
106
  }
107
 
108
  /**
109
- * @param \WP_User $user
110
  * @return string
111
  */
112
  public function resetSecret( \WP_User $user ) {
@@ -144,7 +141,6 @@ abstract class BaseProvider {
144
  }
145
 
146
  /**
147
- * @param \WP_User $user
148
  * @return string|mixed
149
  */
150
  protected function genNewSecret( \WP_User $user ) {
@@ -155,7 +151,6 @@ abstract class BaseProvider {
155
 
156
  /**
157
  * Only to be fired if and when Login has been completely verified.
158
- * @param \WP_User $user
159
  * @return $this
160
  */
161
  public function postSuccessActions( \WP_User $user ) {
@@ -165,8 +160,6 @@ abstract class BaseProvider {
165
  /**
166
  * This MUST only ever be hooked into when the User is looking at their OWN profile, so we can use "current user"
167
  * functions. Otherwise we need to be careful of mixing up users.
168
- * @param \WP_User $user
169
- * @return string
170
  */
171
  public function renderUserProfileOptions( \WP_User $user ) :string {
172
  return $this->getMod()
@@ -179,8 +172,6 @@ abstract class BaseProvider {
179
  /**
180
  * This MUST only ever be hooked into when the User is looking at their OWN profile, so we can use "current user"
181
  * functions. Otherwise we need to be careful of mixing up users.
182
- * @param \WP_User $user
183
- * @return string
184
  */
185
  public function renderUserProfileCustomForm( \WP_User $user ) :string {
186
  $data = $this->getProfileRenderData( $user );
49
  }
50
 
51
  /**
 
52
  * @return string|array
53
  */
54
  protected function getSecret( \WP_User $user ) {
65
  }
66
 
67
  /**
 
68
  * @return bool
69
  */
70
  protected function hasValidSecret( \WP_User $user ) {
104
  }
105
 
106
  /**
 
107
  * @return string
108
  */
109
  public function resetSecret( \WP_User $user ) {
141
  }
142
 
143
  /**
 
144
  * @return string|mixed
145
  */
146
  protected function genNewSecret( \WP_User $user ) {
151
 
152
  /**
153
  * Only to be fired if and when Login has been completely verified.
 
154
  * @return $this
155
  */
156
  public function postSuccessActions( \WP_User $user ) {
160
  /**
161
  * This MUST only ever be hooked into when the User is looking at their OWN profile, so we can use "current user"
162
  * functions. Otherwise we need to be careful of mixing up users.
 
 
163
  */
164
  public function renderUserProfileOptions( \WP_User $user ) :string {
165
  return $this->getMod()
172
  /**
173
  * This MUST only ever be hooked into when the User is looking at their OWN profile, so we can use "current user"
174
  * functions. Otherwise we need to be careful of mixing up users.
 
 
175
  */
176
  public function renderUserProfileCustomForm( \WP_User $user ) :string {
177
  $data = $this->getProfileRenderData( $user );
src/lib/src/Modules/LoginGuard/Lib/TwoFactor/UserProfile.php CHANGED
@@ -2,18 +2,18 @@
2
 
3
  namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\LoginGuard\Lib\TwoFactor;
4
 
 
5
  use FernleafSystems\Wordpress\Plugin\Shield;
6
- use FernleafSystems\Wordpress\Services\Services;
7
 
 
 
 
8
  class UserProfile {
9
 
10
  use MfaControllerConsumer;
 
11
 
12
- public function run() {
13
- if ( is_admin() ) {
14
- add_action( 'show_user_profile', [ $this, 'addOptionsToUserProfile' ] );
15
- add_action( 'edit_user_profile', [ $this, 'addOptionsToUserEditProfile' ] );
16
- }
17
  }
18
 
19
  /**
@@ -22,30 +22,6 @@ class UserProfile {
22
  * @param \WP_User $user
23
  */
24
  public function addOptionsToUserProfile( $user ) {
25
- $oMC = $this->getMfaCon();
26
- $WPU = Services::WpUsers();
27
- $providers = $oMC->getProvidersForUser( $user );
28
- if ( count( $providers ) > 0 ) {
29
- $rows = [];
30
- foreach ( $providers as $provider ) {
31
- $rows[ $provider::SLUG ] = $provider->renderUserProfileOptions( $user );
32
- }
33
-
34
- echo $oMC->getMod()
35
- ->renderTemplate(
36
- '/admin/user/profile/mfa/mfa_container.twig',
37
- [
38
- 'user_to_edit_is_admin' => $WPU->isUserAdmin( $user ),
39
- 'strings' => [
40
- 'title' => __( 'Multi-Factor Authentication', 'wp-simple-firewall' ),
41
- 'provided_by' => sprintf( __( 'Provided by %s', 'wp-simple-firewall' ), $oMC->getCon()
42
- ->getHumanName() )
43
- ],
44
- 'mfa_rows' => $rows,
45
- ],
46
- true
47
- );
48
- }
49
  }
50
 
51
  /**
@@ -53,46 +29,5 @@ class UserProfile {
53
  * @param \WP_User $user
54
  */
55
  public function addOptionsToUserEditProfile( $user ) {
56
- $mfaCon = $this->getMfaCon();
57
- $con = $mfaCon->getCon();
58
- $WPU = Services::WpUsers();
59
- $pluginName = $con->getHumanName();
60
-
61
- $providers = array_map(
62
- function ( $provider ) {
63
- return $provider->getProviderName();
64
- },
65
- $mfaCon->getProvidersForUser( $user, true )
66
- );
67
-
68
- echo $mfaCon->getMod()
69
- ->renderTemplate(
70
- '/admin/user/profile/mfa/remove_for_other_user.twig',
71
- [
72
- 'flags' => [
73
- 'has_factors' => count( $providers ) > 0,
74
- 'is_admin_profile' => $WPU->isUserAdmin( $user ),
75
- 'can_remove' => $con->isPluginAdmin() || !$WPU->isUserAdmin( $user ),
76
- ],
77
- 'vars' => [
78
- 'user_id' => $user->ID,
79
- 'mfa_factor_names' => $providers,
80
- ],
81
- 'strings' => [
82
- 'title' => __( 'Multi-Factor Authentication', 'wp-simple-firewall' ),
83
- 'provided_by' => sprintf( __( 'Provided by %s', 'wp-simple-firewall' ), $pluginName ),
84
- 'currently_active' => __( 'Currently active MFA Providers on this profile are' ),
85
- 'remove_all' => __( 'Remove All MFA Providers' ),
86
- 'remove_all_from' => __( 'Remove All MFA Providers From This User Profile' ),
87
- 'remove_warning' => __( "Certain providers may not be removed if they're enforced." ),
88
- 'no_providers' => __( 'There are no MFA providers active on this user account.' ),
89
- 'only_secadmin' => sprintf( __( 'Only %s Security Admins may modify the MFA settings of another admin account.' ),
90
- $pluginName ),
91
- 'authenticate' => sprintf( __( 'You may authenticate with the %s Security Admin system and return here.' ),
92
- $pluginName ),
93
- ],
94
- ],
95
- true
96
- );
97
  }
98
  }
2
 
3
  namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\LoginGuard\Lib\TwoFactor;
4
 
5
+ use FernleafSystems\Utilities\Logic\ExecOnce;
6
  use FernleafSystems\Wordpress\Plugin\Shield;
 
7
 
8
+ /**
9
+ * @deprecated 13.0.5
10
+ */
11
  class UserProfile {
12
 
13
  use MfaControllerConsumer;
14
+ use ExecOnce;
15
 
16
+ protected function run() {
 
 
 
 
17
  }
18
 
19
  /**
22
  * @param \WP_User $user
23
  */
24
  public function addOptionsToUserProfile( $user ) {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
25
  }
26
 
27
  /**
29
  * @param \WP_User $user
30
  */
31
  public function addOptionsToUserEditProfile( $user ) {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
32
  }
33
  }
src/lib/src/Modules/LoginGuard/Lib/TwoFactor/ValidateLoginIntentRequest.php CHANGED
@@ -11,7 +11,6 @@ class ValidateLoginIntentRequest {
11
  use MfaControllerConsumer;
12
 
13
  /**
14
- * @return bool
15
  * @throws \Exception
16
  */
17
  public function run() :bool {
11
  use MfaControllerConsumer;
12
 
13
  /**
 
14
  * @throws \Exception
15
  */
16
  public function run() :bool {
src/lib/src/Modules/LoginGuard/ModCon.php CHANGED
@@ -48,6 +48,8 @@ class ModCon extends BaseShield\ModCon {
48
  $opts->setOpt( 'enable_google_recaptcha_login', 'disabled' );
49
  $opts->setOpt( 'enable_login_gasp_check', 'N' );
50
  }
 
 
51
  }
52
 
53
  public function ensureCorrectCaptchaConfig() {
@@ -148,24 +150,12 @@ class ModCon extends BaseShield\ModCon {
148
  }
149
 
150
  /**
151
- * @param bool $bAsOptDefaults
152
- * @return array
153
  */
154
- public function getOptEmailTwoFactorRolesDefaults( $bAsOptDefaults = true ) {
155
- $aTwoAuthRoles = [
156
- 'type' => 'multiple_select',
157
- 0 => __( 'Subscribers', 'wp-simple-firewall' ),
158
- 1 => __( 'Contributors', 'wp-simple-firewall' ),
159
- 2 => __( 'Authors', 'wp-simple-firewall' ),
160
- 3 => __( 'Editors', 'wp-simple-firewall' ),
161
- 8 => __( 'Administrators', 'wp-simple-firewall' )
162
- ];
163
- if ( $bAsOptDefaults ) {
164
- unset( $aTwoAuthRoles[ 'type' ] );
165
- unset( $aTwoAuthRoles[ 0 ] );
166
- return array_keys( $aTwoAuthRoles );
167
- }
168
- return $aTwoAuthRoles;
169
  }
170
 
171
  public function getGaspKey() :string {
48
  $opts->setOpt( 'enable_google_recaptcha_login', 'disabled' );
49
  $opts->setOpt( 'enable_login_gasp_check', 'N' );
50
  }
51
+
52
+ $opts->setOpt( 'two_factor_auth_user_roles', $opts->getEmail2FaRoles() );
53
  }
54
 
55
  public function ensureCorrectCaptchaConfig() {
150
  }
151
 
152
  /**
153
+ * @deprecated 13.0.5
 
154
  */
155
+ public function getOptEmailTwoFactorRolesDefaults() {
156
+ /** @var Options $opts */
157
+ $opts = $this->getOptions();
158
+ return $opts->getEmail2FaRoles();
 
 
 
 
 
 
 
 
 
 
 
159
  }
160
 
161
  public function getGaspKey() :string {
src/lib/src/Modules/LoginGuard/Options.php CHANGED
@@ -31,17 +31,15 @@ class Options extends BaseShield\Options {
31
  }
32
 
33
  public function getEmail2FaRoles() :array {
34
- /** @var ModCon $mod */
35
- $mod = $this->getMod();
36
- $roles = $this->getOpt( 'two_factor_auth_user_roles', [] );
37
- if ( empty( $roles ) || !is_array( $roles ) ) {
38
- $roles = $mod->getOptEmailTwoFactorRolesDefaults();
39
- $this->setOpt( 'two_factor_auth_user_roles', $roles );
40
- }
41
- if ( $this->isPremium() ) {
42
- $roles = apply_filters( 'odp-shield-2fa_email_user_roles', $roles );
43
- }
44
- return is_array( $roles ) ? $roles : $mod->getOptEmailTwoFactorRolesDefaults();
45
  }
46
 
47
  public function getIfCanSendEmailVerified() :bool {
31
  }
32
 
33
  public function getEmail2FaRoles() :array {
34
+ /** @var Options $opts */
35
+ $opts = $this->getOptions();
36
+ $roles = apply_filters(
37
+ 'shield/2fa_email_enforced_user_roles',
38
+ apply_filters( 'odp-shield-2fa_email_user_roles', $this->getOpt( 'two_factor_auth_user_roles' ) )
39
+ );
40
+ return array_unique( array_filter( array_map( 'sanitize_key',
41
+ is_array( $roles ) ? $roles : $opts->getOptDefault( 'two_factor_auth_user_roles' )
42
+ ) ) );
 
 
43
  }
44
 
45
  public function getIfCanSendEmailVerified() :bool {
src/lib/src/Modules/LoginGuard/Processor.php CHANGED
@@ -15,24 +15,33 @@ class Processor extends BaseShield\Processor {
15
  if ( Services::WpGeneral()->isXmlrpc() && $mod->isXmlrpcBypass() ) {
16
  return;
17
  }
18
-
 
 
 
 
 
19
  ( new Lib\Rename\RenameLogin() )
20
  ->setMod( $mod )
21
  ->execute();
22
 
23
- if ( !$mod->isVisitorWhitelisted() ) {
24
-
25
- add_action( 'init', function () {
26
- $this->launchAntiBot();
27
- }, -100 );
28
-
29
- $mod->getLoginIntentController()->execute();
30
- }
31
  }
32
 
33
- private function launchAntiBot() {
34
  ( new Lib\AntiBot\AntibotSetup() )
35
  ->setMod( $this->getMod() )
36
  ->execute();
37
  }
 
 
 
 
 
 
 
 
 
 
 
38
  }
15
  if ( Services::WpGeneral()->isXmlrpc() && $mod->isXmlrpcBypass() ) {
16
  return;
17
  }
18
+ //
19
+ // /** @var Options $opts */
20
+ // $opts = $this->getOptions();
21
+ // var_dump( $opts->getEmail2FaRoles() );
22
+ // die(0);
23
+ //;
24
  ( new Lib\Rename\RenameLogin() )
25
  ->setMod( $mod )
26
  ->execute();
27
 
28
+ $mod->getLoginIntentController()->execute();
 
 
 
 
 
 
 
29
  }
30
 
31
+ public function onWpInit() {
32
  ( new Lib\AntiBot\AntibotSetup() )
33
  ->setMod( $this->getMod() )
34
  ->execute();
35
  }
36
+
37
+ protected function getWpHookPriority( string $hook ) :int {
38
+ switch ( $hook ) {
39
+ case 'init':
40
+ $pri = -100;
41
+ break;
42
+ default:
43
+ $pri = parent::getWpHookPriority( $hook );
44
+ }
45
+ return $pri;
46
+ }
47
  }
src/lib/src/Modules/LoginGuard/Strings.php CHANGED
@@ -3,6 +3,7 @@
3
  namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\LoginGuard;
4
 
5
  use FernleafSystems\Wordpress\Plugin\Shield\Modules\Base;
 
6
 
7
  class Strings extends Base\Strings {
8
 
@@ -215,8 +216,13 @@ class Strings extends Base\Strings {
215
  case 'two_factor_auth_user_roles' :
216
  $name = sprintf( '%s - %s', __( 'Enforce', 'wp-simple-firewall' ), __( 'Email Authentication', 'wp-simple-firewall' ) );
217
  $summary = __( 'All User Roles Subject To Email Authentication', 'wp-simple-firewall' );
218
- $desc = __( 'Enforces email-based authentication on all users with the selected roles.', 'wp-simple-firewall' )
219
- .'<br /><strong>'.sprintf( '%s: %s', __( 'Note', 'wp-simple-firewall' ), sprintf( __( 'This setting only applies to %s.', 'wp-simple-firewall' ), __( 'Email Authentication', 'wp-simple-firewall' ) ) ).'</strong>';
 
 
 
 
 
220
  break;
221
 
222
  case 'enable_google_recaptcha_login' :
3
  namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\LoginGuard;
4
 
5
  use FernleafSystems\Wordpress\Plugin\Shield\Modules\Base;
6
+ use FernleafSystems\Wordpress\Services\Services;
7
 
8
  class Strings extends Base\Strings {
9
 
216
  case 'two_factor_auth_user_roles' :
217
  $name = sprintf( '%s - %s', __( 'Enforce', 'wp-simple-firewall' ), __( 'Email Authentication', 'wp-simple-firewall' ) );
218
  $summary = __( 'All User Roles Subject To Email Authentication', 'wp-simple-firewall' );
219
+ $desc = [
220
+ sprintf( '<strong>%s</strong>: %s', __( 'Important', 'wp-simple-firewall' ), sprintf( __( 'This setting only applies to %s.', 'wp-simple-firewall' ), __( 'Email Authentication', 'wp-simple-firewall' ) ) ),
221
+ __( 'Enforces email-based authentication on all users with the selected roles.', 'wp-simple-firewall' ),
222
+ __( 'If a user has multiple roles assigned to it, all roles will be checked against this list.', 'wp-simple-firewall' ),
223
+ sprintf( '%s:<br /><ul><li><code>%s</code></li></ul>', __( 'All User Roles Available On This Site', 'wp-simple-firewall' ),
224
+ implode( '</code></li><li><code>', Services::WpUsers()->getAvailableUserRoles() ) )
225
+ ];
226
  break;
227
 
228
  case 'enable_google_recaptcha_login' :
src/lib/src/Modules/LoginGuard/UI.php CHANGED
@@ -3,10 +3,34 @@
3
  namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\LoginGuard;
4
 
5
  use FernleafSystems\Wordpress\Plugin\Shield\Modules\BaseShield;
 
6
  use FernleafSystems\Wordpress\Plugin\Shield\Utilities\Time\WorldTimeApi;
 
7
 
8
  class UI extends BaseShield\UI {
9
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
10
  protected function getSectionWarnings( string $section ) :array {
11
  $con = $this->getCon();
12
  /** @var Options $opts */
@@ -20,14 +44,16 @@ class UI extends BaseShield\UI {
20
  $warnings[] = __( "AntiBot detection isn't being applied to your site because you haven't selected any forms to protect, such as Login or Register.", 'wp-simple-firewall' );
21
  }
22
 
 
23
  $installedButNotEnabledProviders = array_filter(
24
- $con->getModule_Integrations()
25
- ->getController_UserForms()
26
- ->getInstalledProviders(),
27
- function ( $provider ) {
28
- return !$provider->isEnabled();
29
  }
30
  );
 
31
  if ( !empty( $installedButNotEnabledProviders ) ) {
32
  $warnings[] = sprintf( __( "%s has an integration available to protect the login forms of a 3rd party plugin you're using: %s", 'wp-simple-firewall' ),
33
  $con->getHumanName(),
@@ -49,18 +75,16 @@ class UI extends BaseShield\UI {
49
  catch ( \Exception $e ) {
50
  }
51
  }
52
-
53
- if ( $section == 'section_2fa_email' ) {
54
-
55
- if ( $opts->isEnabledEmailAuth() && !$opts->getIfCanSendEmailVerified() ) {
56
- $warnings[] = __( "The ability of this site to send email hasn't been verified.", 'wp-simple-firewall' )
57
- .'<br/>'.__( 'Please click to re-save your settings to trigger another verification email.', 'wp-simple-firewall' );
 
 
 
58
  }
59
-
60
- $warnings[] =
61
- __( '2FA by email demands that your WP site is properly configured to send email.', 'wp-simple-firewall' )
62
- .'<br/>'.__( 'This is a common problem and you may get locked out in the future if you ignore this.', 'wp-simple-firewall' )
63
- .' '.sprintf( '<a href="%s" target="_blank" class="alert-link">%s</a>', 'https://shsec.io/dd', trim( __( 'Learn More.', 'wp-simple-firewall' ), '.' ) );
64
  }
65
 
66
  return $warnings;
3
  namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\LoginGuard;
4
 
5
  use FernleafSystems\Wordpress\Plugin\Shield\Modules\BaseShield;
6
+ use FernleafSystems\Wordpress\Plugin\Shield\Modules\Integrations\Lib\Bots\Common\BaseHandler;
7
  use FernleafSystems\Wordpress\Plugin\Shield\Utilities\Time\WorldTimeApi;
8
+ use FernleafSystems\Wordpress\Services\Services;
9
 
10
  class UI extends BaseShield\UI {
11
 
12
+ protected function getSectionNotices( string $section ) :array {
13
+ /** @var Options $opts */
14
+ $opts = $this->getOptions();
15
+
16
+ $notices = [];
17
+
18
+ if ( $section == 'section_2fa_email' ) {
19
+
20
+ if ( $opts->isEnabledEmailAuth() && !$opts->getIfCanSendEmailVerified() ) {
21
+ $notices[] = __( "The ability of this site to send email hasn't been verified.", 'wp-simple-firewall' )
22
+ .'<br/>'.__( 'Please click to re-save your settings to trigger another verification email.', 'wp-simple-firewall' );
23
+ }
24
+
25
+ $notices[] =
26
+ __( '2FA by email demands that your WP site is properly configured to send email.', 'wp-simple-firewall' )
27
+ .'<br/>'.__( 'This is a common problem and you may get locked out in the future if you ignore this.', 'wp-simple-firewall' )
28
+ .' '.sprintf( '<a href="%s" target="_blank" class="alert-link">%s</a>', 'https://shsec.io/dd', trim( __( 'Learn More.', 'wp-simple-firewall' ), '.' ) );
29
+ }
30
+
31
+ return $notices;
32
+ }
33
+
34
  protected function getSectionWarnings( string $section ) :array {
35
  $con = $this->getCon();
36
  /** @var Options $opts */
44
  $warnings[] = __( "AntiBot detection isn't being applied to your site because you haven't selected any forms to protect, such as Login or Register.", 'wp-simple-firewall' );
45
  }
46
 
47
+ $modIntegrations = $con->getModule_Integrations();
48
  $installedButNotEnabledProviders = array_filter(
49
+ $modIntegrations->getController_UserForms()->enumProviders(),
50
+ function ( $providerClass ) use ( $modIntegrations ) {
51
+ /** @var BaseHandler $provider */
52
+ $provider = ( new $providerClass() )->setMod( $modIntegrations );
53
+ return !$provider->isEnabled() && $provider::IsProviderInstalled();
54
  }
55
  );
56
+
57
  if ( !empty( $installedButNotEnabledProviders ) ) {
58
  $warnings[] = sprintf( __( "%s has an integration available to protect the login forms of a 3rd party plugin you're using: %s", 'wp-simple-firewall' ),
59
  $con->getHumanName(),
75
  catch ( \Exception $e ) {
76
  }
77
  }
78
+ elseif ( $section == 'section_2fa_email' ) {
79
+ $nonRoles = array_diff(
80
+ $opts->getEmail2FaRoles(),
81
+ Services::WpUsers()->getAvailableUserRoles()
82
+ );
83
+ if ( count( $nonRoles ) > 0 ) {
84
+ $warnings[] = sprintf( '%s: %s',
85
+ __( "Certain user roles are set for email authentication enforcement that aren't currently available" ),
86
+ implode( ', ', $nonRoles ) );
87
  }
 
 
 
 
 
88
  }
89
 
90
  return $warnings;
src/lib/src/Modules/ModConsumer.php CHANGED
@@ -5,10 +5,6 @@ namespace FernleafSystems\Wordpress\Plugin\Shield\Modules;
5
  use FernleafSystems\Wordpress\Plugin\Shield\Controller\Controller;
6
  use FernleafSystems\Wordpress\Plugin\Shield\Modules;
7
 
8
- /**
9
- * Trait ModConsumer
10
- * @package FernleafSystems\Wordpress\Plugin\Shield\Modules
11
- */
12
  trait ModConsumer {
13
 
14
  /**
5
  use FernleafSystems\Wordpress\Plugin\Shield\Controller\Controller;
6
  use FernleafSystems\Wordpress\Plugin\Shield\Modules;
7
 
 
 
 
 
8
  trait ModConsumer {
9
 
10
  /**
src/lib/src/Modules/OptsConsumer.php CHANGED
@@ -4,10 +4,6 @@ namespace FernleafSystems\Wordpress\Plugin\Shield\Modules;
4
 
5
  use FernleafSystems\Wordpress\Plugin\Shield\Modules\Base\Options;
6
 
7
- /**
8
- * Trait OptsConsumer
9
- * @package FernleafSystems\Wordpress\Plugin\Shield\Modules
10
- */
11
  trait OptsConsumer {
12
 
13
  /**
4
 
5
  use FernleafSystems\Wordpress\Plugin\Shield\Modules\Base\Options;
6
 
 
 
 
 
7
  trait OptsConsumer {
8
 
9
  /**
src/lib/src/Modules/Plugin/AdminNotices.php CHANGED
@@ -179,27 +179,17 @@ class AdminNotices extends Shield\Modules\Base\AdminNotices {
179
  'notice_attributes' => [],
180
  'strings' => [
181
  'yes' => "Yes please! I'd love to join in and learn more",
182
- 'no' => "No thanks, I'm not interested in such groups",
183
- 'your_name' => __( 'Your Name', 'wp-simple-firewall' ),
184
- 'your_email' => __( 'Your Email', 'wp-simple-firewall' ),
185
- 'signup' => __( 'Sign-Up', 'wp-simple-firewall' ),
186
- 'dismiss' => "No thanks, I'm not interested in such informative groups",
187
  'summary' => sprintf( 'The %s team is helping raise awareness of WP Security issues
188
  and to provide guidance with the %s plugin.', $name, $name ),
189
- 'privacy_policy' => sprintf(
190
- 'I certify that I have read and agree to the <a href="%s" target="_blank">Privacy Policy</a>',
191
- $opts->getDef( 'href_privacy_policy' )
192
- ),
193
- 'consent' => __( 'I agree to Ts & Cs', 'wp-simple-firewall' )
194
  ],
195
  'hrefs' => [
196
- 'privacy_policy' => $opts->getDef( 'href_privacy_policy' )
197
  ],
198
  'install_days' => $opts->getInstallationDays(),
199
  'vars' => [
200
  'name' => $user->first_name,
201
  'user_email' => $user->user_email,
202
- 'drip_form_id' => $notice->drip_form_id
203
  ]
204
  ];
205
  }
179
  'notice_attributes' => [],
180
  'strings' => [
181
  'yes' => "Yes please! I'd love to join in and learn more",
182
+ 'dismiss' => "No thanks",
 
 
 
 
183
  'summary' => sprintf( 'The %s team is helping raise awareness of WP Security issues
184
  and to provide guidance with the %s plugin.', $name, $name ),
 
 
 
 
 
185
  ],
186
  'hrefs' => [
187
+ 'form' => 'https://shsec.io/shieldpluginnewsletter'
188
  ],
189
  'install_days' => $opts->getInstallationDays(),
190
  'vars' => [
191
  'name' => $user->first_name,
192
  'user_email' => $user->user_email,
 
193
  ]
194
  ];
195
  }
src/lib/src/Modules/Plugin/Processor.php CHANGED
@@ -74,5 +74,8 @@ class Processor extends BaseShield\Processor {
74
  if ( class_exists( 'AIO_WP_Security' ) && isset( $GLOBALS[ 'aio_wp_security' ] ) ) {
75
  remove_action( 'init', [ $GLOBALS[ 'aio_wp_security' ], 'wp_security_plugin_init' ], 0 );
76
  }
 
 
 
77
  }
78
  }
74
  if ( class_exists( 'AIO_WP_Security' ) && isset( $GLOBALS[ 'aio_wp_security' ] ) ) {
75
  remove_action( 'init', [ $GLOBALS[ 'aio_wp_security' ], 'wp_security_plugin_init' ], 0 );
76
  }
77
+ if ( @function_exists( '\wp_cache_setting' ) ) {
78
+ @wp_cache_setting( 'wp_super_cache_late_init', 1 );
79
+ }
80
  }
81
  }
src/lib/src/Scans/Afs/ResultItem.php CHANGED
@@ -71,7 +71,7 @@ class ResultItem extends Base\ResultItem {
71
  $value = json_encode( $value );
72
  break;
73
  case 'mal_file_lines':
74
- $value = base64_encode( json_encode( $value ) );
75
  break;
76
  case 'mal_sig':
77
  $value = base64_encode( $value );
71
  $value = json_encode( $value );
72
  break;
73
  case 'mal_file_lines':
74
+ $value = base64_encode( json_encode( is_array( $value ) ? $value : [] ) );
75
  break;
76
  case 'mal_sig':
77
  $value = base64_encode( $value );
src/lib/src/ShieldNetApi/HandshakingNonce.php CHANGED
@@ -1,4 +1,4 @@
1
- <?php
2
 
3
  namespace FernleafSystems\Wordpress\Plugin\Shield\ShieldNetApi;
4
 
@@ -33,7 +33,7 @@ class HandshakingNonce {
33
  /**
34
  * @return int[]
35
  */
36
- private function getNonces() {
37
  return $this->getCon()
38
  ->getModule_Plugin()
39
  ->getShieldNetApiController()->vo->nonces;
@@ -42,7 +42,6 @@ class HandshakingNonce {
42
  /**
43
  * Also filters out expired nonces on-save
44
  * @param int[] $nonces
45
- * @return $this
46
  */
47
  private function storeNonces( array $nonces ) {
48
  $snapiCon = $this->getCon()
@@ -55,6 +54,5 @@ class HandshakingNonce {
55
  }
56
  );
57
  $snapiCon->storeVoData();
58
- return $this;
59
  }
60
  }
1
+ <?php declare( strict_types=1 );
2
 
3
  namespace FernleafSystems\Wordpress\Plugin\Shield\ShieldNetApi;
4
 
33
  /**
34
  * @return int[]
35
  */
36
+ private function getNonces() :array {
37
  return $this->getCon()
38
  ->getModule_Plugin()
39
  ->getShieldNetApiController()->vo->nonces;
42
  /**
43
  * Also filters out expired nonces on-save
44
  * @param int[] $nonces
 
45
  */
46
  private function storeNonces( array $nonces ) {
47
  $snapiCon = $this->getCon()
54
  }
55
  );
56
  $snapiCon->storeVoData();
 
57
  }
58
  }
src/lib/src/ShieldNetApi/ShieldNetApiController.php CHANGED
@@ -13,8 +13,6 @@ use FernleafSystems\Wordpress\Plugin\Shield\ShieldNetApi\Reputation\SendIPReputa
13
  use FernleafSystems\Wordpress\Services\Services;
14
 
15
  /**
16
- * Class ShieldNetApiController
17
- * @package FernleafSystems\Wordpress\Plugin\Shield\ShieldNetApi
18
  * @property ShieldNetApiDataVO $vo
19
  */
20
  class ShieldNetApiController extends DynPropertiesClass {
13
  use FernleafSystems\Wordpress\Services\Services;
14
 
15
  /**
 
 
16
  * @property ShieldNetApiDataVO $vo
17
  */
18
  class ShieldNetApiController extends DynPropertiesClass {
src/lib/src/ShieldNetApi/ShieldNetApiDataVO.php CHANGED
@@ -5,8 +5,6 @@ namespace FernleafSystems\Wordpress\Plugin\Shield\ShieldNetApi;
5
  use FernleafSystems\Utilities\Data\Adapter\DynPropertiesClass;
6
 
7
  /**
8
- * Class ShieldNetApiDataVO
9
- * @package FernleafSystems\Wordpress\Plugin\Shield\ShieldNetApi
10
  * @property int $last_handshake_at
11
  * @property int $last_handshake_attempt_at
12
  * @property int $last_send_iprep_at
5
  use FernleafSystems\Utilities\Data\Adapter\DynPropertiesClass;
6
 
7
  /**
 
 
8
  * @property int $last_handshake_at
9
  * @property int $last_handshake_attempt_at
10
  * @property int $last_send_iprep_at
src/lib/vendor/composer/ClassLoader.php CHANGED
@@ -42,75 +42,30 @@ namespace Composer\Autoload;
42
  */
43
  class ClassLoader
44
  {
45
- /** @var ?string */
46
  private $vendorDir;
47
 
48
  // PSR-4
49
- /**
50
- * @var array[]
51
- * @psalm-var array<string, array<string, int>>
52
- */
53
  private $prefixLengthsPsr4 = array();
54
- /**
55
- * @var array[]
56
- * @psalm-var array<string, array<int, string>>
57
- */
58
  private $prefixDirsPsr4 = array();
59
- /**
60
- * @var array[]
61
- * @psalm-var array<string, string>
62
- */
63
  private $fallbackDirsPsr4 = array();
64
 
65
  // PSR-0
66
- /**
67
- * @var array[]
68
- * @psalm-var array<string, array<string, string[]>>
69
- */
70
  private $prefixesPsr0 = array();
71
- /**
72
- * @var array[]
73
- * @psalm-var array<string, string>
74
- */
75
  private $fallbackDirsPsr0 = array();
76
 
77
- /** @var bool */
78
  private $useIncludePath = false;
79
-
80
- /**
81
- * @var string[]
82
- * @psalm-var array<string, string>
83
- */
84
  private $classMap = array();
85
-
86
- /** @var bool */
87
  private $classMapAuthoritative = false;
88
-
89
- /**
90
- * @var bool[]
91
- * @psalm-var array<string, bool>
92
- */
93
  private $missingClasses = array();
94
-
95
- /** @var ?string */
96
  private $apcuPrefix;
97
 
98
- /**
99
- * @var self[]
100
- */
101
  private static $registeredLoaders = array();
102
 
103
- /**
104
- * @param ?string $vendorDir
105
- */
106
  public function __construct($vendorDir = null)
107
  {
108
  $this->vendorDir = $vendorDir;
109
  }
110
 
111
- /**
112
- * @return string[]
113
- */
114
  public function getPrefixes()
115
  {
116
  if (!empty($this->prefixesPsr0)) {
@@ -120,47 +75,28 @@ class ClassLoader
120
  return array();
121
  }
122
 
123
- /**
124
- * @return array[]
125
- * @psalm-return array<string, array<int, string>>
126
- */
127
  public function getPrefixesPsr4()
128
  {
129
  return $this->prefixDirsPsr4;
130
  }
131
 
132
- /**
133
- * @return array[]
134
- * @psalm-return array<string, string>
135
- */
136
  public function getFallbackDirs()
137
  {
138
  return $this->fallbackDirsPsr0;
139
  }
140
 
141
- /**
142
- * @return array[]
143
- * @psalm-return array<string, string>
144
- */
145
  public function getFallbackDirsPsr4()
146
  {
147
  return $this->fallbackDirsPsr4;
148
  }
149
 
150
- /**
151
- * @return string[] Array of classname => path
152
- * @psalm-var array<string, string>
153
- */
154
  public function getClassMap()
155
  {
156
  return $this->classMap;
157
  }
158
 
159
  /**
160
- * @param string[] $classMap Class to filename map
161
- * @psalm-param array<string, string> $classMap
162
- *
163
- * @return void
164
  */
165
  public function addClassMap(array $classMap)
166
  {
@@ -175,11 +111,9 @@ class ClassLoader
175
  * Registers a set of PSR-0 directories for a given prefix, either
176
  * appending or prepending to the ones previously set for this prefix.
177
  *
178
- * @param string $prefix The prefix
179
- * @param string[]|string $paths The PSR-0 root directories
180
- * @param bool $prepend Whether to prepend the directories
181
- *
182
- * @return void
183
  */
184
  public function add($prefix, $paths, $prepend = false)
185
  {
@@ -222,13 +156,11 @@ class ClassLoader
222
  * Registers a set of PSR-4 directories for a given namespace, either
223
  * appending or prepending to the ones previously set for this namespace.
224
  *
225
- * @param string $prefix The prefix/namespace, with trailing '\\'
226
- * @param string[]|string $paths The PSR-4 base directories
227
- * @param bool $prepend Whether to prepend the directories
228
  *
229
  * @throws \InvalidArgumentException
230
- *
231
- * @return void
232
  */
233
  public function addPsr4($prefix, $paths, $prepend = false)
234
  {
@@ -272,10 +204,8 @@ class ClassLoader
272
  * Registers a set of PSR-0 directories for a given prefix,
273
  * replacing any others previously set for this prefix.
274
  *
275
- * @param string $prefix The prefix
276
- * @param string[]|string $paths The PSR-0 base directories
277
- *
278
- * @return void
279
  */
280
  public function set($prefix, $paths)
281
  {
@@ -290,12 +220,10 @@ class ClassLoader
290
  * Registers a set of PSR-4 directories for a given namespace,
291
  * replacing any others previously set for this namespace.
292
  *
293
- * @param string $prefix The prefix/namespace, with trailing '\\'
294
- * @param string[]|string $paths The PSR-4 base directories
295
  *
296
  * @throws \InvalidArgumentException
297
- *
298
- * @return void
299
  */
300
  public function setPsr4($prefix, $paths)
301
  {
@@ -315,8 +243,6 @@ class ClassLoader
315
  * Turns on searching the include path for class files.
316
  *
317
  * @param bool $useIncludePath
318
- *
319
- * @return void
320
  */
321
  public function setUseIncludePath($useIncludePath)
322
  {
@@ -339,8 +265,6 @@ class ClassLoader
339
  * that have not been registered with the class map.
340
  *
341
  * @param bool $classMapAuthoritative
342
- *
343
- * @return void
344
  */
345
  public function setClassMapAuthoritative($classMapAuthoritative)
346
  {
@@ -361,8 +285,6 @@ class ClassLoader
361
  * APCu prefix to use to cache found/not-found classes, if the extension is enabled.
362
  *
363
  * @param string|null $apcuPrefix
364
- *
365
- * @return void
366
  */
367
  public function setApcuPrefix($apcuPrefix)
368
  {
@@ -383,18 +305,14 @@ class ClassLoader
383
  * Registers this instance as an autoloader.
384
  *
385
  * @param bool $prepend Whether to prepend the autoloader or not
386
- *
387
- * @return void
388
  */
389
  public function register($prepend = false)
390
  {
391
  spl_autoload_register(array($this, 'loadClass'), true, $prepend);
392
 
393
  if (null === $this->vendorDir) {
394
- return;
395
- }
396
-
397
- if ($prepend) {
398
  self::$registeredLoaders = array($this->vendorDir => $this) + self::$registeredLoaders;
399
  } else {
400
  unset(self::$registeredLoaders[$this->vendorDir]);
@@ -404,8 +322,6 @@ class ClassLoader
404
 
405
  /**
406
  * Unregisters this instance as an autoloader.
407
- *
408
- * @return void
409
  */
410
  public function unregister()
411
  {
@@ -420,7 +336,7 @@ class ClassLoader
420
  * Loads the given class or interface.
421
  *
422
  * @param string $class The name of the class
423
- * @return true|null True if loaded, null otherwise
424
  */
425
  public function loadClass($class)
426
  {
@@ -429,8 +345,6 @@ class ClassLoader
429
 
430
  return true;
431
  }
432
-
433
- return null;
434
  }
435
 
436
  /**
@@ -485,11 +399,6 @@ class ClassLoader
485
  return self::$registeredLoaders;
486
  }
487
 
488
- /**
489
- * @param string $class
490
- * @param string $ext
491
- * @return string|false
492
- */
493
  private function findFileWithExtension($class, $ext)
494
  {
495
  // PSR-4 lookup
@@ -561,10 +470,6 @@ class ClassLoader
561
  * Scope isolated include.
562
  *
563
  * Prevents access to $this/self from included files.
564
- *
565
- * @param string $file
566
- * @return void
567
- * @private
568
  */
569
  function includeFile($file)
570
  {
42
  */
43
  class ClassLoader
44
  {
 
45
  private $vendorDir;
46
 
47
  // PSR-4
 
 
 
 
48
  private $prefixLengthsPsr4 = array();
 
 
 
 
49
  private $prefixDirsPsr4 = array();
 
 
 
 
50
  private $fallbackDirsPsr4 = array();
51
 
52
  // PSR-0
 
 
 
 
53
  private $prefixesPsr0 = array();
 
 
 
 
54
  private $fallbackDirsPsr0 = array();
55
 
 
56
  private $useIncludePath = false;
 
 
 
 
 
57
  private $classMap = array();
 
 
58
  private $classMapAuthoritative = false;
 
 
 
 
 
59
  private $missingClasses = array();
 
 
60
  private $apcuPrefix;
61
 
 
 
 
62
  private static $registeredLoaders = array();
63
 
 
 
 
64
  public function __construct($vendorDir = null)
65
  {
66
  $this->vendorDir = $vendorDir;
67
  }
68
 
 
 
 
69
  public function getPrefixes()
70
  {
71
  if (!empty($this->prefixesPsr0)) {
75
  return array();
76
  }
77
 
 
 
 
 
78
  public function getPrefixesPsr4()
79
  {
80
  return $this->prefixDirsPsr4;
81
  }
82
 
 
 
 
 
83
  public function getFallbackDirs()
84
  {
85
  return $this->fallbackDirsPsr0;
86
  }
87
 
 
 
 
 
88
  public function getFallbackDirsPsr4()
89
  {
90
  return $this->fallbackDirsPsr4;
91
  }
92
 
 
 
 
 
93
  public function getClassMap()
94
  {
95
  return $this->classMap;
96
  }
97
 
98
  /**
99
+ * @param array $classMap Class to filename map
 
 
 
100
  */
101
  public function addClassMap(array $classMap)
102
  {
111
  * Registers a set of PSR-0 directories for a given prefix, either
112
  * appending or prepending to the ones previously set for this prefix.
113
  *
114
+ * @param string $prefix The prefix
115
+ * @param array|string $paths The PSR-0 root directories
116
+ * @param bool $prepend Whether to prepend the directories
 
 
117
  */
118
  public function add($prefix, $paths, $prepend = false)
119
  {
156
  * Registers a set of PSR-4 directories for a given namespace, either
157
  * appending or prepending to the ones previously set for this namespace.
158
  *
159
+ * @param string $prefix The prefix/namespace, with trailing '\\'
160
+ * @param array|string $paths The PSR-4 base directories
161
+ * @param bool $prepend Whether to prepend the directories
162
  *
163
  * @throws \InvalidArgumentException
 
 
164
  */
165
  public function addPsr4($prefix, $paths, $prepend = false)
166
  {
204
  * Registers a set of PSR-0 directories for a given prefix,
205
  * replacing any others previously set for this prefix.
206
  *
207
+ * @param string $prefix The prefix
208
+ * @param array|string $paths The PSR-0 base directories
 
 
209
  */
210
  public function set($prefix, $paths)
211
  {
220
  * Registers a set of PSR-4 directories for a given namespace,
221
  * replacing any others previously set for this namespace.
222
  *
223
+ * @param string $prefix The prefix/namespace, with trailing '\\'
224
+ * @param array|string $paths The PSR-4 base directories
225
  *
226
  * @throws \InvalidArgumentException
 
 
227
  */
228
  public function setPsr4($prefix, $paths)
229
  {
243
  * Turns on searching the include path for class files.
244
  *
245
  * @param bool $useIncludePath
 
 
246
  */
247
  public function setUseIncludePath($useIncludePath)
248
  {
265
  * that have not been registered with the class map.
266
  *
267
  * @param bool $classMapAuthoritative
 
 
268
  */
269
  public function setClassMapAuthoritative($classMapAuthoritative)
270
  {
285
  * APCu prefix to use to cache found/not-found classes, if the extension is enabled.
286
  *
287
  * @param string|null $apcuPrefix
 
 
288
  */
289
  public function setApcuPrefix($apcuPrefix)
290
  {
305
  * Registers this instance as an autoloader.
306
  *
307
  * @param bool $prepend Whether to prepend the autoloader or not
 
 
308
  */
309
  public function register($prepend = false)
310
  {
311
  spl_autoload_register(array($this, 'loadClass'), true, $prepend);
312
 
313
  if (null === $this->vendorDir) {
314
+ //no-op
315
+ } elseif ($prepend) {
 
 
316
  self::$registeredLoaders = array($this->vendorDir => $this) + self::$registeredLoaders;
317
  } else {
318
  unset(self::$registeredLoaders[$this->vendorDir]);
322
 
323
  /**
324
  * Unregisters this instance as an autoloader.
 
 
325
  */
326
  public function unregister()
327
  {
336
  * Loads the given class or interface.
337
  *
338
  * @param string $class The name of the class
339
+ * @return bool|null True if loaded, null otherwise
340
  */
341
  public function loadClass($class)
342
  {
345
 
346
  return true;
347
  }
 
 
348
  }
349
 
350
  /**
399
  return self::$registeredLoaders;
400
  }
401
 
 
 
 
 
 
402
  private function findFileWithExtension($class, $ext)
403
  {
404
  // PSR-4 lookup
470
  * Scope isolated include.
471
  *
472
  * Prevents access to $this/self from included files.
 
 
 
 
473
  */
474
  function includeFile($file)
475
  {
src/lib/vendor/fernleafsystems/wordpress-services/src/Utilities/Email.php CHANGED
@@ -7,8 +7,6 @@ use FernleafSystems\Wordpress\Services\Services;
7
  use Html2Text\Html2Text;
8
 
9
  /**
10
- * Class Email
11
- * @package FernleafSystems\Wordpress\Services\Utilities
12
  * @property string $to_email
13
  * @property string $to_name
14
  * @property string $from_email
7
  use Html2Text\Html2Text;
8
 
9
  /**
 
 
10
  * @property string $to_email
11
  * @property string $to_name
12
  * @property string $from_email
src/lib/vendor/fernleafsystems/wordpress-services/src/Utilities/GeoIp.php CHANGED
@@ -4,10 +4,6 @@ namespace FernleafSystems\Wordpress\Services\Utilities;
4
 
5
  use FernleafSystems\Wordpress\Services\Services;
6
 
7
- /**
8
- * Class GeoIp
9
- * @package FernleafSystems\Wordpress\Services\Utilities
10
- */
11
  class GeoIp {
12
 
13
  const URL_REDIRECTLI = 'https://api.redirect.li/v1/ip/';
4
 
5
  use FernleafSystems\Wordpress\Services\Services;
6
 
 
 
 
 
7
  class GeoIp {
8
 
9
  const URL_REDIRECTLI = 'https://api.redirect.li/v1/ip/';
src/lib/vendor/fernleafsystems/wordpress-services/src/Utilities/Html.php CHANGED
@@ -2,10 +2,6 @@
2
 
3
  namespace FernleafSystems\Wordpress\Services\Utilities;
4
 
5
- /**
6
- * Class Html
7
- * @package FernleafSystems\Wordpress\Services\Utilities
8
- */
9
  class Html {
10
 
11
  /**
2
 
3
  namespace FernleafSystems\Wordpress\Services\Utilities;
4
 
 
 
 
 
5
  class Html {
6
 
7
  /**
src/lib/vendor/fernleafsystems/wordpress-services/src/Utilities/Licenses/EddLicenseVO.php CHANGED
@@ -6,8 +6,6 @@ use FernleafSystems\Utilities\Data\Adapter\DynPropertiesClass;
6
  use FernleafSystems\Wordpress\Services\Services;
7
 
8
  /**
9
- * Class EddLicenseVO
10
- * @package FernleafSystems\Wordpress\Services\Utilities\Licenses
11
  * @property int $activations_left
12
  * @property string $customer_email
13
  * @property string $checksum
@@ -21,6 +19,7 @@ use FernleafSystems\Wordpress\Services\Services;
21
  * @property int $site_count
22
  * @property string $license
23
  * @property string $payment_id
 
24
  * @property bool $success
25
  * @property bool $is_staging
26
  * @property bool $has_support
6
  use FernleafSystems\Wordpress\Services\Services;
7
 
8
  /**
 
 
9
  * @property int $activations_left
10
  * @property string $customer_email
11
  * @property string $checksum
19
  * @property int $site_count
20
  * @property string $license
21
  * @property string $payment_id
22
+ * @property string $url
23
  * @property bool $success
24
  * @property bool $is_staging
25
  * @property bool $has_support
src/lib/vendor/fernleafsystems/wordpress-services/src/Utilities/Obfuscate.php CHANGED
@@ -4,10 +4,6 @@ namespace FernleafSystems\Wordpress\Services\Utilities;
4
 
5
  class Obfuscate {
6
 
7
- /**
8
- * @param string $email
9
- * @return string
10
- */
11
  public static function Email( string $email ) :string {
12
  list( $left, $right ) = explode( '@', $email, 2 );
13
  return substr( $left, 0, 1 ).'****'.substr( $left, -1, 1 )
4
 
5
  class Obfuscate {
6
 
 
 
 
 
7
  public static function Email( string $email ) :string {
8
  list( $left, $right ) = explode( '@', $email, 2 );
9
  return substr( $left, 0, 1 ).'****'.substr( $left, -1, 1 )
src/lib/vendor/fernleafsystems/wordpress-services/src/Utilities/ServiceProviders.php CHANGED
@@ -9,10 +9,6 @@ use FernleafSystems\Wordpress\Services\Utilities\Integrations\WpHashes\Services\
9
  };
10
  use FernleafSystems\Wordpress\Services\Utilities\Options\Transient;
11
 
12
- /**
13
- * Class ServiceProviders
14
- * @package FernleafSystems\Wordpress\Services\Utilities
15
- */
16
  class ServiceProviders {
17
 
18
  /**
9
  };
10
  use FernleafSystems\Wordpress\Services\Utilities\Options\Transient;
11
 
 
 
 
 
12
  class ServiceProviders {
13
 
14
  /**
templates/twig/admin/user/profile/mfa/mfa_container.twig DELETED
@@ -1,12 +0,0 @@
1
- <div id="shield-options-mfa-authentication" class="shield-user-options-block">
2
- <h3>{{ strings.title }}<small style="margin-left: 10px">({{ strings.provided_by }})</small></h3>
3
-
4
- <table class="form-table">
5
- <tbody>
6
- {% for mfa_slug,mfa_row in mfa_rows %}
7
- {{ mfa_row|raw }}
8
- {% endfor %}
9
- </tbody>
10
- </table>
11
- </div>
12
- {% include '/admin/user/profile/mfa/mfa_dialog.twig' %}
 
 
 
 
 
 
 
 
 
 
 
 
templates/twig/admin/user/profile/mfa/mfa_email.twig CHANGED
@@ -4,7 +4,7 @@
4
  height: 34px;
5
  position: relative;
6
  width: 60px;
7
- margin: 20px;
8
  }
9
  .switch.disabled {
10
  opacity: 0.5;
4
  height: 34px;
5
  position: relative;
6
  width: 60px;
7
+ margin: 0 20px;
8
  }
9
  .switch.disabled {
10
  opacity: 0.5;
templates/twig/components/options_form/main.twig CHANGED
@@ -78,7 +78,7 @@
78
  {% for section_notice in opt_section.notices %}
79
  <div class="row">
80
  <div class="col">
81
- <div class="alert alert-success text-center">{{ section_notice|raw }}</div>
82
  </div>
83
  </div>
84
  {% endfor %}
78
  {% for section_notice in opt_section.notices %}
79
  <div class="row">
80
  <div class="col">
81
+ <div class="alert alert-info text-center">{{ section_notice|raw }}</div>
82
  </div>
83
  </div>
84
  {% endfor %}
templates/twig/notices/plugin-mailing-list-signup.twig CHANGED
@@ -3,12 +3,8 @@
3
  {% block notice_body %}
4
  <div class="row">
5
  <div class="col">
6
- {% include '/snippets/optin_form_drip_inline.twig' %}
7
- </div>
8
- </div>
9
- <div class="row">
10
- <div class="col">
11
- {{ strings.summary }}
12
  </div>
13
  </div>
14
  {% endblock %}
3
  {% block notice_body %}
4
  <div class="row">
5
  <div class="col">
6
+ <p>{{ strings.summary }}</p>
7
+ <p><a class="button" target="_blank" href="{{ hrefs.form }}">{{ strings.yes }}</a></p>
 
 
 
 
8
  </div>
9
  </div>
10
  {% endblock %}
templates/twig/user/profile/mfa/main.twig CHANGED
@@ -1,6 +1,11 @@
1
  <div id="ShieldUserProfileMFA">
2
 
3
- <h3>{{ strings.title }}</h3>
 
 
 
 
 
4
 
5
  <table>
6
  {% if flags.logged_in %}
1
  <div id="ShieldUserProfileMFA">
2
 
3
+ <h3>
4
+ {{ strings.title }}
5
+ {% if strings.subtitle|default('') is not empty %}
6
+ <small style="margin-left: 10px">({{ strings.subtitle }})</small>
7
+ {% endif %}
8
+ </h3>
9
 
10
  <table>
11
  {% if flags.logged_in %}